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);
122 backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
124 /* setup basic packing characteristics for the table used on the main
125 * tab of the notebook
128 basic_packer.set_spacings (6);
129 basic_packer.set_border_width (12);
130 basic_packer.set_homogeneous (false);
134 basic_hbox.pack_start (basic_packer, false, false);
136 /* latency measurement tab */
138 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
141 lm_table.set_row_spacings (12);
142 lm_table.set_col_spacings (6);
143 lm_table.set_homogeneous (false);
145 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
148 lm_preamble.set_width_chars (60);
149 lm_preamble.set_line_wrap (true);
150 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
152 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
155 Gtk::Label* preamble;
156 preamble = manage (new Label);
157 preamble->set_width_chars (60);
158 preamble->set_line_wrap (true);
159 preamble->set_markup (_("Select two channels below and connect them using a cable."));
161 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
164 label = manage (new Label (_("Output channel")));
165 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
167 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
168 misc_align->add (lm_output_channel_combo);
169 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
172 label = manage (new Label (_("Input channel")));
173 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
175 misc_align = manage (new Alignment (0.0, 0.5));
176 misc_align->add (lm_input_channel_combo);
177 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
180 xopt = AttachOptions(0);
182 lm_measure_label.set_padding (10, 10);
183 lm_measure_button.add (lm_measure_label);
184 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
185 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
186 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
188 lm_use_button.set_sensitive (false);
190 /* Increase the default spacing around the labels of these three
196 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
197 l->set_padding (10, 10);
200 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
201 l->set_padding (10, 10);
204 preamble = manage (new Label);
205 preamble->set_width_chars (60);
206 preamble->set_line_wrap (true);
207 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
208 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
211 preamble = manage (new Label);
212 preamble->set_width_chars (60);
213 preamble->set_line_wrap (true);
214 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
215 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
217 ++row; // skip a row in the table
218 ++row; // skip a row in the table
220 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
222 ++row; // skip a row in the table
223 ++row; // skip a row in the table
225 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
226 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
227 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
229 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
231 lm_vbox.set_border_width (12);
232 lm_vbox.pack_start (lm_table, false, false);
234 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
238 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
239 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
240 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
241 notebook.set_border_width (12);
243 notebook.set_show_tabs (false);
244 notebook.show_all ();
246 notebook.set_name ("SettingsNotebook");
248 /* packup the notebook */
250 get_vbox()->set_border_width (12);
251 get_vbox()->pack_start (notebook);
253 get_action_area()->pack_start (engine_status);
254 engine_status.show();
256 /* need a special function to print "all available channels" when the
257 * channel counts hit zero.
260 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
261 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
263 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
264 midi_devices_button.set_sensitive (false);
265 midi_devices_button.set_name ("generic button");
266 midi_devices_button.set_can_focus(true);
268 control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
269 manage_control_app_sensitivity ();
271 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
272 apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
273 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
275 /* Pick up any existing audio setup configuration, if appropriate */
277 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
279 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
280 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
281 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
282 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
285 set_state (*audio_setup);
288 if (backend_combo.get_active_text().empty()) {
289 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
290 backend_combo.set_active_text (backend_names.front());
295 /* in case the setting the backend failed, e.g. stale config, from set_state(), try again */
296 if (0 == ARDOUR::AudioEngine::instance()->current_backend()) {
297 backend_combo.set_active_text (backend_names.back());
298 /* ignore: don't save state */
299 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
304 /* Connect to signals */
306 driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
307 sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
308 buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
309 device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed));
310 midi_option_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::midi_option_changed));
312 input_device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::input_device_changed));
313 output_device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::output_device_changed));
315 input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
316 output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
317 input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
318 output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
320 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
322 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
323 connect_disconnect_button.set_no_show_all();
328 EngineControl::on_show ()
330 ArdourDialog::on_show ();
331 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
332 // re-check _have_control (jackd running) see #6041
336 input_device_changed ();
337 output_device_changed ();
338 ok_button->grab_focus();
342 EngineControl::on_response (int response_id)
344 ArdourDialog::on_response (response_id);
346 switch (response_id) {
348 push_state_to_backend (true);
351 #ifdef PLATFORM_WINDOWS
352 // For some reason we don't understand, 'hide()'
353 // needs to get called first in Windows
356 // But if there's no session open, this can produce
357 // a long gap when nothing appears to be happening.
358 // Let's show the splash image while we're waiting.
359 if ( !ARDOUR_COMMAND_LINE::no_splash ) {
360 if ( ARDOUR_UI::instance() ) {
361 if ( !ARDOUR_UI::instance()->session_loaded ) {
362 ARDOUR_UI::instance()->show_splash();
366 push_state_to_backend (true);
369 push_state_to_backend (true);
373 case RESPONSE_DELETE_EVENT:
376 ev.type = GDK_BUTTON_PRESS;
378 on_delete_event ((GdkEventAny*) &ev);
387 EngineControl::build_notebook ()
390 AttachOptions xopt = AttachOptions (FILL|EXPAND);
392 /* clear the table */
394 Gtkmm2ext::container_clear (basic_vbox);
395 Gtkmm2ext::container_clear (basic_packer);
397 if (control_app_button.get_parent()) {
398 control_app_button.get_parent()->remove (control_app_button);
401 label = manage (left_aligned_label (_("Audio System:")));
402 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
403 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
405 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
406 lm_button_audio.set_name ("generic button");
407 lm_button_audio.set_can_focus(true);
410 build_full_control_notebook ();
412 build_no_control_notebook ();
415 basic_vbox.pack_start (basic_hbox, false, false);
418 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
419 basic_vbox.show_all ();
424 EngineControl::build_full_control_notebook ()
426 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
429 using namespace Notebook_Helpers;
431 vector<string> strings;
432 AttachOptions xopt = AttachOptions (FILL|EXPAND);
433 int row = 1; // row zero == backend combo
435 /* start packing it up */
437 if (backend->requires_driver_selection()) {
438 label = manage (left_aligned_label (_("Driver:")));
439 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
440 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
444 if (backend->use_separate_input_and_output_devices()) {
445 label = manage (left_aligned_label (_("Input Device:")));
446 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
447 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
449 label = manage (left_aligned_label (_("Output Device:")));
450 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
451 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
453 // reset so it isn't used in state comparisons
454 device_combo.set_active_text ("");
456 label = manage (left_aligned_label (_("Device:")));
457 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
458 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
460 // reset these so they don't get used in state comparisons
461 input_device_combo.set_active_text ("");
462 output_device_combo.set_active_text ("");
465 label = manage (left_aligned_label (_("Sample rate:")));
466 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
467 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
471 label = manage (left_aligned_label (_("Buffer size:")));
472 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
473 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
474 buffer_size_duration_label.set_alignment (0.0); /* left-align */
475 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
477 /* button spans 2 rows */
479 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
482 input_channels.set_name ("InputChannels");
483 input_channels.set_flags (Gtk::CAN_FOCUS);
484 input_channels.set_digits (0);
485 input_channels.set_wrap (false);
486 output_channels.set_editable (true);
488 if (!ARDOUR::Profile->get_mixbus()) {
489 label = manage (left_aligned_label (_("Input Channels:")));
490 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
491 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
495 output_channels.set_name ("OutputChannels");
496 output_channels.set_flags (Gtk::CAN_FOCUS);
497 output_channels.set_digits (0);
498 output_channels.set_wrap (false);
499 output_channels.set_editable (true);
501 if (!ARDOUR::Profile->get_mixbus()) {
502 label = manage (left_aligned_label (_("Output Channels:")));
503 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
504 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
508 input_latency.set_name ("InputLatency");
509 input_latency.set_flags (Gtk::CAN_FOCUS);
510 input_latency.set_digits (0);
511 input_latency.set_wrap (false);
512 input_latency.set_editable (true);
514 label = manage (left_aligned_label (_("Hardware input latency:")));
515 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
516 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
517 label = manage (left_aligned_label (_("samples")));
518 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
521 output_latency.set_name ("OutputLatency");
522 output_latency.set_flags (Gtk::CAN_FOCUS);
523 output_latency.set_digits (0);
524 output_latency.set_wrap (false);
525 output_latency.set_editable (true);
527 label = manage (left_aligned_label (_("Hardware output latency:")));
528 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
529 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
530 label = manage (left_aligned_label (_("samples")));
531 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
533 /* button spans 2 rows */
535 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
538 label = manage (left_aligned_label (_("MIDI System:")));
539 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
540 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
541 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
546 EngineControl::build_no_control_notebook ()
548 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
551 using namespace Notebook_Helpers;
553 vector<string> strings;
554 AttachOptions xopt = AttachOptions (FILL|EXPAND);
555 int row = 1; // row zero == backend combo
556 const string msg = string_compose (_("The %1 audio backend was configured and started externally.\nThis limits your control over it."), backend->name());
558 label = manage (new Label);
559 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
560 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
563 if (backend->can_change_sample_rate_when_running()) {
564 label = manage (left_aligned_label (_("Sample rate:")));
565 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
566 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
570 if (backend->can_change_buffer_size_when_running()) {
571 label = manage (left_aligned_label (_("Buffer size:")));
572 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
573 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
574 buffer_size_duration_label.set_alignment (0.0); /* left-align */
575 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
579 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
583 EngineControl::~EngineControl ()
585 ignore_changes = true;
589 EngineControl::disable_latency_tab ()
591 vector<string> empty;
592 set_popdown_strings (lm_output_channel_combo, empty);
593 set_popdown_strings (lm_input_channel_combo, empty);
594 lm_measure_button.set_sensitive (false);
595 lm_use_button.set_sensitive (false);
599 EngineControl::enable_latency_tab ()
601 vector<string> outputs;
602 vector<string> inputs;
604 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
605 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
606 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
608 if (!ARDOUR::AudioEngine::instance()->running()) {
609 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
610 notebook.set_current_page (0);
614 else if (inputs.empty() || outputs.empty()) {
615 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
616 notebook.set_current_page (0);
621 lm_back_button_signal.disconnect();
623 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
626 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
630 set_popdown_strings (lm_output_channel_combo, outputs);
631 lm_output_channel_combo.set_active_text (outputs.front());
632 lm_output_channel_combo.set_sensitive (true);
634 set_popdown_strings (lm_input_channel_combo, inputs);
635 lm_input_channel_combo.set_active_text (inputs.front());
636 lm_input_channel_combo.set_sensitive (true);
638 lm_measure_button.set_sensitive (true);
642 EngineControl::setup_midi_tab_for_backend ()
644 string backend = backend_combo.get_active_text ();
646 Gtkmm2ext::container_clear (midi_vbox);
648 midi_vbox.set_border_width (12);
649 midi_device_table.set_border_width (12);
651 if (backend == "JACK") {
652 setup_midi_tab_for_jack ();
655 midi_vbox.pack_start (midi_device_table, true, true);
656 midi_vbox.pack_start (midi_back_button, false, false);
657 midi_vbox.show_all ();
661 EngineControl::setup_midi_tab_for_jack ()
666 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
668 device->input_latency = a->get_value();
670 device->output_latency = a->get_value();
675 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
676 b->set_active (!b->get_active());
677 device->enabled = b->get_active();
678 refresh_midi_display(device->name);
682 EngineControl::refresh_midi_display (std::string focus)
684 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
688 AttachOptions xopt = AttachOptions (FILL|EXPAND);
691 Gtkmm2ext::container_clear (midi_device_table);
693 midi_device_table.set_spacings (6);
695 l = manage (new Label);
696 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
697 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
698 l->set_alignment (0.5, 0.5);
702 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
703 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
704 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
705 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
707 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
708 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
709 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
710 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
713 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
718 bool enabled = (*p)->enabled;
720 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
721 m->set_name ("midi device");
722 m->set_can_focus (Gtk::CAN_FOCUS);
723 m->add_events (Gdk::BUTTON_RELEASE_MASK);
724 m->set_active (enabled);
725 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
726 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
727 if ((*p)->name == focus) {
731 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
732 s = manage (new Gtk::SpinButton (*a));
733 a->set_value ((*p)->input_latency);
734 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
735 s->set_sensitive (_can_set_midi_latencies && enabled);
736 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
738 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
739 s = manage (new Gtk::SpinButton (*a));
740 a->set_value ((*p)->output_latency);
741 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
742 s->set_sensitive (_can_set_midi_latencies && enabled);
743 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
745 b = manage (new Button (_("Calibrate")));
746 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
747 b->set_sensitive (_can_set_midi_latencies && enabled);
748 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
755 EngineControl::update_sensitivity ()
760 EngineControl::backend_changed ()
762 string backend_name = backend_combo.get_active_text();
763 boost::shared_ptr<ARDOUR::AudioBackend> backend;
765 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
766 /* eh? setting the backend failed... how ? */
767 /* A: stale config contains a backend that does not exist in current build */
771 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
774 setup_midi_tab_for_backend ();
775 _midi_devices.clear();
777 if (backend->requires_driver_selection()) {
778 vector<string> drivers = backend->enumerate_drivers();
779 driver_combo.set_sensitive (true);
781 if (!drivers.empty()) {
783 string current_driver;
784 current_driver = backend->driver_name ();
786 // driver might not have been set yet
787 if (current_driver == "") {
788 current_driver = driver_combo.get_active_text ();
789 if (current_driver == "")
790 // driver has never been set, make sure it's not blank
791 current_driver = drivers.front ();
794 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
795 set_popdown_strings (driver_combo, drivers);
796 driver_combo.set_active_text (current_driver);
803 driver_combo.set_sensitive (false);
804 /* this will change the device text which will cause a call to
805 * device changed which will set up parameters
810 vector<string> midi_options = backend->enumerate_midi_options();
812 if (midi_options.size() == 1) {
813 /* only contains the "none" option */
814 midi_option_combo.set_sensitive (false);
817 set_popdown_strings (midi_option_combo, midi_options);
818 midi_option_combo.set_active_text (midi_options.front());
819 midi_option_combo.set_sensitive (true);
821 midi_option_combo.set_sensitive (false);
825 connect_disconnect_button.hide();
827 midi_option_changed();
829 started_at_least_once = false;
831 if (!ignore_changes) {
832 maybe_display_saved_state ();
837 EngineControl::print_channel_count (Gtk::SpinButton* sb)
839 if (ARDOUR::Profile->get_mixbus()) {
843 uint32_t cnt = (uint32_t) sb->get_value();
845 sb->set_text (_("all available channels"));
848 snprintf (buf, sizeof (buf), "%d", cnt);
854 // @return true if there are devices available
856 EngineControl::set_device_popdown_strings ()
858 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
859 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
861 /* NOTE: Ardour currently does not display the "available" field of the
864 * Doing so would require a different GUI widget than the combo
865 * box/popdown that we currently use, since it has no way to list
866 * items that are not selectable. Something more like a popup menu,
867 * which could have unselectable items, would be appropriate.
870 vector<string> available_devices;
872 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
873 available_devices.push_back (i->name);
877 if (!available_devices.empty()) {
878 update_sensitivity ();
881 string current_device, found_device;
882 current_device = device_combo.get_active_text ();
883 if (current_device == "") {
884 current_device = backend->device_name ();
887 // Make sure that the active text is still relevant for this
888 // device (it might only be relevant to the previous device!!)
889 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
890 if (*i == current_device)
891 found_device = current_device;
893 if (found_device == "")
894 // device has never been set (or was not relevant
895 // for this backend) Let's make sure it's not blank
896 current_device = available_devices.front ();
898 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
899 set_popdown_strings (device_combo, available_devices);
901 device_combo.set_active_text (current_device);
910 // @return true if there are input devices available
912 EngineControl::set_input_device_popdown_strings ()
914 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
915 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
917 vector<string> available_devices;
919 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
920 available_devices.push_back (i->name);
923 if (!available_devices.empty()) {
924 update_sensitivity ();
927 string current_device, found_device;
928 current_device = input_device_combo.get_active_text ();
929 if (current_device == "") {
930 current_device = backend->input_device_name ();
933 // Make sure that the active text is still relevant for this
934 // device (it might only be relevant to the previous device!!)
935 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
936 if (*i == current_device)
937 found_device = current_device;
939 if (found_device == "")
940 // device has never been set (or was not relevant
941 // for this backend) Let's make sure it's not blank
942 current_device = available_devices.front ();
944 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
945 set_popdown_strings (input_device_combo, available_devices);
947 input_device_combo.set_active_text (current_device);
950 input_device_changed ();
957 // @return true if there are output devices available
959 EngineControl::set_output_device_popdown_strings ()
961 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
962 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
964 vector<string> available_devices;
966 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
967 available_devices.push_back (i->name);
970 if (!available_devices.empty()) {
971 update_sensitivity ();
974 string current_device, found_device;
975 current_device = output_device_combo.get_active_text ();
976 if (current_device == "") {
977 current_device = backend->output_device_name ();
980 // Make sure that the active text is still relevant for this
981 // device (it might only be relevant to the previous device!!)
982 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
983 if (*i == current_device)
984 found_device = current_device;
986 if (found_device == "")
987 // device has never been set (or was not relevant
988 // for this backend) Let's make sure it's not blank
989 current_device = available_devices.front ();
991 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
992 set_popdown_strings (output_device_combo, available_devices);
994 output_device_combo.set_active_text (current_device);
997 output_device_changed ();
1005 EngineControl::list_devices ()
1007 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1010 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1012 bool devices_available = false;
1014 if (backend->use_separate_input_and_output_devices ()) {
1015 bool input_devices_available = set_input_device_popdown_strings ();
1016 bool output_devices_available = set_output_device_popdown_strings ();
1017 devices_available = input_devices_available || output_devices_available;
1019 devices_available = set_device_popdown_strings ();
1022 if (devices_available) {
1023 input_latency.set_sensitive (true);
1024 output_latency.set_sensitive (true);
1025 input_channels.set_sensitive (true);
1026 output_channels.set_sensitive (true);
1028 ok_button->set_sensitive (true);
1029 apply_button->set_sensitive (true);
1032 device_combo.clear();
1033 input_device_combo.clear();
1034 output_device_combo.clear();
1035 sample_rate_combo.set_sensitive (false);
1036 buffer_size_combo.set_sensitive (false);
1037 input_latency.set_sensitive (false);
1038 output_latency.set_sensitive (false);
1039 input_channels.set_sensitive (false);
1040 output_channels.set_sensitive (false);
1041 if (_have_control) {
1042 ok_button->set_sensitive (false);
1043 apply_button->set_sensitive (false);
1045 ok_button->set_sensitive (true);
1046 apply_button->set_sensitive (true);
1047 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
1048 sample_rate_combo.set_sensitive (true);
1050 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
1051 buffer_size_combo.set_sensitive (true);
1059 EngineControl::driver_changed ()
1061 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1064 backend->set_driver (driver_combo.get_active_text());
1067 if (!ignore_changes) {
1068 maybe_display_saved_state ();
1073 EngineControl::set_samplerate_popdown_strings (const std::string& device_name)
1075 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1080 if (_have_control) {
1081 sr = backend->available_sample_rates (device_name);
1084 sr.push_back (8000.0f);
1085 sr.push_back (16000.0f);
1086 sr.push_back (32000.0f);
1087 sr.push_back (44100.0f);
1088 sr.push_back (48000.0f);
1089 sr.push_back (88200.0f);
1090 sr.push_back (96000.0f);
1091 sr.push_back (192000.0f);
1092 sr.push_back (384000.0f);
1095 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1096 s.push_back (rate_as_string (*x));
1097 if (*x == _desired_sample_rate) {
1103 sample_rate_combo.set_sensitive (true);
1104 set_popdown_strings (sample_rate_combo, s);
1106 if (desired.empty()) {
1107 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
1109 sample_rate_combo.set_active_text (desired);
1113 sample_rate_combo.set_sensitive (false);
1118 EngineControl::set_buffersize_popdown_strings (const std::string& device_name)
1120 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1121 vector<uint32_t> bs;
1124 if (_have_control) {
1125 bs = backend->available_buffer_sizes (device_name);
1126 } else if (backend->can_change_buffer_size_when_running()) {
1134 bs.push_back (1024);
1135 bs.push_back (2048);
1136 bs.push_back (4096);
1137 bs.push_back (8192);
1140 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1141 s.push_back (bufsize_as_string (*x));
1145 buffer_size_combo.set_sensitive (true);
1146 set_popdown_strings (buffer_size_combo, s);
1148 uint32_t period = backend->buffer_size();
1150 period = backend->default_buffer_size(device_name);
1152 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1153 show_buffer_duration ();
1155 buffer_size_combo.set_sensitive (false);
1160 EngineControl::device_changed ()
1162 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1164 string device_name = device_combo.get_active_text ();
1166 if (device_name != backend->device_name()) {
1167 /* we set the backend-device to query various device related intormation.
1168 * This has the side effect that backend->device_name() will match
1169 * the device_name and 'change_device' will never be true.
1170 * so work around this by setting...
1172 queue_device_changed = true;
1175 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1176 backend->set_device_name(device_name);
1179 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1181 /* don't allow programmatic change to combos to cause a
1182 recursive call to this method.
1185 set_samplerate_popdown_strings (device_name);
1186 set_buffersize_popdown_strings (device_name);
1187 /* XXX theoretically need to set min + max channel counts here
1190 manage_control_app_sensitivity ();
1193 /* pick up any saved state for this device */
1195 if (!ignore_changes) {
1196 maybe_display_saved_state ();
1201 EngineControl::input_device_changed ()
1203 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1205 string input_device_name = input_device_combo.get_active_text ();
1207 if (input_device_name != backend->input_device_name()) {
1208 queue_device_changed = true;
1211 backend->set_input_device_name(input_device_name);
1214 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1216 set_samplerate_popdown_strings (input_device_name);
1217 set_buffersize_popdown_strings (input_device_name);
1218 /* XXX theoretically need to set min + max channel counts here
1221 manage_control_app_sensitivity ();
1224 /* pick up any saved state for this device */
1226 if (!ignore_changes) {
1227 maybe_display_saved_state ();
1232 EngineControl::output_device_changed ()
1234 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1236 string output_device_name = output_device_combo.get_active_text ();
1238 if (output_device_name != backend->output_device_name()) {
1239 queue_device_changed = true;
1242 backend->set_output_device_name(output_device_name);
1245 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1247 set_samplerate_popdown_strings (output_device_name);
1248 set_buffersize_popdown_strings (output_device_name);
1249 /* XXX theoretically need to set min + max channel counts here
1252 manage_control_app_sensitivity ();
1255 /* pick up any saved state for this device */
1257 if (!ignore_changes) {
1258 maybe_display_saved_state ();
1263 EngineControl::bufsize_as_string (uint32_t sz)
1265 /* Translators: "samples" is always plural here, so no
1266 need for plural+singular forms.
1269 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1274 EngineControl::sample_rate_changed ()
1276 /* reset the strings for buffer size to show the correct msec value
1277 (reflecting the new sample rate).
1280 show_buffer_duration ();
1285 EngineControl::buffer_size_changed ()
1287 show_buffer_duration ();
1291 EngineControl::show_buffer_duration ()
1294 /* buffer sizes - convert from just samples to samples + msecs for
1295 * the displayed string
1298 string bs_text = buffer_size_combo.get_active_text ();
1299 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1300 uint32_t rate = get_rate();
1302 /* Developers: note the hard-coding of a double buffered model
1303 in the (2 * samples) computation of latency. we always start
1304 the audiobackend in this configuration.
1306 /* note to jack1 developers: ardour also always starts the engine
1307 * in async mode (no jack2 --sync option) which adds an extra cycle
1308 * of latency with jack2 (and *3 would be correct)
1309 * The value can also be wrong if jackd is started externally..
1311 * At the time of writing the ALSA backend always uses double-buffering *2,
1312 * The Dummy backend *1, and who knows what ASIO really does :)
1314 * So just display the period size, that's also what
1315 * ARDOUR_UI::update_sample_rate() does for the status bar.
1316 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1317 * but still, that's the buffer period, not [round-trip] latency)
1320 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1321 buffer_size_duration_label.set_text (buf);
1325 EngineControl::midi_option_changed ()
1327 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1330 backend->set_midi_option (get_midi_option());
1332 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1334 //_midi_devices.clear(); // TODO merge with state-saved settings..
1335 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1336 std::vector<MidiDeviceSettings> new_devices;
1338 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1339 MidiDeviceSettings mds = find_midi_device (i->name);
1340 if (i->available && !mds) {
1341 uint32_t input_latency = 0;
1342 uint32_t output_latency = 0;
1343 if (_can_set_midi_latencies) {
1344 input_latency = backend->systemic_midi_input_latency (i->name);
1345 output_latency = backend->systemic_midi_output_latency (i->name);
1347 bool enabled = backend->midi_device_enabled (i->name);
1348 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1349 new_devices.push_back (ptr);
1350 } else if (i->available) {
1351 new_devices.push_back (mds);
1354 _midi_devices = new_devices;
1356 if (_midi_devices.empty()) {
1357 midi_devices_button.set_sensitive (false);
1359 midi_devices_button.set_sensitive (true);
1364 EngineControl::parameter_changed ()
1368 EngineControl::State
1369 EngineControl::get_matching_state (
1370 const string& backend,
1371 const string& driver,
1372 const string& device)
1374 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1375 if ((*i)->backend == backend &&
1376 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1384 EngineControl::State
1385 EngineControl::get_matching_state (
1386 const string& backend,
1387 const string& driver,
1388 const string& input_device,
1389 const string& output_device)
1391 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1392 if ((*i)->backend == backend &&
1393 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1401 EngineControl::State
1402 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1404 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1407 if (backend->use_separate_input_and_output_devices ()) {
1408 return get_matching_state (backend_combo.get_active_text(),
1409 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1410 input_device_combo.get_active_text(),
1411 output_device_combo.get_active_text());
1413 return get_matching_state (backend_combo.get_active_text(),
1414 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1415 device_combo.get_active_text());
1419 return get_matching_state (backend_combo.get_active_text(),
1421 device_combo.get_active_text());
1424 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1425 const EngineControl::State& state2)
1427 if (state1->backend == state2->backend &&
1428 state1->driver == state2->driver &&
1429 state1->device == state2->device &&
1430 state1->input_device == state2->input_device &&
1431 state1->output_device == state2->output_device) {
1437 EngineControl::State
1438 EngineControl::save_state ()
1442 if (!_have_control) {
1443 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1447 state.reset(new StateStruct);
1448 state->backend = get_backend ();
1450 state.reset(new StateStruct);
1451 store_state (state);
1454 for (StateList::iterator i = states.begin(); i != states.end();) {
1455 if (equivalent_states (*i, state)) {
1456 i = states.erase(i);
1462 states.push_back (state);
1468 EngineControl::store_state (State state)
1470 state->backend = get_backend ();
1471 state->driver = get_driver ();
1472 state->device = get_device_name ();
1473 state->input_device = get_input_device_name ();
1474 state->output_device = get_output_device_name ();
1475 state->sample_rate = get_rate ();
1476 state->buffer_size = get_buffer_size ();
1477 state->input_latency = get_input_latency ();
1478 state->output_latency = get_output_latency ();
1479 state->input_channels = get_input_channels ();
1480 state->output_channels = get_output_channels ();
1481 state->midi_option = get_midi_option ();
1482 state->midi_devices = _midi_devices;
1486 EngineControl::maybe_display_saved_state ()
1488 if (!_have_control) {
1492 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1495 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1497 if (!_desired_sample_rate) {
1498 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1500 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1501 /* call this explicitly because we're ignoring changes to
1502 the controls at this point.
1504 show_buffer_duration ();
1505 input_latency.set_value (state->input_latency);
1506 output_latency.set_value (state->output_latency);
1508 if (!state->midi_option.empty()) {
1509 midi_option_combo.set_active_text (state->midi_option);
1510 _midi_devices = state->midi_devices;
1516 EngineControl::get_state ()
1518 XMLNode* root = new XMLNode ("AudioMIDISetup");
1521 if (!states.empty()) {
1522 XMLNode* state_nodes = new XMLNode ("EngineStates");
1524 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1526 XMLNode* node = new XMLNode ("State");
1528 node->add_property ("backend", (*i)->backend);
1529 node->add_property ("driver", (*i)->driver);
1530 node->add_property ("device", (*i)->device);
1531 node->add_property ("input-device", (*i)->input_device);
1532 node->add_property ("output-device", (*i)->output_device);
1533 node->add_property ("sample-rate", (*i)->sample_rate);
1534 node->add_property ("buffer-size", (*i)->buffer_size);
1535 node->add_property ("input-latency", (*i)->input_latency);
1536 node->add_property ("output-latency", (*i)->output_latency);
1537 node->add_property ("input-channels", (*i)->input_channels);
1538 node->add_property ("output-channels", (*i)->output_channels);
1539 node->add_property ("active", (*i)->active ? "yes" : "no");
1540 node->add_property ("midi-option", (*i)->midi_option);
1542 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1543 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1544 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1545 midi_device_stuff->add_property (X_("name"), (*p)->name);
1546 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1547 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1548 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1549 midi_devices->add_child_nocopy (*midi_device_stuff);
1551 node->add_child_nocopy (*midi_devices);
1553 state_nodes->add_child_nocopy (*node);
1556 root->add_child_nocopy (*state_nodes);
1563 EngineControl::set_state (const XMLNode& root)
1565 XMLNodeList clist, cclist;
1566 XMLNodeConstIterator citer, cciter;
1568 XMLNode* grandchild;
1569 XMLProperty* prop = NULL;
1571 fprintf (stderr, "EngineControl::set_state\n");
1573 if (root.name() != "AudioMIDISetup") {
1577 clist = root.children();
1581 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1585 if (child->name() != "EngineStates") {
1589 cclist = child->children();
1591 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1592 State state (new StateStruct);
1594 grandchild = *cciter;
1596 if (grandchild->name() != "State") {
1600 if ((prop = grandchild->property ("backend")) == 0) {
1603 state->backend = prop->value ();
1605 if ((prop = grandchild->property ("driver")) == 0) {
1608 state->driver = prop->value ();
1610 if ((prop = grandchild->property ("device")) == 0) {
1613 state->device = prop->value ();
1615 if ((prop = grandchild->property ("input-device")) == 0) {
1618 state->input_device = prop->value ();
1620 if ((prop = grandchild->property ("output-device")) == 0) {
1623 state->output_device = prop->value ();
1625 if ((prop = grandchild->property ("sample-rate")) == 0) {
1628 state->sample_rate = atof (prop->value ());
1630 if ((prop = grandchild->property ("buffer-size")) == 0) {
1633 state->buffer_size = atoi (prop->value ());
1635 if ((prop = grandchild->property ("input-latency")) == 0) {
1638 state->input_latency = atoi (prop->value ());
1640 if ((prop = grandchild->property ("output-latency")) == 0) {
1643 state->output_latency = atoi (prop->value ());
1645 if ((prop = grandchild->property ("input-channels")) == 0) {
1648 state->input_channels = atoi (prop->value ());
1650 if ((prop = grandchild->property ("output-channels")) == 0) {
1653 state->output_channels = atoi (prop->value ());
1655 if ((prop = grandchild->property ("active")) == 0) {
1658 state->active = string_is_affirmative (prop->value ());
1660 if ((prop = grandchild->property ("midi-option")) == 0) {
1663 state->midi_option = prop->value ();
1665 state->midi_devices.clear();
1667 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1668 const XMLNodeList mnc = midinode->children();
1669 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1670 if ((*n)->property (X_("name")) == 0
1671 || (*n)->property (X_("enabled")) == 0
1672 || (*n)->property (X_("input-latency")) == 0
1673 || (*n)->property (X_("output-latency")) == 0
1678 MidiDeviceSettings ptr (new MidiDeviceSetting(
1679 (*n)->property (X_("name"))->value (),
1680 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1681 atoi ((*n)->property (X_("input-latency"))->value ()),
1682 atoi ((*n)->property (X_("output-latency"))->value ())
1684 state->midi_devices.push_back (ptr);
1689 /* remove accumulated duplicates (due to bug in ealier version)
1690 * this can be removed again before release
1692 for (StateList::iterator i = states.begin(); i != states.end();) {
1693 if ((*i)->backend == state->backend &&
1694 (*i)->driver == state->driver &&
1695 (*i)->device == state->device) {
1696 i = states.erase(i);
1703 states.push_back (state);
1707 /* now see if there was an active state and switch the setup to it */
1709 // purge states of backend that are not available in this built
1710 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1711 vector<std::string> backend_names;
1713 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1714 backend_names.push_back((*i)->name);
1716 for (StateList::iterator i = states.begin(); i != states.end();) {
1717 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1718 i = states.erase(i);
1724 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1727 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1728 backend_combo.set_active_text ((*i)->backend);
1729 driver_combo.set_active_text ((*i)->driver);
1730 device_combo.set_active_text ((*i)->device);
1731 fprintf (stderr, "setting input device to: %s ", (*i)->input_device.c_str());
1732 input_device_combo.set_active_text ((*i)->input_device);
1733 fprintf (stderr, "setting output device to: %s ", (*i)->output_device.c_str());
1734 output_device_combo.set_active_text ((*i)->output_device);
1735 sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1736 set_active_text_if_present (buffer_size_combo, bufsize_as_string ((*i)->buffer_size));
1737 input_latency.set_value ((*i)->input_latency);
1738 output_latency.set_value ((*i)->output_latency);
1739 midi_option_combo.set_active_text ((*i)->midi_option);
1746 EngineControl::push_state_to_backend (bool start)
1748 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1754 /* figure out what is going to change */
1756 bool restart_required = false;
1757 bool was_running = ARDOUR::AudioEngine::instance()->running();
1758 bool change_driver = false;
1759 bool change_device = false;
1760 bool change_rate = false;
1761 bool change_bufsize = false;
1762 bool change_latency = false;
1763 bool change_channels = false;
1764 bool change_midi = false;
1766 uint32_t ochan = get_output_channels ();
1767 uint32_t ichan = get_input_channels ();
1769 if (_have_control) {
1771 if (started_at_least_once) {
1773 /* we can control the backend */
1775 if (backend->requires_driver_selection()) {
1776 if (get_driver() != backend->driver_name()) {
1777 change_driver = true;
1781 if (backend->use_separate_input_and_output_devices()) {
1782 if (get_input_device_name() != backend->input_device_name()) {
1783 change_device = true;
1785 if (get_output_device_name() != backend->output_device_name()) {
1786 change_device = true;
1789 if (get_device_name() != backend->device_name()) {
1790 change_device = true;
1794 if (queue_device_changed) {
1795 change_device = true;
1798 if (get_rate() != backend->sample_rate()) {
1802 if (get_buffer_size() != backend->buffer_size()) {
1803 change_bufsize = true;
1806 if (get_midi_option() != backend->midi_option()) {
1810 /* zero-requested channels means "all available" */
1813 ichan = backend->input_channels();
1817 ochan = backend->output_channels();
1820 if (ichan != backend->input_channels()) {
1821 change_channels = true;
1824 if (ochan != backend->output_channels()) {
1825 change_channels = true;
1828 if (get_input_latency() != backend->systemic_input_latency() ||
1829 get_output_latency() != backend->systemic_output_latency()) {
1830 change_latency = true;
1833 /* backend never started, so we have to force a group
1836 change_device = true;
1837 if (backend->requires_driver_selection()) {
1838 change_driver = true;
1841 change_bufsize = true;
1842 change_channels = true;
1843 change_latency = true;
1849 /* we have no control over the backend, meaning that we can
1850 * only possibly change sample rate and buffer size.
1854 if (get_rate() != backend->sample_rate()) {
1855 change_bufsize = true;
1858 if (get_buffer_size() != backend->buffer_size()) {
1859 change_bufsize = true;
1863 queue_device_changed = false;
1865 if (!_have_control) {
1867 /* We do not have control over the backend, so the best we can
1868 * do is try to change the sample rate and/or bufsize and get
1872 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1876 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1881 backend->set_sample_rate (get_rate());
1884 if (change_bufsize) {
1885 backend->set_buffer_size (get_buffer_size());
1889 if (ARDOUR::AudioEngine::instance()->start ()) {
1890 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1900 /* determine if we need to stop the backend before changing parameters */
1902 if (change_driver || change_device || change_channels || change_latency ||
1903 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1905 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1906 restart_required = true;
1908 restart_required = false;
1913 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1914 /* no changes in any parameters that absolutely require a
1915 * restart, so check those that might be changeable without a
1919 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1920 /* can't do this while running ... */
1921 restart_required = true;
1924 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1925 /* can't do this while running ... */
1926 restart_required = true;
1932 if (restart_required) {
1933 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1940 if (change_driver && backend->set_driver (get_driver())) {
1941 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1944 if (backend->use_separate_input_and_output_devices()) {
1945 if (change_device && backend->set_input_device_name (get_input_device_name())) {
1946 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
1949 if (change_device && backend->set_output_device_name (get_output_device_name())) {
1950 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
1954 if (change_device && backend->set_device_name (get_device_name())) {
1955 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1959 if (change_rate && backend->set_sample_rate (get_rate())) {
1960 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1963 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1964 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1968 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1969 if (backend->set_input_channels (get_input_channels())) {
1970 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1973 if (backend->set_output_channels (get_output_channels())) {
1974 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1978 if (change_latency) {
1979 if (backend->set_systemic_input_latency (get_input_latency())) {
1980 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1983 if (backend->set_systemic_output_latency (get_output_latency())) {
1984 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1990 backend->set_midi_option (get_midi_option());
1994 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1995 if (_measure_midi) {
1996 if (*p == _measure_midi) {
1997 backend->set_midi_device_enabled ((*p)->name, true);
1999 backend->set_midi_device_enabled ((*p)->name, false);
2003 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2004 if (backend->can_set_systemic_midi_latencies()) {
2005 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2006 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2011 if (start || (was_running && restart_required)) {
2012 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2023 EngineControl::post_push ()
2025 /* get a pointer to the current state object, creating one if
2029 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2032 state = save_state ();
2040 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2041 (*i)->active = false;
2044 /* mark this one active (to be used next time the dialog is
2048 state->active = true;
2050 if (_have_control) { // XXX
2051 manage_control_app_sensitivity ();
2054 /* schedule a redisplay of MIDI ports */
2055 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2060 EngineControl::get_rate () const
2062 float r = atof (sample_rate_combo.get_active_text ());
2063 /* the string may have been translated with an abbreviation for
2064 * thousands, so use a crude heuristic to fix this.
2074 EngineControl::get_buffer_size () const
2076 string txt = buffer_size_combo.get_active_text ();
2079 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2080 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2081 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2089 EngineControl::get_midi_option () const
2091 return midi_option_combo.get_active_text();
2095 EngineControl::get_input_channels() const
2097 if (ARDOUR::Profile->get_mixbus()) {
2098 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2099 if (!backend) return 0;
2100 return backend->input_channels();
2102 return (uint32_t) input_channels_adjustment.get_value();
2106 EngineControl::get_output_channels() const
2108 if (ARDOUR::Profile->get_mixbus()) {
2109 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2110 if (!backend) return 0;
2111 return backend->input_channels();
2113 return (uint32_t) output_channels_adjustment.get_value();
2117 EngineControl::get_input_latency() const
2119 return (uint32_t) input_latency_adjustment.get_value();
2123 EngineControl::get_output_latency() const
2125 return (uint32_t) output_latency_adjustment.get_value();
2129 EngineControl::get_backend () const
2131 return backend_combo.get_active_text ();
2135 EngineControl::get_driver () const
2137 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2138 return driver_combo.get_active_text ();
2145 EngineControl::get_device_name () const
2147 return device_combo.get_active_text ();
2151 EngineControl::get_input_device_name () const
2153 return input_device_combo.get_active_text ();
2157 EngineControl::get_output_device_name () const
2159 return output_device_combo.get_active_text ();
2163 EngineControl::control_app_button_clicked ()
2165 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2171 backend->launch_control_app ();
2175 EngineControl::manage_control_app_sensitivity ()
2177 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2183 string appname = backend->control_app_name();
2185 if (appname.empty()) {
2186 control_app_button.set_sensitive (false);
2188 control_app_button.set_sensitive (true);
2193 EngineControl::set_desired_sample_rate (uint32_t sr)
2195 _desired_sample_rate = sr;
2197 input_device_changed ();
2198 output_device_changed ();
2202 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2204 if (page_num == 0) {
2205 cancel_button->set_sensitive (true);
2206 ok_button->set_sensitive (true);
2207 apply_button->set_sensitive (true);
2208 _measure_midi.reset();
2210 cancel_button->set_sensitive (false);
2211 ok_button->set_sensitive (false);
2212 apply_button->set_sensitive (false);
2215 if (page_num == midi_tab) {
2217 refresh_midi_display ();
2220 if (page_num == latency_tab) {
2223 if (ARDOUR::AudioEngine::instance()->running()) {
2224 // TODO - mark as 'stopped for latency
2225 ARDOUR_UI::instance()->disconnect_from_engine ();
2229 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2231 /* save any existing latency values */
2233 uint32_t il = (uint32_t) input_latency.get_value ();
2234 uint32_t ol = (uint32_t) input_latency.get_value ();
2236 /* reset to zero so that our new test instance
2237 will be clean of any existing latency measures.
2239 NB. this should really be done by the backend
2240 when stated for latency measurement.
2243 input_latency.set_value (0);
2244 output_latency.set_value (0);
2246 push_state_to_backend (false);
2250 input_latency.set_value (il);
2251 output_latency.set_value (ol);
2254 // This should be done in push_state_to_backend()
2255 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2256 disable_latency_tab ();
2259 enable_latency_tab ();
2263 end_latency_detection ();
2264 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2269 /* latency measurement */
2272 EngineControl::check_audio_latency_measurement ()
2274 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2276 if (mtdm->resolve () < 0) {
2277 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2281 if (mtdm->err () > 0.3) {
2287 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2289 if (sample_rate == 0) {
2290 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2291 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2295 int frames_total = mtdm->del();
2296 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2298 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2299 _("Detected roundtrip latency: "),
2300 frames_total, frames_total * 1000.0f/sample_rate,
2301 _("Systemic latency: "),
2302 extra, extra * 1000.0f/sample_rate);
2306 if (mtdm->err () > 0.2) {
2308 strcat (buf, _("(signal detection error)"));
2314 strcat (buf, _("(inverted - bad wiring)"));
2318 lm_results.set_markup (string_compose (results_markup, buf));
2321 have_lm_results = true;
2322 end_latency_detection ();
2323 lm_use_button.set_sensitive (true);
2331 EngineControl::check_midi_latency_measurement ()
2333 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2335 if (!mididm->have_signal () || mididm->latency () == 0) {
2336 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2341 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2343 if (sample_rate == 0) {
2344 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2345 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2349 ARDOUR::framecnt_t frames_total = mididm->latency();
2350 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2351 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2352 _("Detected roundtrip latency: "),
2353 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2354 _("Systemic latency: "),
2355 extra, extra * 1000.0f / sample_rate);
2359 if (!mididm->ok ()) {
2361 strcat (buf, _("(averaging)"));
2365 if (mididm->deviation () > 50.0) {
2367 strcat (buf, _("(too large jitter)"));
2369 } else if (mididm->deviation () > 10.0) {
2371 strcat (buf, _("(large jitter)"));
2375 have_lm_results = true;
2376 end_latency_detection ();
2377 lm_use_button.set_sensitive (true);
2378 lm_results.set_markup (string_compose (results_markup, buf));
2380 } else if (mididm->processed () > 400) {
2381 have_lm_results = false;
2382 end_latency_detection ();
2383 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2387 lm_results.set_markup (string_compose (results_markup, buf));
2393 EngineControl::start_latency_detection ()
2395 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2396 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2398 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2399 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2400 if (_measure_midi) {
2401 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2403 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2405 lm_measure_label.set_text (_("Cancel"));
2406 have_lm_results = false;
2407 lm_use_button.set_sensitive (false);
2408 lm_input_channel_combo.set_sensitive (false);
2409 lm_output_channel_combo.set_sensitive (false);
2415 EngineControl::end_latency_detection ()
2417 latency_timeout.disconnect ();
2418 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2419 lm_measure_label.set_text (_("Measure"));
2420 if (!have_lm_results) {
2421 lm_use_button.set_sensitive (false);
2423 lm_input_channel_combo.set_sensitive (true);
2424 lm_output_channel_combo.set_sensitive (true);
2429 EngineControl::latency_button_clicked ()
2432 start_latency_detection ();
2434 end_latency_detection ();
2439 EngineControl::use_latency_button_clicked ()
2441 if (_measure_midi) {
2442 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2446 ARDOUR::framecnt_t frames_total = mididm->latency();
2447 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2448 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2449 _measure_midi->input_latency = one_way;
2450 _measure_midi->output_latency = one_way;
2451 notebook.set_current_page (midi_tab);
2453 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2459 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2460 one_way = std::max (0., one_way);
2462 input_latency_adjustment.set_value (one_way);
2463 output_latency_adjustment.set_value (one_way);
2465 /* back to settings page */
2466 notebook.set_current_page (0);
2472 EngineControl::on_delete_event (GdkEventAny* ev)
2474 if (notebook.get_current_page() == 2) {
2475 /* currently on latency tab - be sure to clean up */
2476 end_latency_detection ();
2478 return ArdourDialog::on_delete_event (ev);
2482 EngineControl::engine_running ()
2484 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2487 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2488 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2490 buffer_size_combo.set_sensitive (true);
2491 sample_rate_combo.set_sensitive (true);
2493 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2494 connect_disconnect_button.show();
2496 started_at_least_once = true;
2497 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2501 EngineControl::engine_stopped ()
2503 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2506 buffer_size_combo.set_sensitive (false);
2507 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2508 connect_disconnect_button.show();
2510 sample_rate_combo.set_sensitive (true);
2511 buffer_size_combo.set_sensitive (true);
2512 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2516 EngineControl::device_list_changed ()
2518 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2520 midi_option_changed();
2524 EngineControl::connect_disconnect_click()
2526 if (ARDOUR::AudioEngine::instance()->running()) {
2527 ARDOUR_UI::instance()->disconnect_from_engine ();
2529 ARDOUR_UI::instance()->reconnect_to_engine ();
2534 EngineControl::calibrate_audio_latency ()
2536 _measure_midi.reset ();
2537 have_lm_results = false;
2538 lm_use_button.set_sensitive (false);
2539 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2540 notebook.set_current_page (latency_tab);
2544 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2547 have_lm_results = false;
2548 lm_use_button.set_sensitive (false);
2549 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2550 notebook.set_current_page (latency_tab);
2554 EngineControl::configure_midi_devices ()
2556 notebook.set_current_page (midi_tab);