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 , lm_measure_label (_("Measure"))
91 , lm_use_button (_("Use results"))
92 , lm_back_button (_("Back to settings ... (ignore results)"))
93 , lm_button_audio (_("Calibrate Audio"))
95 , have_lm_results (false)
97 , midi_back_button (_("Back to settings"))
99 , ignore_device_changes (0)
100 , _desired_sample_rate (0)
101 , started_at_least_once (false)
102 , queue_device_changed (false)
103 , _have_control (true)
106 using namespace Notebook_Helpers;
107 vector<string> backend_names;
109 AttachOptions xopt = AttachOptions (FILL|EXPAND);
112 set_name (X_("AudioMIDISetup"));
114 /* the backend combo is the one thing that is ALWAYS visible */
116 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
118 if (backends.empty()) {
119 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));
121 throw failed_constructor ();
124 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
125 backend_names.push_back ((*b)->name);
128 set_popdown_strings (backend_combo, backend_names);
130 /* setup basic packing characteristics for the table used on the main
131 * tab of the notebook
134 basic_packer.set_spacings (6);
135 basic_packer.set_border_width (12);
136 basic_packer.set_homogeneous (false);
140 basic_hbox.pack_start (basic_packer, false, false);
142 /* latency measurement tab */
144 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
147 lm_table.set_row_spacings (12);
148 lm_table.set_col_spacings (6);
149 lm_table.set_homogeneous (false);
151 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
154 lm_preamble.set_width_chars (60);
155 lm_preamble.set_line_wrap (true);
156 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
158 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
161 Gtk::Label* preamble;
162 preamble = manage (new Label);
163 preamble->set_width_chars (60);
164 preamble->set_line_wrap (true);
165 preamble->set_markup (_("Select two channels below and connect them using a cable."));
167 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
170 label = manage (new Label (_("Output channel")));
171 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
173 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
174 misc_align->add (lm_output_channel_combo);
175 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
178 label = manage (new Label (_("Input channel")));
179 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
181 misc_align = manage (new Alignment (0.0, 0.5));
182 misc_align->add (lm_input_channel_combo);
183 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
186 lm_measure_label.set_padding (10, 10);
187 lm_measure_button.add (lm_measure_label);
188 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
189 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
190 lm_back_button_signal = lm_back_button.signal_clicked().connect(
191 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
193 lm_use_button.set_sensitive (false);
195 /* Increase the default spacing around the labels of these three
201 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
202 l->set_padding (10, 10);
205 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
206 l->set_padding (10, 10);
209 preamble = manage (new Label);
210 preamble->set_width_chars (60);
211 preamble->set_line_wrap (true);
212 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
213 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
216 preamble = manage (new Label);
217 preamble->set_width_chars (60);
218 preamble->set_line_wrap (true);
219 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
220 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
222 ++row; // skip a row in the table
223 ++row; // skip a row in the table
225 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
227 ++row; // skip a row in the table
228 ++row; // skip a row in the table
230 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
231 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
232 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
234 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
236 lm_vbox.set_border_width (12);
237 lm_vbox.pack_start (lm_table, false, false);
239 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
243 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
244 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
245 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
246 notebook.set_border_width (12);
248 notebook.set_show_tabs (false);
249 notebook.show_all ();
251 notebook.set_name ("SettingsNotebook");
253 /* packup the notebook */
255 get_vbox()->set_border_width (12);
256 get_vbox()->pack_start (notebook);
258 /* need a special function to print "all available channels" when the
259 * channel counts hit zero.
262 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
263 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
265 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
266 midi_devices_button.set_sensitive (false);
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 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
286 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
288 /* Pick up any existing audio setup configuration, if appropriate */
290 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
292 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
293 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
294 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
295 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
298 if (!set_state (*audio_setup)) {
299 set_default_state ();
302 set_default_state ();
305 connect_changed_signals ();
307 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
309 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
310 connect_disconnect_button.set_no_show_all();
315 EngineControl::connect_changed_signals ()
317 backend_combo_connection = backend_combo.signal_changed ().connect (
318 sigc::mem_fun (*this, &EngineControl::backend_changed));
319 driver_combo_connection = driver_combo.signal_changed ().connect (
320 sigc::mem_fun (*this, &EngineControl::driver_changed));
321 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
322 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
323 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
324 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
325 nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
326 sigc::mem_fun (*this, &EngineControl::nperiods_changed));
327 device_combo_connection = device_combo.signal_changed ().connect (
328 sigc::mem_fun (*this, &EngineControl::device_changed));
329 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
330 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
332 input_device_combo_connection = input_device_combo.signal_changed ().connect (
333 sigc::mem_fun (*this, &EngineControl::input_device_changed));
334 output_device_combo_connection = output_device_combo.signal_changed ().connect (
335 sigc::mem_fun (*this, &EngineControl::output_device_changed));
337 input_latency_connection = input_latency.signal_changed ().connect (
338 sigc::mem_fun (*this, &EngineControl::parameter_changed));
339 output_latency_connection = output_latency.signal_changed ().connect (
340 sigc::mem_fun (*this, &EngineControl::parameter_changed));
341 input_channels_connection = input_channels.signal_changed ().connect (
342 sigc::mem_fun (*this, &EngineControl::parameter_changed));
343 output_channels_connection = output_channels.signal_changed ().connect (
344 sigc::mem_fun (*this, &EngineControl::parameter_changed));
348 EngineControl::block_changed_signals ()
350 if (block_signals++ == 0) {
351 DEBUG_ECONTROL ("Blocking changed signals");
352 backend_combo_connection.block ();
353 driver_combo_connection.block ();
354 sample_rate_combo_connection.block ();
355 buffer_size_combo_connection.block ();
356 nperiods_combo_connection.block ();
357 device_combo_connection.block ();
358 input_device_combo_connection.block ();
359 output_device_combo_connection.block ();
360 midi_option_combo_connection.block ();
361 input_latency_connection.block ();
362 output_latency_connection.block ();
363 input_channels_connection.block ();
364 output_channels_connection.block ();
369 EngineControl::unblock_changed_signals ()
371 if (--block_signals == 0) {
372 DEBUG_ECONTROL ("Unblocking changed signals");
373 backend_combo_connection.unblock ();
374 driver_combo_connection.unblock ();
375 sample_rate_combo_connection.unblock ();
376 buffer_size_combo_connection.unblock ();
377 nperiods_combo_connection.unblock ();
378 device_combo_connection.unblock ();
379 input_device_combo_connection.unblock ();
380 output_device_combo_connection.unblock ();
381 midi_option_combo_connection.unblock ();
382 input_latency_connection.unblock ();
383 output_latency_connection.unblock ();
384 input_channels_connection.unblock ();
385 output_channels_connection.unblock ();
389 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
390 const std::string& reason)
391 : ec (engine_control)
394 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
395 ec.block_changed_signals ();
398 EngineControl::SignalBlocker::~SignalBlocker ()
400 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
401 ec.unblock_changed_signals ();
405 EngineControl::on_show ()
407 ArdourDialog::on_show ();
408 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
409 // re-check _have_control (jackd running) see #6041
413 ok_button->grab_focus();
417 EngineControl::start_engine ()
419 if (push_state_to_backend(true) != 0) {
420 MessageDialog msg(*this,
421 ARDOUR::AudioEngine::instance()->get_last_backend_error());
429 EngineControl::stop_engine (bool for_latency)
431 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
432 MessageDialog msg(*this,
433 ARDOUR::AudioEngine::instance()->get_last_backend_error());
441 EngineControl::on_response (int response_id)
443 ArdourDialog::on_response (response_id);
445 switch (response_id) {
447 if (!start_engine()) {
452 #ifdef PLATFORM_WINDOWS
454 // But if there's no session open, this can produce
455 // a long gap when nothing appears to be happening.
456 // Let's show the splash image while we're waiting.
457 if (!ARDOUR_COMMAND_LINE::no_splash) {
458 if (ARDOUR_UI::instance()) {
459 if (!ARDOUR_UI::instance()->session_loaded) {
460 ARDOUR_UI::instance()->show_splash();
466 case RESPONSE_DELETE_EVENT: {
468 ev.type = GDK_BUTTON_PRESS;
470 on_delete_event((GdkEventAny*)&ev);
473 case RESPONSE_CANCEL:
474 if (ARDOUR_UI::instance() && ARDOUR_UI::instance()->session_loaded) {
475 ARDOUR_UI::instance()->check_audioengine(*this);
484 EngineControl::build_notebook ()
487 AttachOptions xopt = AttachOptions (FILL|EXPAND);
489 /* clear the table */
491 Gtkmm2ext::container_clear (basic_vbox);
492 Gtkmm2ext::container_clear (basic_packer);
494 if (control_app_button.get_parent()) {
495 control_app_button.get_parent()->remove (control_app_button);
498 label = manage (left_aligned_label (_("Audio System:")));
499 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
500 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
502 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
503 engine_status.show();
505 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
506 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
508 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
509 lm_button_audio.set_name ("generic button");
510 lm_button_audio.set_can_focus(true);
513 build_full_control_notebook ();
515 build_no_control_notebook ();
518 basic_vbox.pack_start (basic_hbox, false, false);
521 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
522 basic_vbox.show_all ();
527 EngineControl::build_full_control_notebook ()
529 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
532 using namespace Notebook_Helpers;
534 vector<string> strings;
535 AttachOptions xopt = AttachOptions (FILL|EXPAND);
536 int row = 1; // row zero == backend combo
538 /* start packing it up */
540 if (backend->requires_driver_selection()) {
541 label = manage (left_aligned_label (_("Driver:")));
542 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
543 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
547 if (backend->use_separate_input_and_output_devices()) {
548 label = manage (left_aligned_label (_("Input Device:")));
549 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
550 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
552 label = manage (left_aligned_label (_("Output Device:")));
553 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
554 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
556 // reset so it isn't used in state comparisons
557 device_combo.set_active_text ("");
559 label = manage (left_aligned_label (_("Device:")));
560 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
561 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
563 // reset these so they don't get used in state comparisons
564 input_device_combo.set_active_text ("");
565 output_device_combo.set_active_text ("");
568 label = manage (left_aligned_label (_("Sample rate:")));
569 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
570 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
574 label = manage (left_aligned_label (_("Buffer size:")));
575 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
576 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
577 buffer_size_duration_label.set_alignment (0.0); /* left-align */
578 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
580 int ctrl_btn_span = 1;
581 if (backend->can_set_period_size ()) {
583 label = manage (left_aligned_label (_("Periods:")));
584 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
585 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
589 /* button spans 2 or 3 rows */
591 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
594 input_channels.set_name ("InputChannels");
595 input_channels.set_flags (Gtk::CAN_FOCUS);
596 input_channels.set_digits (0);
597 input_channels.set_wrap (false);
598 output_channels.set_editable (true);
600 if (!ARDOUR::Profile->get_mixbus()) {
601 label = manage (left_aligned_label (_("Input Channels:")));
602 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
603 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
607 output_channels.set_name ("OutputChannels");
608 output_channels.set_flags (Gtk::CAN_FOCUS);
609 output_channels.set_digits (0);
610 output_channels.set_wrap (false);
611 output_channels.set_editable (true);
613 if (!ARDOUR::Profile->get_mixbus()) {
614 label = manage (left_aligned_label (_("Output Channels:")));
615 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
616 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
620 input_latency.set_name ("InputLatency");
621 input_latency.set_flags (Gtk::CAN_FOCUS);
622 input_latency.set_digits (0);
623 input_latency.set_wrap (false);
624 input_latency.set_editable (true);
626 label = manage (left_aligned_label (_("Hardware input latency:")));
627 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
628 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
629 label = manage (left_aligned_label (_("samples")));
630 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
633 output_latency.set_name ("OutputLatency");
634 output_latency.set_flags (Gtk::CAN_FOCUS);
635 output_latency.set_digits (0);
636 output_latency.set_wrap (false);
637 output_latency.set_editable (true);
639 label = manage (left_aligned_label (_("Hardware output latency:")));
640 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
641 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
642 label = manage (left_aligned_label (_("samples")));
643 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
645 /* button spans 2 rows */
647 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
650 label = manage (left_aligned_label (_("MIDI System:")));
651 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
652 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
653 #if ! defined __APPLE__ && ! defined PLATFORM_WINDOWS // => linux, YAY
654 /* Currently the only backend with dedicated Midi setup is ALSA.
655 * lot of people complain that this is greyed out
656 * "I can't use MIDI, the setup is greyed out"
658 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);
865 if (backend->can_request_update_devices()) {
866 update_devices_button.show();
868 update_devices_button.hide();
870 start_stop_button.set_text("Start");
871 update_devices_button.set_sensitive(true);
874 update_devices_button.set_sensitive(false);
875 update_devices_button.hide();
876 start_stop_button.set_sensitive(false);
877 start_stop_button.hide();
880 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
881 input_device_combo.set_sensitive (false);
882 output_device_combo.set_sensitive (false);
883 device_combo.set_sensitive (false);
884 driver_combo.set_sensitive (false);
886 input_device_combo.set_sensitive (true);
887 output_device_combo.set_sensitive (true);
888 device_combo.set_sensitive (true);
889 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
890 driver_combo.set_sensitive (true);
892 driver_combo.set_sensitive (false);
896 if (valid || !_have_control) {
897 ok_button->set_sensitive (true);
899 ok_button->set_sensitive (false);
904 EngineControl::setup_midi_tab_for_jack ()
909 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
911 device->input_latency = a->get_value();
913 device->output_latency = a->get_value();
918 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
919 b->set_active (!b->get_active());
920 device->enabled = b->get_active();
921 refresh_midi_display(device->name);
925 EngineControl::refresh_midi_display (std::string focus)
927 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
931 AttachOptions xopt = AttachOptions (FILL|EXPAND);
934 Gtkmm2ext::container_clear (midi_device_table);
936 midi_device_table.set_spacings (6);
938 l = manage (new Label);
939 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
940 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
941 l->set_alignment (0.5, 0.5);
945 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
946 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
947 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
948 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
950 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
951 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
952 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
953 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
956 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
961 bool enabled = (*p)->enabled;
963 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
964 m->set_name ("midi device");
965 m->set_can_focus (Gtk::CAN_FOCUS);
966 m->add_events (Gdk::BUTTON_RELEASE_MASK);
967 m->set_active (enabled);
968 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
969 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
970 if ((*p)->name == focus) {
974 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
975 s = manage (new Gtk::SpinButton (*a));
976 a->set_value ((*p)->input_latency);
977 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
978 s->set_sensitive (_can_set_midi_latencies && enabled);
979 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
981 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
982 s = manage (new Gtk::SpinButton (*a));
983 a->set_value ((*p)->output_latency);
984 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
985 s->set_sensitive (_can_set_midi_latencies && enabled);
986 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
988 b = manage (new Button (_("Calibrate")));
989 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
990 b->set_sensitive (_can_set_midi_latencies && enabled);
991 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
998 EngineControl::backend_changed ()
1000 SignalBlocker blocker (*this, "backend_changed");
1001 string backend_name = backend_combo.get_active_text();
1002 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1004 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1005 /* eh? setting the backend failed... how ? */
1006 /* A: stale config contains a backend that does not exist in current build */
1010 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1012 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1015 setup_midi_tab_for_backend ();
1016 _midi_devices.clear();
1018 if (backend->requires_driver_selection()) {
1019 if (set_driver_popdown_strings ()) {
1023 /* this will change the device text which will cause a call to
1024 * device changed which will set up parameters
1029 update_midi_options ();
1031 connect_disconnect_button.hide();
1033 midi_option_changed();
1035 started_at_least_once = false;
1037 /* changing the backend implies stopping the engine
1038 * ARDOUR::AudioEngine() may or may not emit this signal
1039 * depending on previous engine state
1041 engine_stopped (); // set "active/inactive"
1043 if (!_have_control) {
1044 // set settings from backend that we do have control over
1045 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1048 if (_have_control && !ignore_changes) {
1049 // set driver & devices
1050 State state = get_matching_state (backend_combo.get_active_text());
1052 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1053 set_current_state (state);
1057 if (!ignore_changes) {
1058 maybe_display_saved_state ();
1063 EngineControl::update_midi_options ()
1065 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1066 vector<string> midi_options = backend->enumerate_midi_options();
1068 if (midi_options.size() == 1) {
1069 /* only contains the "none" option */
1070 midi_option_combo.set_sensitive (false);
1072 if (_have_control) {
1073 set_popdown_strings (midi_option_combo, midi_options);
1074 midi_option_combo.set_active_text (midi_options.front());
1075 midi_option_combo.set_sensitive (true);
1077 midi_option_combo.set_sensitive (false);
1083 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1085 if (ARDOUR::Profile->get_mixbus()) {
1089 uint32_t cnt = (uint32_t) sb->get_value();
1091 sb->set_text (_("all available channels"));
1094 snprintf (buf, sizeof (buf), "%d", cnt);
1100 // @return true if there are drivers available
1102 EngineControl::set_driver_popdown_strings ()
1104 DEBUG_ECONTROL ("set_driver_popdown_strings");
1105 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1106 vector<string> drivers = backend->enumerate_drivers();
1108 if (drivers.empty ()) {
1109 // This is an error...?
1113 string current_driver = backend->driver_name ();
1115 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1117 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1120 current_driver = drivers.front ();
1123 set_popdown_strings (driver_combo, drivers);
1125 string_compose ("driver_combo.set_active_text: %1", current_driver));
1126 driver_combo.set_active_text (current_driver);
1131 EngineControl::get_default_device(const string& current_device_name,
1132 const vector<string>& available_devices)
1134 // If the current device is available, use it as default
1135 if (std::find (available_devices.begin (),
1136 available_devices.end (),
1137 current_device_name) != available_devices.end ()) {
1139 return current_device_name;
1142 using namespace ARDOUR;
1144 string default_device_name =
1145 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1147 vector<string>::const_iterator i;
1149 // If there is a "Default" device available, use it
1150 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1151 if (*i == default_device_name) {
1156 string none_device_name =
1157 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1159 // Use the first device that isn't "None"
1160 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1161 if (*i != none_device_name) {
1166 // Use "None" if there are no other available
1167 return available_devices.front();
1170 // @return true if there are devices available
1172 EngineControl::set_device_popdown_strings ()
1174 DEBUG_ECONTROL ("set_device_popdown_strings");
1175 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1176 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1178 /* NOTE: Ardour currently does not display the "available" field of the
1181 * Doing so would require a different GUI widget than the combo
1182 * box/popdown that we currently use, since it has no way to list
1183 * items that are not selectable. Something more like a popup menu,
1184 * which could have unselectable items, would be appropriate.
1187 vector<string> available_devices;
1189 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1190 available_devices.push_back (i->name);
1193 if (available_devices.empty ()) {
1197 set_popdown_strings (device_combo, available_devices);
1199 std::string default_device =
1200 get_default_device(backend->device_name(), available_devices);
1203 string_compose ("set device_combo active text: %1", default_device));
1205 device_combo.set_active_text(default_device);
1209 // @return true if there are input devices available
1211 EngineControl::set_input_device_popdown_strings ()
1213 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1214 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1215 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1217 vector<string> available_devices;
1219 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1220 available_devices.push_back (i->name);
1223 if (available_devices.empty()) {
1227 set_popdown_strings (input_device_combo, available_devices);
1229 std::string default_device =
1230 get_default_device(backend->input_device_name(), available_devices);
1233 string_compose ("set input_device_combo active text: %1", default_device));
1234 input_device_combo.set_active_text(default_device);
1238 // @return true if there are output devices available
1240 EngineControl::set_output_device_popdown_strings ()
1242 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1243 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1244 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1246 vector<string> available_devices;
1248 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1249 available_devices.push_back (i->name);
1252 if (available_devices.empty()) {
1256 set_popdown_strings (output_device_combo, available_devices);
1258 std::string default_device =
1259 get_default_device(backend->output_device_name(), available_devices);
1262 string_compose ("set output_device_combo active text: %1", default_device));
1263 output_device_combo.set_active_text(default_device);
1268 EngineControl::list_devices ()
1270 DEBUG_ECONTROL ("list_devices");
1271 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1274 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1276 bool devices_available = false;
1278 if (backend->use_separate_input_and_output_devices ()) {
1279 bool input_devices_available = set_input_device_popdown_strings ();
1280 bool output_devices_available = set_output_device_popdown_strings ();
1281 devices_available = input_devices_available || output_devices_available;
1283 devices_available = set_device_popdown_strings ();
1286 if (devices_available) {
1289 device_combo.clear();
1290 input_device_combo.clear();
1291 output_device_combo.clear();
1293 update_sensitivity ();
1297 EngineControl::driver_changed ()
1299 SignalBlocker blocker (*this, "driver_changed");
1300 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1303 backend->set_driver (driver_combo.get_active_text());
1306 // TODO load LRU device(s) for backend + driver combo
1308 if (!ignore_changes) {
1309 maybe_display_saved_state ();
1314 EngineControl::get_sample_rates_for_all_devices ()
1316 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1317 ARDOUR::AudioEngine::instance ()->current_backend ();
1318 vector<float> all_rates;
1320 if (backend->use_separate_input_and_output_devices ()) {
1321 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1323 all_rates = backend->available_sample_rates (get_device_name ());
1329 EngineControl::get_default_sample_rates ()
1331 vector<float> rates;
1332 rates.push_back (8000.0f);
1333 rates.push_back (16000.0f);
1334 rates.push_back (32000.0f);
1335 rates.push_back (44100.0f);
1336 rates.push_back (48000.0f);
1337 rates.push_back (88200.0f);
1338 rates.push_back (96000.0f);
1339 rates.push_back (192000.0f);
1340 rates.push_back (384000.0f);
1345 EngineControl::set_samplerate_popdown_strings ()
1347 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1348 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1353 if (_have_control) {
1354 sr = get_sample_rates_for_all_devices ();
1356 sr = get_default_sample_rates ();
1359 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1360 s.push_back (rate_as_string (*x));
1361 if (*x == _desired_sample_rate) {
1366 set_popdown_strings (sample_rate_combo, s);
1369 if (desired.empty ()) {
1370 float new_active_sr = backend->default_sample_rate ();
1372 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1373 new_active_sr = sr.front ();
1376 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1378 sample_rate_combo.set_active_text (desired);
1382 update_sensitivity ();
1386 EngineControl::get_buffer_sizes_for_all_devices ()
1388 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1389 ARDOUR::AudioEngine::instance ()->current_backend ();
1390 vector<uint32_t> all_sizes;
1392 if (backend->use_separate_input_and_output_devices ()) {
1393 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1395 all_sizes = backend->available_buffer_sizes (get_device_name ());
1401 EngineControl::get_default_buffer_sizes ()
1403 vector<uint32_t> sizes;
1404 sizes.push_back (8);
1405 sizes.push_back (16);
1406 sizes.push_back (32);
1407 sizes.push_back (64);
1408 sizes.push_back (128);
1409 sizes.push_back (256);
1410 sizes.push_back (512);
1411 sizes.push_back (1024);
1412 sizes.push_back (2048);
1413 sizes.push_back (4096);
1414 sizes.push_back (8192);
1419 EngineControl::set_buffersize_popdown_strings ()
1421 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1422 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1423 vector<uint32_t> bs;
1426 if (_have_control) {
1427 bs = get_buffer_sizes_for_all_devices ();
1428 } else if (backend->can_change_buffer_size_when_running()) {
1429 bs = get_default_buffer_sizes ();
1432 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1433 s.push_back (bufsize_as_string (*x));
1436 uint32_t previous_size = 0;
1437 if (!buffer_size_combo.get_active_text().empty()) {
1438 previous_size = get_buffer_size ();
1441 set_popdown_strings (buffer_size_combo, s);
1445 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1446 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1449 buffer_size_combo.set_active_text(s.front());
1451 uint32_t period = backend->buffer_size();
1452 if (0 == period && backend->use_separate_input_and_output_devices()) {
1453 period = backend->default_buffer_size(get_input_device_name());
1455 if (0 == period && backend->use_separate_input_and_output_devices()) {
1456 period = backend->default_buffer_size(get_output_device_name());
1458 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1459 period = backend->default_buffer_size(get_device_name());
1462 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1464 show_buffer_duration ();
1466 update_sensitivity ();
1470 EngineControl::set_nperiods_popdown_strings ()
1472 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1473 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1474 vector<uint32_t> np;
1477 if (backend->can_set_period_size()) {
1478 np = backend->available_period_sizes (get_driver());
1481 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1482 s.push_back (nperiods_as_string (*x));
1485 set_popdown_strings (nperiods_combo, s);
1488 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX
1491 update_sensitivity ();
1495 EngineControl::device_changed ()
1497 SignalBlocker blocker (*this, "device_changed");
1498 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1501 string device_name_in;
1502 string device_name_out; // only used if backend support separate I/O devices
1504 if (backend->use_separate_input_and_output_devices()) {
1505 device_name_in = get_input_device_name ();
1506 device_name_out = get_output_device_name ();
1508 device_name_in = get_device_name ();
1511 /* we set the backend-device to query various device related intormation.
1512 * This has the side effect that backend->device_name() will match
1513 * the device_name and 'change_device' will never be true.
1514 * so work around this by setting...
1516 if (backend->use_separate_input_and_output_devices()) {
1517 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1518 queue_device_changed = true;
1521 if (device_name_in != backend->device_name()) {
1522 queue_device_changed = true;
1526 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1527 if (backend->use_separate_input_and_output_devices()) {
1528 backend->set_input_device_name (device_name_in);
1529 backend->set_output_device_name (device_name_out);
1531 backend->set_device_name(device_name_in);
1535 /* don't allow programmatic change to combos to cause a
1536 recursive call to this method.
1538 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1540 set_samplerate_popdown_strings ();
1541 set_buffersize_popdown_strings ();
1542 set_nperiods_popdown_strings ();
1544 /* TODO set min + max channel counts here */
1546 manage_control_app_sensitivity ();
1549 /* pick up any saved state for this device */
1551 if (!ignore_changes) {
1552 maybe_display_saved_state ();
1557 EngineControl::input_device_changed ()
1559 DEBUG_ECONTROL ("input_device_changed");
1564 EngineControl::output_device_changed ()
1566 DEBUG_ECONTROL ("output_device_changed");
1571 EngineControl::bufsize_as_string (uint32_t sz)
1573 /* Translators: "samples" is always plural here, so no
1574 need for plural+singular forms.
1577 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1582 EngineControl::nperiods_as_string (uint32_t np)
1585 snprintf (buf, sizeof (buf), "%u", np);
1591 EngineControl::sample_rate_changed ()
1593 DEBUG_ECONTROL ("sample_rate_changed");
1594 /* reset the strings for buffer size to show the correct msec value
1595 (reflecting the new sample rate).
1598 show_buffer_duration ();
1603 EngineControl::buffer_size_changed ()
1605 DEBUG_ECONTROL ("buffer_size_changed");
1606 show_buffer_duration ();
1610 EngineControl::nperiods_changed ()
1612 DEBUG_ECONTROL ("nperiods_changed");
1613 show_buffer_duration ();
1617 EngineControl::show_buffer_duration ()
1619 DEBUG_ECONTROL ("show_buffer_duration");
1620 /* buffer sizes - convert from just samples to samples + msecs for
1621 * the displayed string
1624 string bs_text = buffer_size_combo.get_active_text ();
1625 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1626 uint32_t rate = get_rate();
1628 /* Except for ALSA and Dummy backends, we don't know the number of periods
1629 * per cycle and settings.
1631 * jack1 vs jack2 have different default latencies since jack2 start
1632 * in async-mode unless --sync is given which adds an extra cycle
1633 * of latency. The value is not known if jackd is started externally..
1635 * So just display the period size, that's also what
1636 * ARDOUR_UI::update_sample_rate() does for the status bar.
1637 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1638 * but still, that's the buffer period, not [round-trip] latency)
1641 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1642 buffer_size_duration_label.set_text (buf);
1646 EngineControl::midi_option_changed ()
1648 DEBUG_ECONTROL ("midi_option_changed");
1649 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1652 backend->set_midi_option (get_midi_option());
1654 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1656 //_midi_devices.clear(); // TODO merge with state-saved settings..
1657 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1658 std::vector<MidiDeviceSettings> new_devices;
1660 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1661 MidiDeviceSettings mds = find_midi_device (i->name);
1662 if (i->available && !mds) {
1663 uint32_t input_latency = 0;
1664 uint32_t output_latency = 0;
1665 if (_can_set_midi_latencies) {
1666 input_latency = backend->systemic_midi_input_latency (i->name);
1667 output_latency = backend->systemic_midi_output_latency (i->name);
1669 bool enabled = backend->midi_device_enabled (i->name);
1670 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1671 new_devices.push_back (ptr);
1672 } else if (i->available) {
1673 new_devices.push_back (mds);
1676 _midi_devices = new_devices;
1678 if (_midi_devices.empty()) {
1679 midi_devices_button.set_sensitive (false);
1681 midi_devices_button.set_sensitive (true);
1686 EngineControl::parameter_changed ()
1690 EngineControl::State
1691 EngineControl::get_matching_state (const string& backend)
1693 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1694 if ((*i)->backend == backend) {
1701 EngineControl::State
1702 EngineControl::get_matching_state (
1703 const string& backend,
1704 const string& driver,
1705 const string& device)
1707 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1708 if ((*i)->backend == backend &&
1709 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1717 EngineControl::State
1718 EngineControl::get_matching_state (
1719 const string& backend,
1720 const string& driver,
1721 const string& input_device,
1722 const string& output_device)
1724 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1725 if ((*i)->backend == backend &&
1726 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1734 EngineControl::State
1735 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1737 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1740 if (backend->use_separate_input_and_output_devices ()) {
1741 return get_matching_state (backend_combo.get_active_text(),
1742 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1743 input_device_combo.get_active_text(),
1744 output_device_combo.get_active_text());
1746 return get_matching_state (backend_combo.get_active_text(),
1747 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1748 device_combo.get_active_text());
1752 return get_matching_state (backend_combo.get_active_text(),
1754 device_combo.get_active_text());
1757 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1758 const EngineControl::State& state2)
1760 if (state1->backend == state2->backend &&
1761 state1->driver == state2->driver &&
1762 state1->device == state2->device &&
1763 state1->input_device == state2->input_device &&
1764 state1->output_device == state2->output_device) {
1771 EngineControl::state_sort_cmp (const State &a, const State &b) {
1775 else if (b->active) {
1779 return a->lru < b->lru;
1783 EngineControl::State
1784 EngineControl::save_state ()
1788 if (!_have_control) {
1789 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1791 state->lru = time (NULL) ;
1794 state.reset(new StateStruct);
1795 state->backend = get_backend ();
1797 state.reset(new StateStruct);
1798 store_state (state);
1801 for (StateList::iterator i = states.begin(); i != states.end();) {
1802 if (equivalent_states (*i, state)) {
1803 i = states.erase(i);
1809 states.push_back (state);
1811 states.sort (state_sort_cmp);
1817 EngineControl::store_state (State state)
1819 state->backend = get_backend ();
1820 state->driver = get_driver ();
1821 state->device = get_device_name ();
1822 state->input_device = get_input_device_name ();
1823 state->output_device = get_output_device_name ();
1824 state->sample_rate = get_rate ();
1825 state->buffer_size = get_buffer_size ();
1826 state->n_periods = get_nperiods ();
1827 state->input_latency = get_input_latency ();
1828 state->output_latency = get_output_latency ();
1829 state->input_channels = get_input_channels ();
1830 state->output_channels = get_output_channels ();
1831 state->midi_option = get_midi_option ();
1832 state->midi_devices = _midi_devices;
1833 state->lru = time (NULL) ;
1837 EngineControl::maybe_display_saved_state ()
1839 if (!_have_control) {
1843 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1846 DEBUG_ECONTROL ("Restoring saved state");
1847 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1849 if (!_desired_sample_rate) {
1850 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1852 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1854 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1855 /* call this explicitly because we're ignoring changes to
1856 the controls at this point.
1858 show_buffer_duration ();
1859 input_latency.set_value (state->input_latency);
1860 output_latency.set_value (state->output_latency);
1862 if (!state->midi_option.empty()) {
1863 midi_option_combo.set_active_text (state->midi_option);
1864 _midi_devices = state->midi_devices;
1867 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1872 EngineControl::get_state ()
1874 LocaleGuard lg (X_("C"));
1876 XMLNode* root = new XMLNode ("AudioMIDISetup");
1879 if (!states.empty()) {
1880 XMLNode* state_nodes = new XMLNode ("EngineStates");
1882 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1884 XMLNode* node = new XMLNode ("State");
1886 node->add_property ("backend", (*i)->backend);
1887 node->add_property ("driver", (*i)->driver);
1888 node->add_property ("device", (*i)->device);
1889 node->add_property ("input-device", (*i)->input_device);
1890 node->add_property ("output-device", (*i)->output_device);
1891 node->add_property ("sample-rate", (*i)->sample_rate);
1892 node->add_property ("buffer-size", (*i)->buffer_size);
1893 node->add_property ("n-periods", (*i)->n_periods);
1894 node->add_property ("input-latency", (*i)->input_latency);
1895 node->add_property ("output-latency", (*i)->output_latency);
1896 node->add_property ("input-channels", (*i)->input_channels);
1897 node->add_property ("output-channels", (*i)->output_channels);
1898 node->add_property ("active", (*i)->active ? "yes" : "no");
1899 node->add_property ("midi-option", (*i)->midi_option);
1900 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1902 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1903 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1904 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1905 midi_device_stuff->add_property (X_("name"), (*p)->name);
1906 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1907 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1908 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1909 midi_devices->add_child_nocopy (*midi_device_stuff);
1911 node->add_child_nocopy (*midi_devices);
1913 state_nodes->add_child_nocopy (*node);
1916 root->add_child_nocopy (*state_nodes);
1923 EngineControl::set_default_state ()
1925 vector<string> backend_names;
1926 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1928 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1929 backend_names.push_back ((*b)->name);
1931 backend_combo.set_active_text (backend_names.front());
1933 // We could set default backends per platform etc here
1939 EngineControl::set_state (const XMLNode& root)
1941 XMLNodeList clist, cclist;
1942 XMLNodeConstIterator citer, cciter;
1944 XMLNode* grandchild;
1945 XMLProperty* prop = NULL;
1947 fprintf (stderr, "EngineControl::set_state\n");
1949 if (root.name() != "AudioMIDISetup") {
1953 clist = root.children();
1957 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1961 if (child->name() != "EngineStates") {
1965 cclist = child->children();
1967 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1968 State state (new StateStruct);
1970 grandchild = *cciter;
1972 if (grandchild->name() != "State") {
1976 if ((prop = grandchild->property ("backend")) == 0) {
1979 state->backend = prop->value ();
1981 if ((prop = grandchild->property ("driver")) == 0) {
1984 state->driver = prop->value ();
1986 if ((prop = grandchild->property ("device")) == 0) {
1989 state->device = prop->value ();
1991 if ((prop = grandchild->property ("input-device")) == 0) {
1994 state->input_device = prop->value ();
1996 if ((prop = grandchild->property ("output-device")) == 0) {
1999 state->output_device = prop->value ();
2001 if ((prop = grandchild->property ("sample-rate")) == 0) {
2004 state->sample_rate = atof (prop->value ());
2006 if ((prop = grandchild->property ("buffer-size")) == 0) {
2009 state->buffer_size = atoi (prop->value ());
2011 if ((prop = grandchild->property ("n-periods")) == 0) {
2012 // optional (new value in 4.5)
2013 state->n_periods = 0;
2015 state->n_periods = atoi (prop->value ());
2018 if ((prop = grandchild->property ("input-latency")) == 0) {
2021 state->input_latency = atoi (prop->value ());
2023 if ((prop = grandchild->property ("output-latency")) == 0) {
2026 state->output_latency = atoi (prop->value ());
2028 if ((prop = grandchild->property ("input-channels")) == 0) {
2031 state->input_channels = atoi (prop->value ());
2033 if ((prop = grandchild->property ("output-channels")) == 0) {
2036 state->output_channels = atoi (prop->value ());
2038 if ((prop = grandchild->property ("active")) == 0) {
2041 state->active = string_is_affirmative (prop->value ());
2043 if ((prop = grandchild->property ("midi-option")) == 0) {
2046 state->midi_option = prop->value ();
2048 state->midi_devices.clear();
2050 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2051 const XMLNodeList mnc = midinode->children();
2052 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2053 if ((*n)->property (X_("name")) == 0
2054 || (*n)->property (X_("enabled")) == 0
2055 || (*n)->property (X_("input-latency")) == 0
2056 || (*n)->property (X_("output-latency")) == 0
2061 MidiDeviceSettings ptr (new MidiDeviceSetting(
2062 (*n)->property (X_("name"))->value (),
2063 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2064 atoi ((*n)->property (X_("input-latency"))->value ()),
2065 atoi ((*n)->property (X_("output-latency"))->value ())
2067 state->midi_devices.push_back (ptr);
2071 if ((prop = grandchild->property ("lru"))) {
2072 state->lru = atoi (prop->value ());
2076 /* remove accumulated duplicates (due to bug in ealier version)
2077 * this can be removed again before release
2079 for (StateList::iterator i = states.begin(); i != states.end();) {
2080 if ((*i)->backend == state->backend &&
2081 (*i)->driver == state->driver &&
2082 (*i)->device == state->device) {
2083 i = states.erase(i);
2090 states.push_back (state);
2094 /* now see if there was an active state and switch the setup to it */
2096 // purge states of backend that are not available in this built
2097 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2098 vector<std::string> backend_names;
2100 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2101 backend_names.push_back((*i)->name);
2103 for (StateList::iterator i = states.begin(); i != states.end();) {
2104 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2105 i = states.erase(i);
2111 states.sort (state_sort_cmp);
2113 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2116 return set_current_state (*i);
2123 EngineControl::set_current_state (const State& state)
2125 DEBUG_ECONTROL ("set_current_state");
2127 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2129 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2130 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2131 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2132 // this shouldn't happen as the invalid backend names should have been
2133 // removed from the list of states.
2137 // now reflect the change in the backend in the GUI so backend_changed will
2138 // do the right thing
2139 backend_combo.set_active_text (state->backend);
2141 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2143 // we don't have control don't restore state
2148 if (!state->driver.empty ()) {
2149 if (!backend->requires_driver_selection ()) {
2150 DEBUG_ECONTROL ("Backend should require driver selection");
2151 // A backend has changed from having driver selection to not having
2152 // it or someone has been manually editing a config file and messed
2157 if (backend->set_driver (state->driver) != 0) {
2158 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2159 // Driver names for a backend have changed and the name in the
2160 // config file is now invalid or support for driver is no longer
2161 // included in the backend
2164 // no need to set the driver_combo as backend_changed will use
2165 // backend->driver_name to set the active driver
2168 if (!state->device.empty ()) {
2169 if (backend->set_device_name (state->device) != 0) {
2171 string_compose ("Unable to set device name %1", state->device));
2172 // device is no longer available on the system
2175 // no need to set active device as it will be picked up in
2176 // via backend_changed ()/set_device_popdown_strings
2179 // backend supports separate input/output devices
2180 if (backend->set_input_device_name (state->input_device) != 0) {
2181 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2182 state->input_device));
2183 // input device is no longer available on the system
2187 if (backend->set_output_device_name (state->output_device) != 0) {
2188 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2189 state->input_device));
2190 // output device is no longer available on the system
2193 // no need to set active devices as it will be picked up in via
2194 // backend_changed ()/set_*_device_popdown_strings
2199 // Now restore the state of the rest of the controls
2201 // We don't use a SignalBlocker as set_current_state is currently only
2202 // called from set_state before any signals are connected. If at some point
2203 // a more general named state mechanism is implemented and
2204 // set_current_state is called while signals are connected then a
2205 // SignalBlocker will need to be instantiated before setting these.
2207 device_combo.set_active_text (state->device);
2208 input_device_combo.set_active_text (state->input_device);
2209 output_device_combo.set_active_text (state->output_device);
2210 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2211 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2212 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2213 input_latency.set_value (state->input_latency);
2214 output_latency.set_value (state->output_latency);
2215 midi_option_combo.set_active_text (state->midi_option);
2220 EngineControl::push_state_to_backend (bool start)
2222 DEBUG_ECONTROL ("push_state_to_backend");
2223 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2224 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2230 /* figure out what is going to change */
2232 bool restart_required = false;
2233 bool was_running = ARDOUR::AudioEngine::instance()->running();
2234 bool change_driver = false;
2235 bool change_device = false;
2236 bool change_rate = false;
2237 bool change_bufsize = false;
2238 bool change_nperiods = false;
2239 bool change_latency = false;
2240 bool change_channels = false;
2241 bool change_midi = false;
2243 uint32_t ochan = get_output_channels ();
2244 uint32_t ichan = get_input_channels ();
2246 if (_have_control) {
2248 if (started_at_least_once) {
2250 /* we can control the backend */
2252 if (backend->requires_driver_selection()) {
2253 if (get_driver() != backend->driver_name()) {
2254 change_driver = true;
2258 if (backend->use_separate_input_and_output_devices()) {
2259 if (get_input_device_name() != backend->input_device_name()) {
2260 change_device = true;
2262 if (get_output_device_name() != backend->output_device_name()) {
2263 change_device = true;
2266 if (get_device_name() != backend->device_name()) {
2267 change_device = true;
2271 if (queue_device_changed) {
2272 change_device = true;
2275 if (get_rate() != backend->sample_rate()) {
2279 if (get_buffer_size() != backend->buffer_size()) {
2280 change_bufsize = true;
2283 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2284 && get_nperiods() != backend->period_size()) {
2285 change_nperiods = true;
2288 if (get_midi_option() != backend->midi_option()) {
2292 /* zero-requested channels means "all available" */
2295 ichan = backend->input_channels();
2299 ochan = backend->output_channels();
2302 if (ichan != backend->input_channels()) {
2303 change_channels = true;
2306 if (ochan != backend->output_channels()) {
2307 change_channels = true;
2310 if (get_input_latency() != backend->systemic_input_latency() ||
2311 get_output_latency() != backend->systemic_output_latency()) {
2312 change_latency = true;
2315 /* backend never started, so we have to force a group
2318 change_device = true;
2319 if (backend->requires_driver_selection()) {
2320 change_driver = true;
2323 change_bufsize = true;
2324 change_channels = true;
2325 change_latency = true;
2327 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2332 /* we have no control over the backend, meaning that we can
2333 * only possibly change sample rate and buffer size.
2337 if (get_rate() != backend->sample_rate()) {
2338 change_bufsize = true;
2341 if (get_buffer_size() != backend->buffer_size()) {
2342 change_bufsize = true;
2346 queue_device_changed = false;
2348 if (!_have_control) {
2350 /* We do not have control over the backend, so the best we can
2351 * do is try to change the sample rate and/or bufsize and get
2355 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2359 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2364 backend->set_sample_rate (get_rate());
2367 if (change_bufsize) {
2368 backend->set_buffer_size (get_buffer_size());
2372 if (ARDOUR::AudioEngine::instance()->start ()) {
2373 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2383 /* determine if we need to stop the backend before changing parameters */
2385 if (change_driver || change_device || change_channels || change_nperiods ||
2386 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2387 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2389 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2390 restart_required = true;
2392 restart_required = false;
2397 if (restart_required) {
2398 if (ARDOUR::AudioEngine::instance()->stop()) {
2404 if (change_driver && backend->set_driver (get_driver())) {
2405 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2408 if (backend->use_separate_input_and_output_devices()) {
2409 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2410 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2413 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2414 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2418 if (change_device && backend->set_device_name (get_device_name())) {
2419 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2423 if (change_rate && backend->set_sample_rate (get_rate())) {
2424 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2427 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2428 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2431 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2432 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2436 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2437 if (backend->set_input_channels (get_input_channels())) {
2438 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2441 if (backend->set_output_channels (get_output_channels())) {
2442 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2446 if (change_latency) {
2447 if (backend->set_systemic_input_latency (get_input_latency())) {
2448 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2451 if (backend->set_systemic_output_latency (get_output_latency())) {
2452 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2458 backend->set_midi_option (get_midi_option());
2462 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2463 if (_measure_midi) {
2464 if (*p == _measure_midi) {
2465 backend->set_midi_device_enabled ((*p)->name, true);
2467 backend->set_midi_device_enabled ((*p)->name, false);
2469 if (backend->can_change_systemic_latency_when_running ()) {
2470 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2471 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2475 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2476 if (backend->can_set_systemic_midi_latencies()) {
2477 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2478 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2483 if (start || (was_running && restart_required)) {
2484 if (ARDOUR::AudioEngine::instance()->start()) {
2495 EngineControl::post_push ()
2497 /* get a pointer to the current state object, creating one if
2501 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2504 state = save_state ();
2510 states.sort (state_sort_cmp);
2514 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2515 (*i)->active = false;
2518 /* mark this one active (to be used next time the dialog is
2522 state->active = true;
2524 if (_have_control) { // XXX
2525 manage_control_app_sensitivity ();
2528 /* schedule a redisplay of MIDI ports */
2529 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2534 EngineControl::get_rate () const
2536 float r = atof (sample_rate_combo.get_active_text ());
2537 /* the string may have been translated with an abbreviation for
2538 * thousands, so use a crude heuristic to fix this.
2548 EngineControl::get_buffer_size () const
2550 string txt = buffer_size_combo.get_active_text ();
2553 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2554 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2555 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2563 EngineControl::get_nperiods () const
2565 string txt = nperiods_combo.get_active_text ();
2566 return atoi (txt.c_str());
2570 EngineControl::get_midi_option () const
2572 return midi_option_combo.get_active_text();
2576 EngineControl::get_input_channels() const
2578 if (ARDOUR::Profile->get_mixbus()) {
2579 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2580 if (!backend) return 0;
2581 return backend->input_channels();
2583 return (uint32_t) input_channels_adjustment.get_value();
2587 EngineControl::get_output_channels() const
2589 if (ARDOUR::Profile->get_mixbus()) {
2590 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2591 if (!backend) return 0;
2592 return backend->input_channels();
2594 return (uint32_t) output_channels_adjustment.get_value();
2598 EngineControl::get_input_latency() const
2600 return (uint32_t) input_latency_adjustment.get_value();
2604 EngineControl::get_output_latency() const
2606 return (uint32_t) output_latency_adjustment.get_value();
2610 EngineControl::get_backend () const
2612 return backend_combo.get_active_text ();
2616 EngineControl::get_driver () const
2618 if (driver_combo.get_parent()) {
2619 return driver_combo.get_active_text ();
2626 EngineControl::get_device_name () const
2628 return device_combo.get_active_text ();
2632 EngineControl::get_input_device_name () const
2634 return input_device_combo.get_active_text ();
2638 EngineControl::get_output_device_name () const
2640 return output_device_combo.get_active_text ();
2644 EngineControl::control_app_button_clicked ()
2646 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2652 backend->launch_control_app ();
2656 EngineControl::start_stop_button_clicked ()
2658 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2664 if (ARDOUR::AudioEngine::instance()->running()) {
2665 ARDOUR::AudioEngine::instance()->stop ();
2672 EngineControl::update_devices_button_clicked ()
2674 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2680 if (backend->update_devices()) {
2681 device_list_changed ();
2686 EngineControl::manage_control_app_sensitivity ()
2688 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2694 string appname = backend->control_app_name();
2696 if (appname.empty()) {
2697 control_app_button.set_sensitive (false);
2699 control_app_button.set_sensitive (true);
2704 EngineControl::set_desired_sample_rate (uint32_t sr)
2706 _desired_sample_rate = sr;
2711 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2713 if (page_num == 0) {
2714 cancel_button->set_sensitive (true);
2715 _measure_midi.reset();
2716 update_sensitivity ();
2718 cancel_button->set_sensitive (false);
2719 ok_button->set_sensitive (false);
2722 if (page_num == midi_tab) {
2724 refresh_midi_display ();
2727 if (page_num == latency_tab) {
2730 if (ARDOUR::AudioEngine::instance()->running()) {
2735 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2737 /* save any existing latency values */
2739 uint32_t il = (uint32_t) input_latency.get_value ();
2740 uint32_t ol = (uint32_t) input_latency.get_value ();
2742 /* reset to zero so that our new test instance
2743 will be clean of any existing latency measures.
2745 NB. this should really be done by the backend
2746 when stated for latency measurement.
2749 input_latency.set_value (0);
2750 output_latency.set_value (0);
2752 push_state_to_backend (false);
2756 input_latency.set_value (il);
2757 output_latency.set_value (ol);
2760 // This should be done in push_state_to_backend()
2761 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2762 disable_latency_tab ();
2765 enable_latency_tab ();
2769 end_latency_detection ();
2770 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2775 /* latency measurement */
2778 EngineControl::check_audio_latency_measurement ()
2780 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2782 if (mtdm->resolve () < 0) {
2783 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2787 if (mtdm->get_peak () > 0.707f) {
2788 // get_peak() resets the peak-hold in the detector.
2789 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2790 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2794 if (mtdm->err () > 0.3) {
2800 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2802 if (sample_rate == 0) {
2803 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2804 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2808 int frames_total = mtdm->del();
2809 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2811 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2812 _("Detected roundtrip latency: "),
2813 frames_total, frames_total * 1000.0f/sample_rate,
2814 _("Systemic latency: "),
2815 extra, extra * 1000.0f/sample_rate);
2819 if (mtdm->err () > 0.2) {
2821 strcat (buf, _("(signal detection error)"));
2827 strcat (buf, _("(inverted - bad wiring)"));
2831 lm_results.set_markup (string_compose (results_markup, buf));
2834 have_lm_results = true;
2835 end_latency_detection ();
2836 lm_use_button.set_sensitive (true);
2844 EngineControl::check_midi_latency_measurement ()
2846 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2848 if (!mididm->have_signal () || mididm->latency () == 0) {
2849 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2854 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2856 if (sample_rate == 0) {
2857 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2858 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2862 ARDOUR::framecnt_t frames_total = mididm->latency();
2863 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2864 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2865 _("Detected roundtrip latency: "),
2866 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2867 _("Systemic latency: "),
2868 extra, extra * 1000.0f / sample_rate);
2872 if (!mididm->ok ()) {
2874 strcat (buf, _("(averaging)"));
2878 if (mididm->deviation () > 50.0) {
2880 strcat (buf, _("(too large jitter)"));
2882 } else if (mididm->deviation () > 10.0) {
2884 strcat (buf, _("(large jitter)"));
2888 have_lm_results = true;
2889 end_latency_detection ();
2890 lm_use_button.set_sensitive (true);
2891 lm_results.set_markup (string_compose (results_markup, buf));
2893 } else if (mididm->processed () > 400) {
2894 have_lm_results = false;
2895 end_latency_detection ();
2896 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2900 lm_results.set_markup (string_compose (results_markup, buf));
2906 EngineControl::start_latency_detection ()
2908 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2909 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2911 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2912 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2913 if (_measure_midi) {
2914 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2916 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2918 lm_measure_label.set_text (_("Cancel"));
2919 have_lm_results = false;
2920 lm_use_button.set_sensitive (false);
2921 lm_input_channel_combo.set_sensitive (false);
2922 lm_output_channel_combo.set_sensitive (false);
2928 EngineControl::end_latency_detection ()
2930 latency_timeout.disconnect ();
2931 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2932 lm_measure_label.set_text (_("Measure"));
2933 if (!have_lm_results) {
2934 lm_use_button.set_sensitive (false);
2936 lm_input_channel_combo.set_sensitive (true);
2937 lm_output_channel_combo.set_sensitive (true);
2942 EngineControl::latency_button_clicked ()
2945 start_latency_detection ();
2947 end_latency_detection ();
2952 EngineControl::latency_back_button_clicked ()
2954 ARDOUR::AudioEngine::instance()->stop(true);
2955 notebook.set_current_page(0);
2959 EngineControl::use_latency_button_clicked ()
2961 if (_measure_midi) {
2962 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2966 ARDOUR::framecnt_t frames_total = mididm->latency();
2967 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2968 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2969 _measure_midi->input_latency = one_way;
2970 _measure_midi->output_latency = one_way;
2971 notebook.set_current_page (midi_tab);
2973 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2979 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2980 one_way = std::max (0., one_way);
2982 input_latency_adjustment.set_value (one_way);
2983 output_latency_adjustment.set_value (one_way);
2985 /* back to settings page */
2986 notebook.set_current_page (0);
2991 EngineControl::on_delete_event (GdkEventAny* ev)
2993 if (notebook.get_current_page() == 2) {
2994 /* currently on latency tab - be sure to clean up */
2995 end_latency_detection ();
2997 return ArdourDialog::on_delete_event (ev);
3001 EngineControl::engine_running ()
3003 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3006 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3007 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3009 if (backend->can_set_period_size ()) {
3010 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3013 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3014 connect_disconnect_button.show();
3016 started_at_least_once = true;
3017 if (_have_control) {
3018 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3020 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3022 update_sensitivity();
3026 EngineControl::engine_stopped ()
3028 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3031 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3032 connect_disconnect_button.show();
3034 if (_have_control) {
3035 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3037 engine_status.set_markup(X_(""));
3040 update_sensitivity();
3044 EngineControl::device_list_changed ()
3046 if (ignore_device_changes) {
3049 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3051 midi_option_changed();
3055 EngineControl::connect_disconnect_click()
3057 if (ARDOUR::AudioEngine::instance()->running()) {
3065 EngineControl::calibrate_audio_latency ()
3067 _measure_midi.reset ();
3068 have_lm_results = false;
3069 lm_use_button.set_sensitive (false);
3070 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3071 notebook.set_current_page (latency_tab);
3075 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3078 have_lm_results = false;
3079 lm_use_button.set_sensitive (false);
3080 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3081 notebook.set_current_page (latency_tab);
3085 EngineControl::configure_midi_devices ()
3087 notebook.set_current_page (midi_tab);