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.
26 #include <boost/scoped_ptr.hpp>
28 #include <gtkmm/messagedialog.h>
30 #include "pbd/error.h"
31 #include "pbd/xml++.h"
32 #include "pbd/unwind.h"
33 #include "pbd/failed_constructor.h"
35 #include <gtkmm/alignment.h>
36 #include <gtkmm/stock.h>
37 #include <gtkmm/notebook.h>
38 #include <gtkmm2ext/utils.h>
40 #include "ardour/audio_backend.h"
41 #include "ardour/audioengine.h"
42 #include "ardour/mtdm.h"
43 #include "ardour/mididm.h"
44 #include "ardour/rc_configuration.h"
45 #include "ardour/types.h"
46 #include "ardour/profile.h"
48 #include "pbd/convert.h"
49 #include "pbd/error.h"
53 #include "ardour_ui.h"
54 #include "engine_dialog.h"
55 #include "gui_thread.h"
61 using namespace Gtkmm2ext;
64 using namespace ARDOUR_UI_UTILS;
66 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
68 static const unsigned int midi_tab = 2;
69 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
71 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
73 EngineControl::EngineControl ()
74 : ArdourDialog (_("Audio/MIDI Setup"))
77 , input_latency_adjustment (0, 0, 99999, 1)
78 , input_latency (input_latency_adjustment)
79 , output_latency_adjustment (0, 0, 99999, 1)
80 , output_latency (output_latency_adjustment)
81 , input_channels_adjustment (0, 0, 256, 1)
82 , input_channels (input_channels_adjustment)
83 , output_channels_adjustment (0, 0, 256, 1)
84 , output_channels (output_channels_adjustment)
85 , ports_adjustment (128, 8, 1024, 1, 16)
86 , ports_spinner (ports_adjustment)
87 , control_app_button (_("Device Control Panel"))
88 , midi_devices_button (_("Midi Device Setup"))
89 , start_stop_button (_("Stop"))
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 , _desired_sample_rate (0)
100 , started_at_least_once (false)
101 , queue_device_changed (false)
104 using namespace Notebook_Helpers;
105 vector<string> backend_names;
107 AttachOptions xopt = AttachOptions (FILL|EXPAND);
110 set_name (X_("AudioMIDISetup"));
112 /* the backend combo is the one thing that is ALWAYS visible */
114 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
116 if (backends.empty()) {
117 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));
119 throw failed_constructor ();
122 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
123 backend_names.push_back ((*b)->name);
126 set_popdown_strings (backend_combo, backend_names);
128 /* setup basic packing characteristics for the table used on the main
129 * tab of the notebook
132 basic_packer.set_spacings (6);
133 basic_packer.set_border_width (12);
134 basic_packer.set_homogeneous (false);
138 basic_hbox.pack_start (basic_packer, false, false);
140 /* latency measurement tab */
142 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
145 lm_table.set_row_spacings (12);
146 lm_table.set_col_spacings (6);
147 lm_table.set_homogeneous (false);
149 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
152 lm_preamble.set_width_chars (60);
153 lm_preamble.set_line_wrap (true);
154 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
156 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
159 Gtk::Label* preamble;
160 preamble = manage (new Label);
161 preamble->set_width_chars (60);
162 preamble->set_line_wrap (true);
163 preamble->set_markup (_("Select two channels below and connect them using a cable."));
165 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
168 label = manage (new Label (_("Output channel")));
169 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
171 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
172 misc_align->add (lm_output_channel_combo);
173 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
176 label = manage (new Label (_("Input channel")));
177 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
179 misc_align = manage (new Alignment (0.0, 0.5));
180 misc_align->add (lm_input_channel_combo);
181 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
184 lm_measure_label.set_padding (10, 10);
185 lm_measure_button.add (lm_measure_label);
186 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
187 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
188 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
190 lm_use_button.set_sensitive (false);
192 /* Increase the default spacing around the labels of these three
198 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
199 l->set_padding (10, 10);
202 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
203 l->set_padding (10, 10);
206 preamble = manage (new Label);
207 preamble->set_width_chars (60);
208 preamble->set_line_wrap (true);
209 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
210 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
213 preamble = manage (new Label);
214 preamble->set_width_chars (60);
215 preamble->set_line_wrap (true);
216 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
217 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
219 ++row; // skip a row in the table
220 ++row; // skip a row in the table
222 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
224 ++row; // skip a row in the table
225 ++row; // skip a row in the table
227 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
228 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
229 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
231 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
233 lm_vbox.set_border_width (12);
234 lm_vbox.pack_start (lm_table, false, false);
236 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
240 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
241 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
242 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
243 notebook.set_border_width (12);
245 notebook.set_show_tabs (false);
246 notebook.show_all ();
248 notebook.set_name ("SettingsNotebook");
250 /* packup the notebook */
252 get_vbox()->set_border_width (12);
253 get_vbox()->pack_start (notebook);
255 /* need a special function to print "all available channels" when the
256 * channel counts hit zero.
259 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
260 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
262 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
263 midi_devices_button.set_sensitive (false);
264 midi_devices_button.set_name ("generic button");
265 midi_devices_button.set_can_focus(true);
267 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
268 control_app_button.set_name ("generic button");
269 control_app_button.set_can_focus(true);
270 manage_control_app_sensitivity ();
272 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
273 start_stop_button.set_sensitive (false);
274 start_stop_button.set_name ("generic button");
275 start_stop_button.set_can_focus(true);
277 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
278 apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
279 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
281 /* Pick up any existing audio setup configuration, if appropriate */
283 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
285 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
286 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
287 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
288 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
291 if (!set_state (*audio_setup)) {
292 set_default_state ();
295 set_default_state ();
298 connect_changed_signals ();
300 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
302 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
303 connect_disconnect_button.set_no_show_all();
308 EngineControl::connect_changed_signals ()
310 backend_combo_connection = backend_combo.signal_changed ().connect (
311 sigc::mem_fun (*this, &EngineControl::backend_changed));
312 driver_combo_connection = driver_combo.signal_changed ().connect (
313 sigc::mem_fun (*this, &EngineControl::driver_changed));
314 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
315 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
316 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
317 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
318 device_combo_connection = device_combo.signal_changed ().connect (
319 sigc::mem_fun (*this, &EngineControl::device_changed));
320 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
321 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
323 input_device_combo_connection = input_device_combo.signal_changed ().connect (
324 sigc::mem_fun (*this, &EngineControl::input_device_changed));
325 output_device_combo_connection = output_device_combo.signal_changed ().connect (
326 sigc::mem_fun (*this, &EngineControl::output_device_changed));
328 input_latency_connection = input_latency.signal_changed ().connect (
329 sigc::mem_fun (*this, &EngineControl::parameter_changed));
330 output_latency_connection = output_latency.signal_changed ().connect (
331 sigc::mem_fun (*this, &EngineControl::parameter_changed));
332 input_channels_connection = input_channels.signal_changed ().connect (
333 sigc::mem_fun (*this, &EngineControl::parameter_changed));
334 output_channels_connection = output_channels.signal_changed ().connect (
335 sigc::mem_fun (*this, &EngineControl::parameter_changed));
339 EngineControl::block_changed_signals ()
341 if (block_signals++ == 0) {
342 DEBUG_ECONTROL ("Blocking changed signals");
343 backend_combo_connection.block ();
344 driver_combo_connection.block ();
345 sample_rate_combo_connection.block ();
346 buffer_size_combo_connection.block ();
347 device_combo_connection.block ();
348 input_device_combo_connection.block ();
349 output_device_combo_connection.block ();
350 midi_option_combo_connection.block ();
351 input_latency_connection.block ();
352 output_latency_connection.block ();
353 input_channels_connection.block ();
354 output_channels_connection.block ();
359 EngineControl::unblock_changed_signals ()
361 if (--block_signals == 0) {
362 DEBUG_ECONTROL ("Unblocking changed signals");
363 backend_combo_connection.unblock ();
364 driver_combo_connection.unblock ();
365 sample_rate_combo_connection.unblock ();
366 buffer_size_combo_connection.unblock ();
367 device_combo_connection.unblock ();
368 input_device_combo_connection.unblock ();
369 output_device_combo_connection.unblock ();
370 midi_option_combo_connection.unblock ();
371 input_latency_connection.unblock ();
372 output_latency_connection.unblock ();
373 input_channels_connection.unblock ();
374 output_channels_connection.unblock ();
378 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
379 const std::string& reason)
380 : ec (engine_control)
383 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
384 ec.block_changed_signals ();
387 EngineControl::SignalBlocker::~SignalBlocker ()
389 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
390 ec.unblock_changed_signals ();
394 EngineControl::on_show ()
396 ArdourDialog::on_show ();
397 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
398 // re-check _have_control (jackd running) see #6041
402 ok_button->grab_focus();
406 EngineControl::on_response (int response_id)
408 ArdourDialog::on_response (response_id);
410 switch (response_id) {
412 push_state_to_backend (true);
415 #ifdef PLATFORM_WINDOWS
416 // For some reason we don't understand, 'hide()'
417 // needs to get called first in Windows
420 // But if there's no session open, this can produce
421 // a long gap when nothing appears to be happening.
422 // Let's show the splash image while we're waiting.
423 if ( !ARDOUR_COMMAND_LINE::no_splash ) {
424 if ( ARDOUR_UI::instance() ) {
425 if ( !ARDOUR_UI::instance()->session_loaded ) {
426 ARDOUR_UI::instance()->show_splash();
430 push_state_to_backend (true);
433 push_state_to_backend (true);
437 case RESPONSE_DELETE_EVENT:
440 ev.type = GDK_BUTTON_PRESS;
442 on_delete_event ((GdkEventAny*) &ev);
451 EngineControl::build_notebook ()
454 AttachOptions xopt = AttachOptions (FILL|EXPAND);
456 /* clear the table */
458 Gtkmm2ext::container_clear (basic_vbox);
459 Gtkmm2ext::container_clear (basic_packer);
461 if (control_app_button.get_parent()) {
462 control_app_button.get_parent()->remove (control_app_button);
465 label = manage (left_aligned_label (_("Audio System:")));
466 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
467 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
469 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
470 engine_status.show();
472 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
474 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
475 lm_button_audio.set_name ("generic button");
476 lm_button_audio.set_can_focus(true);
479 build_full_control_notebook ();
481 build_no_control_notebook ();
484 basic_vbox.pack_start (basic_hbox, false, false);
487 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
488 basic_vbox.show_all ();
493 EngineControl::build_full_control_notebook ()
495 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
498 using namespace Notebook_Helpers;
500 vector<string> strings;
501 AttachOptions xopt = AttachOptions (FILL|EXPAND);
502 int row = 1; // row zero == backend combo
504 /* start packing it up */
506 if (backend->requires_driver_selection()) {
507 label = manage (left_aligned_label (_("Driver:")));
508 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
509 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
513 if (backend->use_separate_input_and_output_devices()) {
514 label = manage (left_aligned_label (_("Input Device:")));
515 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
516 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
518 label = manage (left_aligned_label (_("Output Device:")));
519 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
520 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
522 // reset so it isn't used in state comparisons
523 device_combo.set_active_text ("");
525 label = manage (left_aligned_label (_("Device:")));
526 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
527 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
529 // reset these so they don't get used in state comparisons
530 input_device_combo.set_active_text ("");
531 output_device_combo.set_active_text ("");
534 label = manage (left_aligned_label (_("Sample rate:")));
535 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
536 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
540 label = manage (left_aligned_label (_("Buffer size:")));
541 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
542 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
543 buffer_size_duration_label.set_alignment (0.0); /* left-align */
544 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
546 /* button spans 2 rows */
548 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
551 input_channels.set_name ("InputChannels");
552 input_channels.set_flags (Gtk::CAN_FOCUS);
553 input_channels.set_digits (0);
554 input_channels.set_wrap (false);
555 output_channels.set_editable (true);
557 if (!ARDOUR::Profile->get_mixbus()) {
558 label = manage (left_aligned_label (_("Input Channels:")));
559 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
560 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
564 output_channels.set_name ("OutputChannels");
565 output_channels.set_flags (Gtk::CAN_FOCUS);
566 output_channels.set_digits (0);
567 output_channels.set_wrap (false);
568 output_channels.set_editable (true);
570 if (!ARDOUR::Profile->get_mixbus()) {
571 label = manage (left_aligned_label (_("Output Channels:")));
572 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
573 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
577 input_latency.set_name ("InputLatency");
578 input_latency.set_flags (Gtk::CAN_FOCUS);
579 input_latency.set_digits (0);
580 input_latency.set_wrap (false);
581 input_latency.set_editable (true);
583 label = manage (left_aligned_label (_("Hardware input latency:")));
584 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
585 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
586 label = manage (left_aligned_label (_("samples")));
587 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
590 output_latency.set_name ("OutputLatency");
591 output_latency.set_flags (Gtk::CAN_FOCUS);
592 output_latency.set_digits (0);
593 output_latency.set_wrap (false);
594 output_latency.set_editable (true);
596 label = manage (left_aligned_label (_("Hardware output latency:")));
597 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
598 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
599 label = manage (left_aligned_label (_("samples")));
600 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
602 /* button spans 2 rows */
604 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
607 label = manage (left_aligned_label (_("MIDI System:")));
608 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
609 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
610 #if ! defined __APPLE__ && ! defined PLATFORM_WINDOWS // => linux, YAY
611 /* Currently the only backend with dedicated Midi setup is ALSA.
612 * lot of people complain that this is greyed out
613 * "I can't use MIDI, the setup is greyed out"
615 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
621 EngineControl::build_no_control_notebook ()
623 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
626 using namespace Notebook_Helpers;
628 vector<string> strings;
629 AttachOptions xopt = AttachOptions (FILL|EXPAND);
630 int row = 1; // row zero == backend combo
631 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
633 label = manage (new Label);
634 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
635 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
638 if (backend->can_change_sample_rate_when_running()) {
639 label = manage (left_aligned_label (_("Sample rate:")));
640 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
641 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
645 if (backend->can_change_buffer_size_when_running()) {
646 label = manage (left_aligned_label (_("Buffer size:")));
647 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
648 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
649 buffer_size_duration_label.set_alignment (0.0); /* left-align */
650 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
654 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
658 EngineControl::~EngineControl ()
660 ignore_changes = true;
664 EngineControl::disable_latency_tab ()
666 vector<string> empty;
667 set_popdown_strings (lm_output_channel_combo, empty);
668 set_popdown_strings (lm_input_channel_combo, empty);
669 lm_measure_button.set_sensitive (false);
670 lm_use_button.set_sensitive (false);
674 EngineControl::enable_latency_tab ()
676 vector<string> outputs;
677 vector<string> inputs;
679 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
680 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
681 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
683 if (!ARDOUR::AudioEngine::instance()->running()) {
684 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
685 notebook.set_current_page (0);
689 else if (inputs.empty() || outputs.empty()) {
690 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
691 notebook.set_current_page (0);
696 lm_back_button_signal.disconnect();
698 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
701 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
705 set_popdown_strings (lm_output_channel_combo, outputs);
706 lm_output_channel_combo.set_active_text (outputs.front());
707 lm_output_channel_combo.set_sensitive (true);
709 set_popdown_strings (lm_input_channel_combo, inputs);
710 lm_input_channel_combo.set_active_text (inputs.front());
711 lm_input_channel_combo.set_sensitive (true);
713 lm_measure_button.set_sensitive (true);
717 EngineControl::setup_midi_tab_for_backend ()
719 string backend = backend_combo.get_active_text ();
721 Gtkmm2ext::container_clear (midi_vbox);
723 midi_vbox.set_border_width (12);
724 midi_device_table.set_border_width (12);
726 if (backend == "JACK") {
727 setup_midi_tab_for_jack ();
730 midi_vbox.pack_start (midi_device_table, true, true);
731 midi_vbox.pack_start (midi_back_button, false, false);
732 midi_vbox.show_all ();
736 EngineControl::update_sensitivity ()
738 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
740 ok_button->set_sensitive (false);
741 apply_button->set_sensitive (false);
742 start_stop_button.set_sensitive (false);
747 size_t devices_available = 0;
749 if (backend->use_separate_input_and_output_devices ()) {
750 devices_available += get_popdown_string_count (input_device_combo);
751 devices_available += get_popdown_string_count (output_device_combo);
753 devices_available += get_popdown_string_count (device_combo);
756 if (devices_available == 0) {
758 input_latency.set_sensitive (false);
759 output_latency.set_sensitive (false);
760 input_channels.set_sensitive (false);
761 output_channels.set_sensitive (false);
763 input_latency.set_sensitive (true);
764 output_latency.set_sensitive (true);
765 input_channels.set_sensitive (true);
766 output_channels.set_sensitive (true);
769 if (get_popdown_string_count (buffer_size_combo) > 0) {
770 if (!ARDOUR::AudioEngine::instance()->running()) {
771 buffer_size_combo.set_sensitive (valid);
772 } else if (backend->can_change_sample_rate_when_running()) {
773 buffer_size_combo.set_sensitive (valid || !_have_control);
777 * Currently there is no way to manually stop the
778 * engine in order to re-configure it.
779 * This needs to remain sensitive for now.
781 * (it's also handy to implicily
782 * re-start the engine)
784 buffer_size_combo.set_sensitive (true);
786 buffer_size_combo.set_sensitive (false);
790 buffer_size_combo.set_sensitive (false);
794 if (get_popdown_string_count (sample_rate_combo) > 0) {
795 if (!ARDOUR::AudioEngine::instance()->running()) {
796 sample_rate_combo.set_sensitive (true);
798 sample_rate_combo.set_sensitive (false);
801 sample_rate_combo.set_sensitive (false);
806 start_stop_button.set_sensitive(true);
807 start_stop_button.show();
808 if (ARDOUR::AudioEngine::instance()->running()) {
809 start_stop_button.set_text("Stop");
811 start_stop_button.set_text("Start");
814 start_stop_button.set_sensitive(false);
815 start_stop_button.hide();
818 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
819 input_device_combo.set_sensitive (false);
820 output_device_combo.set_sensitive (false);
821 device_combo.set_sensitive (false);
822 driver_combo.set_sensitive (false);
824 input_device_combo.set_sensitive (true);
825 output_device_combo.set_sensitive (true);
826 device_combo.set_sensitive (true);
827 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
828 driver_combo.set_sensitive (true);
830 driver_combo.set_sensitive (false);
834 if (valid || !_have_control) {
835 ok_button->set_sensitive (true);
836 apply_button->set_sensitive (true);
838 ok_button->set_sensitive (false);
839 apply_button->set_sensitive (false);
844 EngineControl::setup_midi_tab_for_jack ()
849 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
851 device->input_latency = a->get_value();
853 device->output_latency = a->get_value();
858 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
859 b->set_active (!b->get_active());
860 device->enabled = b->get_active();
861 refresh_midi_display(device->name);
865 EngineControl::refresh_midi_display (std::string focus)
867 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
871 AttachOptions xopt = AttachOptions (FILL|EXPAND);
874 Gtkmm2ext::container_clear (midi_device_table);
876 midi_device_table.set_spacings (6);
878 l = manage (new Label);
879 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
880 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
881 l->set_alignment (0.5, 0.5);
885 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
886 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
887 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
888 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
890 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
891 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
892 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
893 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
896 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
901 bool enabled = (*p)->enabled;
903 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
904 m->set_name ("midi device");
905 m->set_can_focus (Gtk::CAN_FOCUS);
906 m->add_events (Gdk::BUTTON_RELEASE_MASK);
907 m->set_active (enabled);
908 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
909 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
910 if ((*p)->name == focus) {
914 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
915 s = manage (new Gtk::SpinButton (*a));
916 a->set_value ((*p)->input_latency);
917 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
918 s->set_sensitive (_can_set_midi_latencies && enabled);
919 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
921 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
922 s = manage (new Gtk::SpinButton (*a));
923 a->set_value ((*p)->output_latency);
924 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
925 s->set_sensitive (_can_set_midi_latencies && enabled);
926 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
928 b = manage (new Button (_("Calibrate")));
929 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
930 b->set_sensitive (_can_set_midi_latencies && enabled);
931 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
938 EngineControl::backend_changed ()
940 SignalBlocker blocker (*this, "backend_changed");
941 string backend_name = backend_combo.get_active_text();
942 boost::shared_ptr<ARDOUR::AudioBackend> backend;
944 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (PROGRAM_NAME), ""))) {
945 /* eh? setting the backend failed... how ? */
946 /* A: stale config contains a backend that does not exist in current build */
950 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
952 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
955 setup_midi_tab_for_backend ();
956 _midi_devices.clear();
958 if (backend->requires_driver_selection()) {
959 if (set_driver_popdown_strings ()) {
963 /* this will change the device text which will cause a call to
964 * device changed which will set up parameters
969 update_midi_options ();
971 connect_disconnect_button.hide();
973 midi_option_changed();
975 started_at_least_once = false;
977 /* changing the backend implies stopping the engine
978 * ARDOUR::AudioEngine() may or may not emit this signal
979 * depending on previous engine state
981 engine_stopped (); // set "active/inactive"
983 if (!ignore_changes) {
984 maybe_display_saved_state ();
989 EngineControl::update_midi_options ()
991 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
992 vector<string> midi_options = backend->enumerate_midi_options();
994 if (midi_options.size() == 1) {
995 /* only contains the "none" option */
996 midi_option_combo.set_sensitive (false);
999 set_popdown_strings (midi_option_combo, midi_options);
1000 midi_option_combo.set_active_text (midi_options.front());
1001 midi_option_combo.set_sensitive (true);
1003 midi_option_combo.set_sensitive (false);
1009 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1011 if (ARDOUR::Profile->get_mixbus()) {
1015 uint32_t cnt = (uint32_t) sb->get_value();
1017 sb->set_text (_("all available channels"));
1020 snprintf (buf, sizeof (buf), "%d", cnt);
1026 // @return true if there are drivers available
1028 EngineControl::set_driver_popdown_strings ()
1030 DEBUG_ECONTROL ("set_driver_popdown_strings");
1031 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1032 vector<string> drivers = backend->enumerate_drivers();
1034 if (drivers.empty ()) {
1035 // This is an error...?
1039 string current_driver = backend->driver_name ();
1041 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1043 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1046 current_driver = drivers.front ();
1049 set_popdown_strings (driver_combo, drivers);
1051 string_compose ("driver_combo.set_active_text: %1", current_driver));
1052 driver_combo.set_active_text (current_driver);
1056 // @return true if there are devices available
1058 EngineControl::set_device_popdown_strings ()
1060 DEBUG_ECONTROL ("set_device_popdown_strings");
1061 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1062 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1064 /* NOTE: Ardour currently does not display the "available" field of the
1067 * Doing so would require a different GUI widget than the combo
1068 * box/popdown that we currently use, since it has no way to list
1069 * items that are not selectable. Something more like a popup menu,
1070 * which could have unselectable items, would be appropriate.
1073 vector<string> available_devices;
1075 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1076 available_devices.push_back (i->name);
1079 if (available_devices.empty ()) {
1083 string current_device = backend->device_name ();
1085 // Make sure that backend->device_name () is a valid
1086 // device, the backend may not return a valid device if it hasn't
1088 if (std::find (available_devices.begin (),
1089 available_devices.end (),
1090 current_device) == available_devices.end ()) {
1092 current_device = available_devices.front ();
1095 set_popdown_strings (device_combo, available_devices);
1097 string_compose ("set device_combo active text: %1", current_device));
1099 device_combo.set_active_text (current_device);
1103 // @return true if there are input devices available
1105 EngineControl::set_input_device_popdown_strings ()
1107 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1108 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1109 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1111 vector<string> available_devices;
1113 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1114 available_devices.push_back (i->name);
1117 if (available_devices.empty()) {
1121 string current_device = backend->input_device_name ();
1123 // Make sure that backend->input_device_name () is a valid
1124 // device, the backend may not return a valid device if it hasn't
1126 if (std::find (available_devices.begin (),
1127 available_devices.end (),
1128 current_device) == available_devices.end ()) {
1130 current_device = available_devices.front ();
1133 set_popdown_strings (input_device_combo, available_devices);
1136 string_compose ("set input_device_combo active text: %1", current_device));
1137 input_device_combo.set_active_text (current_device);
1141 // @return true if there are output devices available
1143 EngineControl::set_output_device_popdown_strings ()
1145 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1146 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1147 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1149 vector<string> available_devices;
1151 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1152 available_devices.push_back (i->name);
1155 if (available_devices.empty()) {
1159 string current_device = backend->output_device_name ();
1161 // Make sure that backend->output_device_name () is a valid
1162 // device, the backend may not return a valid device if it hasn't
1164 if (std::find (available_devices.begin (),
1165 available_devices.end (),
1166 current_device) == available_devices.end ()) {
1168 current_device = available_devices.front ();
1171 set_popdown_strings (output_device_combo, available_devices);
1174 string_compose ("set output_device_combo active text: %1", current_device));
1175 output_device_combo.set_active_text (current_device);
1180 EngineControl::list_devices ()
1182 DEBUG_ECONTROL ("list_devices");
1183 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1186 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1188 bool devices_available = false;
1190 if (backend->use_separate_input_and_output_devices ()) {
1191 bool input_devices_available = set_input_device_popdown_strings ();
1192 bool output_devices_available = set_output_device_popdown_strings ();
1193 devices_available = input_devices_available || output_devices_available;
1195 devices_available = set_device_popdown_strings ();
1198 if (devices_available) {
1201 device_combo.clear();
1202 input_device_combo.clear();
1203 output_device_combo.clear();
1205 update_sensitivity ();
1209 EngineControl::driver_changed ()
1211 SignalBlocker blocker (*this, "driver_changed");
1212 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1215 backend->set_driver (driver_combo.get_active_text());
1218 if (!ignore_changes) {
1219 maybe_display_saved_state ();
1224 EngineControl::get_sample_rates_for_all_devices ()
1226 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1227 ARDOUR::AudioEngine::instance ()->current_backend ();
1228 vector<float> all_rates;
1230 if (backend->use_separate_input_and_output_devices ()) {
1231 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1233 all_rates = backend->available_sample_rates (get_device_name ());
1239 EngineControl::get_default_sample_rates ()
1241 vector<float> rates;
1242 rates.push_back (8000.0f);
1243 rates.push_back (16000.0f);
1244 rates.push_back (32000.0f);
1245 rates.push_back (44100.0f);
1246 rates.push_back (48000.0f);
1247 rates.push_back (88200.0f);
1248 rates.push_back (96000.0f);
1249 rates.push_back (192000.0f);
1250 rates.push_back (384000.0f);
1255 EngineControl::set_samplerate_popdown_strings ()
1257 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1258 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1263 if (_have_control) {
1264 sr = get_sample_rates_for_all_devices ();
1266 sr = get_default_sample_rates ();
1269 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1270 s.push_back (rate_as_string (*x));
1271 if (*x == _desired_sample_rate) {
1276 set_popdown_strings (sample_rate_combo, s);
1279 if (desired.empty ()) {
1280 float new_active_sr = backend->default_sample_rate ();
1282 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1283 new_active_sr = sr.front ();
1286 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1288 sample_rate_combo.set_active_text (desired);
1292 update_sensitivity ();
1296 EngineControl::get_buffer_sizes_for_all_devices ()
1298 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1299 ARDOUR::AudioEngine::instance ()->current_backend ();
1300 vector<uint32_t> all_sizes;
1302 if (backend->use_separate_input_and_output_devices ()) {
1303 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1305 all_sizes = backend->available_buffer_sizes (get_device_name ());
1311 EngineControl::get_default_buffer_sizes ()
1313 vector<uint32_t> sizes;
1314 sizes.push_back (8);
1315 sizes.push_back (16);
1316 sizes.push_back (32);
1317 sizes.push_back (64);
1318 sizes.push_back (128);
1319 sizes.push_back (256);
1320 sizes.push_back (512);
1321 sizes.push_back (1024);
1322 sizes.push_back (2048);
1323 sizes.push_back (4096);
1324 sizes.push_back (8192);
1329 EngineControl::set_buffersize_popdown_strings ()
1331 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1332 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1333 vector<uint32_t> bs;
1336 if (_have_control) {
1337 bs = get_buffer_sizes_for_all_devices ();
1338 } else if (backend->can_change_buffer_size_when_running()) {
1339 bs = get_default_buffer_sizes ();
1342 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1343 s.push_back (bufsize_as_string (*x));
1346 set_popdown_strings (buffer_size_combo, s);
1349 buffer_size_combo.set_active_text (s.front());
1351 uint32_t period = backend->buffer_size();
1352 if (0 == period && backend->use_separate_input_and_output_devices ()) {
1353 period = backend->default_buffer_size (get_input_device_name ());
1355 if (0 == period && backend->use_separate_input_and_output_devices ()) {
1356 period = backend->default_buffer_size (get_output_device_name ());
1358 if (0 == period && !backend->use_separate_input_and_output_devices ()) {
1359 period = backend->default_buffer_size (get_device_name ());
1362 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1363 show_buffer_duration ();
1365 update_sensitivity ();
1369 EngineControl::device_changed ()
1371 SignalBlocker blocker (*this, "device_changed");
1372 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1375 string device_name_in;
1376 string device_name_out; // only used if backend support separate I/O devices
1378 if (backend->use_separate_input_and_output_devices()) {
1379 device_name_in = get_input_device_name ();
1380 device_name_out = get_output_device_name ();
1382 device_name_in = get_device_name ();
1385 /* we set the backend-device to query various device related intormation.
1386 * This has the side effect that backend->device_name() will match
1387 * the device_name and 'change_device' will never be true.
1388 * so work around this by setting...
1390 if (backend->use_separate_input_and_output_devices()) {
1391 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1392 queue_device_changed = true;
1395 if (device_name_in != backend->device_name()) {
1396 queue_device_changed = true;
1400 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1401 if (backend->use_separate_input_and_output_devices()) {
1402 backend->set_input_device_name (device_name_in);
1403 backend->set_output_device_name (device_name_out);
1405 backend->set_device_name(device_name_in);
1409 /* don't allow programmatic change to combos to cause a
1410 recursive call to this method.
1412 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1414 set_samplerate_popdown_strings ();
1415 set_buffersize_popdown_strings ();
1417 /* TODO set min + max channel counts here */
1419 manage_control_app_sensitivity ();
1422 /* pick up any saved state for this device */
1424 if (!ignore_changes) {
1425 maybe_display_saved_state ();
1430 EngineControl::input_device_changed ()
1432 DEBUG_ECONTROL ("input_device_changed");
1437 EngineControl::output_device_changed ()
1439 DEBUG_ECONTROL ("output_device_changed");
1444 EngineControl::bufsize_as_string (uint32_t sz)
1446 /* Translators: "samples" is always plural here, so no
1447 need for plural+singular forms.
1450 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1455 EngineControl::sample_rate_changed ()
1457 DEBUG_ECONTROL ("sample_rate_changed");
1458 /* reset the strings for buffer size to show the correct msec value
1459 (reflecting the new sample rate).
1462 show_buffer_duration ();
1467 EngineControl::buffer_size_changed ()
1469 DEBUG_ECONTROL ("buffer_size_changed");
1470 show_buffer_duration ();
1474 EngineControl::show_buffer_duration ()
1476 DEBUG_ECONTROL ("show_buffer_duration");
1477 /* buffer sizes - convert from just samples to samples + msecs for
1478 * the displayed string
1481 string bs_text = buffer_size_combo.get_active_text ();
1482 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1483 uint32_t rate = get_rate();
1485 /* Developers: note the hard-coding of a double buffered model
1486 in the (2 * samples) computation of latency. we always start
1487 the audiobackend in this configuration.
1489 /* note to jack1 developers: ardour also always starts the engine
1490 * in async mode (no jack2 --sync option) which adds an extra cycle
1491 * of latency with jack2 (and *3 would be correct)
1492 * The value can also be wrong if jackd is started externally..
1494 * At the time of writing the ALSA backend always uses double-buffering *2,
1495 * The Dummy backend *1, and who knows what ASIO really does :)
1497 * So just display the period size, that's also what
1498 * ARDOUR_UI::update_sample_rate() does for the status bar.
1499 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1500 * but still, that's the buffer period, not [round-trip] latency)
1503 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1504 buffer_size_duration_label.set_text (buf);
1508 EngineControl::midi_option_changed ()
1510 DEBUG_ECONTROL ("midi_option_changed");
1511 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1514 backend->set_midi_option (get_midi_option());
1516 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1518 //_midi_devices.clear(); // TODO merge with state-saved settings..
1519 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1520 std::vector<MidiDeviceSettings> new_devices;
1522 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1523 MidiDeviceSettings mds = find_midi_device (i->name);
1524 if (i->available && !mds) {
1525 uint32_t input_latency = 0;
1526 uint32_t output_latency = 0;
1527 if (_can_set_midi_latencies) {
1528 input_latency = backend->systemic_midi_input_latency (i->name);
1529 output_latency = backend->systemic_midi_output_latency (i->name);
1531 bool enabled = backend->midi_device_enabled (i->name);
1532 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1533 new_devices.push_back (ptr);
1534 } else if (i->available) {
1535 new_devices.push_back (mds);
1538 _midi_devices = new_devices;
1540 if (_midi_devices.empty()) {
1541 midi_devices_button.set_sensitive (false);
1543 midi_devices_button.set_sensitive (true);
1548 EngineControl::parameter_changed ()
1552 EngineControl::State
1553 EngineControl::get_matching_state (
1554 const string& backend,
1555 const string& driver,
1556 const string& device)
1558 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1559 if ((*i)->backend == backend &&
1560 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1568 EngineControl::State
1569 EngineControl::get_matching_state (
1570 const string& backend,
1571 const string& driver,
1572 const string& input_device,
1573 const string& output_device)
1575 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1576 if ((*i)->backend == backend &&
1577 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1585 EngineControl::State
1586 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1588 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1591 if (backend->use_separate_input_and_output_devices ()) {
1592 return get_matching_state (backend_combo.get_active_text(),
1593 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1594 input_device_combo.get_active_text(),
1595 output_device_combo.get_active_text());
1597 return get_matching_state (backend_combo.get_active_text(),
1598 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1599 device_combo.get_active_text());
1603 return get_matching_state (backend_combo.get_active_text(),
1605 device_combo.get_active_text());
1608 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1609 const EngineControl::State& state2)
1611 if (state1->backend == state2->backend &&
1612 state1->driver == state2->driver &&
1613 state1->device == state2->device &&
1614 state1->input_device == state2->input_device &&
1615 state1->output_device == state2->output_device) {
1621 EngineControl::State
1622 EngineControl::save_state ()
1626 if (!_have_control) {
1627 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1631 state.reset(new StateStruct);
1632 state->backend = get_backend ();
1634 state.reset(new StateStruct);
1635 store_state (state);
1638 for (StateList::iterator i = states.begin(); i != states.end();) {
1639 if (equivalent_states (*i, state)) {
1640 i = states.erase(i);
1646 states.push_back (state);
1652 EngineControl::store_state (State state)
1654 state->backend = get_backend ();
1655 state->driver = get_driver ();
1656 state->device = get_device_name ();
1657 state->input_device = get_input_device_name ();
1658 state->output_device = get_output_device_name ();
1659 state->sample_rate = get_rate ();
1660 state->buffer_size = get_buffer_size ();
1661 state->input_latency = get_input_latency ();
1662 state->output_latency = get_output_latency ();
1663 state->input_channels = get_input_channels ();
1664 state->output_channels = get_output_channels ();
1665 state->midi_option = get_midi_option ();
1666 state->midi_devices = _midi_devices;
1670 EngineControl::maybe_display_saved_state ()
1672 if (!_have_control) {
1676 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1679 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1681 if (!_desired_sample_rate) {
1682 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1684 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1685 /* call this explicitly because we're ignoring changes to
1686 the controls at this point.
1688 show_buffer_duration ();
1689 input_latency.set_value (state->input_latency);
1690 output_latency.set_value (state->output_latency);
1692 if (!state->midi_option.empty()) {
1693 midi_option_combo.set_active_text (state->midi_option);
1694 _midi_devices = state->midi_devices;
1700 EngineControl::get_state ()
1702 LocaleGuard lg (X_("C"));
1704 XMLNode* root = new XMLNode ("AudioMIDISetup");
1707 if (!states.empty()) {
1708 XMLNode* state_nodes = new XMLNode ("EngineStates");
1710 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1712 XMLNode* node = new XMLNode ("State");
1714 node->add_property ("backend", (*i)->backend);
1715 node->add_property ("driver", (*i)->driver);
1716 node->add_property ("device", (*i)->device);
1717 node->add_property ("input-device", (*i)->input_device);
1718 node->add_property ("output-device", (*i)->output_device);
1719 node->add_property ("sample-rate", (*i)->sample_rate);
1720 node->add_property ("buffer-size", (*i)->buffer_size);
1721 node->add_property ("input-latency", (*i)->input_latency);
1722 node->add_property ("output-latency", (*i)->output_latency);
1723 node->add_property ("input-channels", (*i)->input_channels);
1724 node->add_property ("output-channels", (*i)->output_channels);
1725 node->add_property ("active", (*i)->active ? "yes" : "no");
1726 node->add_property ("midi-option", (*i)->midi_option);
1728 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1729 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1730 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1731 midi_device_stuff->add_property (X_("name"), (*p)->name);
1732 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1733 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1734 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1735 midi_devices->add_child_nocopy (*midi_device_stuff);
1737 node->add_child_nocopy (*midi_devices);
1739 state_nodes->add_child_nocopy (*node);
1742 root->add_child_nocopy (*state_nodes);
1749 EngineControl::set_default_state ()
1751 vector<string> backend_names;
1752 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1754 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1755 backend_names.push_back ((*b)->name);
1757 backend_combo.set_active_text (backend_names.front());
1759 // We could set default backends per platform etc here
1765 EngineControl::set_state (const XMLNode& root)
1767 XMLNodeList clist, cclist;
1768 XMLNodeConstIterator citer, cciter;
1770 XMLNode* grandchild;
1771 XMLProperty* prop = NULL;
1773 fprintf (stderr, "EngineControl::set_state\n");
1775 if (root.name() != "AudioMIDISetup") {
1779 clist = root.children();
1783 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1787 if (child->name() != "EngineStates") {
1791 cclist = child->children();
1793 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1794 State state (new StateStruct);
1796 grandchild = *cciter;
1798 if (grandchild->name() != "State") {
1802 if ((prop = grandchild->property ("backend")) == 0) {
1805 state->backend = prop->value ();
1807 if ((prop = grandchild->property ("driver")) == 0) {
1810 state->driver = prop->value ();
1812 if ((prop = grandchild->property ("device")) == 0) {
1815 state->device = prop->value ();
1817 if ((prop = grandchild->property ("input-device")) == 0) {
1820 state->input_device = prop->value ();
1822 if ((prop = grandchild->property ("output-device")) == 0) {
1825 state->output_device = prop->value ();
1827 if ((prop = grandchild->property ("sample-rate")) == 0) {
1830 state->sample_rate = atof (prop->value ());
1832 if ((prop = grandchild->property ("buffer-size")) == 0) {
1835 state->buffer_size = atoi (prop->value ());
1837 if ((prop = grandchild->property ("input-latency")) == 0) {
1840 state->input_latency = atoi (prop->value ());
1842 if ((prop = grandchild->property ("output-latency")) == 0) {
1845 state->output_latency = atoi (prop->value ());
1847 if ((prop = grandchild->property ("input-channels")) == 0) {
1850 state->input_channels = atoi (prop->value ());
1852 if ((prop = grandchild->property ("output-channels")) == 0) {
1855 state->output_channels = atoi (prop->value ());
1857 if ((prop = grandchild->property ("active")) == 0) {
1860 state->active = string_is_affirmative (prop->value ());
1862 if ((prop = grandchild->property ("midi-option")) == 0) {
1865 state->midi_option = prop->value ();
1867 state->midi_devices.clear();
1869 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1870 const XMLNodeList mnc = midinode->children();
1871 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1872 if ((*n)->property (X_("name")) == 0
1873 || (*n)->property (X_("enabled")) == 0
1874 || (*n)->property (X_("input-latency")) == 0
1875 || (*n)->property (X_("output-latency")) == 0
1880 MidiDeviceSettings ptr (new MidiDeviceSetting(
1881 (*n)->property (X_("name"))->value (),
1882 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1883 atoi ((*n)->property (X_("input-latency"))->value ()),
1884 atoi ((*n)->property (X_("output-latency"))->value ())
1886 state->midi_devices.push_back (ptr);
1891 /* remove accumulated duplicates (due to bug in ealier version)
1892 * this can be removed again before release
1894 for (StateList::iterator i = states.begin(); i != states.end();) {
1895 if ((*i)->backend == state->backend &&
1896 (*i)->driver == state->driver &&
1897 (*i)->device == state->device) {
1898 i = states.erase(i);
1905 states.push_back (state);
1909 /* now see if there was an active state and switch the setup to it */
1911 // purge states of backend that are not available in this built
1912 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1913 vector<std::string> backend_names;
1915 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1916 backend_names.push_back((*i)->name);
1918 for (StateList::iterator i = states.begin(); i != states.end();) {
1919 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1920 i = states.erase(i);
1926 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1929 return set_current_state (*i);
1936 EngineControl::set_current_state (const State& state)
1938 DEBUG_ECONTROL ("set_current_state");
1940 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1942 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1943 state->backend, downcase (PROGRAM_NAME), ""))) {
1944 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1945 // this shouldn't happen as the invalid backend names should have been
1946 // removed from the list of states.
1950 // now reflect the change in the backend in the GUI so backend_changed will
1951 // do the right thing
1952 backend_combo.set_active_text (state->backend);
1954 if (!state->driver.empty ()) {
1955 if (!backend->requires_driver_selection ()) {
1956 DEBUG_ECONTROL ("Backend should require driver selection");
1957 // A backend has changed from having driver selection to not having
1958 // it or someone has been manually editing a config file and messed
1963 if (backend->set_driver (state->driver) != 0) {
1964 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
1965 // Driver names for a backend have changed and the name in the
1966 // config file is now invalid or support for driver is no longer
1967 // included in the backend
1970 // no need to set the driver_combo as backend_changed will use
1971 // backend->driver_name to set the active driver
1974 if (!state->device.empty ()) {
1975 if (backend->set_device_name (state->device) != 0) {
1977 string_compose ("Unable to set device name %1", state->device));
1978 // device is no longer available on the system
1981 // no need to set active device as it will be picked up in
1982 // via backend_changed ()/set_device_popdown_strings
1985 // backend supports separate input/output devices
1986 if (backend->set_input_device_name (state->input_device) != 0) {
1987 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
1988 state->input_device));
1989 // input device is no longer available on the system
1993 if (backend->set_output_device_name (state->output_device) != 0) {
1994 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
1995 state->input_device));
1996 // output device is no longer available on the system
1999 // no need to set active devices as it will be picked up in via
2000 // backend_changed ()/set_*_device_popdown_strings
2005 // Now restore the state of the rest of the controls
2007 // We don't use a SignalBlocker as set_current_state is currently only
2008 // called from set_state before any signals are connected. If at some point
2009 // a more general named state mechanism is implemented and
2010 // set_current_state is called while signals are connected then a
2011 // SignalBlocker will need to be instantiated before setting these.
2013 device_combo.set_active_text (state->device);
2014 input_device_combo.set_active_text (state->input_device);
2015 output_device_combo.set_active_text (state->output_device);
2016 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2017 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2018 input_latency.set_value (state->input_latency);
2019 output_latency.set_value (state->output_latency);
2020 midi_option_combo.set_active_text (state->midi_option);
2025 EngineControl::push_state_to_backend (bool start)
2027 DEBUG_ECONTROL ("push_state_to_backend");
2028 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2034 /* figure out what is going to change */
2036 bool restart_required = false;
2037 bool was_running = ARDOUR::AudioEngine::instance()->running();
2038 bool change_driver = false;
2039 bool change_device = false;
2040 bool change_rate = false;
2041 bool change_bufsize = false;
2042 bool change_latency = false;
2043 bool change_channels = false;
2044 bool change_midi = false;
2046 uint32_t ochan = get_output_channels ();
2047 uint32_t ichan = get_input_channels ();
2049 if (_have_control) {
2051 if (started_at_least_once) {
2053 /* we can control the backend */
2055 if (backend->requires_driver_selection()) {
2056 if (get_driver() != backend->driver_name()) {
2057 change_driver = true;
2061 if (backend->use_separate_input_and_output_devices()) {
2062 if (get_input_device_name() != backend->input_device_name()) {
2063 change_device = true;
2065 if (get_output_device_name() != backend->output_device_name()) {
2066 change_device = true;
2069 if (get_device_name() != backend->device_name()) {
2070 change_device = true;
2074 if (queue_device_changed) {
2075 change_device = true;
2078 if (get_rate() != backend->sample_rate()) {
2082 if (get_buffer_size() != backend->buffer_size()) {
2083 change_bufsize = true;
2086 if (get_midi_option() != backend->midi_option()) {
2090 /* zero-requested channels means "all available" */
2093 ichan = backend->input_channels();
2097 ochan = backend->output_channels();
2100 if (ichan != backend->input_channels()) {
2101 change_channels = true;
2104 if (ochan != backend->output_channels()) {
2105 change_channels = true;
2108 if (get_input_latency() != backend->systemic_input_latency() ||
2109 get_output_latency() != backend->systemic_output_latency()) {
2110 change_latency = true;
2113 /* backend never started, so we have to force a group
2116 change_device = true;
2117 if (backend->requires_driver_selection()) {
2118 change_driver = true;
2121 change_bufsize = true;
2122 change_channels = true;
2123 change_latency = true;
2129 /* we have no control over the backend, meaning that we can
2130 * only possibly change sample rate and buffer size.
2134 if (get_rate() != backend->sample_rate()) {
2135 change_bufsize = true;
2138 if (get_buffer_size() != backend->buffer_size()) {
2139 change_bufsize = true;
2143 queue_device_changed = false;
2145 if (!_have_control) {
2147 /* We do not have control over the backend, so the best we can
2148 * do is try to change the sample rate and/or bufsize and get
2152 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2156 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2161 backend->set_sample_rate (get_rate());
2164 if (change_bufsize) {
2165 backend->set_buffer_size (get_buffer_size());
2169 if (ARDOUR::AudioEngine::instance()->start ()) {
2170 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2180 /* determine if we need to stop the backend before changing parameters */
2182 if (change_driver || change_device || change_channels || change_latency ||
2183 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2185 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2186 restart_required = true;
2188 restart_required = false;
2193 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2194 /* no changes in any parameters that absolutely require a
2195 * restart, so check those that might be changeable without a
2199 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2200 /* can't do this while running ... */
2201 restart_required = true;
2204 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2205 /* can't do this while running ... */
2206 restart_required = true;
2212 if (restart_required) {
2213 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2220 if (change_driver && backend->set_driver (get_driver())) {
2221 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2224 if (backend->use_separate_input_and_output_devices()) {
2225 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2226 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2229 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2230 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2234 if (change_device && backend->set_device_name (get_device_name())) {
2235 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2239 if (change_rate && backend->set_sample_rate (get_rate())) {
2240 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2243 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2244 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2248 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2249 if (backend->set_input_channels (get_input_channels())) {
2250 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2253 if (backend->set_output_channels (get_output_channels())) {
2254 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2258 if (change_latency) {
2259 if (backend->set_systemic_input_latency (get_input_latency())) {
2260 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2263 if (backend->set_systemic_output_latency (get_output_latency())) {
2264 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2270 backend->set_midi_option (get_midi_option());
2274 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2275 if (_measure_midi) {
2276 if (*p == _measure_midi) {
2277 backend->set_midi_device_enabled ((*p)->name, true);
2279 backend->set_midi_device_enabled ((*p)->name, false);
2283 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2284 if (backend->can_set_systemic_midi_latencies()) {
2285 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2286 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2291 if (start || (was_running && restart_required)) {
2292 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2303 EngineControl::post_push ()
2305 /* get a pointer to the current state object, creating one if
2309 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2312 state = save_state ();
2320 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2321 (*i)->active = false;
2324 /* mark this one active (to be used next time the dialog is
2328 state->active = true;
2330 if (_have_control) { // XXX
2331 manage_control_app_sensitivity ();
2334 /* schedule a redisplay of MIDI ports */
2335 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2340 EngineControl::get_rate () const
2342 float r = atof (sample_rate_combo.get_active_text ());
2343 /* the string may have been translated with an abbreviation for
2344 * thousands, so use a crude heuristic to fix this.
2354 EngineControl::get_buffer_size () const
2356 string txt = buffer_size_combo.get_active_text ();
2359 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2360 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2361 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2369 EngineControl::get_midi_option () const
2371 return midi_option_combo.get_active_text();
2375 EngineControl::get_input_channels() const
2377 if (ARDOUR::Profile->get_mixbus()) {
2378 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2379 if (!backend) return 0;
2380 return backend->input_channels();
2382 return (uint32_t) input_channels_adjustment.get_value();
2386 EngineControl::get_output_channels() const
2388 if (ARDOUR::Profile->get_mixbus()) {
2389 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2390 if (!backend) return 0;
2391 return backend->input_channels();
2393 return (uint32_t) output_channels_adjustment.get_value();
2397 EngineControl::get_input_latency() const
2399 return (uint32_t) input_latency_adjustment.get_value();
2403 EngineControl::get_output_latency() const
2405 return (uint32_t) output_latency_adjustment.get_value();
2409 EngineControl::get_backend () const
2411 return backend_combo.get_active_text ();
2415 EngineControl::get_driver () const
2417 if (driver_combo.get_parent()) {
2418 return driver_combo.get_active_text ();
2425 EngineControl::get_device_name () const
2427 return device_combo.get_active_text ();
2431 EngineControl::get_input_device_name () const
2433 return input_device_combo.get_active_text ();
2437 EngineControl::get_output_device_name () const
2439 return output_device_combo.get_active_text ();
2443 EngineControl::control_app_button_clicked ()
2445 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2451 backend->launch_control_app ();
2455 EngineControl::start_stop_button_clicked ()
2457 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2463 if (ARDOUR::AudioEngine::instance()->running()) {
2464 ARDOUR::AudioEngine::instance()->stop ();
2466 push_state_to_backend (true);
2471 EngineControl::manage_control_app_sensitivity ()
2473 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2479 string appname = backend->control_app_name();
2481 if (appname.empty()) {
2482 control_app_button.set_sensitive (false);
2484 control_app_button.set_sensitive (true);
2489 EngineControl::set_desired_sample_rate (uint32_t sr)
2491 _desired_sample_rate = sr;
2496 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2498 if (page_num == 0) {
2499 cancel_button->set_sensitive (true);
2500 _measure_midi.reset();
2501 update_sensitivity ();
2503 cancel_button->set_sensitive (false);
2504 ok_button->set_sensitive (false);
2505 apply_button->set_sensitive (false);
2508 if (page_num == midi_tab) {
2510 refresh_midi_display ();
2513 if (page_num == latency_tab) {
2516 if (ARDOUR::AudioEngine::instance()->running()) {
2517 // TODO - mark as 'stopped for latency
2518 ARDOUR_UI::instance()->disconnect_from_engine ();
2522 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2524 /* save any existing latency values */
2526 uint32_t il = (uint32_t) input_latency.get_value ();
2527 uint32_t ol = (uint32_t) input_latency.get_value ();
2529 /* reset to zero so that our new test instance
2530 will be clean of any existing latency measures.
2532 NB. this should really be done by the backend
2533 when stated for latency measurement.
2536 input_latency.set_value (0);
2537 output_latency.set_value (0);
2539 push_state_to_backend (false);
2543 input_latency.set_value (il);
2544 output_latency.set_value (ol);
2547 // This should be done in push_state_to_backend()
2548 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2549 disable_latency_tab ();
2552 enable_latency_tab ();
2556 end_latency_detection ();
2557 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2562 /* latency measurement */
2565 EngineControl::check_audio_latency_measurement ()
2567 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2569 if (mtdm->resolve () < 0) {
2570 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2574 if (mtdm->err () > 0.3) {
2580 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2582 if (sample_rate == 0) {
2583 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2584 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2588 int frames_total = mtdm->del();
2589 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2591 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2592 _("Detected roundtrip latency: "),
2593 frames_total, frames_total * 1000.0f/sample_rate,
2594 _("Systemic latency: "),
2595 extra, extra * 1000.0f/sample_rate);
2599 if (mtdm->err () > 0.2) {
2601 strcat (buf, _("(signal detection error)"));
2607 strcat (buf, _("(inverted - bad wiring)"));
2611 lm_results.set_markup (string_compose (results_markup, buf));
2614 have_lm_results = true;
2615 end_latency_detection ();
2616 lm_use_button.set_sensitive (true);
2624 EngineControl::check_midi_latency_measurement ()
2626 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2628 if (!mididm->have_signal () || mididm->latency () == 0) {
2629 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2634 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2636 if (sample_rate == 0) {
2637 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2638 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2642 ARDOUR::framecnt_t frames_total = mididm->latency();
2643 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2644 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2645 _("Detected roundtrip latency: "),
2646 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2647 _("Systemic latency: "),
2648 extra, extra * 1000.0f / sample_rate);
2652 if (!mididm->ok ()) {
2654 strcat (buf, _("(averaging)"));
2658 if (mididm->deviation () > 50.0) {
2660 strcat (buf, _("(too large jitter)"));
2662 } else if (mididm->deviation () > 10.0) {
2664 strcat (buf, _("(large jitter)"));
2668 have_lm_results = true;
2669 end_latency_detection ();
2670 lm_use_button.set_sensitive (true);
2671 lm_results.set_markup (string_compose (results_markup, buf));
2673 } else if (mididm->processed () > 400) {
2674 have_lm_results = false;
2675 end_latency_detection ();
2676 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2680 lm_results.set_markup (string_compose (results_markup, buf));
2686 EngineControl::start_latency_detection ()
2688 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2689 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2691 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2692 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2693 if (_measure_midi) {
2694 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2696 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2698 lm_measure_label.set_text (_("Cancel"));
2699 have_lm_results = false;
2700 lm_use_button.set_sensitive (false);
2701 lm_input_channel_combo.set_sensitive (false);
2702 lm_output_channel_combo.set_sensitive (false);
2708 EngineControl::end_latency_detection ()
2710 latency_timeout.disconnect ();
2711 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2712 lm_measure_label.set_text (_("Measure"));
2713 if (!have_lm_results) {
2714 lm_use_button.set_sensitive (false);
2716 lm_input_channel_combo.set_sensitive (true);
2717 lm_output_channel_combo.set_sensitive (true);
2722 EngineControl::latency_button_clicked ()
2725 start_latency_detection ();
2727 end_latency_detection ();
2732 EngineControl::use_latency_button_clicked ()
2734 if (_measure_midi) {
2735 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2739 ARDOUR::framecnt_t frames_total = mididm->latency();
2740 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2741 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2742 _measure_midi->input_latency = one_way;
2743 _measure_midi->output_latency = one_way;
2744 notebook.set_current_page (midi_tab);
2746 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2752 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2753 one_way = std::max (0., one_way);
2755 input_latency_adjustment.set_value (one_way);
2756 output_latency_adjustment.set_value (one_way);
2758 /* back to settings page */
2759 notebook.set_current_page (0);
2765 EngineControl::on_delete_event (GdkEventAny* ev)
2767 if (notebook.get_current_page() == 2) {
2768 /* currently on latency tab - be sure to clean up */
2769 end_latency_detection ();
2771 return ArdourDialog::on_delete_event (ev);
2775 EngineControl::engine_running ()
2777 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2780 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2781 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2783 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2784 connect_disconnect_button.show();
2786 started_at_least_once = true;
2787 if (_have_control) {
2788 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2790 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2792 update_sensitivity();
2796 EngineControl::engine_stopped ()
2798 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2801 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2802 connect_disconnect_button.show();
2804 if (_have_control) {
2805 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
2807 engine_status.set_markup(X_(""));
2810 update_sensitivity();
2814 EngineControl::device_list_changed ()
2816 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2818 midi_option_changed();
2822 EngineControl::connect_disconnect_click()
2824 if (ARDOUR::AudioEngine::instance()->running()) {
2825 ARDOUR_UI::instance()->disconnect_from_engine ();
2827 ARDOUR_UI::instance()->reconnect_to_engine ();
2832 EngineControl::calibrate_audio_latency ()
2834 _measure_midi.reset ();
2835 have_lm_results = false;
2836 lm_use_button.set_sensitive (false);
2837 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2838 notebook.set_current_page (latency_tab);
2842 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2845 have_lm_results = false;
2846 lm_use_button.set_sensitive (false);
2847 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2848 notebook.set_current_page (latency_tab);
2852 EngineControl::configure_midi_devices ()
2854 notebook.set_current_page (midi_tab);