2 Copyright (C) 2010 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <boost/scoped_ptr.hpp>
27 #include <gtkmm/messagedialog.h>
29 #include "pbd/error.h"
30 #include "pbd/xml++.h"
31 #include "pbd/unwind.h"
32 #include "pbd/failed_constructor.h"
34 #include <gtkmm/alignment.h>
35 #include <gtkmm/stock.h>
36 #include <gtkmm/notebook.h>
37 #include <gtkmm2ext/utils.h>
39 #include "ardour/audio_backend.h"
40 #include "ardour/audioengine.h"
41 #include "ardour/mtdm.h"
42 #include "ardour/mididm.h"
43 #include "ardour/rc_configuration.h"
44 #include "ardour/types.h"
45 #include "ardour/profile.h"
47 #include "pbd/convert.h"
48 #include "pbd/error.h"
52 #include "ardour_ui.h"
53 #include "engine_dialog.h"
54 #include "gui_thread.h"
60 using namespace Gtkmm2ext;
63 using namespace ARDOUR_UI_UTILS;
65 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
67 static const unsigned int midi_tab = 2;
68 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
70 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
72 EngineControl::EngineControl ()
73 : ArdourDialog (_("Audio/MIDI Setup"))
76 , input_latency_adjustment (0, 0, 99999, 1)
77 , input_latency (input_latency_adjustment)
78 , output_latency_adjustment (0, 0, 99999, 1)
79 , output_latency (output_latency_adjustment)
80 , input_channels_adjustment (0, 0, 256, 1)
81 , input_channels (input_channels_adjustment)
82 , output_channels_adjustment (0, 0, 256, 1)
83 , output_channels (output_channels_adjustment)
84 , ports_adjustment (128, 8, 1024, 1, 16)
85 , ports_spinner (ports_adjustment)
86 , control_app_button (_("Device Control Panel"))
87 , midi_devices_button (_("Midi Device Setup"))
88 , start_stop_button (_("Stop"))
89 , update_devices_button (_("Refresh Devices"))
90 , use_buffered_io_button (_("Use Buffered I/O"), ArdourButton::led_default_elements)
91 , lm_measure_label (_("Measure"))
92 , lm_use_button (_("Use results"))
93 , lm_back_button (_("Back to settings ... (ignore results)"))
94 , lm_button_audio (_("Calibrate Audio"))
96 , have_lm_results (false)
98 , midi_back_button (_("Back to settings"))
100 , ignore_device_changes (0)
101 , _desired_sample_rate (0)
102 , started_at_least_once (false)
103 , queue_device_changed (false)
104 , _have_control (true)
107 using namespace Notebook_Helpers;
108 vector<string> backend_names;
110 AttachOptions xopt = AttachOptions (FILL|EXPAND);
113 set_name (X_("AudioMIDISetup"));
115 /* the backend combo is the one thing that is ALWAYS visible */
117 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
119 if (backends.empty()) {
120 MessageDialog msg (string_compose (_("No audio/MIDI backends detected. %1 cannot run\n\n(This is a build/packaging/system error. It should never happen.)"), PROGRAM_NAME));
122 throw failed_constructor ();
125 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
126 backend_names.push_back ((*b)->name);
129 set_popdown_strings (backend_combo, backend_names);
131 /* setup basic packing characteristics for the table used on the main
132 * tab of the notebook
135 basic_packer.set_spacings (6);
136 basic_packer.set_border_width (12);
137 basic_packer.set_homogeneous (false);
141 basic_hbox.pack_start (basic_packer, false, false);
143 /* latency measurement tab */
145 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
148 lm_table.set_row_spacings (12);
149 lm_table.set_col_spacings (6);
150 lm_table.set_homogeneous (false);
152 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
155 lm_preamble.set_width_chars (60);
156 lm_preamble.set_line_wrap (true);
157 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
159 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
162 Gtk::Label* preamble;
163 preamble = manage (new Label);
164 preamble->set_width_chars (60);
165 preamble->set_line_wrap (true);
166 preamble->set_markup (_("Select two channels below and connect them using a cable."));
168 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
171 label = manage (new Label (_("Output channel")));
172 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
174 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
175 misc_align->add (lm_output_channel_combo);
176 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
179 label = manage (new Label (_("Input channel")));
180 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
182 misc_align = manage (new Alignment (0.0, 0.5));
183 misc_align->add (lm_input_channel_combo);
184 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
187 lm_measure_label.set_padding (10, 10);
188 lm_measure_button.add (lm_measure_label);
189 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
190 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
191 lm_back_button_signal = lm_back_button.signal_clicked().connect(
192 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
194 lm_use_button.set_sensitive (false);
196 /* Increase the default spacing around the labels of these three
202 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
203 l->set_padding (10, 10);
206 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
207 l->set_padding (10, 10);
210 preamble = manage (new Label);
211 preamble->set_width_chars (60);
212 preamble->set_line_wrap (true);
213 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
214 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
217 preamble = manage (new Label);
218 preamble->set_width_chars (60);
219 preamble->set_line_wrap (true);
220 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
221 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
223 ++row; // skip a row in the table
224 ++row; // skip a row in the table
226 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
228 ++row; // skip a row in the table
229 ++row; // skip a row in the table
231 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
232 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
233 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
235 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
237 lm_vbox.set_border_width (12);
238 lm_vbox.pack_start (lm_table, false, false);
240 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
244 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
245 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
246 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
247 notebook.set_border_width (12);
249 notebook.set_show_tabs (false);
250 notebook.show_all ();
252 notebook.set_name ("SettingsNotebook");
254 /* packup the notebook */
256 get_vbox()->set_border_width (12);
257 get_vbox()->pack_start (notebook);
259 /* need a special function to print "all available channels" when the
260 * channel counts hit zero.
263 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
264 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
266 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
267 midi_devices_button.set_name ("generic button");
268 midi_devices_button.set_can_focus(true);
270 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
271 control_app_button.set_name ("generic button");
272 control_app_button.set_can_focus(true);
273 manage_control_app_sensitivity ();
275 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
276 start_stop_button.set_sensitive (false);
277 start_stop_button.set_name ("generic button");
278 start_stop_button.set_can_focus(true);
280 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
281 update_devices_button.set_sensitive (false);
282 update_devices_button.set_name ("generic button");
283 update_devices_button.set_can_focus(true);
285 use_buffered_io_button.signal_clicked.connect (mem_fun (*this, &EngineControl::use_buffered_io_button_clicked));
286 use_buffered_io_button.set_sensitive (false);
287 use_buffered_io_button.set_name ("generic button");
288 use_buffered_io_button.set_can_focus(true);
290 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
291 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
293 /* Pick up any existing audio setup configuration, if appropriate */
295 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
297 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
298 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
299 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
300 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
303 if (!set_state (*audio_setup)) {
304 set_default_state ();
307 set_default_state ();
310 connect_changed_signals ();
312 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
314 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
315 connect_disconnect_button.set_no_show_all();
320 EngineControl::connect_changed_signals ()
322 backend_combo_connection = backend_combo.signal_changed ().connect (
323 sigc::mem_fun (*this, &EngineControl::backend_changed));
324 driver_combo_connection = driver_combo.signal_changed ().connect (
325 sigc::mem_fun (*this, &EngineControl::driver_changed));
326 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
327 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
328 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
329 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
330 nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
331 sigc::mem_fun (*this, &EngineControl::nperiods_changed));
332 device_combo_connection = device_combo.signal_changed ().connect (
333 sigc::mem_fun (*this, &EngineControl::device_changed));
334 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
335 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
337 input_device_combo_connection = input_device_combo.signal_changed ().connect (
338 sigc::mem_fun (*this, &EngineControl::input_device_changed));
339 output_device_combo_connection = output_device_combo.signal_changed ().connect (
340 sigc::mem_fun (*this, &EngineControl::output_device_changed));
342 input_latency_connection = input_latency.signal_changed ().connect (
343 sigc::mem_fun (*this, &EngineControl::parameter_changed));
344 output_latency_connection = output_latency.signal_changed ().connect (
345 sigc::mem_fun (*this, &EngineControl::parameter_changed));
346 input_channels_connection = input_channels.signal_changed ().connect (
347 sigc::mem_fun (*this, &EngineControl::parameter_changed));
348 output_channels_connection = output_channels.signal_changed ().connect (
349 sigc::mem_fun (*this, &EngineControl::parameter_changed));
353 EngineControl::block_changed_signals ()
355 if (block_signals++ == 0) {
356 DEBUG_ECONTROL ("Blocking changed signals");
357 backend_combo_connection.block ();
358 driver_combo_connection.block ();
359 sample_rate_combo_connection.block ();
360 buffer_size_combo_connection.block ();
361 nperiods_combo_connection.block ();
362 device_combo_connection.block ();
363 input_device_combo_connection.block ();
364 output_device_combo_connection.block ();
365 midi_option_combo_connection.block ();
366 input_latency_connection.block ();
367 output_latency_connection.block ();
368 input_channels_connection.block ();
369 output_channels_connection.block ();
374 EngineControl::unblock_changed_signals ()
376 if (--block_signals == 0) {
377 DEBUG_ECONTROL ("Unblocking changed signals");
378 backend_combo_connection.unblock ();
379 driver_combo_connection.unblock ();
380 sample_rate_combo_connection.unblock ();
381 buffer_size_combo_connection.unblock ();
382 nperiods_combo_connection.unblock ();
383 device_combo_connection.unblock ();
384 input_device_combo_connection.unblock ();
385 output_device_combo_connection.unblock ();
386 midi_option_combo_connection.unblock ();
387 input_latency_connection.unblock ();
388 output_latency_connection.unblock ();
389 input_channels_connection.unblock ();
390 output_channels_connection.unblock ();
394 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
395 const std::string& reason)
396 : ec (engine_control)
399 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
400 ec.block_changed_signals ();
403 EngineControl::SignalBlocker::~SignalBlocker ()
405 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
406 ec.unblock_changed_signals ();
410 EngineControl::on_show ()
412 ArdourDialog::on_show ();
413 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
414 // re-check _have_control (jackd running) see #6041
418 ok_button->grab_focus();
422 EngineControl::start_engine ()
424 if (push_state_to_backend(true) != 0) {
425 MessageDialog msg(*this,
426 ARDOUR::AudioEngine::instance()->get_last_backend_error());
434 EngineControl::stop_engine (bool for_latency)
436 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
437 MessageDialog msg(*this,
438 ARDOUR::AudioEngine::instance()->get_last_backend_error());
446 EngineControl::on_response (int response_id)
448 ArdourDialog::on_response (response_id);
450 switch (response_id) {
452 if (!start_engine()) {
457 #ifdef PLATFORM_WINDOWS
459 // But if there's no session open, this can produce
460 // a long gap when nothing appears to be happening.
461 // Let's show the splash image while we're waiting.
462 if (!ARDOUR_COMMAND_LINE::no_splash) {
463 if (ARDOUR_UI::instance()) {
464 if (!ARDOUR_UI::instance()->session_loaded) {
465 ARDOUR_UI::instance()->show_splash();
471 case RESPONSE_DELETE_EVENT: {
473 ev.type = GDK_BUTTON_PRESS;
475 on_delete_event((GdkEventAny*)&ev);
478 case RESPONSE_CANCEL:
479 if (ARDOUR_UI::instance() && ARDOUR_UI::instance()->session_loaded) {
480 ARDOUR_UI::instance()->check_audioengine(*this);
489 EngineControl::build_notebook ()
492 AttachOptions xopt = AttachOptions (FILL|EXPAND);
494 /* clear the table */
496 Gtkmm2ext::container_clear (basic_vbox);
497 Gtkmm2ext::container_clear (basic_packer);
499 if (control_app_button.get_parent()) {
500 control_app_button.get_parent()->remove (control_app_button);
503 label = manage (left_aligned_label (_("Audio System:")));
504 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
505 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
507 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
508 engine_status.show();
510 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
511 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
512 basic_packer.attach (use_buffered_io_button, 3, 4, 2, 3, xopt, xopt);
514 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
515 lm_button_audio.set_name ("generic button");
516 lm_button_audio.set_can_focus(true);
519 build_full_control_notebook ();
521 build_no_control_notebook ();
524 basic_vbox.pack_start (basic_hbox, false, false);
527 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
528 basic_vbox.show_all ();
533 EngineControl::build_full_control_notebook ()
535 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
538 using namespace Notebook_Helpers;
540 vector<string> strings;
541 AttachOptions xopt = AttachOptions (FILL|EXPAND);
542 int row = 1; // row zero == backend combo
544 /* start packing it up */
546 if (backend->requires_driver_selection()) {
547 label = manage (left_aligned_label (_("Driver:")));
548 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
549 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
553 if (backend->use_separate_input_and_output_devices()) {
554 label = manage (left_aligned_label (_("Input Device:")));
555 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
556 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
558 label = manage (left_aligned_label (_("Output Device:")));
559 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
560 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
562 // reset so it isn't used in state comparisons
563 device_combo.set_active_text ("");
565 label = manage (left_aligned_label (_("Device:")));
566 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
567 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
569 // reset these so they don't get used in state comparisons
570 input_device_combo.set_active_text ("");
571 output_device_combo.set_active_text ("");
574 label = manage (left_aligned_label (_("Sample rate:")));
575 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
576 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
580 label = manage (left_aligned_label (_("Buffer size:")));
581 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
582 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
583 buffer_size_duration_label.set_alignment (0.0); /* left-align */
584 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
586 int ctrl_btn_span = 1;
587 if (backend->can_set_period_size ()) {
589 label = manage (left_aligned_label (_("Periods:")));
590 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
591 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
595 /* button spans 2 or 3 rows */
597 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
600 input_channels.set_name ("InputChannels");
601 input_channels.set_flags (Gtk::CAN_FOCUS);
602 input_channels.set_digits (0);
603 input_channels.set_wrap (false);
604 output_channels.set_editable (true);
606 if (!ARDOUR::Profile->get_mixbus()) {
607 label = manage (left_aligned_label (_("Input Channels:")));
608 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
609 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
613 output_channels.set_name ("OutputChannels");
614 output_channels.set_flags (Gtk::CAN_FOCUS);
615 output_channels.set_digits (0);
616 output_channels.set_wrap (false);
617 output_channels.set_editable (true);
619 if (!ARDOUR::Profile->get_mixbus()) {
620 label = manage (left_aligned_label (_("Output Channels:")));
621 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
622 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
626 input_latency.set_name ("InputLatency");
627 input_latency.set_flags (Gtk::CAN_FOCUS);
628 input_latency.set_digits (0);
629 input_latency.set_wrap (false);
630 input_latency.set_editable (true);
632 label = manage (left_aligned_label (_("Hardware input latency:")));
633 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
634 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
635 label = manage (left_aligned_label (_("samples")));
636 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
639 output_latency.set_name ("OutputLatency");
640 output_latency.set_flags (Gtk::CAN_FOCUS);
641 output_latency.set_digits (0);
642 output_latency.set_wrap (false);
643 output_latency.set_editable (true);
645 label = manage (left_aligned_label (_("Hardware output latency:")));
646 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
647 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
648 label = manage (left_aligned_label (_("samples")));
649 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
651 /* button spans 2 rows */
653 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
656 label = manage (left_aligned_label (_("MIDI System:")));
657 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
658 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
659 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
664 EngineControl::build_no_control_notebook ()
666 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
669 using namespace Notebook_Helpers;
671 vector<string> strings;
672 AttachOptions xopt = AttachOptions (FILL|EXPAND);
673 int row = 1; // row zero == backend combo
674 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
676 label = manage (new Label);
677 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
678 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
681 if (backend->can_change_sample_rate_when_running()) {
682 label = manage (left_aligned_label (_("Sample rate:")));
683 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
684 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
688 if (backend->can_change_buffer_size_when_running()) {
689 label = manage (left_aligned_label (_("Buffer size:")));
690 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
691 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
692 buffer_size_duration_label.set_alignment (0.0); /* left-align */
693 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
697 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
701 EngineControl::~EngineControl ()
703 ignore_changes = true;
707 EngineControl::disable_latency_tab ()
709 vector<string> empty;
710 set_popdown_strings (lm_output_channel_combo, empty);
711 set_popdown_strings (lm_input_channel_combo, empty);
712 lm_measure_button.set_sensitive (false);
713 lm_use_button.set_sensitive (false);
717 EngineControl::enable_latency_tab ()
719 vector<string> outputs;
720 vector<string> inputs;
722 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
723 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
724 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
726 if (!ARDOUR::AudioEngine::instance()->running()) {
727 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
728 notebook.set_current_page (0);
732 else if (inputs.empty() || outputs.empty()) {
733 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
734 notebook.set_current_page (0);
739 lm_back_button_signal.disconnect();
741 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
744 lm_back_button_signal = lm_back_button.signal_clicked().connect(
745 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
749 set_popdown_strings (lm_output_channel_combo, outputs);
750 lm_output_channel_combo.set_active_text (outputs.front());
751 lm_output_channel_combo.set_sensitive (true);
753 set_popdown_strings (lm_input_channel_combo, inputs);
754 lm_input_channel_combo.set_active_text (inputs.front());
755 lm_input_channel_combo.set_sensitive (true);
757 lm_measure_button.set_sensitive (true);
761 EngineControl::setup_midi_tab_for_backend ()
763 string backend = backend_combo.get_active_text ();
765 Gtkmm2ext::container_clear (midi_vbox);
767 midi_vbox.set_border_width (12);
768 midi_device_table.set_border_width (12);
770 if (backend == "JACK") {
771 setup_midi_tab_for_jack ();
774 midi_vbox.pack_start (midi_device_table, true, true);
775 midi_vbox.pack_start (midi_back_button, false, false);
776 midi_vbox.show_all ();
780 EngineControl::update_sensitivity ()
782 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
784 ok_button->set_sensitive (false);
785 start_stop_button.set_sensitive (false);
790 size_t devices_available = 0;
792 if (backend->use_separate_input_and_output_devices ()) {
793 devices_available += get_popdown_string_count (input_device_combo);
794 devices_available += get_popdown_string_count (output_device_combo);
796 devices_available += get_popdown_string_count (device_combo);
799 if (devices_available == 0) {
801 input_latency.set_sensitive (false);
802 output_latency.set_sensitive (false);
803 input_channels.set_sensitive (false);
804 output_channels.set_sensitive (false);
806 input_latency.set_sensitive (true);
807 output_latency.set_sensitive (true);
808 input_channels.set_sensitive (true);
809 output_channels.set_sensitive (true);
812 if (get_popdown_string_count (buffer_size_combo) > 0) {
813 if (!ARDOUR::AudioEngine::instance()->running()) {
814 buffer_size_combo.set_sensitive (valid);
815 } else if (backend->can_change_sample_rate_when_running()) {
816 buffer_size_combo.set_sensitive (valid || !_have_control);
820 * Currently there is no way to manually stop the
821 * engine in order to re-configure it.
822 * This needs to remain sensitive for now.
824 * (it's also handy to implicily
825 * re-start the engine)
827 buffer_size_combo.set_sensitive (true);
829 buffer_size_combo.set_sensitive (false);
833 buffer_size_combo.set_sensitive (false);
837 if (get_popdown_string_count (sample_rate_combo) > 0) {
838 if (!ARDOUR::AudioEngine::instance()->running()) {
839 sample_rate_combo.set_sensitive (true);
841 sample_rate_combo.set_sensitive (false);
844 sample_rate_combo.set_sensitive (false);
848 if (get_popdown_string_count (nperiods_combo) > 0) {
849 if (!ARDOUR::AudioEngine::instance()->running()) {
850 nperiods_combo.set_sensitive (true);
852 nperiods_combo.set_sensitive (false);
855 nperiods_combo.set_sensitive (false);
859 start_stop_button.set_sensitive(true);
860 start_stop_button.show();
861 if (ARDOUR::AudioEngine::instance()->running()) {
862 start_stop_button.set_text("Stop");
863 update_devices_button.set_sensitive(false);
864 use_buffered_io_button.set_sensitive(false);
866 if (backend->can_request_update_devices()) {
867 update_devices_button.show();
869 update_devices_button.hide();
871 if (backend->can_use_buffered_io()) {
872 use_buffered_io_button.show();
874 use_buffered_io_button.hide();
876 start_stop_button.set_text("Start");
877 update_devices_button.set_sensitive(true);
878 use_buffered_io_button.set_sensitive(true);
881 update_devices_button.set_sensitive(false);
882 update_devices_button.hide();
883 start_stop_button.set_sensitive(false);
884 start_stop_button.hide();
887 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
888 input_device_combo.set_sensitive (false);
889 output_device_combo.set_sensitive (false);
890 device_combo.set_sensitive (false);
891 driver_combo.set_sensitive (false);
893 input_device_combo.set_sensitive (true);
894 output_device_combo.set_sensitive (true);
895 device_combo.set_sensitive (true);
896 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
897 driver_combo.set_sensitive (true);
899 driver_combo.set_sensitive (false);
903 if (valid || !_have_control) {
904 ok_button->set_sensitive (true);
906 ok_button->set_sensitive (false);
911 EngineControl::setup_midi_tab_for_jack ()
916 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
918 device->input_latency = a->get_value();
920 device->output_latency = a->get_value();
925 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
926 b->set_active (!b->get_active());
927 device->enabled = b->get_active();
928 refresh_midi_display(device->name);
932 EngineControl::refresh_midi_display (std::string focus)
934 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
938 AttachOptions xopt = AttachOptions (FILL|EXPAND);
941 Gtkmm2ext::container_clear (midi_device_table);
943 midi_device_table.set_spacings (6);
945 l = manage (new Label);
946 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
947 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
948 l->set_alignment (0.5, 0.5);
952 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
953 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
954 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
955 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
957 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
958 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
959 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
960 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
963 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
968 bool enabled = (*p)->enabled;
970 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
971 m->set_name ("midi device");
972 m->set_can_focus (Gtk::CAN_FOCUS);
973 m->add_events (Gdk::BUTTON_RELEASE_MASK);
974 m->set_active (enabled);
975 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
976 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
977 if ((*p)->name == focus) {
981 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
982 s = manage (new Gtk::SpinButton (*a));
983 a->set_value ((*p)->input_latency);
984 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
985 s->set_sensitive (_can_set_midi_latencies && enabled);
986 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
988 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
989 s = manage (new Gtk::SpinButton (*a));
990 a->set_value ((*p)->output_latency);
991 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
992 s->set_sensitive (_can_set_midi_latencies && enabled);
993 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
995 b = manage (new Button (_("Calibrate")));
996 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
997 b->set_sensitive (_can_set_midi_latencies && enabled);
998 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
1005 EngineControl::backend_changed ()
1007 SignalBlocker blocker (*this, "backend_changed");
1008 string backend_name = backend_combo.get_active_text();
1009 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1011 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1012 /* eh? setting the backend failed... how ? */
1013 /* A: stale config contains a backend that does not exist in current build */
1017 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1019 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1022 setup_midi_tab_for_backend ();
1023 _midi_devices.clear();
1025 if (backend->requires_driver_selection()) {
1026 if (set_driver_popdown_strings ()) {
1030 /* this will change the device text which will cause a call to
1031 * device changed which will set up parameters
1036 update_midi_options ();
1038 connect_disconnect_button.hide();
1040 midi_option_changed();
1042 started_at_least_once = false;
1044 /* changing the backend implies stopping the engine
1045 * ARDOUR::AudioEngine() may or may not emit this signal
1046 * depending on previous engine state
1048 engine_stopped (); // set "active/inactive"
1050 if (!_have_control) {
1051 // set settings from backend that we do have control over
1052 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1055 if (_have_control && !ignore_changes) {
1056 // set driver & devices
1057 State state = get_matching_state (backend_combo.get_active_text());
1059 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1060 set_current_state (state);
1064 if (!ignore_changes) {
1065 maybe_display_saved_state ();
1070 EngineControl::update_midi_options ()
1072 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1073 vector<string> midi_options = backend->enumerate_midi_options();
1075 if (midi_options.size() == 1) {
1076 /* only contains the "none" option */
1077 midi_option_combo.set_sensitive (false);
1079 if (_have_control) {
1080 set_popdown_strings (midi_option_combo, midi_options);
1081 midi_option_combo.set_active_text (midi_options.front());
1082 midi_option_combo.set_sensitive (true);
1084 midi_option_combo.set_sensitive (false);
1090 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1092 if (ARDOUR::Profile->get_mixbus()) {
1096 uint32_t cnt = (uint32_t) sb->get_value();
1098 sb->set_text (_("all available channels"));
1101 snprintf (buf, sizeof (buf), "%d", cnt);
1107 // @return true if there are drivers available
1109 EngineControl::set_driver_popdown_strings ()
1111 DEBUG_ECONTROL ("set_driver_popdown_strings");
1112 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1113 vector<string> drivers = backend->enumerate_drivers();
1115 if (drivers.empty ()) {
1116 // This is an error...?
1120 string current_driver = backend->driver_name ();
1122 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1124 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1127 current_driver = drivers.front ();
1130 set_popdown_strings (driver_combo, drivers);
1132 string_compose ("driver_combo.set_active_text: %1", current_driver));
1133 driver_combo.set_active_text (current_driver);
1138 EngineControl::get_default_device(const string& current_device_name,
1139 const vector<string>& available_devices)
1141 // If the current device is available, use it as default
1142 if (std::find (available_devices.begin (),
1143 available_devices.end (),
1144 current_device_name) != available_devices.end ()) {
1146 return current_device_name;
1149 using namespace ARDOUR;
1151 string default_device_name =
1152 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1154 vector<string>::const_iterator i;
1156 // If there is a "Default" device available, use it
1157 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1158 if (*i == default_device_name) {
1163 string none_device_name =
1164 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1166 // Use the first device that isn't "None"
1167 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1168 if (*i != none_device_name) {
1173 // Use "None" if there are no other available
1174 return available_devices.front();
1177 // @return true if there are devices available
1179 EngineControl::set_device_popdown_strings ()
1181 DEBUG_ECONTROL ("set_device_popdown_strings");
1182 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1183 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1185 /* NOTE: Ardour currently does not display the "available" field of the
1188 * Doing so would require a different GUI widget than the combo
1189 * box/popdown that we currently use, since it has no way to list
1190 * items that are not selectable. Something more like a popup menu,
1191 * which could have unselectable items, would be appropriate.
1194 vector<string> available_devices;
1196 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1197 available_devices.push_back (i->name);
1200 if (available_devices.empty ()) {
1204 set_popdown_strings (device_combo, available_devices);
1206 std::string default_device =
1207 get_default_device(backend->device_name(), available_devices);
1210 string_compose ("set device_combo active text: %1", default_device));
1212 device_combo.set_active_text(default_device);
1216 // @return true if there are input devices available
1218 EngineControl::set_input_device_popdown_strings ()
1220 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1221 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1222 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1224 vector<string> available_devices;
1226 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1227 available_devices.push_back (i->name);
1230 if (available_devices.empty()) {
1234 set_popdown_strings (input_device_combo, available_devices);
1236 std::string default_device =
1237 get_default_device(backend->input_device_name(), available_devices);
1240 string_compose ("set input_device_combo active text: %1", default_device));
1241 input_device_combo.set_active_text(default_device);
1245 // @return true if there are output devices available
1247 EngineControl::set_output_device_popdown_strings ()
1249 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1250 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1251 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1253 vector<string> available_devices;
1255 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1256 available_devices.push_back (i->name);
1259 if (available_devices.empty()) {
1263 set_popdown_strings (output_device_combo, available_devices);
1265 std::string default_device =
1266 get_default_device(backend->output_device_name(), available_devices);
1269 string_compose ("set output_device_combo active text: %1", default_device));
1270 output_device_combo.set_active_text(default_device);
1275 EngineControl::list_devices ()
1277 DEBUG_ECONTROL ("list_devices");
1278 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1281 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1283 bool devices_available = false;
1285 if (backend->use_separate_input_and_output_devices ()) {
1286 bool input_devices_available = set_input_device_popdown_strings ();
1287 bool output_devices_available = set_output_device_popdown_strings ();
1288 devices_available = input_devices_available || output_devices_available;
1290 devices_available = set_device_popdown_strings ();
1293 if (devices_available) {
1296 device_combo.clear();
1297 input_device_combo.clear();
1298 output_device_combo.clear();
1300 update_sensitivity ();
1304 EngineControl::driver_changed ()
1306 SignalBlocker blocker (*this, "driver_changed");
1307 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1310 backend->set_driver (driver_combo.get_active_text());
1313 // TODO load LRU device(s) for backend + driver combo
1315 if (!ignore_changes) {
1316 maybe_display_saved_state ();
1321 EngineControl::get_sample_rates_for_all_devices ()
1323 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1324 ARDOUR::AudioEngine::instance ()->current_backend ();
1325 vector<float> all_rates;
1327 if (backend->use_separate_input_and_output_devices ()) {
1328 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1330 all_rates = backend->available_sample_rates (get_device_name ());
1336 EngineControl::get_default_sample_rates ()
1338 vector<float> rates;
1339 rates.push_back (8000.0f);
1340 rates.push_back (16000.0f);
1341 rates.push_back (32000.0f);
1342 rates.push_back (44100.0f);
1343 rates.push_back (48000.0f);
1344 rates.push_back (88200.0f);
1345 rates.push_back (96000.0f);
1346 rates.push_back (192000.0f);
1347 rates.push_back (384000.0f);
1352 EngineControl::set_samplerate_popdown_strings ()
1354 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1355 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1360 if (_have_control) {
1361 sr = get_sample_rates_for_all_devices ();
1363 sr = get_default_sample_rates ();
1366 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1367 s.push_back (rate_as_string (*x));
1368 if (*x == _desired_sample_rate) {
1373 set_popdown_strings (sample_rate_combo, s);
1376 if (desired.empty ()) {
1377 float new_active_sr = backend->default_sample_rate ();
1379 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1380 new_active_sr = sr.front ();
1383 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1385 sample_rate_combo.set_active_text (desired);
1389 update_sensitivity ();
1393 EngineControl::get_buffer_sizes_for_all_devices ()
1395 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1396 ARDOUR::AudioEngine::instance ()->current_backend ();
1397 vector<uint32_t> all_sizes;
1399 if (backend->use_separate_input_and_output_devices ()) {
1400 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1402 all_sizes = backend->available_buffer_sizes (get_device_name ());
1408 EngineControl::get_default_buffer_sizes ()
1410 vector<uint32_t> sizes;
1411 sizes.push_back (8);
1412 sizes.push_back (16);
1413 sizes.push_back (32);
1414 sizes.push_back (64);
1415 sizes.push_back (128);
1416 sizes.push_back (256);
1417 sizes.push_back (512);
1418 sizes.push_back (1024);
1419 sizes.push_back (2048);
1420 sizes.push_back (4096);
1421 sizes.push_back (8192);
1426 EngineControl::set_buffersize_popdown_strings ()
1428 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1429 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1430 vector<uint32_t> bs;
1433 if (_have_control) {
1434 bs = get_buffer_sizes_for_all_devices ();
1435 } else if (backend->can_change_buffer_size_when_running()) {
1436 bs = get_default_buffer_sizes ();
1439 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1440 s.push_back (bufsize_as_string (*x));
1443 uint32_t previous_size = 0;
1444 if (!buffer_size_combo.get_active_text().empty()) {
1445 previous_size = get_buffer_size ();
1448 set_popdown_strings (buffer_size_combo, s);
1452 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1453 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1456 buffer_size_combo.set_active_text(s.front());
1458 uint32_t period = backend->buffer_size();
1459 if (0 == period && backend->use_separate_input_and_output_devices()) {
1460 period = backend->default_buffer_size(get_input_device_name());
1462 if (0 == period && backend->use_separate_input_and_output_devices()) {
1463 period = backend->default_buffer_size(get_output_device_name());
1465 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1466 period = backend->default_buffer_size(get_device_name());
1469 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1471 show_buffer_duration ();
1473 update_sensitivity ();
1477 EngineControl::set_nperiods_popdown_strings ()
1479 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1480 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1481 vector<uint32_t> np;
1484 if (backend->can_set_period_size()) {
1485 np = backend->available_period_sizes (get_driver());
1488 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1489 s.push_back (nperiods_as_string (*x));
1492 set_popdown_strings (nperiods_combo, s);
1495 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX
1498 update_sensitivity ();
1502 EngineControl::device_changed ()
1504 SignalBlocker blocker (*this, "device_changed");
1505 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1508 string device_name_in;
1509 string device_name_out; // only used if backend support separate I/O devices
1511 if (backend->use_separate_input_and_output_devices()) {
1512 device_name_in = get_input_device_name ();
1513 device_name_out = get_output_device_name ();
1515 device_name_in = get_device_name ();
1518 /* we set the backend-device to query various device related intormation.
1519 * This has the side effect that backend->device_name() will match
1520 * the device_name and 'change_device' will never be true.
1521 * so work around this by setting...
1523 if (backend->use_separate_input_and_output_devices()) {
1524 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1525 queue_device_changed = true;
1528 if (device_name_in != backend->device_name()) {
1529 queue_device_changed = true;
1533 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1534 if (backend->use_separate_input_and_output_devices()) {
1535 backend->set_input_device_name (device_name_in);
1536 backend->set_output_device_name (device_name_out);
1538 backend->set_device_name(device_name_in);
1542 /* don't allow programmatic change to combos to cause a
1543 recursive call to this method.
1545 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1547 set_samplerate_popdown_strings ();
1548 set_buffersize_popdown_strings ();
1549 set_nperiods_popdown_strings ();
1551 /* TODO set min + max channel counts here */
1553 manage_control_app_sensitivity ();
1556 /* pick up any saved state for this device */
1558 if (!ignore_changes) {
1559 maybe_display_saved_state ();
1564 EngineControl::input_device_changed ()
1566 DEBUG_ECONTROL ("input_device_changed");
1571 EngineControl::output_device_changed ()
1573 DEBUG_ECONTROL ("output_device_changed");
1578 EngineControl::bufsize_as_string (uint32_t sz)
1580 /* Translators: "samples" is always plural here, so no
1581 need for plural+singular forms.
1584 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1589 EngineControl::nperiods_as_string (uint32_t np)
1592 snprintf (buf, sizeof (buf), "%u", np);
1598 EngineControl::sample_rate_changed ()
1600 DEBUG_ECONTROL ("sample_rate_changed");
1601 /* reset the strings for buffer size to show the correct msec value
1602 (reflecting the new sample rate).
1605 show_buffer_duration ();
1610 EngineControl::buffer_size_changed ()
1612 DEBUG_ECONTROL ("buffer_size_changed");
1613 show_buffer_duration ();
1617 EngineControl::nperiods_changed ()
1619 DEBUG_ECONTROL ("nperiods_changed");
1620 show_buffer_duration ();
1624 EngineControl::show_buffer_duration ()
1626 DEBUG_ECONTROL ("show_buffer_duration");
1627 /* buffer sizes - convert from just samples to samples + msecs for
1628 * the displayed string
1631 string bs_text = buffer_size_combo.get_active_text ();
1632 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1633 uint32_t rate = get_rate();
1635 /* Except for ALSA and Dummy backends, we don't know the number of periods
1636 * per cycle and settings.
1638 * jack1 vs jack2 have different default latencies since jack2 start
1639 * in async-mode unless --sync is given which adds an extra cycle
1640 * of latency. The value is not known if jackd is started externally..
1642 * So just display the period size, that's also what
1643 * ARDOUR_UI::update_sample_rate() does for the status bar.
1644 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1645 * but still, that's the buffer period, not [round-trip] latency)
1648 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1649 buffer_size_duration_label.set_text (buf);
1653 EngineControl::midi_option_changed ()
1655 DEBUG_ECONTROL ("midi_option_changed");
1656 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1659 backend->set_midi_option (get_midi_option());
1661 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1663 //_midi_devices.clear(); // TODO merge with state-saved settings..
1664 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1665 std::vector<MidiDeviceSettings> new_devices;
1667 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1668 MidiDeviceSettings mds = find_midi_device (i->name);
1669 if (i->available && !mds) {
1670 uint32_t input_latency = 0;
1671 uint32_t output_latency = 0;
1672 if (_can_set_midi_latencies) {
1673 input_latency = backend->systemic_midi_input_latency (i->name);
1674 output_latency = backend->systemic_midi_output_latency (i->name);
1676 bool enabled = backend->midi_device_enabled (i->name);
1677 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1678 new_devices.push_back (ptr);
1679 } else if (i->available) {
1680 new_devices.push_back (mds);
1683 _midi_devices = new_devices;
1685 if (_midi_devices.empty()) {
1686 midi_devices_button.hide ();
1688 midi_devices_button.show ();
1693 EngineControl::parameter_changed ()
1697 EngineControl::State
1698 EngineControl::get_matching_state (const string& backend)
1700 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1701 if ((*i)->backend == backend) {
1708 EngineControl::State
1709 EngineControl::get_matching_state (
1710 const string& backend,
1711 const string& driver,
1712 const string& device)
1714 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1715 if ((*i)->backend == backend &&
1716 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1724 EngineControl::State
1725 EngineControl::get_matching_state (
1726 const string& backend,
1727 const string& driver,
1728 const string& input_device,
1729 const string& output_device)
1731 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1732 if ((*i)->backend == backend &&
1733 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1741 EngineControl::State
1742 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1744 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1747 if (backend->use_separate_input_and_output_devices ()) {
1748 return get_matching_state (backend_combo.get_active_text(),
1749 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1750 input_device_combo.get_active_text(),
1751 output_device_combo.get_active_text());
1753 return get_matching_state (backend_combo.get_active_text(),
1754 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1755 device_combo.get_active_text());
1759 return get_matching_state (backend_combo.get_active_text(),
1761 device_combo.get_active_text());
1764 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1765 const EngineControl::State& state2)
1767 if (state1->backend == state2->backend &&
1768 state1->driver == state2->driver &&
1769 state1->device == state2->device &&
1770 state1->input_device == state2->input_device &&
1771 state1->output_device == state2->output_device) {
1778 EngineControl::state_sort_cmp (const State &a, const State &b) {
1782 else if (b->active) {
1786 return a->lru < b->lru;
1790 EngineControl::State
1791 EngineControl::save_state ()
1795 if (!_have_control) {
1796 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1798 state->lru = time (NULL) ;
1801 state.reset(new StateStruct);
1802 state->backend = get_backend ();
1804 state.reset(new StateStruct);
1805 store_state (state);
1808 for (StateList::iterator i = states.begin(); i != states.end();) {
1809 if (equivalent_states (*i, state)) {
1810 i = states.erase(i);
1816 states.push_back (state);
1818 states.sort (state_sort_cmp);
1824 EngineControl::store_state (State state)
1826 state->backend = get_backend ();
1827 state->driver = get_driver ();
1828 state->device = get_device_name ();
1829 state->input_device = get_input_device_name ();
1830 state->output_device = get_output_device_name ();
1831 state->sample_rate = get_rate ();
1832 state->buffer_size = get_buffer_size ();
1833 state->n_periods = get_nperiods ();
1834 state->input_latency = get_input_latency ();
1835 state->output_latency = get_output_latency ();
1836 state->input_channels = get_input_channels ();
1837 state->output_channels = get_output_channels ();
1838 state->midi_option = get_midi_option ();
1839 state->midi_devices = _midi_devices;
1840 state->use_buffered_io = get_use_buffered_io ();
1841 state->lru = time (NULL) ;
1845 EngineControl::maybe_display_saved_state ()
1847 if (!_have_control) {
1851 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1854 DEBUG_ECONTROL ("Restoring saved state");
1855 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1857 if (!_desired_sample_rate) {
1858 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1860 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1862 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1863 /* call this explicitly because we're ignoring changes to
1864 the controls at this point.
1866 show_buffer_duration ();
1867 input_latency.set_value (state->input_latency);
1868 output_latency.set_value (state->output_latency);
1870 use_buffered_io_button.set_active (state->use_buffered_io);
1872 if (!state->midi_option.empty()) {
1873 midi_option_combo.set_active_text (state->midi_option);
1874 _midi_devices = state->midi_devices;
1877 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1882 EngineControl::get_state ()
1884 LocaleGuard lg (X_("C"));
1886 XMLNode* root = new XMLNode ("AudioMIDISetup");
1889 if (!states.empty()) {
1890 XMLNode* state_nodes = new XMLNode ("EngineStates");
1892 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1894 XMLNode* node = new XMLNode ("State");
1896 node->add_property ("backend", (*i)->backend);
1897 node->add_property ("driver", (*i)->driver);
1898 node->add_property ("device", (*i)->device);
1899 node->add_property ("input-device", (*i)->input_device);
1900 node->add_property ("output-device", (*i)->output_device);
1901 node->add_property ("sample-rate", (*i)->sample_rate);
1902 node->add_property ("buffer-size", (*i)->buffer_size);
1903 node->add_property ("n-periods", (*i)->n_periods);
1904 node->add_property ("input-latency", (*i)->input_latency);
1905 node->add_property ("output-latency", (*i)->output_latency);
1906 node->add_property ("input-channels", (*i)->input_channels);
1907 node->add_property ("output-channels", (*i)->output_channels);
1908 node->add_property ("active", (*i)->active ? "yes" : "no");
1909 node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
1910 node->add_property ("midi-option", (*i)->midi_option);
1911 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1913 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1914 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1915 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1916 midi_device_stuff->add_property (X_("name"), (*p)->name);
1917 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1918 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1919 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1920 midi_devices->add_child_nocopy (*midi_device_stuff);
1922 node->add_child_nocopy (*midi_devices);
1924 state_nodes->add_child_nocopy (*node);
1927 root->add_child_nocopy (*state_nodes);
1934 EngineControl::set_default_state ()
1936 vector<string> backend_names;
1937 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1939 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1940 backend_names.push_back ((*b)->name);
1942 backend_combo.set_active_text (backend_names.front());
1944 // We could set default backends per platform etc here
1950 EngineControl::set_state (const XMLNode& root)
1952 XMLNodeList clist, cclist;
1953 XMLNodeConstIterator citer, cciter;
1955 XMLNode* grandchild;
1956 XMLProperty* prop = NULL;
1958 fprintf (stderr, "EngineControl::set_state\n");
1960 if (root.name() != "AudioMIDISetup") {
1964 clist = root.children();
1968 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1972 if (child->name() != "EngineStates") {
1976 cclist = child->children();
1978 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1979 State state (new StateStruct);
1981 grandchild = *cciter;
1983 if (grandchild->name() != "State") {
1987 if ((prop = grandchild->property ("backend")) == 0) {
1990 state->backend = prop->value ();
1992 if ((prop = grandchild->property ("driver")) == 0) {
1995 state->driver = prop->value ();
1997 if ((prop = grandchild->property ("device")) == 0) {
2000 state->device = prop->value ();
2002 if ((prop = grandchild->property ("input-device")) == 0) {
2005 state->input_device = prop->value ();
2007 if ((prop = grandchild->property ("output-device")) == 0) {
2010 state->output_device = prop->value ();
2012 if ((prop = grandchild->property ("sample-rate")) == 0) {
2015 state->sample_rate = atof (prop->value ());
2017 if ((prop = grandchild->property ("buffer-size")) == 0) {
2020 state->buffer_size = atoi (prop->value ());
2022 if ((prop = grandchild->property ("n-periods")) == 0) {
2023 // optional (new value in 4.5)
2024 state->n_periods = 0;
2026 state->n_periods = atoi (prop->value ());
2029 if ((prop = grandchild->property ("input-latency")) == 0) {
2032 state->input_latency = atoi (prop->value ());
2034 if ((prop = grandchild->property ("output-latency")) == 0) {
2037 state->output_latency = atoi (prop->value ());
2039 if ((prop = grandchild->property ("input-channels")) == 0) {
2042 state->input_channels = atoi (prop->value ());
2044 if ((prop = grandchild->property ("output-channels")) == 0) {
2047 state->output_channels = atoi (prop->value ());
2049 if ((prop = grandchild->property ("active")) == 0) {
2052 state->active = string_is_affirmative (prop->value ());
2054 if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2057 state->use_buffered_io = string_is_affirmative (prop->value ());
2059 if ((prop = grandchild->property ("midi-option")) == 0) {
2062 state->midi_option = prop->value ();
2064 state->midi_devices.clear();
2066 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2067 const XMLNodeList mnc = midinode->children();
2068 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2069 if ((*n)->property (X_("name")) == 0
2070 || (*n)->property (X_("enabled")) == 0
2071 || (*n)->property (X_("input-latency")) == 0
2072 || (*n)->property (X_("output-latency")) == 0
2077 MidiDeviceSettings ptr (new MidiDeviceSetting(
2078 (*n)->property (X_("name"))->value (),
2079 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2080 atoi ((*n)->property (X_("input-latency"))->value ()),
2081 atoi ((*n)->property (X_("output-latency"))->value ())
2083 state->midi_devices.push_back (ptr);
2087 if ((prop = grandchild->property ("lru"))) {
2088 state->lru = atoi (prop->value ());
2092 /* remove accumulated duplicates (due to bug in ealier version)
2093 * this can be removed again before release
2095 for (StateList::iterator i = states.begin(); i != states.end();) {
2096 if ((*i)->backend == state->backend &&
2097 (*i)->driver == state->driver &&
2098 (*i)->device == state->device) {
2099 i = states.erase(i);
2106 states.push_back (state);
2110 /* now see if there was an active state and switch the setup to it */
2112 // purge states of backend that are not available in this built
2113 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2114 vector<std::string> backend_names;
2116 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2117 backend_names.push_back((*i)->name);
2119 for (StateList::iterator i = states.begin(); i != states.end();) {
2120 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2121 i = states.erase(i);
2127 states.sort (state_sort_cmp);
2129 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2132 return set_current_state (*i);
2139 EngineControl::set_current_state (const State& state)
2141 DEBUG_ECONTROL ("set_current_state");
2143 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2145 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2146 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2147 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2148 // this shouldn't happen as the invalid backend names should have been
2149 // removed from the list of states.
2153 // now reflect the change in the backend in the GUI so backend_changed will
2154 // do the right thing
2155 backend_combo.set_active_text (state->backend);
2157 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2159 // we don't have control don't restore state
2164 if (!state->driver.empty ()) {
2165 if (!backend->requires_driver_selection ()) {
2166 DEBUG_ECONTROL ("Backend should require driver selection");
2167 // A backend has changed from having driver selection to not having
2168 // it or someone has been manually editing a config file and messed
2173 if (backend->set_driver (state->driver) != 0) {
2174 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2175 // Driver names for a backend have changed and the name in the
2176 // config file is now invalid or support for driver is no longer
2177 // included in the backend
2180 // no need to set the driver_combo as backend_changed will use
2181 // backend->driver_name to set the active driver
2184 if (!state->device.empty ()) {
2185 if (backend->set_device_name (state->device) != 0) {
2187 string_compose ("Unable to set device name %1", state->device));
2188 // device is no longer available on the system
2191 // no need to set active device as it will be picked up in
2192 // via backend_changed ()/set_device_popdown_strings
2195 // backend supports separate input/output devices
2196 if (backend->set_input_device_name (state->input_device) != 0) {
2197 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2198 state->input_device));
2199 // input device is no longer available on the system
2203 if (backend->set_output_device_name (state->output_device) != 0) {
2204 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2205 state->input_device));
2206 // output device is no longer available on the system
2209 // no need to set active devices as it will be picked up in via
2210 // backend_changed ()/set_*_device_popdown_strings
2215 // Now restore the state of the rest of the controls
2217 // We don't use a SignalBlocker as set_current_state is currently only
2218 // called from set_state before any signals are connected. If at some point
2219 // a more general named state mechanism is implemented and
2220 // set_current_state is called while signals are connected then a
2221 // SignalBlocker will need to be instantiated before setting these.
2223 device_combo.set_active_text (state->device);
2224 input_device_combo.set_active_text (state->input_device);
2225 output_device_combo.set_active_text (state->output_device);
2226 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2227 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2228 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2229 input_latency.set_value (state->input_latency);
2230 output_latency.set_value (state->output_latency);
2231 midi_option_combo.set_active_text (state->midi_option);
2232 use_buffered_io_button.set_active (state->use_buffered_io);
2237 EngineControl::push_state_to_backend (bool start)
2239 DEBUG_ECONTROL ("push_state_to_backend");
2240 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2241 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2247 /* figure out what is going to change */
2249 bool restart_required = false;
2250 bool was_running = ARDOUR::AudioEngine::instance()->running();
2251 bool change_driver = false;
2252 bool change_device = false;
2253 bool change_rate = false;
2254 bool change_bufsize = false;
2255 bool change_nperiods = false;
2256 bool change_latency = false;
2257 bool change_channels = false;
2258 bool change_midi = false;
2259 bool change_buffered_io = false;
2261 uint32_t ochan = get_output_channels ();
2262 uint32_t ichan = get_input_channels ();
2264 if (_have_control) {
2266 if (started_at_least_once) {
2268 /* we can control the backend */
2270 if (backend->requires_driver_selection()) {
2271 if (get_driver() != backend->driver_name()) {
2272 change_driver = true;
2276 if (backend->use_separate_input_and_output_devices()) {
2277 if (get_input_device_name() != backend->input_device_name()) {
2278 change_device = true;
2280 if (get_output_device_name() != backend->output_device_name()) {
2281 change_device = true;
2284 if (get_device_name() != backend->device_name()) {
2285 change_device = true;
2289 if (queue_device_changed) {
2290 change_device = true;
2293 if (get_rate() != backend->sample_rate()) {
2297 if (get_buffer_size() != backend->buffer_size()) {
2298 change_bufsize = true;
2301 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2302 && get_nperiods() != backend->period_size()) {
2303 change_nperiods = true;
2306 if (get_midi_option() != backend->midi_option()) {
2310 if (backend->can_use_buffered_io()) {
2311 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2312 change_buffered_io = true;
2316 /* zero-requested channels means "all available" */
2319 ichan = backend->input_channels();
2323 ochan = backend->output_channels();
2326 if (ichan != backend->input_channels()) {
2327 change_channels = true;
2330 if (ochan != backend->output_channels()) {
2331 change_channels = true;
2334 if (get_input_latency() != backend->systemic_input_latency() ||
2335 get_output_latency() != backend->systemic_output_latency()) {
2336 change_latency = true;
2339 /* backend never started, so we have to force a group
2342 change_device = true;
2343 if (backend->requires_driver_selection()) {
2344 change_driver = true;
2347 change_bufsize = true;
2348 change_channels = true;
2349 change_latency = true;
2351 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2356 /* we have no control over the backend, meaning that we can
2357 * only possibly change sample rate and buffer size.
2361 if (get_rate() != backend->sample_rate()) {
2362 change_bufsize = true;
2365 if (get_buffer_size() != backend->buffer_size()) {
2366 change_bufsize = true;
2370 queue_device_changed = false;
2372 if (!_have_control) {
2374 /* We do not have control over the backend, so the best we can
2375 * do is try to change the sample rate and/or bufsize and get
2379 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2383 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2388 backend->set_sample_rate (get_rate());
2391 if (change_bufsize) {
2392 backend->set_buffer_size (get_buffer_size());
2396 if (ARDOUR::AudioEngine::instance()->start ()) {
2397 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2407 /* determine if we need to stop the backend before changing parameters */
2409 if (change_driver || change_device || change_channels || change_nperiods ||
2410 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2411 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2413 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2414 restart_required = true;
2416 restart_required = false;
2421 if (restart_required) {
2422 if (ARDOUR::AudioEngine::instance()->stop()) {
2428 if (change_driver && backend->set_driver (get_driver())) {
2429 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2432 if (backend->use_separate_input_and_output_devices()) {
2433 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2434 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2437 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2438 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2442 if (change_device && backend->set_device_name (get_device_name())) {
2443 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2447 if (change_rate && backend->set_sample_rate (get_rate())) {
2448 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2451 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2452 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2455 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2456 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2460 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2461 if (backend->set_input_channels (get_input_channels())) {
2462 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2465 if (backend->set_output_channels (get_output_channels())) {
2466 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2470 if (change_latency) {
2471 if (backend->set_systemic_input_latency (get_input_latency())) {
2472 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2475 if (backend->set_systemic_output_latency (get_output_latency())) {
2476 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2482 backend->set_midi_option (get_midi_option());
2485 if (change_buffered_io) {
2486 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2490 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2491 if (_measure_midi) {
2492 if (*p == _measure_midi) {
2493 backend->set_midi_device_enabled ((*p)->name, true);
2495 backend->set_midi_device_enabled ((*p)->name, false);
2497 if (backend->can_change_systemic_latency_when_running ()) {
2498 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2499 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2503 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2504 if (backend->can_set_systemic_midi_latencies()) {
2505 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2506 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2511 if (start || (was_running && restart_required)) {
2512 if (ARDOUR::AudioEngine::instance()->start()) {
2523 EngineControl::post_push ()
2525 /* get a pointer to the current state object, creating one if
2529 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2532 state = save_state ();
2538 states.sort (state_sort_cmp);
2542 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2543 (*i)->active = false;
2546 /* mark this one active (to be used next time the dialog is
2550 state->active = true;
2552 if (_have_control) { // XXX
2553 manage_control_app_sensitivity ();
2556 /* schedule a redisplay of MIDI ports */
2557 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2562 EngineControl::get_rate () const
2564 float r = atof (sample_rate_combo.get_active_text ());
2565 /* the string may have been translated with an abbreviation for
2566 * thousands, so use a crude heuristic to fix this.
2576 EngineControl::get_buffer_size () const
2578 string txt = buffer_size_combo.get_active_text ();
2581 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2582 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2583 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2591 EngineControl::get_nperiods () const
2593 string txt = nperiods_combo.get_active_text ();
2594 return atoi (txt.c_str());
2598 EngineControl::get_midi_option () const
2600 return midi_option_combo.get_active_text();
2604 EngineControl::get_use_buffered_io () const
2606 return use_buffered_io_button.get_active();
2610 EngineControl::get_input_channels() const
2612 if (ARDOUR::Profile->get_mixbus()) {
2613 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2614 if (!backend) return 0;
2615 return backend->input_channels();
2617 return (uint32_t) input_channels_adjustment.get_value();
2621 EngineControl::get_output_channels() const
2623 if (ARDOUR::Profile->get_mixbus()) {
2624 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2625 if (!backend) return 0;
2626 return backend->input_channels();
2628 return (uint32_t) output_channels_adjustment.get_value();
2632 EngineControl::get_input_latency() const
2634 return (uint32_t) input_latency_adjustment.get_value();
2638 EngineControl::get_output_latency() const
2640 return (uint32_t) output_latency_adjustment.get_value();
2644 EngineControl::get_backend () const
2646 return backend_combo.get_active_text ();
2650 EngineControl::get_driver () const
2652 if (driver_combo.get_parent()) {
2653 return driver_combo.get_active_text ();
2660 EngineControl::get_device_name () const
2662 return device_combo.get_active_text ();
2666 EngineControl::get_input_device_name () const
2668 return input_device_combo.get_active_text ();
2672 EngineControl::get_output_device_name () const
2674 return output_device_combo.get_active_text ();
2678 EngineControl::control_app_button_clicked ()
2680 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2686 backend->launch_control_app ();
2690 EngineControl::start_stop_button_clicked ()
2692 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2698 if (ARDOUR::AudioEngine::instance()->running()) {
2699 ARDOUR::AudioEngine::instance()->stop ();
2706 EngineControl::update_devices_button_clicked ()
2708 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2714 if (backend->update_devices()) {
2715 device_list_changed ();
2720 EngineControl::use_buffered_io_button_clicked ()
2722 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2728 bool set_buffered_io = !use_buffered_io_button.get_active();
2729 use_buffered_io_button.set_active (set_buffered_io);
2730 backend->set_use_buffered_io (set_buffered_io);
2734 EngineControl::manage_control_app_sensitivity ()
2736 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2742 string appname = backend->control_app_name();
2744 if (appname.empty()) {
2745 control_app_button.set_sensitive (false);
2747 control_app_button.set_sensitive (true);
2752 EngineControl::set_desired_sample_rate (uint32_t sr)
2754 _desired_sample_rate = sr;
2759 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2761 if (page_num == 0) {
2762 cancel_button->set_sensitive (true);
2763 _measure_midi.reset();
2764 update_sensitivity ();
2766 cancel_button->set_sensitive (false);
2767 ok_button->set_sensitive (false);
2770 if (page_num == midi_tab) {
2772 refresh_midi_display ();
2775 if (page_num == latency_tab) {
2778 if (ARDOUR::AudioEngine::instance()->running()) {
2783 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2785 /* save any existing latency values */
2787 uint32_t il = (uint32_t) input_latency.get_value ();
2788 uint32_t ol = (uint32_t) input_latency.get_value ();
2790 /* reset to zero so that our new test instance
2791 will be clean of any existing latency measures.
2793 NB. this should really be done by the backend
2794 when stated for latency measurement.
2797 input_latency.set_value (0);
2798 output_latency.set_value (0);
2800 push_state_to_backend (false);
2804 input_latency.set_value (il);
2805 output_latency.set_value (ol);
2808 // This should be done in push_state_to_backend()
2809 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2810 disable_latency_tab ();
2813 enable_latency_tab ();
2817 end_latency_detection ();
2818 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2823 /* latency measurement */
2826 EngineControl::check_audio_latency_measurement ()
2828 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2830 if (mtdm->resolve () < 0) {
2831 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2835 if (mtdm->get_peak () > 0.707f) {
2836 // get_peak() resets the peak-hold in the detector.
2837 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2838 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2842 if (mtdm->err () > 0.3) {
2848 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2850 if (sample_rate == 0) {
2851 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2852 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2856 int frames_total = mtdm->del();
2857 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2859 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2860 _("Detected roundtrip latency: "),
2861 frames_total, frames_total * 1000.0f/sample_rate,
2862 _("Systemic latency: "),
2863 extra, extra * 1000.0f/sample_rate);
2867 if (mtdm->err () > 0.2) {
2869 strcat (buf, _("(signal detection error)"));
2875 strcat (buf, _("(inverted - bad wiring)"));
2879 lm_results.set_markup (string_compose (results_markup, buf));
2882 have_lm_results = true;
2883 end_latency_detection ();
2884 lm_use_button.set_sensitive (true);
2892 EngineControl::check_midi_latency_measurement ()
2894 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2896 if (!mididm->have_signal () || mididm->latency () == 0) {
2897 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2902 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2904 if (sample_rate == 0) {
2905 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2906 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2910 ARDOUR::framecnt_t frames_total = mididm->latency();
2911 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2912 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2913 _("Detected roundtrip latency: "),
2914 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2915 _("Systemic latency: "),
2916 extra, extra * 1000.0f / sample_rate);
2920 if (!mididm->ok ()) {
2922 strcat (buf, _("(averaging)"));
2926 if (mididm->deviation () > 50.0) {
2928 strcat (buf, _("(too large jitter)"));
2930 } else if (mididm->deviation () > 10.0) {
2932 strcat (buf, _("(large jitter)"));
2936 have_lm_results = true;
2937 end_latency_detection ();
2938 lm_use_button.set_sensitive (true);
2939 lm_results.set_markup (string_compose (results_markup, buf));
2941 } else if (mididm->processed () > 400) {
2942 have_lm_results = false;
2943 end_latency_detection ();
2944 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2948 lm_results.set_markup (string_compose (results_markup, buf));
2954 EngineControl::start_latency_detection ()
2956 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2957 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2959 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2960 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2961 if (_measure_midi) {
2962 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2964 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2966 lm_measure_label.set_text (_("Cancel"));
2967 have_lm_results = false;
2968 lm_use_button.set_sensitive (false);
2969 lm_input_channel_combo.set_sensitive (false);
2970 lm_output_channel_combo.set_sensitive (false);
2976 EngineControl::end_latency_detection ()
2978 latency_timeout.disconnect ();
2979 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2980 lm_measure_label.set_text (_("Measure"));
2981 if (!have_lm_results) {
2982 lm_use_button.set_sensitive (false);
2984 lm_input_channel_combo.set_sensitive (true);
2985 lm_output_channel_combo.set_sensitive (true);
2990 EngineControl::latency_button_clicked ()
2993 start_latency_detection ();
2995 end_latency_detection ();
3000 EngineControl::latency_back_button_clicked ()
3002 ARDOUR::AudioEngine::instance()->stop(true);
3003 notebook.set_current_page(0);
3007 EngineControl::use_latency_button_clicked ()
3009 if (_measure_midi) {
3010 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3014 ARDOUR::framecnt_t frames_total = mididm->latency();
3015 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3016 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3017 _measure_midi->input_latency = one_way;
3018 _measure_midi->output_latency = one_way;
3019 notebook.set_current_page (midi_tab);
3021 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3027 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3028 one_way = std::max (0., one_way);
3030 input_latency_adjustment.set_value (one_way);
3031 output_latency_adjustment.set_value (one_way);
3033 /* back to settings page */
3034 notebook.set_current_page (0);
3039 EngineControl::on_delete_event (GdkEventAny* ev)
3041 if (notebook.get_current_page() == 2) {
3042 /* currently on latency tab - be sure to clean up */
3043 end_latency_detection ();
3045 return ArdourDialog::on_delete_event (ev);
3049 EngineControl::engine_running ()
3051 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3054 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3055 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3057 if (backend->can_set_period_size ()) {
3058 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3061 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3062 connect_disconnect_button.show();
3064 started_at_least_once = true;
3065 if (_have_control) {
3066 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3068 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3070 update_sensitivity();
3074 EngineControl::engine_stopped ()
3076 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3079 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3080 connect_disconnect_button.show();
3082 if (_have_control) {
3083 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3085 engine_status.set_markup(X_(""));
3088 update_sensitivity();
3092 EngineControl::device_list_changed ()
3094 if (ignore_device_changes) {
3097 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3099 midi_option_changed();
3103 EngineControl::connect_disconnect_click()
3105 if (ARDOUR::AudioEngine::instance()->running()) {
3113 EngineControl::calibrate_audio_latency ()
3115 _measure_midi.reset ();
3116 have_lm_results = false;
3117 lm_use_button.set_sensitive (false);
3118 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3119 notebook.set_current_page (latency_tab);
3123 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3126 have_lm_results = false;
3127 lm_use_button.set_sensitive (false);
3128 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3129 notebook.set_current_page (latency_tab);
3133 EngineControl::configure_midi_devices ()
3135 notebook.set_current_page (midi_tab);