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 use_buffered_io_button.set_sensitive(false);
884 use_buffered_io_button.hide();
885 start_stop_button.set_sensitive(false);
886 start_stop_button.hide();
889 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
890 input_device_combo.set_sensitive (false);
891 output_device_combo.set_sensitive (false);
892 device_combo.set_sensitive (false);
893 driver_combo.set_sensitive (false);
895 input_device_combo.set_sensitive (true);
896 output_device_combo.set_sensitive (true);
897 device_combo.set_sensitive (true);
898 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
899 driver_combo.set_sensitive (true);
901 driver_combo.set_sensitive (false);
905 if (valid || !_have_control) {
906 ok_button->set_sensitive (true);
908 ok_button->set_sensitive (false);
913 EngineControl::setup_midi_tab_for_jack ()
918 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
920 device->input_latency = a->get_value();
922 device->output_latency = a->get_value();
927 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
928 b->set_active (!b->get_active());
929 device->enabled = b->get_active();
930 refresh_midi_display(device->name);
934 EngineControl::refresh_midi_display (std::string focus)
936 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
940 AttachOptions xopt = AttachOptions (FILL|EXPAND);
943 Gtkmm2ext::container_clear (midi_device_table);
945 midi_device_table.set_spacings (6);
947 l = manage (new Label);
948 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
949 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
950 l->set_alignment (0.5, 0.5);
954 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
955 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
956 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
957 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
959 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
960 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
961 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
962 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
965 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
970 bool enabled = (*p)->enabled;
972 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
973 m->set_name ("midi device");
974 m->set_can_focus (Gtk::CAN_FOCUS);
975 m->add_events (Gdk::BUTTON_RELEASE_MASK);
976 m->set_active (enabled);
977 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
978 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
979 if ((*p)->name == focus) {
983 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
984 s = manage (new Gtk::SpinButton (*a));
985 a->set_value ((*p)->input_latency);
986 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
987 s->set_sensitive (_can_set_midi_latencies && enabled);
988 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
990 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
991 s = manage (new Gtk::SpinButton (*a));
992 a->set_value ((*p)->output_latency);
993 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
994 s->set_sensitive (_can_set_midi_latencies && enabled);
995 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
997 b = manage (new Button (_("Calibrate")));
998 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
999 b->set_sensitive (_can_set_midi_latencies && enabled);
1000 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
1007 EngineControl::backend_changed ()
1009 SignalBlocker blocker (*this, "backend_changed");
1010 string backend_name = backend_combo.get_active_text();
1011 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1013 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1014 /* eh? setting the backend failed... how ? */
1015 /* A: stale config contains a backend that does not exist in current build */
1019 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1021 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1024 setup_midi_tab_for_backend ();
1025 _midi_devices.clear();
1027 if (backend->requires_driver_selection()) {
1028 if (set_driver_popdown_strings ()) {
1032 /* this will change the device text which will cause a call to
1033 * device changed which will set up parameters
1038 update_midi_options ();
1040 connect_disconnect_button.hide();
1042 midi_option_changed();
1044 started_at_least_once = false;
1046 /* changing the backend implies stopping the engine
1047 * ARDOUR::AudioEngine() may or may not emit this signal
1048 * depending on previous engine state
1050 engine_stopped (); // set "active/inactive"
1052 if (!_have_control) {
1053 // set settings from backend that we do have control over
1054 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1057 if (_have_control && !ignore_changes) {
1058 // set driver & devices
1059 State state = get_matching_state (backend_combo.get_active_text());
1061 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1062 set_current_state (state);
1066 if (!ignore_changes) {
1067 maybe_display_saved_state ();
1072 EngineControl::update_midi_options ()
1074 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1075 vector<string> midi_options = backend->enumerate_midi_options();
1077 if (midi_options.size() == 1) {
1078 /* only contains the "none" option */
1079 midi_option_combo.set_sensitive (false);
1081 if (_have_control) {
1082 set_popdown_strings (midi_option_combo, midi_options);
1083 midi_option_combo.set_active_text (midi_options.front());
1084 midi_option_combo.set_sensitive (true);
1086 midi_option_combo.set_sensitive (false);
1092 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1094 if (ARDOUR::Profile->get_mixbus()) {
1098 uint32_t cnt = (uint32_t) sb->get_value();
1100 sb->set_text (_("all available channels"));
1103 snprintf (buf, sizeof (buf), "%d", cnt);
1109 // @return true if there are drivers available
1111 EngineControl::set_driver_popdown_strings ()
1113 DEBUG_ECONTROL ("set_driver_popdown_strings");
1114 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1115 vector<string> drivers = backend->enumerate_drivers();
1117 if (drivers.empty ()) {
1118 // This is an error...?
1122 string current_driver = backend->driver_name ();
1124 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1126 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1129 current_driver = drivers.front ();
1132 set_popdown_strings (driver_combo, drivers);
1134 string_compose ("driver_combo.set_active_text: %1", current_driver));
1135 driver_combo.set_active_text (current_driver);
1140 EngineControl::get_default_device(const string& current_device_name,
1141 const vector<string>& available_devices)
1143 // If the current device is available, use it as default
1144 if (std::find (available_devices.begin (),
1145 available_devices.end (),
1146 current_device_name) != available_devices.end ()) {
1148 return current_device_name;
1151 using namespace ARDOUR;
1153 string default_device_name =
1154 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1156 vector<string>::const_iterator i;
1158 // If there is a "Default" device available, use it
1159 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1160 if (*i == default_device_name) {
1165 string none_device_name =
1166 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1168 // Use the first device that isn't "None"
1169 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1170 if (*i != none_device_name) {
1175 // Use "None" if there are no other available
1176 return available_devices.front();
1179 // @return true if there are devices available
1181 EngineControl::set_device_popdown_strings ()
1183 DEBUG_ECONTROL ("set_device_popdown_strings");
1184 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1185 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1187 /* NOTE: Ardour currently does not display the "available" field of the
1190 * Doing so would require a different GUI widget than the combo
1191 * box/popdown that we currently use, since it has no way to list
1192 * items that are not selectable. Something more like a popup menu,
1193 * which could have unselectable items, would be appropriate.
1196 vector<string> available_devices;
1198 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1199 available_devices.push_back (i->name);
1202 if (available_devices.empty ()) {
1206 set_popdown_strings (device_combo, available_devices);
1208 std::string default_device =
1209 get_default_device(backend->device_name(), available_devices);
1212 string_compose ("set device_combo active text: %1", default_device));
1214 device_combo.set_active_text(default_device);
1218 // @return true if there are input devices available
1220 EngineControl::set_input_device_popdown_strings ()
1222 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1223 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1224 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1226 vector<string> available_devices;
1228 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1229 available_devices.push_back (i->name);
1232 if (available_devices.empty()) {
1236 set_popdown_strings (input_device_combo, available_devices);
1238 std::string default_device =
1239 get_default_device(backend->input_device_name(), available_devices);
1242 string_compose ("set input_device_combo active text: %1", default_device));
1243 input_device_combo.set_active_text(default_device);
1247 // @return true if there are output devices available
1249 EngineControl::set_output_device_popdown_strings ()
1251 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1252 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1253 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1255 vector<string> available_devices;
1257 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1258 available_devices.push_back (i->name);
1261 if (available_devices.empty()) {
1265 set_popdown_strings (output_device_combo, available_devices);
1267 std::string default_device =
1268 get_default_device(backend->output_device_name(), available_devices);
1271 string_compose ("set output_device_combo active text: %1", default_device));
1272 output_device_combo.set_active_text(default_device);
1277 EngineControl::list_devices ()
1279 DEBUG_ECONTROL ("list_devices");
1280 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1283 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1285 bool devices_available = false;
1287 if (backend->use_separate_input_and_output_devices ()) {
1288 bool input_devices_available = set_input_device_popdown_strings ();
1289 bool output_devices_available = set_output_device_popdown_strings ();
1290 devices_available = input_devices_available || output_devices_available;
1292 devices_available = set_device_popdown_strings ();
1295 if (devices_available) {
1298 device_combo.clear();
1299 input_device_combo.clear();
1300 output_device_combo.clear();
1302 update_sensitivity ();
1306 EngineControl::driver_changed ()
1308 SignalBlocker blocker (*this, "driver_changed");
1309 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1312 backend->set_driver (driver_combo.get_active_text());
1315 // TODO load LRU device(s) for backend + driver combo
1317 if (!ignore_changes) {
1318 maybe_display_saved_state ();
1323 EngineControl::get_sample_rates_for_all_devices ()
1325 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1326 ARDOUR::AudioEngine::instance ()->current_backend ();
1327 vector<float> all_rates;
1329 if (backend->use_separate_input_and_output_devices ()) {
1330 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1332 all_rates = backend->available_sample_rates (get_device_name ());
1338 EngineControl::get_default_sample_rates ()
1340 vector<float> rates;
1341 rates.push_back (8000.0f);
1342 rates.push_back (16000.0f);
1343 rates.push_back (32000.0f);
1344 rates.push_back (44100.0f);
1345 rates.push_back (48000.0f);
1346 rates.push_back (88200.0f);
1347 rates.push_back (96000.0f);
1348 rates.push_back (192000.0f);
1349 rates.push_back (384000.0f);
1354 EngineControl::set_samplerate_popdown_strings ()
1356 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1357 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1362 if (_have_control) {
1363 sr = get_sample_rates_for_all_devices ();
1365 sr = get_default_sample_rates ();
1368 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1369 s.push_back (rate_as_string (*x));
1370 if (*x == _desired_sample_rate) {
1375 set_popdown_strings (sample_rate_combo, s);
1378 if (desired.empty ()) {
1379 float new_active_sr = backend->default_sample_rate ();
1381 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1382 new_active_sr = sr.front ();
1385 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1387 sample_rate_combo.set_active_text (desired);
1391 update_sensitivity ();
1395 EngineControl::get_buffer_sizes_for_all_devices ()
1397 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1398 ARDOUR::AudioEngine::instance ()->current_backend ();
1399 vector<uint32_t> all_sizes;
1401 if (backend->use_separate_input_and_output_devices ()) {
1402 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1404 all_sizes = backend->available_buffer_sizes (get_device_name ());
1410 EngineControl::get_default_buffer_sizes ()
1412 vector<uint32_t> sizes;
1413 sizes.push_back (8);
1414 sizes.push_back (16);
1415 sizes.push_back (32);
1416 sizes.push_back (64);
1417 sizes.push_back (128);
1418 sizes.push_back (256);
1419 sizes.push_back (512);
1420 sizes.push_back (1024);
1421 sizes.push_back (2048);
1422 sizes.push_back (4096);
1423 sizes.push_back (8192);
1428 EngineControl::set_buffersize_popdown_strings ()
1430 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1431 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1432 vector<uint32_t> bs;
1435 if (_have_control) {
1436 bs = get_buffer_sizes_for_all_devices ();
1437 } else if (backend->can_change_buffer_size_when_running()) {
1438 bs = get_default_buffer_sizes ();
1441 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1442 s.push_back (bufsize_as_string (*x));
1445 uint32_t previous_size = 0;
1446 if (!buffer_size_combo.get_active_text().empty()) {
1447 previous_size = get_buffer_size ();
1450 set_popdown_strings (buffer_size_combo, s);
1454 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1455 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1458 buffer_size_combo.set_active_text(s.front());
1460 uint32_t period = backend->buffer_size();
1461 if (0 == period && backend->use_separate_input_and_output_devices()) {
1462 period = backend->default_buffer_size(get_input_device_name());
1464 if (0 == period && backend->use_separate_input_and_output_devices()) {
1465 period = backend->default_buffer_size(get_output_device_name());
1467 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1468 period = backend->default_buffer_size(get_device_name());
1471 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1473 show_buffer_duration ();
1475 update_sensitivity ();
1479 EngineControl::set_nperiods_popdown_strings ()
1481 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1482 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1483 vector<uint32_t> np;
1486 if (backend->can_set_period_size()) {
1487 np = backend->available_period_sizes (get_driver());
1490 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1491 s.push_back (nperiods_as_string (*x));
1494 set_popdown_strings (nperiods_combo, s);
1497 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX
1500 update_sensitivity ();
1504 EngineControl::device_changed ()
1506 SignalBlocker blocker (*this, "device_changed");
1507 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1510 string device_name_in;
1511 string device_name_out; // only used if backend support separate I/O devices
1513 if (backend->use_separate_input_and_output_devices()) {
1514 device_name_in = get_input_device_name ();
1515 device_name_out = get_output_device_name ();
1517 device_name_in = get_device_name ();
1520 /* we set the backend-device to query various device related intormation.
1521 * This has the side effect that backend->device_name() will match
1522 * the device_name and 'change_device' will never be true.
1523 * so work around this by setting...
1525 if (backend->use_separate_input_and_output_devices()) {
1526 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1527 queue_device_changed = true;
1530 if (device_name_in != backend->device_name()) {
1531 queue_device_changed = true;
1535 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1536 if (backend->use_separate_input_and_output_devices()) {
1537 backend->set_input_device_name (device_name_in);
1538 backend->set_output_device_name (device_name_out);
1540 backend->set_device_name(device_name_in);
1544 /* don't allow programmatic change to combos to cause a
1545 recursive call to this method.
1547 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1549 set_samplerate_popdown_strings ();
1550 set_buffersize_popdown_strings ();
1551 set_nperiods_popdown_strings ();
1553 /* TODO set min + max channel counts here */
1555 manage_control_app_sensitivity ();
1558 /* pick up any saved state for this device */
1560 if (!ignore_changes) {
1561 maybe_display_saved_state ();
1566 EngineControl::input_device_changed ()
1568 DEBUG_ECONTROL ("input_device_changed");
1573 EngineControl::output_device_changed ()
1575 DEBUG_ECONTROL ("output_device_changed");
1580 EngineControl::bufsize_as_string (uint32_t sz)
1582 /* Translators: "samples" is always plural here, so no
1583 need for plural+singular forms.
1586 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1591 EngineControl::nperiods_as_string (uint32_t np)
1594 snprintf (buf, sizeof (buf), "%u", np);
1600 EngineControl::sample_rate_changed ()
1602 DEBUG_ECONTROL ("sample_rate_changed");
1603 /* reset the strings for buffer size to show the correct msec value
1604 (reflecting the new sample rate).
1607 show_buffer_duration ();
1612 EngineControl::buffer_size_changed ()
1614 DEBUG_ECONTROL ("buffer_size_changed");
1615 show_buffer_duration ();
1619 EngineControl::nperiods_changed ()
1621 DEBUG_ECONTROL ("nperiods_changed");
1622 show_buffer_duration ();
1626 EngineControl::show_buffer_duration ()
1628 DEBUG_ECONTROL ("show_buffer_duration");
1629 /* buffer sizes - convert from just samples to samples + msecs for
1630 * the displayed string
1633 string bs_text = buffer_size_combo.get_active_text ();
1634 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1635 uint32_t rate = get_rate();
1637 /* Except for ALSA and Dummy backends, we don't know the number of periods
1638 * per cycle and settings.
1640 * jack1 vs jack2 have different default latencies since jack2 start
1641 * in async-mode unless --sync is given which adds an extra cycle
1642 * of latency. The value is not known if jackd is started externally..
1644 * So just display the period size, that's also what
1645 * ARDOUR_UI::update_sample_rate() does for the status bar.
1646 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1647 * but still, that's the buffer period, not [round-trip] latency)
1650 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1651 buffer_size_duration_label.set_text (buf);
1655 EngineControl::midi_option_changed ()
1657 DEBUG_ECONTROL ("midi_option_changed");
1658 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1661 backend->set_midi_option (get_midi_option());
1663 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1665 //_midi_devices.clear(); // TODO merge with state-saved settings..
1666 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1667 std::vector<MidiDeviceSettings> new_devices;
1669 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1670 MidiDeviceSettings mds = find_midi_device (i->name);
1671 if (i->available && !mds) {
1672 uint32_t input_latency = 0;
1673 uint32_t output_latency = 0;
1674 if (_can_set_midi_latencies) {
1675 input_latency = backend->systemic_midi_input_latency (i->name);
1676 output_latency = backend->systemic_midi_output_latency (i->name);
1678 bool enabled = backend->midi_device_enabled (i->name);
1679 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1680 new_devices.push_back (ptr);
1681 } else if (i->available) {
1682 new_devices.push_back (mds);
1685 _midi_devices = new_devices;
1687 if (_midi_devices.empty()) {
1688 midi_devices_button.hide ();
1690 midi_devices_button.show ();
1695 EngineControl::parameter_changed ()
1699 EngineControl::State
1700 EngineControl::get_matching_state (const string& backend)
1702 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1703 if ((*i)->backend == backend) {
1710 EngineControl::State
1711 EngineControl::get_matching_state (
1712 const string& backend,
1713 const string& driver,
1714 const string& device)
1716 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1717 if ((*i)->backend == backend &&
1718 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1726 EngineControl::State
1727 EngineControl::get_matching_state (
1728 const string& backend,
1729 const string& driver,
1730 const string& input_device,
1731 const string& output_device)
1733 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1734 if ((*i)->backend == backend &&
1735 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1743 EngineControl::State
1744 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1746 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1749 if (backend->use_separate_input_and_output_devices ()) {
1750 return get_matching_state (backend_combo.get_active_text(),
1751 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1752 input_device_combo.get_active_text(),
1753 output_device_combo.get_active_text());
1755 return get_matching_state (backend_combo.get_active_text(),
1756 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1757 device_combo.get_active_text());
1761 return get_matching_state (backend_combo.get_active_text(),
1763 device_combo.get_active_text());
1766 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1767 const EngineControl::State& state2)
1769 if (state1->backend == state2->backend &&
1770 state1->driver == state2->driver &&
1771 state1->device == state2->device &&
1772 state1->input_device == state2->input_device &&
1773 state1->output_device == state2->output_device) {
1780 EngineControl::state_sort_cmp (const State &a, const State &b) {
1784 else if (b->active) {
1788 return a->lru < b->lru;
1792 EngineControl::State
1793 EngineControl::save_state ()
1797 if (!_have_control) {
1798 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1800 state->lru = time (NULL) ;
1803 state.reset(new StateStruct);
1804 state->backend = get_backend ();
1806 state.reset(new StateStruct);
1807 store_state (state);
1810 for (StateList::iterator i = states.begin(); i != states.end();) {
1811 if (equivalent_states (*i, state)) {
1812 i = states.erase(i);
1818 states.push_back (state);
1820 states.sort (state_sort_cmp);
1826 EngineControl::store_state (State state)
1828 state->backend = get_backend ();
1829 state->driver = get_driver ();
1830 state->device = get_device_name ();
1831 state->input_device = get_input_device_name ();
1832 state->output_device = get_output_device_name ();
1833 state->sample_rate = get_rate ();
1834 state->buffer_size = get_buffer_size ();
1835 state->n_periods = get_nperiods ();
1836 state->input_latency = get_input_latency ();
1837 state->output_latency = get_output_latency ();
1838 state->input_channels = get_input_channels ();
1839 state->output_channels = get_output_channels ();
1840 state->midi_option = get_midi_option ();
1841 state->midi_devices = _midi_devices;
1842 state->use_buffered_io = get_use_buffered_io ();
1843 state->lru = time (NULL) ;
1847 EngineControl::maybe_display_saved_state ()
1849 if (!_have_control) {
1853 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1856 DEBUG_ECONTROL ("Restoring saved state");
1857 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1859 if (!_desired_sample_rate) {
1860 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1862 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1864 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1865 /* call this explicitly because we're ignoring changes to
1866 the controls at this point.
1868 show_buffer_duration ();
1869 input_latency.set_value (state->input_latency);
1870 output_latency.set_value (state->output_latency);
1872 use_buffered_io_button.set_active (state->use_buffered_io);
1874 if (!state->midi_option.empty()) {
1875 midi_option_combo.set_active_text (state->midi_option);
1876 _midi_devices = state->midi_devices;
1879 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1884 EngineControl::get_state ()
1886 LocaleGuard lg (X_("C"));
1888 XMLNode* root = new XMLNode ("AudioMIDISetup");
1891 if (!states.empty()) {
1892 XMLNode* state_nodes = new XMLNode ("EngineStates");
1894 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1896 XMLNode* node = new XMLNode ("State");
1898 node->add_property ("backend", (*i)->backend);
1899 node->add_property ("driver", (*i)->driver);
1900 node->add_property ("device", (*i)->device);
1901 node->add_property ("input-device", (*i)->input_device);
1902 node->add_property ("output-device", (*i)->output_device);
1903 node->add_property ("sample-rate", (*i)->sample_rate);
1904 node->add_property ("buffer-size", (*i)->buffer_size);
1905 node->add_property ("n-periods", (*i)->n_periods);
1906 node->add_property ("input-latency", (*i)->input_latency);
1907 node->add_property ("output-latency", (*i)->output_latency);
1908 node->add_property ("input-channels", (*i)->input_channels);
1909 node->add_property ("output-channels", (*i)->output_channels);
1910 node->add_property ("active", (*i)->active ? "yes" : "no");
1911 node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
1912 node->add_property ("midi-option", (*i)->midi_option);
1913 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1915 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1916 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1917 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1918 midi_device_stuff->add_property (X_("name"), (*p)->name);
1919 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1920 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1921 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1922 midi_devices->add_child_nocopy (*midi_device_stuff);
1924 node->add_child_nocopy (*midi_devices);
1926 state_nodes->add_child_nocopy (*node);
1929 root->add_child_nocopy (*state_nodes);
1936 EngineControl::set_default_state ()
1938 vector<string> backend_names;
1939 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1941 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1942 backend_names.push_back ((*b)->name);
1944 backend_combo.set_active_text (backend_names.front());
1946 // We could set default backends per platform etc here
1952 EngineControl::set_state (const XMLNode& root)
1954 XMLNodeList clist, cclist;
1955 XMLNodeConstIterator citer, cciter;
1957 XMLNode* grandchild;
1958 XMLProperty* prop = NULL;
1960 fprintf (stderr, "EngineControl::set_state\n");
1962 if (root.name() != "AudioMIDISetup") {
1966 clist = root.children();
1970 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1974 if (child->name() != "EngineStates") {
1978 cclist = child->children();
1980 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1981 State state (new StateStruct);
1983 grandchild = *cciter;
1985 if (grandchild->name() != "State") {
1989 if ((prop = grandchild->property ("backend")) == 0) {
1992 state->backend = prop->value ();
1994 if ((prop = grandchild->property ("driver")) == 0) {
1997 state->driver = prop->value ();
1999 if ((prop = grandchild->property ("device")) == 0) {
2002 state->device = prop->value ();
2004 if ((prop = grandchild->property ("input-device")) == 0) {
2007 state->input_device = prop->value ();
2009 if ((prop = grandchild->property ("output-device")) == 0) {
2012 state->output_device = prop->value ();
2014 if ((prop = grandchild->property ("sample-rate")) == 0) {
2017 state->sample_rate = atof (prop->value ());
2019 if ((prop = grandchild->property ("buffer-size")) == 0) {
2022 state->buffer_size = atoi (prop->value ());
2024 if ((prop = grandchild->property ("n-periods")) == 0) {
2025 // optional (new value in 4.5)
2026 state->n_periods = 0;
2028 state->n_periods = atoi (prop->value ());
2031 if ((prop = grandchild->property ("input-latency")) == 0) {
2034 state->input_latency = atoi (prop->value ());
2036 if ((prop = grandchild->property ("output-latency")) == 0) {
2039 state->output_latency = atoi (prop->value ());
2041 if ((prop = grandchild->property ("input-channels")) == 0) {
2044 state->input_channels = atoi (prop->value ());
2046 if ((prop = grandchild->property ("output-channels")) == 0) {
2049 state->output_channels = atoi (prop->value ());
2051 if ((prop = grandchild->property ("active")) == 0) {
2054 state->active = string_is_affirmative (prop->value ());
2056 if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2059 state->use_buffered_io = string_is_affirmative (prop->value ());
2061 if ((prop = grandchild->property ("midi-option")) == 0) {
2064 state->midi_option = prop->value ();
2066 state->midi_devices.clear();
2068 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2069 const XMLNodeList mnc = midinode->children();
2070 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2071 if ((*n)->property (X_("name")) == 0
2072 || (*n)->property (X_("enabled")) == 0
2073 || (*n)->property (X_("input-latency")) == 0
2074 || (*n)->property (X_("output-latency")) == 0
2079 MidiDeviceSettings ptr (new MidiDeviceSetting(
2080 (*n)->property (X_("name"))->value (),
2081 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2082 atoi ((*n)->property (X_("input-latency"))->value ()),
2083 atoi ((*n)->property (X_("output-latency"))->value ())
2085 state->midi_devices.push_back (ptr);
2089 if ((prop = grandchild->property ("lru"))) {
2090 state->lru = atoi (prop->value ());
2094 /* remove accumulated duplicates (due to bug in ealier version)
2095 * this can be removed again before release
2097 for (StateList::iterator i = states.begin(); i != states.end();) {
2098 if ((*i)->backend == state->backend &&
2099 (*i)->driver == state->driver &&
2100 (*i)->device == state->device) {
2101 i = states.erase(i);
2108 states.push_back (state);
2112 /* now see if there was an active state and switch the setup to it */
2114 // purge states of backend that are not available in this built
2115 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2116 vector<std::string> backend_names;
2118 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2119 backend_names.push_back((*i)->name);
2121 for (StateList::iterator i = states.begin(); i != states.end();) {
2122 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2123 i = states.erase(i);
2129 states.sort (state_sort_cmp);
2131 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2134 return set_current_state (*i);
2141 EngineControl::set_current_state (const State& state)
2143 DEBUG_ECONTROL ("set_current_state");
2145 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2147 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2148 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2149 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2150 // this shouldn't happen as the invalid backend names should have been
2151 // removed from the list of states.
2155 // now reflect the change in the backend in the GUI so backend_changed will
2156 // do the right thing
2157 backend_combo.set_active_text (state->backend);
2159 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2161 // we don't have control don't restore state
2166 if (!state->driver.empty ()) {
2167 if (!backend->requires_driver_selection ()) {
2168 DEBUG_ECONTROL ("Backend should require driver selection");
2169 // A backend has changed from having driver selection to not having
2170 // it or someone has been manually editing a config file and messed
2175 if (backend->set_driver (state->driver) != 0) {
2176 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2177 // Driver names for a backend have changed and the name in the
2178 // config file is now invalid or support for driver is no longer
2179 // included in the backend
2182 // no need to set the driver_combo as backend_changed will use
2183 // backend->driver_name to set the active driver
2186 if (!state->device.empty ()) {
2187 if (backend->set_device_name (state->device) != 0) {
2189 string_compose ("Unable to set device name %1", state->device));
2190 // device is no longer available on the system
2193 // no need to set active device as it will be picked up in
2194 // via backend_changed ()/set_device_popdown_strings
2197 // backend supports separate input/output devices
2198 if (backend->set_input_device_name (state->input_device) != 0) {
2199 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2200 state->input_device));
2201 // input device is no longer available on the system
2205 if (backend->set_output_device_name (state->output_device) != 0) {
2206 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2207 state->input_device));
2208 // output device is no longer available on the system
2211 // no need to set active devices as it will be picked up in via
2212 // backend_changed ()/set_*_device_popdown_strings
2217 // Now restore the state of the rest of the controls
2219 // We don't use a SignalBlocker as set_current_state is currently only
2220 // called from set_state before any signals are connected. If at some point
2221 // a more general named state mechanism is implemented and
2222 // set_current_state is called while signals are connected then a
2223 // SignalBlocker will need to be instantiated before setting these.
2225 device_combo.set_active_text (state->device);
2226 input_device_combo.set_active_text (state->input_device);
2227 output_device_combo.set_active_text (state->output_device);
2228 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2229 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2230 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2231 input_latency.set_value (state->input_latency);
2232 output_latency.set_value (state->output_latency);
2233 midi_option_combo.set_active_text (state->midi_option);
2234 use_buffered_io_button.set_active (state->use_buffered_io);
2239 EngineControl::push_state_to_backend (bool start)
2241 DEBUG_ECONTROL ("push_state_to_backend");
2242 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2243 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2249 /* figure out what is going to change */
2251 bool restart_required = false;
2252 bool was_running = ARDOUR::AudioEngine::instance()->running();
2253 bool change_driver = false;
2254 bool change_device = false;
2255 bool change_rate = false;
2256 bool change_bufsize = false;
2257 bool change_nperiods = false;
2258 bool change_latency = false;
2259 bool change_channels = false;
2260 bool change_midi = false;
2261 bool change_buffered_io = false;
2263 uint32_t ochan = get_output_channels ();
2264 uint32_t ichan = get_input_channels ();
2266 if (_have_control) {
2268 if (started_at_least_once) {
2270 /* we can control the backend */
2272 if (backend->requires_driver_selection()) {
2273 if (get_driver() != backend->driver_name()) {
2274 change_driver = true;
2278 if (backend->use_separate_input_and_output_devices()) {
2279 if (get_input_device_name() != backend->input_device_name()) {
2280 change_device = true;
2282 if (get_output_device_name() != backend->output_device_name()) {
2283 change_device = true;
2286 if (get_device_name() != backend->device_name()) {
2287 change_device = true;
2291 if (queue_device_changed) {
2292 change_device = true;
2295 if (get_rate() != backend->sample_rate()) {
2299 if (get_buffer_size() != backend->buffer_size()) {
2300 change_bufsize = true;
2303 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2304 && get_nperiods() != backend->period_size()) {
2305 change_nperiods = true;
2308 if (get_midi_option() != backend->midi_option()) {
2312 if (backend->can_use_buffered_io()) {
2313 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2314 change_buffered_io = true;
2318 /* zero-requested channels means "all available" */
2321 ichan = backend->input_channels();
2325 ochan = backend->output_channels();
2328 if (ichan != backend->input_channels()) {
2329 change_channels = true;
2332 if (ochan != backend->output_channels()) {
2333 change_channels = true;
2336 if (get_input_latency() != backend->systemic_input_latency() ||
2337 get_output_latency() != backend->systemic_output_latency()) {
2338 change_latency = true;
2341 /* backend never started, so we have to force a group
2344 change_device = true;
2345 if (backend->requires_driver_selection()) {
2346 change_driver = true;
2349 change_bufsize = true;
2350 change_channels = true;
2351 change_latency = true;
2353 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2358 /* we have no control over the backend, meaning that we can
2359 * only possibly change sample rate and buffer size.
2363 if (get_rate() != backend->sample_rate()) {
2364 change_bufsize = true;
2367 if (get_buffer_size() != backend->buffer_size()) {
2368 change_bufsize = true;
2372 queue_device_changed = false;
2374 if (!_have_control) {
2376 /* We do not have control over the backend, so the best we can
2377 * do is try to change the sample rate and/or bufsize and get
2381 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2385 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2390 backend->set_sample_rate (get_rate());
2393 if (change_bufsize) {
2394 backend->set_buffer_size (get_buffer_size());
2398 if (ARDOUR::AudioEngine::instance()->start ()) {
2399 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2409 /* determine if we need to stop the backend before changing parameters */
2411 if (change_driver || change_device || change_channels || change_nperiods ||
2412 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2413 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2415 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2416 restart_required = true;
2418 restart_required = false;
2423 if (restart_required) {
2424 if (ARDOUR::AudioEngine::instance()->stop()) {
2430 if (change_driver && backend->set_driver (get_driver())) {
2431 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2434 if (backend->use_separate_input_and_output_devices()) {
2435 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2436 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2439 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2440 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2444 if (change_device && backend->set_device_name (get_device_name())) {
2445 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2449 if (change_rate && backend->set_sample_rate (get_rate())) {
2450 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2453 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2454 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2457 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2458 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2462 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2463 if (backend->set_input_channels (get_input_channels())) {
2464 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2467 if (backend->set_output_channels (get_output_channels())) {
2468 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2472 if (change_latency) {
2473 if (backend->set_systemic_input_latency (get_input_latency())) {
2474 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2477 if (backend->set_systemic_output_latency (get_output_latency())) {
2478 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2484 backend->set_midi_option (get_midi_option());
2487 if (change_buffered_io) {
2488 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2492 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2493 if (_measure_midi) {
2494 if (*p == _measure_midi) {
2495 backend->set_midi_device_enabled ((*p)->name, true);
2497 backend->set_midi_device_enabled ((*p)->name, false);
2499 if (backend->can_change_systemic_latency_when_running ()) {
2500 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2501 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2505 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2506 if (backend->can_set_systemic_midi_latencies()) {
2507 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2508 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2513 if (start || (was_running && restart_required)) {
2514 if (ARDOUR::AudioEngine::instance()->start()) {
2525 EngineControl::post_push ()
2527 /* get a pointer to the current state object, creating one if
2531 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2534 state = save_state ();
2540 states.sort (state_sort_cmp);
2544 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2545 (*i)->active = false;
2548 /* mark this one active (to be used next time the dialog is
2552 state->active = true;
2554 if (_have_control) { // XXX
2555 manage_control_app_sensitivity ();
2558 /* schedule a redisplay of MIDI ports */
2559 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2564 EngineControl::get_rate () const
2566 float r = atof (sample_rate_combo.get_active_text ());
2567 /* the string may have been translated with an abbreviation for
2568 * thousands, so use a crude heuristic to fix this.
2578 EngineControl::get_buffer_size () const
2580 string txt = buffer_size_combo.get_active_text ();
2583 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2584 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2585 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2593 EngineControl::get_nperiods () const
2595 string txt = nperiods_combo.get_active_text ();
2596 return atoi (txt.c_str());
2600 EngineControl::get_midi_option () const
2602 return midi_option_combo.get_active_text();
2606 EngineControl::get_use_buffered_io () const
2608 return use_buffered_io_button.get_active();
2612 EngineControl::get_input_channels() const
2614 if (ARDOUR::Profile->get_mixbus()) {
2615 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2616 if (!backend) return 0;
2617 return backend->input_channels();
2619 return (uint32_t) input_channels_adjustment.get_value();
2623 EngineControl::get_output_channels() const
2625 if (ARDOUR::Profile->get_mixbus()) {
2626 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2627 if (!backend) return 0;
2628 return backend->input_channels();
2630 return (uint32_t) output_channels_adjustment.get_value();
2634 EngineControl::get_input_latency() const
2636 return (uint32_t) input_latency_adjustment.get_value();
2640 EngineControl::get_output_latency() const
2642 return (uint32_t) output_latency_adjustment.get_value();
2646 EngineControl::get_backend () const
2648 return backend_combo.get_active_text ();
2652 EngineControl::get_driver () const
2654 if (driver_combo.get_parent()) {
2655 return driver_combo.get_active_text ();
2662 EngineControl::get_device_name () const
2664 return device_combo.get_active_text ();
2668 EngineControl::get_input_device_name () const
2670 return input_device_combo.get_active_text ();
2674 EngineControl::get_output_device_name () const
2676 return output_device_combo.get_active_text ();
2680 EngineControl::control_app_button_clicked ()
2682 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2688 backend->launch_control_app ();
2692 EngineControl::start_stop_button_clicked ()
2694 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2700 if (ARDOUR::AudioEngine::instance()->running()) {
2701 ARDOUR::AudioEngine::instance()->stop ();
2708 EngineControl::update_devices_button_clicked ()
2710 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2716 if (backend->update_devices()) {
2717 device_list_changed ();
2722 EngineControl::use_buffered_io_button_clicked ()
2724 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2730 bool set_buffered_io = !use_buffered_io_button.get_active();
2731 use_buffered_io_button.set_active (set_buffered_io);
2732 backend->set_use_buffered_io (set_buffered_io);
2736 EngineControl::manage_control_app_sensitivity ()
2738 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2744 string appname = backend->control_app_name();
2746 if (appname.empty()) {
2747 control_app_button.set_sensitive (false);
2749 control_app_button.set_sensitive (true);
2754 EngineControl::set_desired_sample_rate (uint32_t sr)
2756 _desired_sample_rate = sr;
2761 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2763 if (page_num == 0) {
2764 cancel_button->set_sensitive (true);
2765 _measure_midi.reset();
2766 update_sensitivity ();
2768 cancel_button->set_sensitive (false);
2769 ok_button->set_sensitive (false);
2772 if (page_num == midi_tab) {
2774 refresh_midi_display ();
2777 if (page_num == latency_tab) {
2780 if (ARDOUR::AudioEngine::instance()->running()) {
2785 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2787 /* save any existing latency values */
2789 uint32_t il = (uint32_t) input_latency.get_value ();
2790 uint32_t ol = (uint32_t) input_latency.get_value ();
2792 /* reset to zero so that our new test instance
2793 will be clean of any existing latency measures.
2795 NB. this should really be done by the backend
2796 when stated for latency measurement.
2799 input_latency.set_value (0);
2800 output_latency.set_value (0);
2802 push_state_to_backend (false);
2806 input_latency.set_value (il);
2807 output_latency.set_value (ol);
2810 // This should be done in push_state_to_backend()
2811 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2812 disable_latency_tab ();
2815 enable_latency_tab ();
2819 end_latency_detection ();
2820 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2825 /* latency measurement */
2828 EngineControl::check_audio_latency_measurement ()
2830 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2832 if (mtdm->resolve () < 0) {
2833 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2837 if (mtdm->get_peak () > 0.707f) {
2838 // get_peak() resets the peak-hold in the detector.
2839 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2840 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2844 if (mtdm->err () > 0.3) {
2850 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2852 if (sample_rate == 0) {
2853 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2854 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2858 int frames_total = mtdm->del();
2859 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2861 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2862 _("Detected roundtrip latency: "),
2863 frames_total, frames_total * 1000.0f/sample_rate,
2864 _("Systemic latency: "),
2865 extra, extra * 1000.0f/sample_rate);
2869 if (mtdm->err () > 0.2) {
2871 strcat (buf, _("(signal detection error)"));
2877 strcat (buf, _("(inverted - bad wiring)"));
2881 lm_results.set_markup (string_compose (results_markup, buf));
2884 have_lm_results = true;
2885 end_latency_detection ();
2886 lm_use_button.set_sensitive (true);
2894 EngineControl::check_midi_latency_measurement ()
2896 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2898 if (!mididm->have_signal () || mididm->latency () == 0) {
2899 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2904 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2906 if (sample_rate == 0) {
2907 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2908 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2912 ARDOUR::framecnt_t frames_total = mididm->latency();
2913 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2914 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2915 _("Detected roundtrip latency: "),
2916 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2917 _("Systemic latency: "),
2918 extra, extra * 1000.0f / sample_rate);
2922 if (!mididm->ok ()) {
2924 strcat (buf, _("(averaging)"));
2928 if (mididm->deviation () > 50.0) {
2930 strcat (buf, _("(too large jitter)"));
2932 } else if (mididm->deviation () > 10.0) {
2934 strcat (buf, _("(large jitter)"));
2938 have_lm_results = true;
2939 end_latency_detection ();
2940 lm_use_button.set_sensitive (true);
2941 lm_results.set_markup (string_compose (results_markup, buf));
2943 } else if (mididm->processed () > 400) {
2944 have_lm_results = false;
2945 end_latency_detection ();
2946 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2950 lm_results.set_markup (string_compose (results_markup, buf));
2956 EngineControl::start_latency_detection ()
2958 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2959 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2961 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2962 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2963 if (_measure_midi) {
2964 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2966 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2968 lm_measure_label.set_text (_("Cancel"));
2969 have_lm_results = false;
2970 lm_use_button.set_sensitive (false);
2971 lm_input_channel_combo.set_sensitive (false);
2972 lm_output_channel_combo.set_sensitive (false);
2978 EngineControl::end_latency_detection ()
2980 latency_timeout.disconnect ();
2981 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2982 lm_measure_label.set_text (_("Measure"));
2983 if (!have_lm_results) {
2984 lm_use_button.set_sensitive (false);
2986 lm_input_channel_combo.set_sensitive (true);
2987 lm_output_channel_combo.set_sensitive (true);
2992 EngineControl::latency_button_clicked ()
2995 start_latency_detection ();
2997 end_latency_detection ();
3002 EngineControl::latency_back_button_clicked ()
3004 ARDOUR::AudioEngine::instance()->stop(true);
3005 notebook.set_current_page(0);
3009 EngineControl::use_latency_button_clicked ()
3011 if (_measure_midi) {
3012 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3016 ARDOUR::framecnt_t frames_total = mididm->latency();
3017 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3018 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3019 _measure_midi->input_latency = one_way;
3020 _measure_midi->output_latency = one_way;
3021 notebook.set_current_page (midi_tab);
3023 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3029 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3030 one_way = std::max (0., one_way);
3032 input_latency_adjustment.set_value (one_way);
3033 output_latency_adjustment.set_value (one_way);
3035 /* back to settings page */
3036 notebook.set_current_page (0);
3041 EngineControl::on_delete_event (GdkEventAny* ev)
3043 if (notebook.get_current_page() == 2) {
3044 /* currently on latency tab - be sure to clean up */
3045 end_latency_detection ();
3047 return ArdourDialog::on_delete_event (ev);
3051 EngineControl::engine_running ()
3053 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3056 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3057 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3059 if (backend->can_set_period_size ()) {
3060 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3063 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3064 connect_disconnect_button.show();
3066 started_at_least_once = true;
3067 if (_have_control) {
3068 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3070 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3072 update_sensitivity();
3076 EngineControl::engine_stopped ()
3078 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3081 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3082 connect_disconnect_button.show();
3084 if (_have_control) {
3085 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3087 engine_status.set_markup(X_(""));
3090 update_sensitivity();
3094 EngineControl::device_list_changed ()
3096 if (ignore_device_changes) {
3099 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3101 midi_option_changed();
3105 EngineControl::connect_disconnect_click()
3107 if (ARDOUR::AudioEngine::instance()->running()) {
3115 EngineControl::calibrate_audio_latency ()
3117 _measure_midi.reset ();
3118 have_lm_results = false;
3119 lm_use_button.set_sensitive (false);
3120 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3121 notebook.set_current_page (latency_tab);
3125 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3128 have_lm_results = false;
3129 lm_use_button.set_sensitive (false);
3130 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3131 notebook.set_current_page (latency_tab);
3135 EngineControl::configure_midi_devices ()
3137 notebook.set_current_page (midi_tab);