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));
242 pretty_name_column = midi_input_view.append_column (_("Pretty Name"), midi_port_columns.pretty_name) - 1;
243 use_column = midi_input_view.append_column (_("Use"), midi_port_columns.in_use) - 1;
244 music_column = midi_input_view.append_column (_("Use for Music"), midi_port_columns.music_data) - 1;
245 control_column = midi_input_view.append_column (_("Use for Control"), midi_port_columns.control_data) - 1;
246 selection_column = midi_input_view.append_column (_("Follow Selection"), midi_port_columns.control_data) - 1;
248 midi_output_view.append_column (_("Pretty Name"), midi_port_columns.pretty_name);
249 midi_output_view.append_column (_("Use"), midi_port_columns.in_use);
250 midi_output_view.append_column (_("Use for Music"), midi_port_columns.music_data);
251 midi_output_view.append_column (_("Use for Control"), midi_port_columns.control_data);
252 midi_output_view.append_column (_("Follow Selection"), midi_port_columns.control_data);
254 midi_input_view.get_selection()->set_mode (SELECTION_NONE);
255 midi_output_view.get_selection()->set_mode (SELECTION_NONE);
259 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
260 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
261 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
262 notebook.set_border_width (12);
264 //notebook.set_show_tabs (false);
265 notebook.show_all ();
267 notebook.set_name ("SettingsNotebook");
269 /* packup the notebook */
271 get_vbox()->set_border_width (12);
272 get_vbox()->pack_start (notebook);
274 /* need a special function to print "all available channels" when the
275 * channel counts hit zero.
278 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
279 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
281 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
282 midi_devices_button.set_name ("generic button");
283 midi_devices_button.set_can_focus(true);
285 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
286 control_app_button.set_name ("generic button");
287 control_app_button.set_can_focus(true);
288 manage_control_app_sensitivity ();
290 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
291 start_stop_button.set_sensitive (false);
292 start_stop_button.set_name ("generic button");
293 start_stop_button.set_can_focus(true);
295 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
296 update_devices_button.set_sensitive (false);
297 update_devices_button.set_name ("generic button");
298 update_devices_button.set_can_focus(true);
300 use_buffered_io_button.signal_clicked.connect (mem_fun (*this, &EngineControl::use_buffered_io_button_clicked));
301 use_buffered_io_button.set_sensitive (false);
302 use_buffered_io_button.set_name ("generic button");
303 use_buffered_io_button.set_can_focus(true);
305 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
306 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
308 /* Pick up any existing audio setup configuration, if appropriate */
310 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
312 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
313 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
314 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
315 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
318 if (!set_state (*audio_setup)) {
319 set_default_state ();
322 set_default_state ();
325 update_sensitivity ();
326 connect_changed_signals ();
328 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
330 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
332 connect_disconnect_button.set_no_show_all();
333 use_buffered_io_button.set_no_show_all();
334 update_devices_button.set_no_show_all();
335 start_stop_button.set_no_show_all();
336 midi_devices_button.set_no_show_all();
340 EngineControl::connect_changed_signals ()
342 backend_combo_connection = backend_combo.signal_changed ().connect (
343 sigc::mem_fun (*this, &EngineControl::backend_changed));
344 driver_combo_connection = driver_combo.signal_changed ().connect (
345 sigc::mem_fun (*this, &EngineControl::driver_changed));
346 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
347 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
348 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
349 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
350 nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
351 sigc::mem_fun (*this, &EngineControl::nperiods_changed));
352 device_combo_connection = device_combo.signal_changed ().connect (
353 sigc::mem_fun (*this, &EngineControl::device_changed));
354 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
355 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
357 input_device_combo_connection = input_device_combo.signal_changed ().connect (
358 sigc::mem_fun (*this, &EngineControl::input_device_changed));
359 output_device_combo_connection = output_device_combo.signal_changed ().connect (
360 sigc::mem_fun (*this, &EngineControl::output_device_changed));
362 input_latency_connection = input_latency.signal_changed ().connect (
363 sigc::mem_fun (*this, &EngineControl::parameter_changed));
364 output_latency_connection = output_latency.signal_changed ().connect (
365 sigc::mem_fun (*this, &EngineControl::parameter_changed));
366 input_channels_connection = input_channels.signal_changed ().connect (
367 sigc::mem_fun (*this, &EngineControl::parameter_changed));
368 output_channels_connection = output_channels.signal_changed ().connect (
369 sigc::mem_fun (*this, &EngineControl::parameter_changed));
373 EngineControl::block_changed_signals ()
375 if (block_signals++ == 0) {
376 DEBUG_ECONTROL ("Blocking changed signals");
377 backend_combo_connection.block ();
378 driver_combo_connection.block ();
379 sample_rate_combo_connection.block ();
380 buffer_size_combo_connection.block ();
381 nperiods_combo_connection.block ();
382 device_combo_connection.block ();
383 input_device_combo_connection.block ();
384 output_device_combo_connection.block ();
385 midi_option_combo_connection.block ();
386 input_latency_connection.block ();
387 output_latency_connection.block ();
388 input_channels_connection.block ();
389 output_channels_connection.block ();
394 EngineControl::unblock_changed_signals ()
396 if (--block_signals == 0) {
397 DEBUG_ECONTROL ("Unblocking changed signals");
398 backend_combo_connection.unblock ();
399 driver_combo_connection.unblock ();
400 sample_rate_combo_connection.unblock ();
401 buffer_size_combo_connection.unblock ();
402 nperiods_combo_connection.unblock ();
403 device_combo_connection.unblock ();
404 input_device_combo_connection.unblock ();
405 output_device_combo_connection.unblock ();
406 midi_option_combo_connection.unblock ();
407 input_latency_connection.unblock ();
408 output_latency_connection.unblock ();
409 input_channels_connection.unblock ();
410 output_channels_connection.unblock ();
414 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
415 const std::string& reason)
416 : ec (engine_control)
419 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
420 ec.block_changed_signals ();
423 EngineControl::SignalBlocker::~SignalBlocker ()
425 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
426 ec.unblock_changed_signals ();
430 EngineControl::on_show ()
432 ArdourDialog::on_show ();
433 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
434 // re-check _have_control (jackd running) see #6041
438 ok_button->grab_focus();
442 EngineControl::try_autostart ()
444 if (!start_stop_button.get_sensitive()) {
447 if (ARDOUR::AudioEngine::instance()->running()) {
450 return start_engine ();
454 EngineControl::start_engine ()
456 if (push_state_to_backend(true) != 0) {
457 MessageDialog msg(*this,
458 ARDOUR::AudioEngine::instance()->get_last_backend_error());
466 EngineControl::stop_engine (bool for_latency)
468 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
469 MessageDialog msg(*this,
470 ARDOUR::AudioEngine::instance()->get_last_backend_error());
478 EngineControl::on_response (int response_id)
480 ArdourDialog::on_response (response_id);
482 switch (response_id) {
484 if (!start_engine()) {
489 #ifdef PLATFORM_WINDOWS
491 // But if there's no session open, this can produce
492 // a long gap when nothing appears to be happening.
493 // Let's show the splash image while we're waiting.
494 if (!ARDOUR_COMMAND_LINE::no_splash) {
495 if (ARDOUR_UI::instance()) {
496 if (!ARDOUR_UI::instance()->session_loaded) {
497 ARDOUR_UI::instance()->show_splash();
503 case RESPONSE_DELETE_EVENT: {
505 ev.type = GDK_BUTTON_PRESS;
507 on_delete_event((GdkEventAny*)&ev);
510 case RESPONSE_CANCEL:
511 if (ARDOUR_UI::instance() && ARDOUR_UI::instance()->session_loaded) {
512 ARDOUR_UI::instance()->check_audioengine(*this);
521 EngineControl::build_notebook ()
524 AttachOptions xopt = AttachOptions (FILL|EXPAND);
526 /* clear the table */
528 Gtkmm2ext::container_clear (basic_vbox);
529 Gtkmm2ext::container_clear (basic_packer);
531 if (control_app_button.get_parent()) {
532 control_app_button.get_parent()->remove (control_app_button);
535 label = manage (left_aligned_label (_("Audio System:")));
536 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
537 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
539 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
540 engine_status.show();
542 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
543 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
544 basic_packer.attach (use_buffered_io_button, 3, 4, 2, 3, xopt, xopt);
546 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
547 lm_button_audio.set_name ("generic button");
548 lm_button_audio.set_can_focus(true);
551 build_full_control_notebook ();
553 build_no_control_notebook ();
556 basic_vbox.pack_start (basic_hbox, false, false);
559 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
560 basic_vbox.show_all ();
565 EngineControl::build_full_control_notebook ()
567 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
570 using namespace Notebook_Helpers;
572 vector<string> strings;
573 AttachOptions xopt = AttachOptions (FILL|EXPAND);
574 int row = 1; // row zero == backend combo
576 /* start packing it up */
578 if (backend->requires_driver_selection()) {
579 label = manage (left_aligned_label (_("Driver:")));
580 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
581 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
585 if (backend->use_separate_input_and_output_devices()) {
586 label = manage (left_aligned_label (_("Input Device:")));
587 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
588 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
590 label = manage (left_aligned_label (_("Output Device:")));
591 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
592 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
594 // reset so it isn't used in state comparisons
595 device_combo.set_active_text ("");
597 label = manage (left_aligned_label (_("Device:")));
598 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
599 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
601 // reset these so they don't get used in state comparisons
602 input_device_combo.set_active_text ("");
603 output_device_combo.set_active_text ("");
606 label = manage (left_aligned_label (_("Sample rate:")));
607 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
608 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
612 label = manage (left_aligned_label (_("Buffer size:")));
613 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
614 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
615 buffer_size_duration_label.set_alignment (0.0); /* left-align */
616 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
618 int ctrl_btn_span = 1;
619 if (backend->can_set_period_size ()) {
621 label = manage (left_aligned_label (_("Periods:")));
622 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
623 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
627 /* button spans 2 or 3 rows */
629 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
632 input_channels.set_name ("InputChannels");
633 input_channels.set_flags (Gtk::CAN_FOCUS);
634 input_channels.set_digits (0);
635 input_channels.set_wrap (false);
636 output_channels.set_editable (true);
638 if (!ARDOUR::Profile->get_mixbus()) {
639 label = manage (left_aligned_label (_("Input Channels:")));
640 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
641 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
645 output_channels.set_name ("OutputChannels");
646 output_channels.set_flags (Gtk::CAN_FOCUS);
647 output_channels.set_digits (0);
648 output_channels.set_wrap (false);
649 output_channels.set_editable (true);
651 if (!ARDOUR::Profile->get_mixbus()) {
652 label = manage (left_aligned_label (_("Output Channels:")));
653 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
654 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
658 input_latency.set_name ("InputLatency");
659 input_latency.set_flags (Gtk::CAN_FOCUS);
660 input_latency.set_digits (0);
661 input_latency.set_wrap (false);
662 input_latency.set_editable (true);
664 label = manage (left_aligned_label (_("Hardware input latency:")));
665 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
666 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
667 label = manage (left_aligned_label (_("samples")));
668 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
671 output_latency.set_name ("OutputLatency");
672 output_latency.set_flags (Gtk::CAN_FOCUS);
673 output_latency.set_digits (0);
674 output_latency.set_wrap (false);
675 output_latency.set_editable (true);
677 label = manage (left_aligned_label (_("Hardware output latency:")));
678 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
679 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
680 label = manage (left_aligned_label (_("samples")));
681 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
683 /* button spans 2 rows */
685 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
688 label = manage (left_aligned_label (_("MIDI System:")));
689 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
690 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
691 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
696 EngineControl::build_no_control_notebook ()
698 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
701 using namespace Notebook_Helpers;
703 vector<string> strings;
704 AttachOptions xopt = AttachOptions (FILL|EXPAND);
705 int row = 1; // row zero == backend combo
706 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
708 label = manage (new Label);
709 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
710 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
713 if (backend->can_change_sample_rate_when_running()) {
714 label = manage (left_aligned_label (_("Sample rate:")));
715 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
716 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
720 if (backend->can_change_buffer_size_when_running()) {
721 label = manage (left_aligned_label (_("Buffer size:")));
722 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
723 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
724 buffer_size_duration_label.set_alignment (0.0); /* left-align */
725 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
729 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
733 EngineControl::~EngineControl ()
735 ignore_changes = true;
739 EngineControl::disable_latency_tab ()
741 vector<string> empty;
742 set_popdown_strings (lm_output_channel_combo, empty);
743 set_popdown_strings (lm_input_channel_combo, empty);
744 lm_measure_button.set_sensitive (false);
745 lm_use_button.set_sensitive (false);
749 EngineControl::enable_latency_tab ()
751 vector<string> outputs;
752 vector<string> inputs;
754 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
755 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
756 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
758 if (!ARDOUR::AudioEngine::instance()->running()) {
759 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
760 notebook.set_current_page (0);
764 else if (inputs.empty() || outputs.empty()) {
765 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
766 notebook.set_current_page (0);
771 lm_back_button_signal.disconnect();
773 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
776 lm_back_button_signal = lm_back_button.signal_clicked().connect(
777 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
781 set_popdown_strings (lm_output_channel_combo, outputs);
782 lm_output_channel_combo.set_active_text (outputs.front());
783 lm_output_channel_combo.set_sensitive (true);
785 set_popdown_strings (lm_input_channel_combo, inputs);
786 lm_input_channel_combo.set_active_text (inputs.front());
787 lm_input_channel_combo.set_sensitive (true);
789 lm_measure_button.set_sensitive (true);
793 EngineControl::setup_midi_tab_for_backend ()
795 Gtkmm2ext::container_clear (midi_vbox);
797 midi_vbox.set_border_width (12);
798 midi_device_table.set_border_width (12);
800 midi_vbox.pack_start (midi_device_table, true, true);
801 midi_vbox.pack_start (midi_input_view);
802 midi_vbox.pack_start (midi_output_view);
803 midi_vbox.pack_start (midi_back_button, false, false);
805 midi_vbox.show_all ();
809 EngineControl::refill_midi_ports (bool for_input)
811 using namespace ARDOUR;
813 std::vector<string> ports;
815 AudioEngine::instance()->get_ports (string(), DataType::MIDI, for_input ? IsInput : IsOutput, ports);
817 Glib::RefPtr<ListStore> model = Gtk::ListStore::create (midi_port_columns);
819 for (vector<string>::const_iterator s = ports.begin(); s != ports.end(); ++s) {
821 if (AudioEngine::instance()->port_is_mine (*s)) {
825 TreeModel::Row row = *(model->append());
827 string pretty = AudioEngine::instance()->get_pretty_name_by_name (*s);
828 row[midi_port_columns.name] = *s;
829 row[midi_port_columns.pretty_name] = (pretty.empty() ? *s : pretty);
830 row[midi_port_columns.in_use] = true;
831 row[midi_port_columns.music_data] = true;
832 row[midi_port_columns.control_data] = true;
835 Gtk::TreeView& view (for_input ? midi_input_view : midi_output_view);
837 view.set_model (model);
839 CellRendererText* pretty_name_cell = dynamic_cast<CellRendererText*> (view.get_column_cell_renderer (pretty_name_column));
840 pretty_name_cell->property_editable() = true;
841 pretty_name_cell->signal_edited().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::pretty_name_edit), &view));
843 CellRendererToggle* toggle_cell;
845 toggle_cell = dynamic_cast<CellRendererToggle*> (view.get_column_cell_renderer (use_column));
846 toggle_cell->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_use_column_toggled), &view));
848 toggle_cell = dynamic_cast<CellRendererToggle*> (view.get_column_cell_renderer (music_column));
849 toggle_cell->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_music_column_toggled), &view));
851 toggle_cell = dynamic_cast<CellRendererToggle*> (view.get_column_cell_renderer (control_column));
852 toggle_cell->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_control_column_toggled), &view));
854 toggle_cell = dynamic_cast<CellRendererToggle*> (view.get_column_cell_renderer (selection_column));
855 toggle_cell->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_selection_column_toggled), &view));
859 EngineControl::midi_use_column_toggled (string const & path, TreeView* view)
861 TreeIter iter = view->get_model()->get_iter (path);
867 bool value ((*iter)[midi_port_columns.in_use]);
868 (*iter)[midi_port_columns.in_use] = !value;
873 EngineControl::midi_music_column_toggled (string const & path, TreeView* view)
875 TreeIter iter = view->get_model()->get_iter (path);
881 bool value ((*iter)[midi_port_columns.music_data]);
882 (*iter)[midi_port_columns.music_data] = !value;
886 EngineControl::midi_control_column_toggled (string const & path, TreeView* view)
888 TreeIter iter = view->get_model()->get_iter (path);
894 bool value ((*iter)[midi_port_columns.control_data]);
895 (*iter)[midi_port_columns.control_data] = !value;
898 // ARDOUR::AudioEngine::instance()->remove_port_purpose (PortFlags (ControlData));
900 // ARDOUR::AudioEngine::instance()->add_port_purpose (PortFlags (ControlData));
905 EngineControl::midi_selection_column_toggled (string const & path, TreeView* view)
907 TreeIter iter = view->get_model()->get_iter (path);
912 bool value ((*iter)[midi_port_columns.selection]);
913 (*iter)[midi_port_columns.selection] = !value;
917 EngineControl::pretty_name_edit (std::string const & path, string const & new_text, Gtk::TreeView* view)
919 TreeIter iter = view->get_model()->get_iter (path);
925 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
927 ARDOUR::PortEngine::PortHandle ph = backend->get_port_by_name ((*iter)[midi_port_columns.name]);
929 backend->set_port_property (ph, "http://jackaudio.org/metadata/pretty-name", new_text, "");
930 (*iter)[midi_port_columns.pretty_name] = new_text;
936 EngineControl::update_sensitivity ()
938 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
940 ok_button->set_sensitive (false);
941 start_stop_button.set_sensitive (false);
946 size_t devices_available = 0;
948 if (backend->use_separate_input_and_output_devices ()) {
949 devices_available += get_popdown_string_count (input_device_combo);
950 devices_available += get_popdown_string_count (output_device_combo);
952 devices_available += get_popdown_string_count (device_combo);
955 if (devices_available == 0) {
957 input_latency.set_sensitive (false);
958 output_latency.set_sensitive (false);
959 input_channels.set_sensitive (false);
960 output_channels.set_sensitive (false);
962 input_latency.set_sensitive (true);
963 output_latency.set_sensitive (true);
964 input_channels.set_sensitive (true);
965 output_channels.set_sensitive (true);
968 if (get_popdown_string_count (buffer_size_combo) > 0) {
969 if (!ARDOUR::AudioEngine::instance()->running()) {
970 buffer_size_combo.set_sensitive (valid);
971 } else if (backend->can_change_sample_rate_when_running()) {
972 buffer_size_combo.set_sensitive (valid || !_have_control);
976 * Currently there is no way to manually stop the
977 * engine in order to re-configure it.
978 * This needs to remain sensitive for now.
980 * (it's also handy to implicily
981 * re-start the engine)
983 buffer_size_combo.set_sensitive (true);
985 buffer_size_combo.set_sensitive (false);
989 buffer_size_combo.set_sensitive (false);
993 if (get_popdown_string_count (sample_rate_combo) > 0) {
994 bool allow_to_set_rate = false;
995 if (!ARDOUR::AudioEngine::instance()->running()) {
996 if (!ARDOUR_UI::instance()->session_loaded) {
997 // engine is not running, no session loaded -> anything goes.
998 allow_to_set_rate = true;
999 } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
1000 // only allow to change if the current setting is not the native session rate.
1001 allow_to_set_rate = true;
1004 sample_rate_combo.set_sensitive (allow_to_set_rate);
1006 sample_rate_combo.set_sensitive (false);
1010 if (get_popdown_string_count (nperiods_combo) > 0) {
1011 if (!ARDOUR::AudioEngine::instance()->running()) {
1012 nperiods_combo.set_sensitive (true);
1014 nperiods_combo.set_sensitive (false);
1017 nperiods_combo.set_sensitive (false);
1020 if (_have_control) {
1021 start_stop_button.set_sensitive(true);
1022 start_stop_button.show();
1023 if (ARDOUR::AudioEngine::instance()->running()) {
1024 start_stop_button.set_text("Stop");
1025 update_devices_button.set_sensitive(false);
1026 use_buffered_io_button.set_sensitive(false);
1028 if (backend->can_request_update_devices()) {
1029 update_devices_button.show();
1031 update_devices_button.hide();
1033 if (backend->can_use_buffered_io()) {
1034 use_buffered_io_button.show();
1036 use_buffered_io_button.hide();
1038 start_stop_button.set_text("Start");
1039 update_devices_button.set_sensitive(true);
1040 use_buffered_io_button.set_sensitive(true);
1043 update_devices_button.set_sensitive(false);
1044 update_devices_button.hide();
1045 use_buffered_io_button.set_sensitive(false);
1046 use_buffered_io_button.hide();
1047 start_stop_button.set_sensitive(false);
1048 start_stop_button.hide();
1051 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
1052 input_device_combo.set_sensitive (false);
1053 output_device_combo.set_sensitive (false);
1054 device_combo.set_sensitive (false);
1055 driver_combo.set_sensitive (false);
1057 input_device_combo.set_sensitive (true);
1058 output_device_combo.set_sensitive (true);
1059 device_combo.set_sensitive (true);
1060 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
1061 driver_combo.set_sensitive (true);
1063 driver_combo.set_sensitive (false);
1067 if (valid || !_have_control) {
1068 ok_button->set_sensitive (true);
1070 ok_button->set_sensitive (false);
1075 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
1077 device->input_latency = a->get_value();
1079 device->output_latency = a->get_value();
1084 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
1085 b->set_active (!b->get_active());
1086 device->enabled = b->get_active();
1087 refresh_midi_display(device->name);
1091 EngineControl::refresh_midi_display (std::string focus)
1093 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1097 AttachOptions xopt = AttachOptions (FILL|EXPAND);
1100 Gtkmm2ext::container_clear (midi_device_table);
1102 midi_device_table.set_spacings (6);
1104 l = manage (new Label);
1105 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
1106 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
1107 l->set_alignment (0.5, 0.5);
1111 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
1112 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
1113 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
1114 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
1116 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
1117 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
1118 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
1119 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
1122 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1127 bool enabled = (*p)->enabled;
1129 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
1130 m->set_name ("midi device");
1131 m->set_can_focus (Gtk::CAN_FOCUS);
1132 m->add_events (Gdk::BUTTON_RELEASE_MASK);
1133 m->set_active (enabled);
1134 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
1135 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
1136 if ((*p)->name == focus) {
1140 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
1141 s = manage (new Gtk::SpinButton (*a));
1142 a->set_value ((*p)->input_latency);
1143 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
1144 s->set_sensitive (_can_set_midi_latencies && enabled);
1145 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
1147 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
1148 s = manage (new Gtk::SpinButton (*a));
1149 a->set_value ((*p)->output_latency);
1150 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
1151 s->set_sensitive (_can_set_midi_latencies && enabled);
1152 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
1154 b = manage (new Button (_("Calibrate")));
1155 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
1156 b->set_sensitive (_can_set_midi_latencies && enabled);
1157 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
1164 EngineControl::backend_changed ()
1166 SignalBlocker blocker (*this, "backend_changed");
1167 string backend_name = backend_combo.get_active_text();
1168 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1170 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1171 /* eh? setting the backend failed... how ? */
1172 /* A: stale config contains a backend that does not exist in current build */
1176 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1178 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1181 setup_midi_tab_for_backend ();
1182 _midi_devices.clear();
1184 if (backend->requires_driver_selection()) {
1185 if (set_driver_popdown_strings ()) {
1189 /* this will change the device text which will cause a call to
1190 * device changed which will set up parameters
1195 update_midi_options ();
1197 connect_disconnect_button.hide();
1199 midi_option_changed();
1201 started_at_least_once = false;
1203 /* changing the backend implies stopping the engine
1204 * ARDOUR::AudioEngine() may or may not emit this signal
1205 * depending on previous engine state
1207 engine_stopped (); // set "active/inactive"
1209 if (!_have_control) {
1210 // set settings from backend that we do have control over
1211 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1214 if (_have_control && !ignore_changes) {
1215 // set driver & devices
1216 State state = get_matching_state (backend_combo.get_active_text());
1218 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1219 set_current_state (state);
1223 if (!ignore_changes) {
1224 maybe_display_saved_state ();
1229 EngineControl::update_midi_options ()
1231 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1232 vector<string> midi_options = backend->enumerate_midi_options();
1234 if (midi_options.size() == 1) {
1235 /* only contains the "none" option */
1236 midi_option_combo.set_sensitive (false);
1238 if (_have_control) {
1239 set_popdown_strings (midi_option_combo, midi_options);
1240 midi_option_combo.set_active_text (midi_options.front());
1241 midi_option_combo.set_sensitive (true);
1243 midi_option_combo.set_sensitive (false);
1249 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1251 if (ARDOUR::Profile->get_mixbus()) {
1255 uint32_t cnt = (uint32_t) sb->get_value();
1257 sb->set_text (_("all available channels"));
1260 snprintf (buf, sizeof (buf), "%d", cnt);
1266 // @return true if there are drivers available
1268 EngineControl::set_driver_popdown_strings ()
1270 DEBUG_ECONTROL ("set_driver_popdown_strings");
1271 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1272 vector<string> drivers = backend->enumerate_drivers();
1274 if (drivers.empty ()) {
1275 // This is an error...?
1279 string current_driver = backend->driver_name ();
1281 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1283 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1286 current_driver = drivers.front ();
1289 set_popdown_strings (driver_combo, drivers);
1291 string_compose ("driver_combo.set_active_text: %1", current_driver));
1292 driver_combo.set_active_text (current_driver);
1297 EngineControl::get_default_device(const string& current_device_name,
1298 const vector<string>& available_devices)
1300 // If the current device is available, use it as default
1301 if (std::find (available_devices.begin (),
1302 available_devices.end (),
1303 current_device_name) != available_devices.end ()) {
1305 return current_device_name;
1308 using namespace ARDOUR;
1310 string default_device_name =
1311 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1313 vector<string>::const_iterator i;
1315 // If there is a "Default" device available, use it
1316 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1317 if (*i == default_device_name) {
1322 string none_device_name =
1323 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1325 // Use the first device that isn't "None"
1326 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1327 if (*i != none_device_name) {
1332 // Use "None" if there are no other available
1333 return available_devices.front();
1336 // @return true if there are devices available
1338 EngineControl::set_device_popdown_strings ()
1340 DEBUG_ECONTROL ("set_device_popdown_strings");
1341 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1342 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1344 /* NOTE: Ardour currently does not display the "available" field of the
1347 * Doing so would require a different GUI widget than the combo
1348 * box/popdown that we currently use, since it has no way to list
1349 * items that are not selectable. Something more like a popup menu,
1350 * which could have unselectable items, would be appropriate.
1353 vector<string> available_devices;
1355 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1356 available_devices.push_back (i->name);
1359 if (available_devices.empty ()) {
1363 set_popdown_strings (device_combo, available_devices);
1365 std::string default_device =
1366 get_default_device(backend->device_name(), available_devices);
1369 string_compose ("set device_combo active text: %1", default_device));
1371 device_combo.set_active_text(default_device);
1375 // @return true if there are input devices available
1377 EngineControl::set_input_device_popdown_strings ()
1379 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1380 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1381 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1383 vector<string> available_devices;
1385 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1386 available_devices.push_back (i->name);
1389 if (available_devices.empty()) {
1393 set_popdown_strings (input_device_combo, available_devices);
1395 std::string default_device =
1396 get_default_device(backend->input_device_name(), available_devices);
1399 string_compose ("set input_device_combo active text: %1", default_device));
1400 input_device_combo.set_active_text(default_device);
1404 // @return true if there are output devices available
1406 EngineControl::set_output_device_popdown_strings ()
1408 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1409 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1410 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1412 vector<string> available_devices;
1414 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1415 available_devices.push_back (i->name);
1418 if (available_devices.empty()) {
1422 set_popdown_strings (output_device_combo, available_devices);
1424 std::string default_device =
1425 get_default_device(backend->output_device_name(), available_devices);
1428 string_compose ("set output_device_combo active text: %1", default_device));
1429 output_device_combo.set_active_text(default_device);
1434 EngineControl::list_devices ()
1436 DEBUG_ECONTROL ("list_devices");
1437 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1440 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1442 bool devices_available = false;
1444 if (backend->use_separate_input_and_output_devices ()) {
1445 bool input_devices_available = set_input_device_popdown_strings ();
1446 bool output_devices_available = set_output_device_popdown_strings ();
1447 devices_available = input_devices_available || output_devices_available;
1449 devices_available = set_device_popdown_strings ();
1452 if (devices_available) {
1455 device_combo.clear();
1456 input_device_combo.clear();
1457 output_device_combo.clear();
1459 update_sensitivity ();
1463 EngineControl::driver_changed ()
1465 SignalBlocker blocker (*this, "driver_changed");
1466 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1469 backend->set_driver (driver_combo.get_active_text());
1472 // TODO load LRU device(s) for backend + driver combo
1474 if (!ignore_changes) {
1475 maybe_display_saved_state ();
1480 EngineControl::get_sample_rates_for_all_devices ()
1482 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1483 ARDOUR::AudioEngine::instance ()->current_backend ();
1484 vector<float> all_rates;
1486 if (backend->use_separate_input_and_output_devices ()) {
1487 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1489 all_rates = backend->available_sample_rates (get_device_name ());
1495 EngineControl::get_default_sample_rates ()
1497 vector<float> rates;
1498 rates.push_back (8000.0f);
1499 rates.push_back (16000.0f);
1500 rates.push_back (32000.0f);
1501 rates.push_back (44100.0f);
1502 rates.push_back (48000.0f);
1503 rates.push_back (88200.0f);
1504 rates.push_back (96000.0f);
1505 rates.push_back (192000.0f);
1506 rates.push_back (384000.0f);
1511 EngineControl::set_samplerate_popdown_strings ()
1513 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1514 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1519 if (_have_control) {
1520 sr = get_sample_rates_for_all_devices ();
1522 sr = get_default_sample_rates ();
1525 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1526 s.push_back (rate_as_string (*x));
1527 if (*x == _desired_sample_rate) {
1532 set_popdown_strings (sample_rate_combo, s);
1535 if (ARDOUR::AudioEngine::instance()->running()) {
1536 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1538 else if (desired.empty ()) {
1539 float new_active_sr = backend->default_sample_rate ();
1541 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1542 new_active_sr = sr.front ();
1545 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1547 sample_rate_combo.set_active_text (desired);
1551 update_sensitivity ();
1555 EngineControl::get_buffer_sizes_for_all_devices ()
1557 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1558 ARDOUR::AudioEngine::instance ()->current_backend ();
1559 vector<uint32_t> all_sizes;
1561 if (backend->use_separate_input_and_output_devices ()) {
1562 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1564 all_sizes = backend->available_buffer_sizes (get_device_name ());
1570 EngineControl::get_default_buffer_sizes ()
1572 vector<uint32_t> sizes;
1573 sizes.push_back (8);
1574 sizes.push_back (16);
1575 sizes.push_back (32);
1576 sizes.push_back (64);
1577 sizes.push_back (128);
1578 sizes.push_back (256);
1579 sizes.push_back (512);
1580 sizes.push_back (1024);
1581 sizes.push_back (2048);
1582 sizes.push_back (4096);
1583 sizes.push_back (8192);
1588 EngineControl::set_buffersize_popdown_strings ()
1590 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1591 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1592 vector<uint32_t> bs;
1595 if (_have_control) {
1596 bs = get_buffer_sizes_for_all_devices ();
1597 } else if (backend->can_change_buffer_size_when_running()) {
1598 bs = get_default_buffer_sizes ();
1601 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1602 s.push_back (bufsize_as_string (*x));
1605 uint32_t previous_size = 0;
1606 if (!buffer_size_combo.get_active_text().empty()) {
1607 previous_size = get_buffer_size ();
1610 set_popdown_strings (buffer_size_combo, s);
1614 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1615 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1618 buffer_size_combo.set_active_text(s.front());
1620 uint32_t period = backend->buffer_size();
1621 if (0 == period && backend->use_separate_input_and_output_devices()) {
1622 period = backend->default_buffer_size(get_input_device_name());
1624 if (0 == period && backend->use_separate_input_and_output_devices()) {
1625 period = backend->default_buffer_size(get_output_device_name());
1627 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1628 period = backend->default_buffer_size(get_device_name());
1631 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1633 show_buffer_duration ();
1635 update_sensitivity ();
1639 EngineControl::set_nperiods_popdown_strings ()
1641 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1642 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1643 vector<uint32_t> np;
1646 if (backend->can_set_period_size()) {
1647 np = backend->available_period_sizes (get_driver());
1650 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1651 s.push_back (nperiods_as_string (*x));
1654 set_popdown_strings (nperiods_combo, s);
1657 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX
1660 update_sensitivity ();
1664 EngineControl::device_changed ()
1666 SignalBlocker blocker (*this, "device_changed");
1667 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1670 string device_name_in;
1671 string device_name_out; // only used if backend support separate I/O devices
1673 if (backend->use_separate_input_and_output_devices()) {
1674 device_name_in = get_input_device_name ();
1675 device_name_out = get_output_device_name ();
1677 device_name_in = get_device_name ();
1680 /* we set the backend-device to query various device related intormation.
1681 * This has the side effect that backend->device_name() will match
1682 * the device_name and 'change_device' will never be true.
1683 * so work around this by setting...
1685 if (backend->use_separate_input_and_output_devices()) {
1686 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1687 queue_device_changed = true;
1690 if (device_name_in != backend->device_name()) {
1691 queue_device_changed = true;
1695 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1696 if (backend->use_separate_input_and_output_devices()) {
1697 backend->set_input_device_name (device_name_in);
1698 backend->set_output_device_name (device_name_out);
1700 backend->set_device_name(device_name_in);
1704 /* don't allow programmatic change to combos to cause a
1705 recursive call to this method.
1707 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1709 set_samplerate_popdown_strings ();
1710 set_buffersize_popdown_strings ();
1711 set_nperiods_popdown_strings ();
1713 /* TODO set min + max channel counts here */
1715 manage_control_app_sensitivity ();
1718 /* pick up any saved state for this device */
1720 if (!ignore_changes) {
1721 maybe_display_saved_state ();
1726 EngineControl::input_device_changed ()
1728 DEBUG_ECONTROL ("input_device_changed");
1733 EngineControl::output_device_changed ()
1735 DEBUG_ECONTROL ("output_device_changed");
1740 EngineControl::bufsize_as_string (uint32_t sz)
1742 return string_compose (P_("%1 sample", "%1 samples", sz), sz);
1746 EngineControl::nperiods_as_string (uint32_t np)
1749 snprintf (buf, sizeof (buf), "%u", np);
1755 EngineControl::sample_rate_changed ()
1757 DEBUG_ECONTROL ("sample_rate_changed");
1758 /* reset the strings for buffer size to show the correct msec value
1759 (reflecting the new sample rate).
1762 show_buffer_duration ();
1767 EngineControl::buffer_size_changed ()
1769 DEBUG_ECONTROL ("buffer_size_changed");
1770 show_buffer_duration ();
1774 EngineControl::nperiods_changed ()
1776 DEBUG_ECONTROL ("nperiods_changed");
1777 show_buffer_duration ();
1781 EngineControl::show_buffer_duration ()
1783 DEBUG_ECONTROL ("show_buffer_duration");
1784 /* buffer sizes - convert from just samples to samples + msecs for
1785 * the displayed string
1788 string bs_text = buffer_size_combo.get_active_text ();
1789 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1790 uint32_t rate = get_rate();
1792 /* Except for ALSA and Dummy backends, we don't know the number of periods
1793 * per cycle and settings.
1795 * jack1 vs jack2 have different default latencies since jack2 start
1796 * in async-mode unless --sync is given which adds an extra cycle
1797 * of latency. The value is not known if jackd is started externally..
1799 * So just display the period size, that's also what
1800 * ARDOUR_UI::update_sample_rate() does for the status bar.
1801 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1802 * but still, that's the buffer period, not [round-trip] latency)
1805 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1806 buffer_size_duration_label.set_text (buf);
1810 EngineControl::midi_option_changed ()
1812 DEBUG_ECONTROL ("midi_option_changed");
1813 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1816 backend->set_midi_option (get_midi_option());
1818 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1820 //_midi_devices.clear(); // TODO merge with state-saved settings..
1821 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1822 std::vector<MidiDeviceSettings> new_devices;
1824 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1825 MidiDeviceSettings mds = find_midi_device (i->name);
1826 if (i->available && !mds) {
1827 uint32_t input_latency = 0;
1828 uint32_t output_latency = 0;
1829 if (_can_set_midi_latencies) {
1830 input_latency = backend->systemic_midi_input_latency (i->name);
1831 output_latency = backend->systemic_midi_output_latency (i->name);
1833 bool enabled = backend->midi_device_enabled (i->name);
1834 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1835 new_devices.push_back (ptr);
1836 } else if (i->available) {
1837 new_devices.push_back (mds);
1840 _midi_devices = new_devices;
1842 if (_midi_devices.empty()) {
1843 midi_devices_button.hide ();
1845 midi_devices_button.show ();
1850 EngineControl::parameter_changed ()
1854 EngineControl::State
1855 EngineControl::get_matching_state (const string& backend)
1857 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1858 if ((*i)->backend == backend) {
1865 EngineControl::State
1866 EngineControl::get_matching_state (
1867 const string& backend,
1868 const string& driver,
1869 const string& device)
1871 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1872 if ((*i)->backend == backend &&
1873 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1881 EngineControl::State
1882 EngineControl::get_matching_state (
1883 const string& backend,
1884 const string& driver,
1885 const string& input_device,
1886 const string& output_device)
1888 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1889 if ((*i)->backend == backend &&
1890 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1898 EngineControl::State
1899 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1901 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1904 if (backend->use_separate_input_and_output_devices ()) {
1905 return get_matching_state (backend_combo.get_active_text(),
1906 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1907 input_device_combo.get_active_text(),
1908 output_device_combo.get_active_text());
1910 return get_matching_state (backend_combo.get_active_text(),
1911 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1912 device_combo.get_active_text());
1916 return get_matching_state (backend_combo.get_active_text(),
1918 device_combo.get_active_text());
1921 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1922 const EngineControl::State& state2)
1924 if (state1->backend == state2->backend &&
1925 state1->driver == state2->driver &&
1926 state1->device == state2->device &&
1927 state1->input_device == state2->input_device &&
1928 state1->output_device == state2->output_device) {
1935 EngineControl::state_sort_cmp (const State &a, const State &b) {
1939 else if (b->active) {
1943 return a->lru < b->lru;
1947 EngineControl::State
1948 EngineControl::save_state ()
1952 if (!_have_control) {
1953 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1955 state->lru = time (NULL) ;
1958 state.reset(new StateStruct);
1959 state->backend = get_backend ();
1961 state.reset(new StateStruct);
1962 store_state (state);
1965 for (StateList::iterator i = states.begin(); i != states.end();) {
1966 if (equivalent_states (*i, state)) {
1967 i = states.erase(i);
1973 states.push_back (state);
1975 states.sort (state_sort_cmp);
1981 EngineControl::store_state (State state)
1983 state->backend = get_backend ();
1984 state->driver = get_driver ();
1985 state->device = get_device_name ();
1986 state->input_device = get_input_device_name ();
1987 state->output_device = get_output_device_name ();
1988 state->sample_rate = get_rate ();
1989 state->buffer_size = get_buffer_size ();
1990 state->n_periods = get_nperiods ();
1991 state->input_latency = get_input_latency ();
1992 state->output_latency = get_output_latency ();
1993 state->input_channels = get_input_channels ();
1994 state->output_channels = get_output_channels ();
1995 state->midi_option = get_midi_option ();
1996 state->midi_devices = _midi_devices;
1997 state->use_buffered_io = get_use_buffered_io ();
1998 state->lru = time (NULL) ;
2002 EngineControl::maybe_display_saved_state ()
2004 if (!_have_control) {
2008 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2011 DEBUG_ECONTROL ("Restoring saved state");
2012 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2014 if (!_desired_sample_rate) {
2015 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2017 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2019 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2020 /* call this explicitly because we're ignoring changes to
2021 the controls at this point.
2023 show_buffer_duration ();
2024 input_latency.set_value (state->input_latency);
2025 output_latency.set_value (state->output_latency);
2027 use_buffered_io_button.set_active (state->use_buffered_io);
2029 if (!state->midi_option.empty()) {
2030 midi_option_combo.set_active_text (state->midi_option);
2031 _midi_devices = state->midi_devices;
2034 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
2039 EngineControl::get_state ()
2043 XMLNode* root = new XMLNode ("AudioMIDISetup");
2046 if (!states.empty()) {
2047 XMLNode* state_nodes = new XMLNode ("EngineStates");
2049 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2051 XMLNode* node = new XMLNode ("State");
2053 node->add_property ("backend", (*i)->backend);
2054 node->add_property ("driver", (*i)->driver);
2055 node->add_property ("device", (*i)->device);
2056 node->add_property ("input-device", (*i)->input_device);
2057 node->add_property ("output-device", (*i)->output_device);
2058 node->add_property ("sample-rate", (*i)->sample_rate);
2059 node->add_property ("buffer-size", (*i)->buffer_size);
2060 node->add_property ("n-periods", (*i)->n_periods);
2061 node->add_property ("input-latency", (*i)->input_latency);
2062 node->add_property ("output-latency", (*i)->output_latency);
2063 node->add_property ("input-channels", (*i)->input_channels);
2064 node->add_property ("output-channels", (*i)->output_channels);
2065 node->add_property ("active", (*i)->active ? "yes" : "no");
2066 node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
2067 node->add_property ("midi-option", (*i)->midi_option);
2068 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
2070 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
2071 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
2072 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
2073 midi_device_stuff->add_property (X_("name"), (*p)->name);
2074 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
2075 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
2076 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
2077 midi_devices->add_child_nocopy (*midi_device_stuff);
2079 node->add_child_nocopy (*midi_devices);
2081 state_nodes->add_child_nocopy (*node);
2084 root->add_child_nocopy (*state_nodes);
2091 EngineControl::set_default_state ()
2093 vector<string> backend_names;
2094 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2096 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
2097 backend_names.push_back ((*b)->name);
2099 backend_combo.set_active_text (backend_names.front());
2101 // We could set default backends per platform etc here
2107 EngineControl::set_state (const XMLNode& root)
2109 XMLNodeList clist, cclist;
2110 XMLNodeConstIterator citer, cciter;
2111 XMLNode const * child;
2112 XMLNode const * grandchild;
2113 XMLProperty const * prop = NULL;
2115 if (root.name() != "AudioMIDISetup") {
2119 clist = root.children();
2123 for (citer = clist.begin(); citer != clist.end(); ++citer) {
2127 if (child->name() != "EngineStates") {
2131 cclist = child->children();
2133 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2134 State state (new StateStruct);
2136 grandchild = *cciter;
2138 if (grandchild->name() != "State") {
2142 if ((prop = grandchild->property ("backend")) == 0) {
2145 state->backend = prop->value ();
2147 if ((prop = grandchild->property ("driver")) == 0) {
2150 state->driver = prop->value ();
2152 if ((prop = grandchild->property ("device")) == 0) {
2155 state->device = prop->value ();
2157 if ((prop = grandchild->property ("input-device")) == 0) {
2160 state->input_device = prop->value ();
2162 if ((prop = grandchild->property ("output-device")) == 0) {
2165 state->output_device = prop->value ();
2167 if ((prop = grandchild->property ("sample-rate")) == 0) {
2170 state->sample_rate = atof (prop->value ());
2172 if ((prop = grandchild->property ("buffer-size")) == 0) {
2175 state->buffer_size = atoi (prop->value ());
2177 if ((prop = grandchild->property ("n-periods")) == 0) {
2178 // optional (new value in 4.5)
2179 state->n_periods = 0;
2181 state->n_periods = atoi (prop->value ());
2184 if ((prop = grandchild->property ("input-latency")) == 0) {
2187 state->input_latency = atoi (prop->value ());
2189 if ((prop = grandchild->property ("output-latency")) == 0) {
2192 state->output_latency = atoi (prop->value ());
2194 if ((prop = grandchild->property ("input-channels")) == 0) {
2197 state->input_channels = atoi (prop->value ());
2199 if ((prop = grandchild->property ("output-channels")) == 0) {
2202 state->output_channels = atoi (prop->value ());
2204 if ((prop = grandchild->property ("active")) == 0) {
2207 state->active = string_is_affirmative (prop->value ());
2209 if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2212 state->use_buffered_io = string_is_affirmative (prop->value ());
2214 if ((prop = grandchild->property ("midi-option")) == 0) {
2217 state->midi_option = prop->value ();
2219 state->midi_devices.clear();
2221 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2222 const XMLNodeList mnc = midinode->children();
2223 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2224 if ((*n)->property (X_("name")) == 0
2225 || (*n)->property (X_("enabled")) == 0
2226 || (*n)->property (X_("input-latency")) == 0
2227 || (*n)->property (X_("output-latency")) == 0
2232 MidiDeviceSettings ptr (new MidiDeviceSetting(
2233 (*n)->property (X_("name"))->value (),
2234 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2235 atoi ((*n)->property (X_("input-latency"))->value ()),
2236 atoi ((*n)->property (X_("output-latency"))->value ())
2238 state->midi_devices.push_back (ptr);
2242 if ((prop = grandchild->property ("lru"))) {
2243 state->lru = atoi (prop->value ());
2247 /* remove accumulated duplicates (due to bug in ealier version)
2248 * this can be removed again before release
2250 for (StateList::iterator i = states.begin(); i != states.end();) {
2251 if ((*i)->backend == state->backend &&
2252 (*i)->driver == state->driver &&
2253 (*i)->device == state->device) {
2254 i = states.erase(i);
2261 states.push_back (state);
2265 /* now see if there was an active state and switch the setup to it */
2267 // purge states of backend that are not available in this built
2268 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2269 vector<std::string> backend_names;
2271 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2272 backend_names.push_back((*i)->name);
2274 for (StateList::iterator i = states.begin(); i != states.end();) {
2275 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2276 i = states.erase(i);
2282 states.sort (state_sort_cmp);
2284 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2287 return set_current_state (*i);
2294 EngineControl::set_current_state (const State& state)
2296 DEBUG_ECONTROL ("set_current_state");
2298 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2300 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2301 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2302 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2303 // this shouldn't happen as the invalid backend names should have been
2304 // removed from the list of states.
2308 // now reflect the change in the backend in the GUI so backend_changed will
2309 // do the right thing
2310 backend_combo.set_active_text (state->backend);
2312 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2314 // we don't have control don't restore state
2319 if (!state->driver.empty ()) {
2320 if (!backend->requires_driver_selection ()) {
2321 DEBUG_ECONTROL ("Backend should require driver selection");
2322 // A backend has changed from having driver selection to not having
2323 // it or someone has been manually editing a config file and messed
2328 if (backend->set_driver (state->driver) != 0) {
2329 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2330 // Driver names for a backend have changed and the name in the
2331 // config file is now invalid or support for driver is no longer
2332 // included in the backend
2335 // no need to set the driver_combo as backend_changed will use
2336 // backend->driver_name to set the active driver
2339 if (!state->device.empty ()) {
2340 if (backend->set_device_name (state->device) != 0) {
2342 string_compose ("Unable to set device name %1", state->device));
2343 // device is no longer available on the system
2346 // no need to set active device as it will be picked up in
2347 // via backend_changed ()/set_device_popdown_strings
2350 // backend supports separate input/output devices
2351 if (backend->set_input_device_name (state->input_device) != 0) {
2352 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2353 state->input_device));
2354 // input device is no longer available on the system
2358 if (backend->set_output_device_name (state->output_device) != 0) {
2359 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2360 state->input_device));
2361 // output device is no longer available on the system
2364 // no need to set active devices as it will be picked up in via
2365 // backend_changed ()/set_*_device_popdown_strings
2370 // Now restore the state of the rest of the controls
2372 // We don't use a SignalBlocker as set_current_state is currently only
2373 // called from set_state before any signals are connected. If at some point
2374 // a more general named state mechanism is implemented and
2375 // set_current_state is called while signals are connected then a
2376 // SignalBlocker will need to be instantiated before setting these.
2378 device_combo.set_active_text (state->device);
2379 input_device_combo.set_active_text (state->input_device);
2380 output_device_combo.set_active_text (state->output_device);
2381 if (!_desired_sample_rate) {
2382 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2384 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2385 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2386 input_latency.set_value (state->input_latency);
2387 output_latency.set_value (state->output_latency);
2388 midi_option_combo.set_active_text (state->midi_option);
2389 use_buffered_io_button.set_active (state->use_buffered_io);
2394 EngineControl::push_state_to_backend (bool start)
2396 DEBUG_ECONTROL ("push_state_to_backend");
2397 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2398 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2404 /* figure out what is going to change */
2406 bool restart_required = false;
2407 bool was_running = ARDOUR::AudioEngine::instance()->running();
2408 bool change_driver = false;
2409 bool change_device = false;
2410 bool change_rate = false;
2411 bool change_bufsize = false;
2412 bool change_nperiods = false;
2413 bool change_latency = false;
2414 bool change_channels = false;
2415 bool change_midi = false;
2416 bool change_buffered_io = false;
2418 uint32_t ochan = get_output_channels ();
2419 uint32_t ichan = get_input_channels ();
2421 if (_have_control) {
2423 if (started_at_least_once) {
2425 /* we can control the backend */
2427 if (backend->requires_driver_selection()) {
2428 if (get_driver() != backend->driver_name()) {
2429 change_driver = true;
2433 if (backend->use_separate_input_and_output_devices()) {
2434 if (get_input_device_name() != backend->input_device_name()) {
2435 change_device = true;
2437 if (get_output_device_name() != backend->output_device_name()) {
2438 change_device = true;
2441 if (get_device_name() != backend->device_name()) {
2442 change_device = true;
2446 if (queue_device_changed) {
2447 change_device = true;
2450 if (get_rate() != backend->sample_rate()) {
2454 if (get_buffer_size() != backend->buffer_size()) {
2455 change_bufsize = true;
2458 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2459 && get_nperiods() != backend->period_size()) {
2460 change_nperiods = true;
2463 if (get_midi_option() != backend->midi_option()) {
2467 if (backend->can_use_buffered_io()) {
2468 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2469 change_buffered_io = true;
2473 /* zero-requested channels means "all available" */
2476 ichan = backend->input_channels();
2480 ochan = backend->output_channels();
2483 if (ichan != backend->input_channels()) {
2484 change_channels = true;
2487 if (ochan != backend->output_channels()) {
2488 change_channels = true;
2491 if (get_input_latency() != backend->systemic_input_latency() ||
2492 get_output_latency() != backend->systemic_output_latency()) {
2493 change_latency = true;
2496 /* backend never started, so we have to force a group
2499 change_device = true;
2500 if (backend->requires_driver_selection()) {
2501 change_driver = true;
2504 change_bufsize = true;
2505 change_channels = true;
2506 change_latency = true;
2508 change_buffered_io = backend->can_use_buffered_io();
2509 change_channels = true;
2510 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2515 /* we have no control over the backend, meaning that we can
2516 * only possibly change sample rate and buffer size.
2520 if (get_rate() != backend->sample_rate()) {
2521 change_bufsize = true;
2524 if (get_buffer_size() != backend->buffer_size()) {
2525 change_bufsize = true;
2529 queue_device_changed = false;
2531 if (!_have_control) {
2533 /* We do not have control over the backend, so the best we can
2534 * do is try to change the sample rate and/or bufsize and get
2538 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2542 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2547 backend->set_sample_rate (get_rate());
2550 if (change_bufsize) {
2551 backend->set_buffer_size (get_buffer_size());
2555 if (ARDOUR::AudioEngine::instance()->start ()) {
2556 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2566 /* determine if we need to stop the backend before changing parameters */
2568 if (change_driver || change_device || change_channels || change_nperiods ||
2569 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2570 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2571 change_midi || change_buffered_io ||
2572 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2573 restart_required = true;
2575 restart_required = false;
2580 if (restart_required) {
2581 if (ARDOUR::AudioEngine::instance()->stop()) {
2587 if (change_driver && backend->set_driver (get_driver())) {
2588 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2591 if (backend->use_separate_input_and_output_devices()) {
2592 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2593 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2596 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2597 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2601 if (change_device && backend->set_device_name (get_device_name())) {
2602 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2606 if (change_rate && backend->set_sample_rate (get_rate())) {
2607 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2610 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2611 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2614 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2615 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2619 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2620 if (backend->set_input_channels (get_input_channels())) {
2621 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2624 if (backend->set_output_channels (get_output_channels())) {
2625 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2629 if (change_latency) {
2630 if (backend->set_systemic_input_latency (get_input_latency())) {
2631 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2634 if (backend->set_systemic_output_latency (get_output_latency())) {
2635 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2641 backend->set_midi_option (get_midi_option());
2644 if (change_buffered_io) {
2645 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2649 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2650 if (_measure_midi) {
2651 if (*p == _measure_midi) {
2652 backend->set_midi_device_enabled ((*p)->name, true);
2654 backend->set_midi_device_enabled ((*p)->name, false);
2656 if (backend->can_change_systemic_latency_when_running ()) {
2657 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2658 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2662 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2663 if (backend->can_set_systemic_midi_latencies()) {
2664 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2665 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2670 if (start || (was_running && restart_required)) {
2671 if (ARDOUR::AudioEngine::instance()->start()) {
2682 EngineControl::post_push ()
2684 /* get a pointer to the current state object, creating one if
2688 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2691 state = save_state ();
2697 states.sort (state_sort_cmp);
2701 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2702 (*i)->active = false;
2705 /* mark this one active (to be used next time the dialog is
2709 state->active = true;
2711 if (_have_control) { // XXX
2712 manage_control_app_sensitivity ();
2715 /* schedule a redisplay of MIDI ports */
2716 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2721 EngineControl::get_rate () const
2723 float r = atof (sample_rate_combo.get_active_text ());
2724 /* the string may have been translated with an abbreviation for
2725 * thousands, so use a crude heuristic to fix this.
2735 EngineControl::get_buffer_size () const
2737 string txt = buffer_size_combo.get_active_text ();
2740 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2741 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2742 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2750 EngineControl::get_nperiods () const
2752 string txt = nperiods_combo.get_active_text ();
2753 return atoi (txt.c_str());
2757 EngineControl::get_midi_option () const
2759 return midi_option_combo.get_active_text();
2763 EngineControl::get_use_buffered_io () const
2765 return use_buffered_io_button.get_active();
2769 EngineControl::get_input_channels() const
2771 if (ARDOUR::Profile->get_mixbus()) {
2772 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2773 if (!backend) return 0;
2774 return backend->input_channels();
2776 return (uint32_t) input_channels_adjustment.get_value();
2780 EngineControl::get_output_channels() const
2782 if (ARDOUR::Profile->get_mixbus()) {
2783 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2784 if (!backend) return 0;
2785 return backend->input_channels();
2787 return (uint32_t) output_channels_adjustment.get_value();
2791 EngineControl::get_input_latency() const
2793 return (uint32_t) input_latency_adjustment.get_value();
2797 EngineControl::get_output_latency() const
2799 return (uint32_t) output_latency_adjustment.get_value();
2803 EngineControl::get_backend () const
2805 return backend_combo.get_active_text ();
2809 EngineControl::get_driver () const
2811 if (driver_combo.get_parent()) {
2812 return driver_combo.get_active_text ();
2819 EngineControl::get_device_name () const
2821 return device_combo.get_active_text ();
2825 EngineControl::get_input_device_name () const
2827 return input_device_combo.get_active_text ();
2831 EngineControl::get_output_device_name () const
2833 return output_device_combo.get_active_text ();
2837 EngineControl::control_app_button_clicked ()
2839 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2845 backend->launch_control_app ();
2849 EngineControl::start_stop_button_clicked ()
2851 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2857 if (ARDOUR::AudioEngine::instance()->running()) {
2858 ARDOUR::AudioEngine::instance()->stop ();
2865 EngineControl::update_devices_button_clicked ()
2867 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2873 if (backend->update_devices()) {
2874 device_list_changed ();
2879 EngineControl::use_buffered_io_button_clicked ()
2881 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2887 bool set_buffered_io = !use_buffered_io_button.get_active();
2888 use_buffered_io_button.set_active (set_buffered_io);
2889 backend->set_use_buffered_io (set_buffered_io);
2893 EngineControl::manage_control_app_sensitivity ()
2895 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2901 string appname = backend->control_app_name();
2903 if (appname.empty()) {
2904 control_app_button.set_sensitive (false);
2906 control_app_button.set_sensitive (true);
2911 EngineControl::set_desired_sample_rate (uint32_t sr)
2913 _desired_sample_rate = sr;
2914 if (ARDOUR::AudioEngine::instance ()->running ()
2915 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2922 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2924 if (page_num == 0) {
2925 cancel_button->set_sensitive (true);
2926 _measure_midi.reset();
2927 update_sensitivity ();
2929 cancel_button->set_sensitive (false);
2930 ok_button->set_sensitive (false);
2933 if (page_num == midi_tab) {
2935 refresh_midi_display ();
2938 if (page_num == latency_tab) {
2941 if (ARDOUR::AudioEngine::instance()->running()) {
2946 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2948 /* save any existing latency values */
2950 uint32_t il = (uint32_t) input_latency.get_value ();
2951 uint32_t ol = (uint32_t) input_latency.get_value ();
2953 /* reset to zero so that our new test instance
2954 will be clean of any existing latency measures.
2956 NB. this should really be done by the backend
2957 when stated for latency measurement.
2960 input_latency.set_value (0);
2961 output_latency.set_value (0);
2963 push_state_to_backend (false);
2967 input_latency.set_value (il);
2968 output_latency.set_value (ol);
2971 // This should be done in push_state_to_backend()
2972 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2973 disable_latency_tab ();
2976 enable_latency_tab ();
2980 end_latency_detection ();
2981 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2986 /* latency measurement */
2989 EngineControl::check_audio_latency_measurement ()
2991 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2993 if (mtdm->resolve () < 0) {
2994 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2998 if (mtdm->get_peak () > 0.707f) {
2999 // get_peak() resets the peak-hold in the detector.
3000 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
3001 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
3005 if (mtdm->err () > 0.3) {
3011 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3013 if (sample_rate == 0) {
3014 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
3015 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3019 int frames_total = mtdm->del();
3020 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3022 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
3023 _("Detected roundtrip latency: "),
3024 frames_total, frames_total * 1000.0f/sample_rate,
3025 _("Systemic latency: "),
3026 extra, extra * 1000.0f/sample_rate);
3030 if (mtdm->err () > 0.2) {
3032 strcat (buf, _("(signal detection error)"));
3038 strcat (buf, _("(inverted - bad wiring)"));
3042 lm_results.set_markup (string_compose (results_markup, buf));
3045 have_lm_results = true;
3046 end_latency_detection ();
3047 lm_use_button.set_sensitive (true);
3055 EngineControl::check_midi_latency_measurement ()
3057 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3059 if (!mididm->have_signal () || mididm->latency () == 0) {
3060 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
3065 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3067 if (sample_rate == 0) {
3068 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
3069 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3073 ARDOUR::framecnt_t frames_total = mididm->latency();
3074 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3075 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
3076 _("Detected roundtrip latency: "),
3077 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
3078 _("Systemic latency: "),
3079 extra, extra * 1000.0f / sample_rate);
3083 if (!mididm->ok ()) {
3085 strcat (buf, _("(averaging)"));
3089 if (mididm->deviation () > 50.0) {
3091 strcat (buf, _("(too large jitter)"));
3093 } else if (mididm->deviation () > 10.0) {
3095 strcat (buf, _("(large jitter)"));
3099 have_lm_results = true;
3100 end_latency_detection ();
3101 lm_use_button.set_sensitive (true);
3102 lm_results.set_markup (string_compose (results_markup, buf));
3104 } else if (mididm->processed () > 400) {
3105 have_lm_results = false;
3106 end_latency_detection ();
3107 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
3111 lm_results.set_markup (string_compose (results_markup, buf));
3117 EngineControl::start_latency_detection ()
3119 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
3120 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
3122 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
3123 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
3124 if (_measure_midi) {
3125 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
3127 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
3129 lm_measure_label.set_text (_("Cancel"));
3130 have_lm_results = false;
3131 lm_use_button.set_sensitive (false);
3132 lm_input_channel_combo.set_sensitive (false);
3133 lm_output_channel_combo.set_sensitive (false);
3139 EngineControl::end_latency_detection ()
3141 latency_timeout.disconnect ();
3142 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3143 lm_measure_label.set_text (_("Measure"));
3144 if (!have_lm_results) {
3145 lm_use_button.set_sensitive (false);
3147 lm_input_channel_combo.set_sensitive (true);
3148 lm_output_channel_combo.set_sensitive (true);
3153 EngineControl::latency_button_clicked ()
3156 start_latency_detection ();
3158 end_latency_detection ();
3163 EngineControl::latency_back_button_clicked ()
3165 ARDOUR::AudioEngine::instance()->stop(true);
3166 notebook.set_current_page(0);
3170 EngineControl::use_latency_button_clicked ()
3172 if (_measure_midi) {
3173 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3177 ARDOUR::framecnt_t frames_total = mididm->latency();
3178 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3179 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3180 _measure_midi->input_latency = one_way;
3181 _measure_midi->output_latency = one_way;
3182 notebook.set_current_page (midi_tab);
3184 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3190 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3191 one_way = std::max (0., one_way);
3193 input_latency_adjustment.set_value (one_way);
3194 output_latency_adjustment.set_value (one_way);
3196 /* back to settings page */
3197 notebook.set_current_page (0);
3202 EngineControl::on_delete_event (GdkEventAny* ev)
3204 if (notebook.get_current_page() == 2) {
3205 /* currently on latency tab - be sure to clean up */
3206 end_latency_detection ();
3208 return ArdourDialog::on_delete_event (ev);
3212 EngineControl::engine_running ()
3214 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3217 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3218 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3220 if (backend->can_set_period_size ()) {
3221 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3224 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3225 connect_disconnect_button.show();
3227 started_at_least_once = true;
3228 if (_have_control) {
3229 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3231 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3233 update_sensitivity();
3235 refill_midi_ports (true);
3236 refill_midi_ports (false);
3240 EngineControl::engine_stopped ()
3242 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3245 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3246 connect_disconnect_button.show();
3248 if (_have_control) {
3249 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3251 engine_status.set_markup(X_(""));
3254 update_sensitivity();
3258 EngineControl::device_list_changed ()
3260 if (ignore_device_changes) {
3263 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3265 midi_option_changed();
3269 EngineControl::connect_disconnect_click()
3271 if (ARDOUR::AudioEngine::instance()->running()) {
3279 EngineControl::calibrate_audio_latency ()
3281 _measure_midi.reset ();
3282 have_lm_results = false;
3283 lm_use_button.set_sensitive (false);
3284 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3285 notebook.set_current_page (latency_tab);
3289 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3292 have_lm_results = false;
3293 lm_use_button.set_sensitive (false);
3294 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3295 notebook.set_current_page (latency_tab);
3299 EngineControl::configure_midi_devices ()
3301 notebook.set_current_page (midi_tab);