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.
25 #include <boost/scoped_ptr.hpp>
27 #include <gtkmm/messagedialog.h>
29 #include "pbd/error.h"
30 #include "pbd/xml++.h"
31 #include "pbd/unwind.h"
32 #include "pbd/failed_constructor.h"
34 #include <gtkmm/alignment.h>
35 #include <gtkmm/stock.h>
36 #include <gtkmm/notebook.h>
37 #include <gtkmm2ext/utils.h>
39 #include "ardour/audio_backend.h"
40 #include "ardour/audioengine.h"
41 #include "ardour/mtdm.h"
42 #include "ardour/mididm.h"
43 #include "ardour/rc_configuration.h"
44 #include "ardour/types.h"
45 #include "ardour/profile.h"
47 #include "pbd/convert.h"
48 #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 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
67 static const unsigned int midi_tab = 2;
68 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
70 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
72 EngineControl::EngineControl ()
73 : ArdourDialog (_("Audio/MIDI Setup"))
76 , input_latency_adjustment (0, 0, 99999, 1)
77 , input_latency (input_latency_adjustment)
78 , output_latency_adjustment (0, 0, 99999, 1)
79 , output_latency (output_latency_adjustment)
80 , input_channels_adjustment (0, 0, 256, 1)
81 , input_channels (input_channels_adjustment)
82 , output_channels_adjustment (0, 0, 256, 1)
83 , output_channels (output_channels_adjustment)
84 , ports_adjustment (128, 8, 1024, 1, 16)
85 , ports_spinner (ports_adjustment)
86 , control_app_button (_("Device Control Panel"))
87 , midi_devices_button (_("Midi Device Setup"))
88 , start_stop_button (_("Stop"))
89 , update_devices_button (_("Refresh Devices"))
90 , use_buffered_io_button (_("Use Buffered I/O"), ArdourButton::led_default_elements)
91 , lm_measure_label (_("Measure"))
92 , lm_use_button (_("Use results"))
93 , lm_back_button (_("Back to settings ... (ignore results)"))
94 , lm_button_audio (_("Calibrate Audio"))
96 , have_lm_results (false)
98 , midi_back_button (_("Back to settings"))
100 , ignore_device_changes (0)
101 , _desired_sample_rate (0)
102 , started_at_least_once (false)
103 , queue_device_changed (false)
104 , _have_control (true)
107 using namespace Notebook_Helpers;
108 vector<string> backend_names;
110 AttachOptions xopt = AttachOptions (FILL|EXPAND);
113 set_name (X_("AudioMIDISetup"));
115 /* the backend combo is the one thing that is ALWAYS visible */
117 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
119 if (backends.empty()) {
120 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));
122 throw failed_constructor ();
125 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
126 backend_names.push_back ((*b)->name);
129 set_popdown_strings (backend_combo, backend_names);
131 /* setup basic packing characteristics for the table used on the main
132 * tab of the notebook
135 basic_packer.set_spacings (6);
136 basic_packer.set_border_width (12);
137 basic_packer.set_homogeneous (false);
141 basic_hbox.pack_start (basic_packer, false, false);
143 /* latency measurement tab */
145 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
148 lm_table.set_row_spacings (12);
149 lm_table.set_col_spacings (6);
150 lm_table.set_homogeneous (false);
152 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
155 lm_preamble.set_width_chars (60);
156 lm_preamble.set_line_wrap (true);
157 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
159 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
162 Gtk::Label* preamble;
163 preamble = manage (new Label);
164 preamble->set_width_chars (60);
165 preamble->set_line_wrap (true);
166 preamble->set_markup (_("Select two channels below and connect them using a cable."));
168 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
171 label = manage (new Label (_("Output channel")));
172 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
174 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
175 misc_align->add (lm_output_channel_combo);
176 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
179 label = manage (new Label (_("Input channel")));
180 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
182 misc_align = manage (new Alignment (0.0, 0.5));
183 misc_align->add (lm_input_channel_combo);
184 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
187 lm_measure_label.set_padding (10, 10);
188 lm_measure_button.add (lm_measure_label);
189 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
190 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
191 lm_back_button_signal = lm_back_button.signal_clicked().connect(
192 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
194 lm_use_button.set_sensitive (false);
196 /* Increase the default spacing around the labels of these three
202 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
203 l->set_padding (10, 10);
206 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
207 l->set_padding (10, 10);
210 preamble = manage (new Label);
211 preamble->set_width_chars (60);
212 preamble->set_line_wrap (true);
213 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
214 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
217 preamble = manage (new Label);
218 preamble->set_width_chars (60);
219 preamble->set_line_wrap (true);
220 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
221 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
223 ++row; // skip a row in the table
224 ++row; // skip a row in the table
226 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
228 ++row; // skip a row in the table
229 ++row; // skip a row in the table
231 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
232 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
233 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
235 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
237 lm_vbox.set_border_width (12);
238 lm_vbox.pack_start (lm_table, false, false);
240 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
244 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
245 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
246 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
247 notebook.set_border_width (12);
249 //notebook.set_show_tabs (false);
250 notebook.show_all ();
252 notebook.set_name ("SettingsNotebook");
254 /* packup the notebook */
256 get_vbox()->set_border_width (12);
257 get_vbox()->pack_start (notebook);
259 /* need a special function to print "all available channels" when the
260 * channel counts hit zero.
263 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
264 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
266 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
267 midi_devices_button.set_name ("generic button");
268 midi_devices_button.set_can_focus(true);
270 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
271 control_app_button.set_name ("generic button");
272 control_app_button.set_can_focus(true);
273 manage_control_app_sensitivity ();
275 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
276 start_stop_button.set_sensitive (false);
277 start_stop_button.set_name ("generic button");
278 start_stop_button.set_can_focus(true);
280 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
281 update_devices_button.set_sensitive (false);
282 update_devices_button.set_name ("generic button");
283 update_devices_button.set_can_focus(true);
285 use_buffered_io_button.signal_clicked.connect (mem_fun (*this, &EngineControl::use_buffered_io_button_clicked));
286 use_buffered_io_button.set_sensitive (false);
287 use_buffered_io_button.set_name ("generic button");
288 use_buffered_io_button.set_can_focus(true);
290 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
291 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
293 /* Pick up any existing audio setup configuration, if appropriate */
295 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
297 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
298 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
299 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
300 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
303 if (!set_state (*audio_setup)) {
304 set_default_state ();
307 set_default_state ();
310 update_sensitivity ();
311 connect_changed_signals ();
313 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
315 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
317 connect_disconnect_button.set_no_show_all();
318 use_buffered_io_button.set_no_show_all();
319 update_devices_button.set_no_show_all();
320 start_stop_button.set_no_show_all();
321 midi_devices_button.set_no_show_all();
325 EngineControl::connect_changed_signals ()
327 backend_combo_connection = backend_combo.signal_changed ().connect (
328 sigc::mem_fun (*this, &EngineControl::backend_changed));
329 driver_combo_connection = driver_combo.signal_changed ().connect (
330 sigc::mem_fun (*this, &EngineControl::driver_changed));
331 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
332 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
333 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
334 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
335 nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
336 sigc::mem_fun (*this, &EngineControl::nperiods_changed));
337 device_combo_connection = device_combo.signal_changed ().connect (
338 sigc::mem_fun (*this, &EngineControl::device_changed));
339 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
340 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
342 input_device_combo_connection = input_device_combo.signal_changed ().connect (
343 sigc::mem_fun (*this, &EngineControl::input_device_changed));
344 output_device_combo_connection = output_device_combo.signal_changed ().connect (
345 sigc::mem_fun (*this, &EngineControl::output_device_changed));
347 input_latency_connection = input_latency.signal_changed ().connect (
348 sigc::mem_fun (*this, &EngineControl::parameter_changed));
349 output_latency_connection = output_latency.signal_changed ().connect (
350 sigc::mem_fun (*this, &EngineControl::parameter_changed));
351 input_channels_connection = input_channels.signal_changed ().connect (
352 sigc::mem_fun (*this, &EngineControl::parameter_changed));
353 output_channels_connection = output_channels.signal_changed ().connect (
354 sigc::mem_fun (*this, &EngineControl::parameter_changed));
358 EngineControl::block_changed_signals ()
360 if (block_signals++ == 0) {
361 DEBUG_ECONTROL ("Blocking changed signals");
362 backend_combo_connection.block ();
363 driver_combo_connection.block ();
364 sample_rate_combo_connection.block ();
365 buffer_size_combo_connection.block ();
366 nperiods_combo_connection.block ();
367 device_combo_connection.block ();
368 input_device_combo_connection.block ();
369 output_device_combo_connection.block ();
370 midi_option_combo_connection.block ();
371 input_latency_connection.block ();
372 output_latency_connection.block ();
373 input_channels_connection.block ();
374 output_channels_connection.block ();
379 EngineControl::unblock_changed_signals ()
381 if (--block_signals == 0) {
382 DEBUG_ECONTROL ("Unblocking changed signals");
383 backend_combo_connection.unblock ();
384 driver_combo_connection.unblock ();
385 sample_rate_combo_connection.unblock ();
386 buffer_size_combo_connection.unblock ();
387 nperiods_combo_connection.unblock ();
388 device_combo_connection.unblock ();
389 input_device_combo_connection.unblock ();
390 output_device_combo_connection.unblock ();
391 midi_option_combo_connection.unblock ();
392 input_latency_connection.unblock ();
393 output_latency_connection.unblock ();
394 input_channels_connection.unblock ();
395 output_channels_connection.unblock ();
399 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
400 const std::string& reason)
401 : ec (engine_control)
404 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
405 ec.block_changed_signals ();
408 EngineControl::SignalBlocker::~SignalBlocker ()
410 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
411 ec.unblock_changed_signals ();
415 EngineControl::on_show ()
417 ArdourDialog::on_show ();
418 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
419 // re-check _have_control (jackd running) see #6041
423 ok_button->grab_focus();
427 EngineControl::try_autostart ()
429 if (!start_stop_button.get_sensitive()) {
432 if (ARDOUR::AudioEngine::instance()->running()) {
435 return start_engine ();
439 EngineControl::start_engine ()
441 if (push_state_to_backend(true) != 0) {
442 MessageDialog msg(*this,
443 ARDOUR::AudioEngine::instance()->get_last_backend_error());
451 EngineControl::stop_engine (bool for_latency)
453 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
454 MessageDialog msg(*this,
455 ARDOUR::AudioEngine::instance()->get_last_backend_error());
463 EngineControl::on_response (int response_id)
465 ArdourDialog::on_response (response_id);
467 switch (response_id) {
469 if (!start_engine()) {
474 #ifdef PLATFORM_WINDOWS
476 // But if there's no session open, this can produce
477 // a long gap when nothing appears to be happening.
478 // Let's show the splash image while we're waiting.
479 if (!ARDOUR_COMMAND_LINE::no_splash) {
480 if (ARDOUR_UI::instance()) {
481 if (!ARDOUR_UI::instance()->session_loaded) {
482 ARDOUR_UI::instance()->show_splash();
488 case RESPONSE_DELETE_EVENT: {
490 ev.type = GDK_BUTTON_PRESS;
492 on_delete_event((GdkEventAny*)&ev);
495 case RESPONSE_CANCEL:
496 if (ARDOUR_UI::instance() && ARDOUR_UI::instance()->session_loaded) {
497 ARDOUR_UI::instance()->check_audioengine(*this);
506 EngineControl::build_notebook ()
509 AttachOptions xopt = AttachOptions (FILL|EXPAND);
511 /* clear the table */
513 Gtkmm2ext::container_clear (basic_vbox);
514 Gtkmm2ext::container_clear (basic_packer);
516 if (control_app_button.get_parent()) {
517 control_app_button.get_parent()->remove (control_app_button);
520 label = manage (left_aligned_label (_("Audio System:")));
521 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
522 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
524 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
525 engine_status.show();
527 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
528 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
529 basic_packer.attach (use_buffered_io_button, 3, 4, 2, 3, xopt, xopt);
531 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
532 lm_button_audio.set_name ("generic button");
533 lm_button_audio.set_can_focus(true);
536 build_full_control_notebook ();
538 build_no_control_notebook ();
541 basic_vbox.pack_start (basic_hbox, false, false);
544 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
545 basic_vbox.show_all ();
550 EngineControl::build_full_control_notebook ()
552 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
555 using namespace Notebook_Helpers;
557 vector<string> strings;
558 AttachOptions xopt = AttachOptions (FILL|EXPAND);
559 int row = 1; // row zero == backend combo
561 /* start packing it up */
563 if (backend->requires_driver_selection()) {
564 label = manage (left_aligned_label (_("Driver:")));
565 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
566 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
570 if (backend->use_separate_input_and_output_devices()) {
571 label = manage (left_aligned_label (_("Input Device:")));
572 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
573 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
575 label = manage (left_aligned_label (_("Output Device:")));
576 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
577 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
579 // reset so it isn't used in state comparisons
580 device_combo.set_active_text ("");
582 label = manage (left_aligned_label (_("Device:")));
583 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
584 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
586 // reset these so they don't get used in state comparisons
587 input_device_combo.set_active_text ("");
588 output_device_combo.set_active_text ("");
591 label = manage (left_aligned_label (_("Sample rate:")));
592 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
593 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
597 label = manage (left_aligned_label (_("Buffer size:")));
598 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
599 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
600 buffer_size_duration_label.set_alignment (0.0); /* left-align */
601 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
603 int ctrl_btn_span = 1;
604 if (backend->can_set_period_size ()) {
606 label = manage (left_aligned_label (_("Periods:")));
607 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
608 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
612 /* button spans 2 or 3 rows */
614 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
617 input_channels.set_name ("InputChannels");
618 input_channels.set_flags (Gtk::CAN_FOCUS);
619 input_channels.set_digits (0);
620 input_channels.set_wrap (false);
621 output_channels.set_editable (true);
623 if (!ARDOUR::Profile->get_mixbus()) {
624 label = manage (left_aligned_label (_("Input Channels:")));
625 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
626 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
630 output_channels.set_name ("OutputChannels");
631 output_channels.set_flags (Gtk::CAN_FOCUS);
632 output_channels.set_digits (0);
633 output_channels.set_wrap (false);
634 output_channels.set_editable (true);
636 if (!ARDOUR::Profile->get_mixbus()) {
637 label = manage (left_aligned_label (_("Output Channels:")));
638 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
639 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
643 input_latency.set_name ("InputLatency");
644 input_latency.set_flags (Gtk::CAN_FOCUS);
645 input_latency.set_digits (0);
646 input_latency.set_wrap (false);
647 input_latency.set_editable (true);
649 label = manage (left_aligned_label (_("Hardware input latency:")));
650 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
651 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
652 label = manage (left_aligned_label (_("samples")));
653 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
656 output_latency.set_name ("OutputLatency");
657 output_latency.set_flags (Gtk::CAN_FOCUS);
658 output_latency.set_digits (0);
659 output_latency.set_wrap (false);
660 output_latency.set_editable (true);
662 label = manage (left_aligned_label (_("Hardware output latency:")));
663 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
664 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
665 label = manage (left_aligned_label (_("samples")));
666 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
668 /* button spans 2 rows */
670 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
673 label = manage (left_aligned_label (_("MIDI System:")));
674 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
675 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
676 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
681 EngineControl::build_no_control_notebook ()
683 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
686 using namespace Notebook_Helpers;
688 vector<string> strings;
689 AttachOptions xopt = AttachOptions (FILL|EXPAND);
690 int row = 1; // row zero == backend combo
691 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
693 label = manage (new Label);
694 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
695 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
698 if (backend->can_change_sample_rate_when_running()) {
699 label = manage (left_aligned_label (_("Sample rate:")));
700 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
701 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
705 if (backend->can_change_buffer_size_when_running()) {
706 label = manage (left_aligned_label (_("Buffer size:")));
707 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
708 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
709 buffer_size_duration_label.set_alignment (0.0); /* left-align */
710 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
714 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
718 EngineControl::~EngineControl ()
720 ignore_changes = true;
724 EngineControl::disable_latency_tab ()
726 vector<string> empty;
727 set_popdown_strings (lm_output_channel_combo, empty);
728 set_popdown_strings (lm_input_channel_combo, empty);
729 lm_measure_button.set_sensitive (false);
730 lm_use_button.set_sensitive (false);
734 EngineControl::enable_latency_tab ()
736 vector<string> outputs;
737 vector<string> inputs;
739 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
740 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
741 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
743 if (!ARDOUR::AudioEngine::instance()->running()) {
744 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
745 notebook.set_current_page (0);
749 else if (inputs.empty() || outputs.empty()) {
750 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
751 notebook.set_current_page (0);
756 lm_back_button_signal.disconnect();
758 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
761 lm_back_button_signal = lm_back_button.signal_clicked().connect(
762 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
766 set_popdown_strings (lm_output_channel_combo, outputs);
767 lm_output_channel_combo.set_active_text (outputs.front());
768 lm_output_channel_combo.set_sensitive (true);
770 set_popdown_strings (lm_input_channel_combo, inputs);
771 lm_input_channel_combo.set_active_text (inputs.front());
772 lm_input_channel_combo.set_sensitive (true);
774 lm_measure_button.set_sensitive (true);
778 EngineControl::setup_midi_tab_for_backend ()
780 Gtkmm2ext::container_clear (midi_vbox);
782 midi_vbox.set_border_width (12);
783 midi_device_table.set_border_width (12);
785 midi_vbox.pack_start (midi_device_table, true, true);
787 pretty_name_column = midi_input_view.append_column (_("Pretty Name"), midi_port_columns.pretty_name) - 1;
788 use_column = midi_input_view.append_column (_("Use"), midi_port_columns.in_use) - 1;
789 music_column = midi_input_view.append_column (_("Use for Music"), midi_port_columns.music_data) - 1;
790 control_column = midi_input_view.append_column (_("Use for Control"), midi_port_columns.control_data) - 1;
791 selection_column = midi_input_view.append_column (_("Follow Selection"), midi_port_columns.control_data) - 1;
793 midi_output_view.append_column (_("Pretty Name"), midi_port_columns.pretty_name);
794 midi_output_view.append_column (_("Use"), midi_port_columns.in_use);
795 midi_output_view.append_column (_("Use for Music"), midi_port_columns.music_data);
796 midi_output_view.append_column (_("Use for Control"), midi_port_columns.control_data);
797 midi_output_view.append_column (_("Follow Selection"), midi_port_columns.control_data);
799 midi_input_view.get_selection()->set_mode (SELECTION_NONE);
800 midi_output_view.get_selection()->set_mode (SELECTION_NONE);
802 midi_vbox.pack_start (midi_input_view);
803 midi_vbox.pack_start (midi_output_view);
805 midi_vbox.pack_start (midi_back_button, false, false);
806 midi_vbox.show_all ();
810 EngineControl::refill_midi_ports (bool for_input)
812 using namespace ARDOUR;
814 std::vector<string> ports;
816 AudioEngine::instance()->get_ports (string(), DataType::MIDI, for_input ? IsInput : IsOutput, ports);
818 Glib::RefPtr<ListStore> model = Gtk::ListStore::create (midi_port_columns);
820 for (vector<string>::const_iterator s = ports.begin(); s != ports.end(); ++s) {
822 if (AudioEngine::instance()->port_is_mine (*s)) {
826 TreeModel::Row row = *(model->append());
828 string pretty = AudioEngine::instance()->get_pretty_name_by_name (*s);
829 row[midi_port_columns.name] = *s;
830 row[midi_port_columns.pretty_name] = (pretty.empty() ? *s : pretty);
831 row[midi_port_columns.in_use] = true;
832 row[midi_port_columns.music_data] = true;
833 row[midi_port_columns.control_data] = true;
836 Gtk::TreeView& view (for_input ? midi_input_view : midi_output_view);
838 view.set_model (model);
840 CellRendererText* pretty_name_cell = dynamic_cast<CellRendererText*> (view.get_column_cell_renderer (pretty_name_column));
841 pretty_name_cell->property_editable() = true;
842 pretty_name_cell->signal_edited().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::pretty_name_edit), &view));
844 CellRendererToggle* toggle_cell;
846 toggle_cell = dynamic_cast<CellRendererToggle*> (view.get_column_cell_renderer (use_column));
847 toggle_cell->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_use_column_toggled), &view));
849 toggle_cell = dynamic_cast<CellRendererToggle*> (view.get_column_cell_renderer (music_column));
850 toggle_cell->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_music_column_toggled), &view));
852 toggle_cell = dynamic_cast<CellRendererToggle*> (view.get_column_cell_renderer (control_column));
853 toggle_cell->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_control_column_toggled), &view));
855 toggle_cell = dynamic_cast<CellRendererToggle*> (view.get_column_cell_renderer (selection_column));
856 toggle_cell->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_selection_column_toggled), &view));
860 EngineControl::midi_use_column_toggled (string const & path, TreeView* view)
862 TreeIter iter = view->get_model()->get_iter (path);
868 bool value ((*iter)[midi_port_columns.in_use]);
869 (*iter)[midi_port_columns.in_use] = !value;
874 EngineControl::midi_music_column_toggled (string const & path, TreeView* view)
876 TreeIter iter = view->get_model()->get_iter (path);
882 bool value ((*iter)[midi_port_columns.music_data]);
883 (*iter)[midi_port_columns.music_data] = !value;
887 EngineControl::midi_control_column_toggled (string const & path, TreeView* view)
889 TreeIter iter = view->get_model()->get_iter (path);
895 bool value ((*iter)[midi_port_columns.control_data]);
896 (*iter)[midi_port_columns.control_data] = !value;
899 // ARDOUR::AudioEngine::instance()->remove_port_purpose (PortFlags (ControlData));
901 // ARDOUR::AudioEngine::instance()->add_port_purpose (PortFlags (ControlData));
906 EngineControl::midi_selection_column_toggled (string const & path, TreeView* view)
908 TreeIter iter = view->get_model()->get_iter (path);
913 bool value ((*iter)[midi_port_columns.selection]);
914 (*iter)[midi_port_columns.selection] = !value;
918 EngineControl::pretty_name_edit (std::string const & path, string const & new_text, Gtk::TreeView* view)
920 TreeIter iter = view->get_model()->get_iter (path);
926 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
928 ARDOUR::PortEngine::PortHandle ph = backend->get_port_by_name ((*iter)[midi_port_columns.name]);
930 backend->set_port_property (ph, "http://jackaudio.org/metadata/pretty-name", new_text, "");
931 (*iter)[midi_port_columns.pretty_name] = new_text;
937 EngineControl::update_sensitivity ()
939 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
941 ok_button->set_sensitive (false);
942 start_stop_button.set_sensitive (false);
947 size_t devices_available = 0;
949 if (backend->use_separate_input_and_output_devices ()) {
950 devices_available += get_popdown_string_count (input_device_combo);
951 devices_available += get_popdown_string_count (output_device_combo);
953 devices_available += get_popdown_string_count (device_combo);
956 if (devices_available == 0) {
958 input_latency.set_sensitive (false);
959 output_latency.set_sensitive (false);
960 input_channels.set_sensitive (false);
961 output_channels.set_sensitive (false);
963 input_latency.set_sensitive (true);
964 output_latency.set_sensitive (true);
965 input_channels.set_sensitive (true);
966 output_channels.set_sensitive (true);
969 if (get_popdown_string_count (buffer_size_combo) > 0) {
970 if (!ARDOUR::AudioEngine::instance()->running()) {
971 buffer_size_combo.set_sensitive (valid);
972 } else if (backend->can_change_sample_rate_when_running()) {
973 buffer_size_combo.set_sensitive (valid || !_have_control);
977 * Currently there is no way to manually stop the
978 * engine in order to re-configure it.
979 * This needs to remain sensitive for now.
981 * (it's also handy to implicily
982 * re-start the engine)
984 buffer_size_combo.set_sensitive (true);
986 buffer_size_combo.set_sensitive (false);
990 buffer_size_combo.set_sensitive (false);
994 if (get_popdown_string_count (sample_rate_combo) > 0) {
995 bool allow_to_set_rate = false;
996 if (!ARDOUR::AudioEngine::instance()->running()) {
997 if (!ARDOUR_UI::instance()->session_loaded) {
998 // engine is not running, no session loaded -> anything goes.
999 allow_to_set_rate = true;
1000 } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
1001 // only allow to change if the current setting is not the native session rate.
1002 allow_to_set_rate = true;
1005 sample_rate_combo.set_sensitive (allow_to_set_rate);
1007 sample_rate_combo.set_sensitive (false);
1011 if (get_popdown_string_count (nperiods_combo) > 0) {
1012 if (!ARDOUR::AudioEngine::instance()->running()) {
1013 nperiods_combo.set_sensitive (true);
1015 nperiods_combo.set_sensitive (false);
1018 nperiods_combo.set_sensitive (false);
1021 if (_have_control) {
1022 start_stop_button.set_sensitive(true);
1023 start_stop_button.show();
1024 if (ARDOUR::AudioEngine::instance()->running()) {
1025 start_stop_button.set_text("Stop");
1026 update_devices_button.set_sensitive(false);
1027 use_buffered_io_button.set_sensitive(false);
1029 if (backend->can_request_update_devices()) {
1030 update_devices_button.show();
1032 update_devices_button.hide();
1034 if (backend->can_use_buffered_io()) {
1035 use_buffered_io_button.show();
1037 use_buffered_io_button.hide();
1039 start_stop_button.set_text("Start");
1040 update_devices_button.set_sensitive(true);
1041 use_buffered_io_button.set_sensitive(true);
1044 update_devices_button.set_sensitive(false);
1045 update_devices_button.hide();
1046 use_buffered_io_button.set_sensitive(false);
1047 use_buffered_io_button.hide();
1048 start_stop_button.set_sensitive(false);
1049 start_stop_button.hide();
1052 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
1053 input_device_combo.set_sensitive (false);
1054 output_device_combo.set_sensitive (false);
1055 device_combo.set_sensitive (false);
1056 driver_combo.set_sensitive (false);
1058 input_device_combo.set_sensitive (true);
1059 output_device_combo.set_sensitive (true);
1060 device_combo.set_sensitive (true);
1061 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
1062 driver_combo.set_sensitive (true);
1064 driver_combo.set_sensitive (false);
1068 if (valid || !_have_control) {
1069 ok_button->set_sensitive (true);
1071 ok_button->set_sensitive (false);
1076 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
1078 device->input_latency = a->get_value();
1080 device->output_latency = a->get_value();
1085 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
1086 b->set_active (!b->get_active());
1087 device->enabled = b->get_active();
1088 refresh_midi_display(device->name);
1092 EngineControl::refresh_midi_display (std::string focus)
1094 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1098 AttachOptions xopt = AttachOptions (FILL|EXPAND);
1101 Gtkmm2ext::container_clear (midi_device_table);
1103 midi_device_table.set_spacings (6);
1105 l = manage (new Label);
1106 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
1107 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
1108 l->set_alignment (0.5, 0.5);
1112 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
1113 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
1114 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
1115 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
1117 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
1118 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
1119 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
1120 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
1123 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1128 bool enabled = (*p)->enabled;
1130 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
1131 m->set_name ("midi device");
1132 m->set_can_focus (Gtk::CAN_FOCUS);
1133 m->add_events (Gdk::BUTTON_RELEASE_MASK);
1134 m->set_active (enabled);
1135 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
1136 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
1137 if ((*p)->name == focus) {
1141 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
1142 s = manage (new Gtk::SpinButton (*a));
1143 a->set_value ((*p)->input_latency);
1144 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
1145 s->set_sensitive (_can_set_midi_latencies && enabled);
1146 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
1148 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
1149 s = manage (new Gtk::SpinButton (*a));
1150 a->set_value ((*p)->output_latency);
1151 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
1152 s->set_sensitive (_can_set_midi_latencies && enabled);
1153 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
1155 b = manage (new Button (_("Calibrate")));
1156 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
1157 b->set_sensitive (_can_set_midi_latencies && enabled);
1158 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
1165 EngineControl::backend_changed ()
1167 SignalBlocker blocker (*this, "backend_changed");
1168 string backend_name = backend_combo.get_active_text();
1169 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1171 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1172 /* eh? setting the backend failed... how ? */
1173 /* A: stale config contains a backend that does not exist in current build */
1177 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1179 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1182 setup_midi_tab_for_backend ();
1183 _midi_devices.clear();
1185 if (backend->requires_driver_selection()) {
1186 if (set_driver_popdown_strings ()) {
1190 /* this will change the device text which will cause a call to
1191 * device changed which will set up parameters
1196 update_midi_options ();
1198 connect_disconnect_button.hide();
1200 midi_option_changed();
1202 started_at_least_once = false;
1204 /* changing the backend implies stopping the engine
1205 * ARDOUR::AudioEngine() may or may not emit this signal
1206 * depending on previous engine state
1208 engine_stopped (); // set "active/inactive"
1210 if (!_have_control) {
1211 // set settings from backend that we do have control over
1212 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1215 if (_have_control && !ignore_changes) {
1216 // set driver & devices
1217 State state = get_matching_state (backend_combo.get_active_text());
1219 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1220 set_current_state (state);
1224 if (!ignore_changes) {
1225 maybe_display_saved_state ();
1230 EngineControl::update_midi_options ()
1232 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1233 vector<string> midi_options = backend->enumerate_midi_options();
1235 if (midi_options.size() == 1) {
1236 /* only contains the "none" option */
1237 midi_option_combo.set_sensitive (false);
1239 if (_have_control) {
1240 set_popdown_strings (midi_option_combo, midi_options);
1241 midi_option_combo.set_active_text (midi_options.front());
1242 midi_option_combo.set_sensitive (true);
1244 midi_option_combo.set_sensitive (false);
1250 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1252 if (ARDOUR::Profile->get_mixbus()) {
1256 uint32_t cnt = (uint32_t) sb->get_value();
1258 sb->set_text (_("all available channels"));
1261 snprintf (buf, sizeof (buf), "%d", cnt);
1267 // @return true if there are drivers available
1269 EngineControl::set_driver_popdown_strings ()
1271 DEBUG_ECONTROL ("set_driver_popdown_strings");
1272 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1273 vector<string> drivers = backend->enumerate_drivers();
1275 if (drivers.empty ()) {
1276 // This is an error...?
1280 string current_driver = backend->driver_name ();
1282 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1284 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1287 current_driver = drivers.front ();
1290 set_popdown_strings (driver_combo, drivers);
1292 string_compose ("driver_combo.set_active_text: %1", current_driver));
1293 driver_combo.set_active_text (current_driver);
1298 EngineControl::get_default_device(const string& current_device_name,
1299 const vector<string>& available_devices)
1301 // If the current device is available, use it as default
1302 if (std::find (available_devices.begin (),
1303 available_devices.end (),
1304 current_device_name) != available_devices.end ()) {
1306 return current_device_name;
1309 using namespace ARDOUR;
1311 string default_device_name =
1312 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1314 vector<string>::const_iterator i;
1316 // If there is a "Default" device available, use it
1317 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1318 if (*i == default_device_name) {
1323 string none_device_name =
1324 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1326 // Use the first device that isn't "None"
1327 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1328 if (*i != none_device_name) {
1333 // Use "None" if there are no other available
1334 return available_devices.front();
1337 // @return true if there are devices available
1339 EngineControl::set_device_popdown_strings ()
1341 DEBUG_ECONTROL ("set_device_popdown_strings");
1342 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1343 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1345 /* NOTE: Ardour currently does not display the "available" field of the
1348 * Doing so would require a different GUI widget than the combo
1349 * box/popdown that we currently use, since it has no way to list
1350 * items that are not selectable. Something more like a popup menu,
1351 * which could have unselectable items, would be appropriate.
1354 vector<string> available_devices;
1356 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1357 available_devices.push_back (i->name);
1360 if (available_devices.empty ()) {
1364 set_popdown_strings (device_combo, available_devices);
1366 std::string default_device =
1367 get_default_device(backend->device_name(), available_devices);
1370 string_compose ("set device_combo active text: %1", default_device));
1372 device_combo.set_active_text(default_device);
1376 // @return true if there are input devices available
1378 EngineControl::set_input_device_popdown_strings ()
1380 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1381 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1382 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1384 vector<string> available_devices;
1386 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1387 available_devices.push_back (i->name);
1390 if (available_devices.empty()) {
1394 set_popdown_strings (input_device_combo, available_devices);
1396 std::string default_device =
1397 get_default_device(backend->input_device_name(), available_devices);
1400 string_compose ("set input_device_combo active text: %1", default_device));
1401 input_device_combo.set_active_text(default_device);
1405 // @return true if there are output devices available
1407 EngineControl::set_output_device_popdown_strings ()
1409 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1410 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1411 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1413 vector<string> available_devices;
1415 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1416 available_devices.push_back (i->name);
1419 if (available_devices.empty()) {
1423 set_popdown_strings (output_device_combo, available_devices);
1425 std::string default_device =
1426 get_default_device(backend->output_device_name(), available_devices);
1429 string_compose ("set output_device_combo active text: %1", default_device));
1430 output_device_combo.set_active_text(default_device);
1435 EngineControl::list_devices ()
1437 DEBUG_ECONTROL ("list_devices");
1438 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1441 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1443 bool devices_available = false;
1445 if (backend->use_separate_input_and_output_devices ()) {
1446 bool input_devices_available = set_input_device_popdown_strings ();
1447 bool output_devices_available = set_output_device_popdown_strings ();
1448 devices_available = input_devices_available || output_devices_available;
1450 devices_available = set_device_popdown_strings ();
1453 if (devices_available) {
1456 device_combo.clear();
1457 input_device_combo.clear();
1458 output_device_combo.clear();
1460 update_sensitivity ();
1464 EngineControl::driver_changed ()
1466 SignalBlocker blocker (*this, "driver_changed");
1467 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1470 backend->set_driver (driver_combo.get_active_text());
1473 // TODO load LRU device(s) for backend + driver combo
1475 if (!ignore_changes) {
1476 maybe_display_saved_state ();
1481 EngineControl::get_sample_rates_for_all_devices ()
1483 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1484 ARDOUR::AudioEngine::instance ()->current_backend ();
1485 vector<float> all_rates;
1487 if (backend->use_separate_input_and_output_devices ()) {
1488 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1490 all_rates = backend->available_sample_rates (get_device_name ());
1496 EngineControl::get_default_sample_rates ()
1498 vector<float> rates;
1499 rates.push_back (8000.0f);
1500 rates.push_back (16000.0f);
1501 rates.push_back (32000.0f);
1502 rates.push_back (44100.0f);
1503 rates.push_back (48000.0f);
1504 rates.push_back (88200.0f);
1505 rates.push_back (96000.0f);
1506 rates.push_back (192000.0f);
1507 rates.push_back (384000.0f);
1512 EngineControl::set_samplerate_popdown_strings ()
1514 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1515 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1520 if (_have_control) {
1521 sr = get_sample_rates_for_all_devices ();
1523 sr = get_default_sample_rates ();
1526 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1527 s.push_back (rate_as_string (*x));
1528 if (*x == _desired_sample_rate) {
1533 set_popdown_strings (sample_rate_combo, s);
1536 if (ARDOUR::AudioEngine::instance()->running()) {
1537 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1539 else if (desired.empty ()) {
1540 float new_active_sr = backend->default_sample_rate ();
1542 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1543 new_active_sr = sr.front ();
1546 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1548 sample_rate_combo.set_active_text (desired);
1552 update_sensitivity ();
1556 EngineControl::get_buffer_sizes_for_all_devices ()
1558 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1559 ARDOUR::AudioEngine::instance ()->current_backend ();
1560 vector<uint32_t> all_sizes;
1562 if (backend->use_separate_input_and_output_devices ()) {
1563 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1565 all_sizes = backend->available_buffer_sizes (get_device_name ());
1571 EngineControl::get_default_buffer_sizes ()
1573 vector<uint32_t> sizes;
1574 sizes.push_back (8);
1575 sizes.push_back (16);
1576 sizes.push_back (32);
1577 sizes.push_back (64);
1578 sizes.push_back (128);
1579 sizes.push_back (256);
1580 sizes.push_back (512);
1581 sizes.push_back (1024);
1582 sizes.push_back (2048);
1583 sizes.push_back (4096);
1584 sizes.push_back (8192);
1589 EngineControl::set_buffersize_popdown_strings ()
1591 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1592 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1593 vector<uint32_t> bs;
1596 if (_have_control) {
1597 bs = get_buffer_sizes_for_all_devices ();
1598 } else if (backend->can_change_buffer_size_when_running()) {
1599 bs = get_default_buffer_sizes ();
1602 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1603 s.push_back (bufsize_as_string (*x));
1606 uint32_t previous_size = 0;
1607 if (!buffer_size_combo.get_active_text().empty()) {
1608 previous_size = get_buffer_size ();
1611 set_popdown_strings (buffer_size_combo, s);
1615 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1616 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1619 buffer_size_combo.set_active_text(s.front());
1621 uint32_t period = backend->buffer_size();
1622 if (0 == period && backend->use_separate_input_and_output_devices()) {
1623 period = backend->default_buffer_size(get_input_device_name());
1625 if (0 == period && backend->use_separate_input_and_output_devices()) {
1626 period = backend->default_buffer_size(get_output_device_name());
1628 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1629 period = backend->default_buffer_size(get_device_name());
1632 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1634 show_buffer_duration ();
1636 update_sensitivity ();
1640 EngineControl::set_nperiods_popdown_strings ()
1642 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1643 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1644 vector<uint32_t> np;
1647 if (backend->can_set_period_size()) {
1648 np = backend->available_period_sizes (get_driver());
1651 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1652 s.push_back (nperiods_as_string (*x));
1655 set_popdown_strings (nperiods_combo, s);
1658 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX
1661 update_sensitivity ();
1665 EngineControl::device_changed ()
1667 SignalBlocker blocker (*this, "device_changed");
1668 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1671 string device_name_in;
1672 string device_name_out; // only used if backend support separate I/O devices
1674 if (backend->use_separate_input_and_output_devices()) {
1675 device_name_in = get_input_device_name ();
1676 device_name_out = get_output_device_name ();
1678 device_name_in = get_device_name ();
1681 /* we set the backend-device to query various device related intormation.
1682 * This has the side effect that backend->device_name() will match
1683 * the device_name and 'change_device' will never be true.
1684 * so work around this by setting...
1686 if (backend->use_separate_input_and_output_devices()) {
1687 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1688 queue_device_changed = true;
1691 if (device_name_in != backend->device_name()) {
1692 queue_device_changed = true;
1696 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1697 if (backend->use_separate_input_and_output_devices()) {
1698 backend->set_input_device_name (device_name_in);
1699 backend->set_output_device_name (device_name_out);
1701 backend->set_device_name(device_name_in);
1705 /* don't allow programmatic change to combos to cause a
1706 recursive call to this method.
1708 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1710 set_samplerate_popdown_strings ();
1711 set_buffersize_popdown_strings ();
1712 set_nperiods_popdown_strings ();
1714 /* TODO set min + max channel counts here */
1716 manage_control_app_sensitivity ();
1719 /* pick up any saved state for this device */
1721 if (!ignore_changes) {
1722 maybe_display_saved_state ();
1727 EngineControl::input_device_changed ()
1729 DEBUG_ECONTROL ("input_device_changed");
1734 EngineControl::output_device_changed ()
1736 DEBUG_ECONTROL ("output_device_changed");
1741 EngineControl::bufsize_as_string (uint32_t sz)
1743 return string_compose (P_("%1 sample", "%1 samples", sz), sz);
1747 EngineControl::nperiods_as_string (uint32_t np)
1750 snprintf (buf, sizeof (buf), "%u", np);
1756 EngineControl::sample_rate_changed ()
1758 DEBUG_ECONTROL ("sample_rate_changed");
1759 /* reset the strings for buffer size to show the correct msec value
1760 (reflecting the new sample rate).
1763 show_buffer_duration ();
1768 EngineControl::buffer_size_changed ()
1770 DEBUG_ECONTROL ("buffer_size_changed");
1771 show_buffer_duration ();
1775 EngineControl::nperiods_changed ()
1777 DEBUG_ECONTROL ("nperiods_changed");
1778 show_buffer_duration ();
1782 EngineControl::show_buffer_duration ()
1784 DEBUG_ECONTROL ("show_buffer_duration");
1785 /* buffer sizes - convert from just samples to samples + msecs for
1786 * the displayed string
1789 string bs_text = buffer_size_combo.get_active_text ();
1790 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1791 uint32_t rate = get_rate();
1793 /* Except for ALSA and Dummy backends, we don't know the number of periods
1794 * per cycle and settings.
1796 * jack1 vs jack2 have different default latencies since jack2 start
1797 * in async-mode unless --sync is given which adds an extra cycle
1798 * of latency. The value is not known if jackd is started externally..
1800 * So just display the period size, that's also what
1801 * ARDOUR_UI::update_sample_rate() does for the status bar.
1802 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1803 * but still, that's the buffer period, not [round-trip] latency)
1806 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1807 buffer_size_duration_label.set_text (buf);
1811 EngineControl::midi_option_changed ()
1813 DEBUG_ECONTROL ("midi_option_changed");
1814 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1817 backend->set_midi_option (get_midi_option());
1819 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1821 //_midi_devices.clear(); // TODO merge with state-saved settings..
1822 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1823 std::vector<MidiDeviceSettings> new_devices;
1825 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1826 MidiDeviceSettings mds = find_midi_device (i->name);
1827 if (i->available && !mds) {
1828 uint32_t input_latency = 0;
1829 uint32_t output_latency = 0;
1830 if (_can_set_midi_latencies) {
1831 input_latency = backend->systemic_midi_input_latency (i->name);
1832 output_latency = backend->systemic_midi_output_latency (i->name);
1834 bool enabled = backend->midi_device_enabled (i->name);
1835 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1836 new_devices.push_back (ptr);
1837 } else if (i->available) {
1838 new_devices.push_back (mds);
1841 _midi_devices = new_devices;
1843 if (_midi_devices.empty()) {
1844 midi_devices_button.hide ();
1846 midi_devices_button.show ();
1851 EngineControl::parameter_changed ()
1855 EngineControl::State
1856 EngineControl::get_matching_state (const string& backend)
1858 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1859 if ((*i)->backend == backend) {
1866 EngineControl::State
1867 EngineControl::get_matching_state (
1868 const string& backend,
1869 const string& driver,
1870 const string& device)
1872 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1873 if ((*i)->backend == backend &&
1874 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1882 EngineControl::State
1883 EngineControl::get_matching_state (
1884 const string& backend,
1885 const string& driver,
1886 const string& input_device,
1887 const string& output_device)
1889 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1890 if ((*i)->backend == backend &&
1891 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1899 EngineControl::State
1900 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1902 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1905 if (backend->use_separate_input_and_output_devices ()) {
1906 return get_matching_state (backend_combo.get_active_text(),
1907 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1908 input_device_combo.get_active_text(),
1909 output_device_combo.get_active_text());
1911 return get_matching_state (backend_combo.get_active_text(),
1912 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1913 device_combo.get_active_text());
1917 return get_matching_state (backend_combo.get_active_text(),
1919 device_combo.get_active_text());
1922 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1923 const EngineControl::State& state2)
1925 if (state1->backend == state2->backend &&
1926 state1->driver == state2->driver &&
1927 state1->device == state2->device &&
1928 state1->input_device == state2->input_device &&
1929 state1->output_device == state2->output_device) {
1936 EngineControl::state_sort_cmp (const State &a, const State &b) {
1940 else if (b->active) {
1944 return a->lru < b->lru;
1948 EngineControl::State
1949 EngineControl::save_state ()
1953 if (!_have_control) {
1954 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1956 state->lru = time (NULL) ;
1959 state.reset(new StateStruct);
1960 state->backend = get_backend ();
1962 state.reset(new StateStruct);
1963 store_state (state);
1966 for (StateList::iterator i = states.begin(); i != states.end();) {
1967 if (equivalent_states (*i, state)) {
1968 i = states.erase(i);
1974 states.push_back (state);
1976 states.sort (state_sort_cmp);
1982 EngineControl::store_state (State state)
1984 state->backend = get_backend ();
1985 state->driver = get_driver ();
1986 state->device = get_device_name ();
1987 state->input_device = get_input_device_name ();
1988 state->output_device = get_output_device_name ();
1989 state->sample_rate = get_rate ();
1990 state->buffer_size = get_buffer_size ();
1991 state->n_periods = get_nperiods ();
1992 state->input_latency = get_input_latency ();
1993 state->output_latency = get_output_latency ();
1994 state->input_channels = get_input_channels ();
1995 state->output_channels = get_output_channels ();
1996 state->midi_option = get_midi_option ();
1997 state->midi_devices = _midi_devices;
1998 state->use_buffered_io = get_use_buffered_io ();
1999 state->lru = time (NULL) ;
2003 EngineControl::maybe_display_saved_state ()
2005 if (!_have_control) {
2009 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2012 DEBUG_ECONTROL ("Restoring saved state");
2013 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2015 if (!_desired_sample_rate) {
2016 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2018 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2020 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2021 /* call this explicitly because we're ignoring changes to
2022 the controls at this point.
2024 show_buffer_duration ();
2025 input_latency.set_value (state->input_latency);
2026 output_latency.set_value (state->output_latency);
2028 use_buffered_io_button.set_active (state->use_buffered_io);
2030 if (!state->midi_option.empty()) {
2031 midi_option_combo.set_active_text (state->midi_option);
2032 _midi_devices = state->midi_devices;
2035 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
2040 EngineControl::get_state ()
2044 XMLNode* root = new XMLNode ("AudioMIDISetup");
2047 if (!states.empty()) {
2048 XMLNode* state_nodes = new XMLNode ("EngineStates");
2050 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2052 XMLNode* node = new XMLNode ("State");
2054 node->add_property ("backend", (*i)->backend);
2055 node->add_property ("driver", (*i)->driver);
2056 node->add_property ("device", (*i)->device);
2057 node->add_property ("input-device", (*i)->input_device);
2058 node->add_property ("output-device", (*i)->output_device);
2059 node->add_property ("sample-rate", (*i)->sample_rate);
2060 node->add_property ("buffer-size", (*i)->buffer_size);
2061 node->add_property ("n-periods", (*i)->n_periods);
2062 node->add_property ("input-latency", (*i)->input_latency);
2063 node->add_property ("output-latency", (*i)->output_latency);
2064 node->add_property ("input-channels", (*i)->input_channels);
2065 node->add_property ("output-channels", (*i)->output_channels);
2066 node->add_property ("active", (*i)->active ? "yes" : "no");
2067 node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
2068 node->add_property ("midi-option", (*i)->midi_option);
2069 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
2071 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
2072 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
2073 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
2074 midi_device_stuff->add_property (X_("name"), (*p)->name);
2075 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
2076 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
2077 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
2078 midi_devices->add_child_nocopy (*midi_device_stuff);
2080 node->add_child_nocopy (*midi_devices);
2082 state_nodes->add_child_nocopy (*node);
2085 root->add_child_nocopy (*state_nodes);
2092 EngineControl::set_default_state ()
2094 vector<string> backend_names;
2095 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2097 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
2098 backend_names.push_back ((*b)->name);
2100 backend_combo.set_active_text (backend_names.front());
2102 // We could set default backends per platform etc here
2108 EngineControl::set_state (const XMLNode& root)
2110 XMLNodeList clist, cclist;
2111 XMLNodeConstIterator citer, cciter;
2112 XMLNode const * child;
2113 XMLNode const * grandchild;
2114 XMLProperty const * prop = NULL;
2116 if (root.name() != "AudioMIDISetup") {
2120 clist = root.children();
2124 for (citer = clist.begin(); citer != clist.end(); ++citer) {
2128 if (child->name() != "EngineStates") {
2132 cclist = child->children();
2134 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2135 State state (new StateStruct);
2137 grandchild = *cciter;
2139 if (grandchild->name() != "State") {
2143 if ((prop = grandchild->property ("backend")) == 0) {
2146 state->backend = prop->value ();
2148 if ((prop = grandchild->property ("driver")) == 0) {
2151 state->driver = prop->value ();
2153 if ((prop = grandchild->property ("device")) == 0) {
2156 state->device = prop->value ();
2158 if ((prop = grandchild->property ("input-device")) == 0) {
2161 state->input_device = prop->value ();
2163 if ((prop = grandchild->property ("output-device")) == 0) {
2166 state->output_device = prop->value ();
2168 if ((prop = grandchild->property ("sample-rate")) == 0) {
2171 state->sample_rate = atof (prop->value ());
2173 if ((prop = grandchild->property ("buffer-size")) == 0) {
2176 state->buffer_size = atoi (prop->value ());
2178 if ((prop = grandchild->property ("n-periods")) == 0) {
2179 // optional (new value in 4.5)
2180 state->n_periods = 0;
2182 state->n_periods = atoi (prop->value ());
2185 if ((prop = grandchild->property ("input-latency")) == 0) {
2188 state->input_latency = atoi (prop->value ());
2190 if ((prop = grandchild->property ("output-latency")) == 0) {
2193 state->output_latency = atoi (prop->value ());
2195 if ((prop = grandchild->property ("input-channels")) == 0) {
2198 state->input_channels = atoi (prop->value ());
2200 if ((prop = grandchild->property ("output-channels")) == 0) {
2203 state->output_channels = atoi (prop->value ());
2205 if ((prop = grandchild->property ("active")) == 0) {
2208 state->active = string_is_affirmative (prop->value ());
2210 if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2213 state->use_buffered_io = string_is_affirmative (prop->value ());
2215 if ((prop = grandchild->property ("midi-option")) == 0) {
2218 state->midi_option = prop->value ();
2220 state->midi_devices.clear();
2222 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2223 const XMLNodeList mnc = midinode->children();
2224 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2225 if ((*n)->property (X_("name")) == 0
2226 || (*n)->property (X_("enabled")) == 0
2227 || (*n)->property (X_("input-latency")) == 0
2228 || (*n)->property (X_("output-latency")) == 0
2233 MidiDeviceSettings ptr (new MidiDeviceSetting(
2234 (*n)->property (X_("name"))->value (),
2235 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2236 atoi ((*n)->property (X_("input-latency"))->value ()),
2237 atoi ((*n)->property (X_("output-latency"))->value ())
2239 state->midi_devices.push_back (ptr);
2243 if ((prop = grandchild->property ("lru"))) {
2244 state->lru = atoi (prop->value ());
2248 /* remove accumulated duplicates (due to bug in ealier version)
2249 * this can be removed again before release
2251 for (StateList::iterator i = states.begin(); i != states.end();) {
2252 if ((*i)->backend == state->backend &&
2253 (*i)->driver == state->driver &&
2254 (*i)->device == state->device) {
2255 i = states.erase(i);
2262 states.push_back (state);
2266 /* now see if there was an active state and switch the setup to it */
2268 // purge states of backend that are not available in this built
2269 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2270 vector<std::string> backend_names;
2272 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2273 backend_names.push_back((*i)->name);
2275 for (StateList::iterator i = states.begin(); i != states.end();) {
2276 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2277 i = states.erase(i);
2283 states.sort (state_sort_cmp);
2285 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2288 return set_current_state (*i);
2295 EngineControl::set_current_state (const State& state)
2297 DEBUG_ECONTROL ("set_current_state");
2299 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2301 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2302 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2303 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2304 // this shouldn't happen as the invalid backend names should have been
2305 // removed from the list of states.
2309 // now reflect the change in the backend in the GUI so backend_changed will
2310 // do the right thing
2311 backend_combo.set_active_text (state->backend);
2313 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2315 // we don't have control don't restore state
2320 if (!state->driver.empty ()) {
2321 if (!backend->requires_driver_selection ()) {
2322 DEBUG_ECONTROL ("Backend should require driver selection");
2323 // A backend has changed from having driver selection to not having
2324 // it or someone has been manually editing a config file and messed
2329 if (backend->set_driver (state->driver) != 0) {
2330 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2331 // Driver names for a backend have changed and the name in the
2332 // config file is now invalid or support for driver is no longer
2333 // included in the backend
2336 // no need to set the driver_combo as backend_changed will use
2337 // backend->driver_name to set the active driver
2340 if (!state->device.empty ()) {
2341 if (backend->set_device_name (state->device) != 0) {
2343 string_compose ("Unable to set device name %1", state->device));
2344 // device is no longer available on the system
2347 // no need to set active device as it will be picked up in
2348 // via backend_changed ()/set_device_popdown_strings
2351 // backend supports separate input/output devices
2352 if (backend->set_input_device_name (state->input_device) != 0) {
2353 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2354 state->input_device));
2355 // input device is no longer available on the system
2359 if (backend->set_output_device_name (state->output_device) != 0) {
2360 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2361 state->input_device));
2362 // output device is no longer available on the system
2365 // no need to set active devices as it will be picked up in via
2366 // backend_changed ()/set_*_device_popdown_strings
2371 // Now restore the state of the rest of the controls
2373 // We don't use a SignalBlocker as set_current_state is currently only
2374 // called from set_state before any signals are connected. If at some point
2375 // a more general named state mechanism is implemented and
2376 // set_current_state is called while signals are connected then a
2377 // SignalBlocker will need to be instantiated before setting these.
2379 device_combo.set_active_text (state->device);
2380 input_device_combo.set_active_text (state->input_device);
2381 output_device_combo.set_active_text (state->output_device);
2382 if (!_desired_sample_rate) {
2383 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2385 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2386 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2387 input_latency.set_value (state->input_latency);
2388 output_latency.set_value (state->output_latency);
2389 midi_option_combo.set_active_text (state->midi_option);
2390 use_buffered_io_button.set_active (state->use_buffered_io);
2395 EngineControl::push_state_to_backend (bool start)
2397 DEBUG_ECONTROL ("push_state_to_backend");
2398 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2399 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2405 /* figure out what is going to change */
2407 bool restart_required = false;
2408 bool was_running = ARDOUR::AudioEngine::instance()->running();
2409 bool change_driver = false;
2410 bool change_device = false;
2411 bool change_rate = false;
2412 bool change_bufsize = false;
2413 bool change_nperiods = false;
2414 bool change_latency = false;
2415 bool change_channels = false;
2416 bool change_midi = false;
2417 bool change_buffered_io = false;
2419 uint32_t ochan = get_output_channels ();
2420 uint32_t ichan = get_input_channels ();
2422 if (_have_control) {
2424 if (started_at_least_once) {
2426 /* we can control the backend */
2428 if (backend->requires_driver_selection()) {
2429 if (get_driver() != backend->driver_name()) {
2430 change_driver = true;
2434 if (backend->use_separate_input_and_output_devices()) {
2435 if (get_input_device_name() != backend->input_device_name()) {
2436 change_device = true;
2438 if (get_output_device_name() != backend->output_device_name()) {
2439 change_device = true;
2442 if (get_device_name() != backend->device_name()) {
2443 change_device = true;
2447 if (queue_device_changed) {
2448 change_device = true;
2451 if (get_rate() != backend->sample_rate()) {
2455 if (get_buffer_size() != backend->buffer_size()) {
2456 change_bufsize = true;
2459 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2460 && get_nperiods() != backend->period_size()) {
2461 change_nperiods = true;
2464 if (get_midi_option() != backend->midi_option()) {
2468 if (backend->can_use_buffered_io()) {
2469 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2470 change_buffered_io = true;
2474 /* zero-requested channels means "all available" */
2477 ichan = backend->input_channels();
2481 ochan = backend->output_channels();
2484 if (ichan != backend->input_channels()) {
2485 change_channels = true;
2488 if (ochan != backend->output_channels()) {
2489 change_channels = true;
2492 if (get_input_latency() != backend->systemic_input_latency() ||
2493 get_output_latency() != backend->systemic_output_latency()) {
2494 change_latency = true;
2497 /* backend never started, so we have to force a group
2500 change_device = true;
2501 if (backend->requires_driver_selection()) {
2502 change_driver = true;
2505 change_bufsize = true;
2506 change_channels = true;
2507 change_latency = true;
2509 change_buffered_io = backend->can_use_buffered_io();
2510 change_channels = true;
2511 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2516 /* we have no control over the backend, meaning that we can
2517 * only possibly change sample rate and buffer size.
2521 if (get_rate() != backend->sample_rate()) {
2522 change_bufsize = true;
2525 if (get_buffer_size() != backend->buffer_size()) {
2526 change_bufsize = true;
2530 queue_device_changed = false;
2532 if (!_have_control) {
2534 /* We do not have control over the backend, so the best we can
2535 * do is try to change the sample rate and/or bufsize and get
2539 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2543 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2548 backend->set_sample_rate (get_rate());
2551 if (change_bufsize) {
2552 backend->set_buffer_size (get_buffer_size());
2556 if (ARDOUR::AudioEngine::instance()->start ()) {
2557 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2567 /* determine if we need to stop the backend before changing parameters */
2569 if (change_driver || change_device || change_channels || change_nperiods ||
2570 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2571 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2572 change_midi || change_buffered_io ||
2573 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2574 restart_required = true;
2576 restart_required = false;
2581 if (restart_required) {
2582 if (ARDOUR::AudioEngine::instance()->stop()) {
2588 if (change_driver && backend->set_driver (get_driver())) {
2589 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2592 if (backend->use_separate_input_and_output_devices()) {
2593 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2594 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2597 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2598 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2602 if (change_device && backend->set_device_name (get_device_name())) {
2603 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2607 if (change_rate && backend->set_sample_rate (get_rate())) {
2608 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2611 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2612 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2615 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2616 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2620 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2621 if (backend->set_input_channels (get_input_channels())) {
2622 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2625 if (backend->set_output_channels (get_output_channels())) {
2626 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2630 if (change_latency) {
2631 if (backend->set_systemic_input_latency (get_input_latency())) {
2632 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2635 if (backend->set_systemic_output_latency (get_output_latency())) {
2636 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2642 backend->set_midi_option (get_midi_option());
2645 if (change_buffered_io) {
2646 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2650 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2651 if (_measure_midi) {
2652 if (*p == _measure_midi) {
2653 backend->set_midi_device_enabled ((*p)->name, true);
2655 backend->set_midi_device_enabled ((*p)->name, false);
2657 if (backend->can_change_systemic_latency_when_running ()) {
2658 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2659 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2663 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2664 if (backend->can_set_systemic_midi_latencies()) {
2665 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2666 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2671 if (start || (was_running && restart_required)) {
2672 if (ARDOUR::AudioEngine::instance()->start()) {
2683 EngineControl::post_push ()
2685 /* get a pointer to the current state object, creating one if
2689 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2692 state = save_state ();
2698 states.sort (state_sort_cmp);
2702 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2703 (*i)->active = false;
2706 /* mark this one active (to be used next time the dialog is
2710 state->active = true;
2712 if (_have_control) { // XXX
2713 manage_control_app_sensitivity ();
2716 /* schedule a redisplay of MIDI ports */
2717 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2722 EngineControl::get_rate () const
2724 float r = atof (sample_rate_combo.get_active_text ());
2725 /* the string may have been translated with an abbreviation for
2726 * thousands, so use a crude heuristic to fix this.
2736 EngineControl::get_buffer_size () const
2738 string txt = buffer_size_combo.get_active_text ();
2741 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2742 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2743 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2751 EngineControl::get_nperiods () const
2753 string txt = nperiods_combo.get_active_text ();
2754 return atoi (txt.c_str());
2758 EngineControl::get_midi_option () const
2760 return midi_option_combo.get_active_text();
2764 EngineControl::get_use_buffered_io () const
2766 return use_buffered_io_button.get_active();
2770 EngineControl::get_input_channels() const
2772 if (ARDOUR::Profile->get_mixbus()) {
2773 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2774 if (!backend) return 0;
2775 return backend->input_channels();
2777 return (uint32_t) input_channels_adjustment.get_value();
2781 EngineControl::get_output_channels() const
2783 if (ARDOUR::Profile->get_mixbus()) {
2784 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2785 if (!backend) return 0;
2786 return backend->input_channels();
2788 return (uint32_t) output_channels_adjustment.get_value();
2792 EngineControl::get_input_latency() const
2794 return (uint32_t) input_latency_adjustment.get_value();
2798 EngineControl::get_output_latency() const
2800 return (uint32_t) output_latency_adjustment.get_value();
2804 EngineControl::get_backend () const
2806 return backend_combo.get_active_text ();
2810 EngineControl::get_driver () const
2812 if (driver_combo.get_parent()) {
2813 return driver_combo.get_active_text ();
2820 EngineControl::get_device_name () const
2822 return device_combo.get_active_text ();
2826 EngineControl::get_input_device_name () const
2828 return input_device_combo.get_active_text ();
2832 EngineControl::get_output_device_name () const
2834 return output_device_combo.get_active_text ();
2838 EngineControl::control_app_button_clicked ()
2840 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2846 backend->launch_control_app ();
2850 EngineControl::start_stop_button_clicked ()
2852 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2858 if (ARDOUR::AudioEngine::instance()->running()) {
2859 ARDOUR::AudioEngine::instance()->stop ();
2866 EngineControl::update_devices_button_clicked ()
2868 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2874 if (backend->update_devices()) {
2875 device_list_changed ();
2880 EngineControl::use_buffered_io_button_clicked ()
2882 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2888 bool set_buffered_io = !use_buffered_io_button.get_active();
2889 use_buffered_io_button.set_active (set_buffered_io);
2890 backend->set_use_buffered_io (set_buffered_io);
2894 EngineControl::manage_control_app_sensitivity ()
2896 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2902 string appname = backend->control_app_name();
2904 if (appname.empty()) {
2905 control_app_button.set_sensitive (false);
2907 control_app_button.set_sensitive (true);
2912 EngineControl::set_desired_sample_rate (uint32_t sr)
2914 _desired_sample_rate = sr;
2915 if (ARDOUR::AudioEngine::instance ()->running ()
2916 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2923 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2925 if (page_num == 0) {
2926 cancel_button->set_sensitive (true);
2927 _measure_midi.reset();
2928 update_sensitivity ();
2930 cancel_button->set_sensitive (false);
2931 ok_button->set_sensitive (false);
2934 if (page_num == midi_tab) {
2936 refresh_midi_display ();
2939 if (page_num == latency_tab) {
2942 if (ARDOUR::AudioEngine::instance()->running()) {
2947 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2949 /* save any existing latency values */
2951 uint32_t il = (uint32_t) input_latency.get_value ();
2952 uint32_t ol = (uint32_t) input_latency.get_value ();
2954 /* reset to zero so that our new test instance
2955 will be clean of any existing latency measures.
2957 NB. this should really be done by the backend
2958 when stated for latency measurement.
2961 input_latency.set_value (0);
2962 output_latency.set_value (0);
2964 push_state_to_backend (false);
2968 input_latency.set_value (il);
2969 output_latency.set_value (ol);
2972 // This should be done in push_state_to_backend()
2973 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2974 disable_latency_tab ();
2977 enable_latency_tab ();
2981 end_latency_detection ();
2982 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2987 /* latency measurement */
2990 EngineControl::check_audio_latency_measurement ()
2992 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2994 if (mtdm->resolve () < 0) {
2995 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2999 if (mtdm->get_peak () > 0.707f) {
3000 // get_peak() resets the peak-hold in the detector.
3001 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
3002 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
3006 if (mtdm->err () > 0.3) {
3012 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3014 if (sample_rate == 0) {
3015 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
3016 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3020 int frames_total = mtdm->del();
3021 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3023 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
3024 _("Detected roundtrip latency: "),
3025 frames_total, frames_total * 1000.0f/sample_rate,
3026 _("Systemic latency: "),
3027 extra, extra * 1000.0f/sample_rate);
3031 if (mtdm->err () > 0.2) {
3033 strcat (buf, _("(signal detection error)"));
3039 strcat (buf, _("(inverted - bad wiring)"));
3043 lm_results.set_markup (string_compose (results_markup, buf));
3046 have_lm_results = true;
3047 end_latency_detection ();
3048 lm_use_button.set_sensitive (true);
3056 EngineControl::check_midi_latency_measurement ()
3058 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3060 if (!mididm->have_signal () || mididm->latency () == 0) {
3061 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
3066 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3068 if (sample_rate == 0) {
3069 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
3070 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3074 ARDOUR::framecnt_t frames_total = mididm->latency();
3075 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3076 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
3077 _("Detected roundtrip latency: "),
3078 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
3079 _("Systemic latency: "),
3080 extra, extra * 1000.0f / sample_rate);
3084 if (!mididm->ok ()) {
3086 strcat (buf, _("(averaging)"));
3090 if (mididm->deviation () > 50.0) {
3092 strcat (buf, _("(too large jitter)"));
3094 } else if (mididm->deviation () > 10.0) {
3096 strcat (buf, _("(large jitter)"));
3100 have_lm_results = true;
3101 end_latency_detection ();
3102 lm_use_button.set_sensitive (true);
3103 lm_results.set_markup (string_compose (results_markup, buf));
3105 } else if (mididm->processed () > 400) {
3106 have_lm_results = false;
3107 end_latency_detection ();
3108 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
3112 lm_results.set_markup (string_compose (results_markup, buf));
3118 EngineControl::start_latency_detection ()
3120 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
3121 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
3123 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
3124 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
3125 if (_measure_midi) {
3126 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
3128 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
3130 lm_measure_label.set_text (_("Cancel"));
3131 have_lm_results = false;
3132 lm_use_button.set_sensitive (false);
3133 lm_input_channel_combo.set_sensitive (false);
3134 lm_output_channel_combo.set_sensitive (false);
3140 EngineControl::end_latency_detection ()
3142 latency_timeout.disconnect ();
3143 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3144 lm_measure_label.set_text (_("Measure"));
3145 if (!have_lm_results) {
3146 lm_use_button.set_sensitive (false);
3148 lm_input_channel_combo.set_sensitive (true);
3149 lm_output_channel_combo.set_sensitive (true);
3154 EngineControl::latency_button_clicked ()
3157 start_latency_detection ();
3159 end_latency_detection ();
3164 EngineControl::latency_back_button_clicked ()
3166 ARDOUR::AudioEngine::instance()->stop(true);
3167 notebook.set_current_page(0);
3171 EngineControl::use_latency_button_clicked ()
3173 if (_measure_midi) {
3174 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3178 ARDOUR::framecnt_t frames_total = mididm->latency();
3179 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3180 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3181 _measure_midi->input_latency = one_way;
3182 _measure_midi->output_latency = one_way;
3183 notebook.set_current_page (midi_tab);
3185 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3191 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3192 one_way = std::max (0., one_way);
3194 input_latency_adjustment.set_value (one_way);
3195 output_latency_adjustment.set_value (one_way);
3197 /* back to settings page */
3198 notebook.set_current_page (0);
3203 EngineControl::on_delete_event (GdkEventAny* ev)
3205 if (notebook.get_current_page() == 2) {
3206 /* currently on latency tab - be sure to clean up */
3207 end_latency_detection ();
3209 return ArdourDialog::on_delete_event (ev);
3213 EngineControl::engine_running ()
3215 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3218 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3219 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3221 if (backend->can_set_period_size ()) {
3222 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3225 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3226 connect_disconnect_button.show();
3228 started_at_least_once = true;
3229 if (_have_control) {
3230 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3232 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3234 update_sensitivity();
3236 refill_midi_ports (true);
3237 refill_midi_ports (false);
3241 EngineControl::engine_stopped ()
3243 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3246 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3247 connect_disconnect_button.show();
3249 if (_have_control) {
3250 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3252 engine_status.set_markup(X_(""));
3255 update_sensitivity();
3259 EngineControl::device_list_changed ()
3261 if (ignore_device_changes) {
3264 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3266 midi_option_changed();
3270 EngineControl::connect_disconnect_click()
3272 if (ARDOUR::AudioEngine::instance()->running()) {
3280 EngineControl::calibrate_audio_latency ()
3282 _measure_midi.reset ();
3283 have_lm_results = false;
3284 lm_use_button.set_sensitive (false);
3285 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3286 notebook.set_current_page (latency_tab);
3290 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3293 have_lm_results = false;
3294 lm_use_button.set_sensitive (false);
3295 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3296 notebook.set_current_page (latency_tab);
3300 EngineControl::configure_midi_devices ()
3302 notebook.set_current_page (midi_tab);