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 , stop_engine_button (_("Stop (Reconfigure)"))
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 stop_engine_button.signal_clicked.connect (mem_fun (*this, &EngineControl::stop_engine_button_clicked));
273 stop_engine_button.set_sensitive (false);
274 stop_engine_button.set_name ("generic button");
275 stop_engine_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 (stop_engine_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 stop_engine_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);
805 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
806 input_device_combo.set_sensitive (false);
807 output_device_combo.set_sensitive (false);
808 device_combo.set_sensitive (false);
809 driver_combo.set_sensitive (false);
810 stop_engine_button.set_sensitive (true);
811 stop_engine_button.show ();
813 input_device_combo.set_sensitive (true);
814 output_device_combo.set_sensitive (true);
815 device_combo.set_sensitive (true);
816 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
817 driver_combo.set_sensitive (true);
819 driver_combo.set_sensitive (false);
821 stop_engine_button.set_sensitive (false);
822 stop_engine_button.hide ();
825 if (valid || !_have_control) {
826 ok_button->set_sensitive (true);
827 apply_button->set_sensitive (true);
829 ok_button->set_sensitive (false);
830 apply_button->set_sensitive (false);
835 EngineControl::setup_midi_tab_for_jack ()
840 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
842 device->input_latency = a->get_value();
844 device->output_latency = a->get_value();
849 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
850 b->set_active (!b->get_active());
851 device->enabled = b->get_active();
852 refresh_midi_display(device->name);
856 EngineControl::refresh_midi_display (std::string focus)
858 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
862 AttachOptions xopt = AttachOptions (FILL|EXPAND);
865 Gtkmm2ext::container_clear (midi_device_table);
867 midi_device_table.set_spacings (6);
869 l = manage (new Label);
870 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
871 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
872 l->set_alignment (0.5, 0.5);
876 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
877 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
878 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
879 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
881 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
882 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
883 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
884 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
887 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
892 bool enabled = (*p)->enabled;
894 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
895 m->set_name ("midi device");
896 m->set_can_focus (Gtk::CAN_FOCUS);
897 m->add_events (Gdk::BUTTON_RELEASE_MASK);
898 m->set_active (enabled);
899 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
900 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
901 if ((*p)->name == focus) {
905 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
906 s = manage (new Gtk::SpinButton (*a));
907 a->set_value ((*p)->input_latency);
908 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
909 s->set_sensitive (_can_set_midi_latencies && enabled);
910 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
912 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
913 s = manage (new Gtk::SpinButton (*a));
914 a->set_value ((*p)->output_latency);
915 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
916 s->set_sensitive (_can_set_midi_latencies && enabled);
917 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
919 b = manage (new Button (_("Calibrate")));
920 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
921 b->set_sensitive (_can_set_midi_latencies && enabled);
922 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
929 EngineControl::backend_changed ()
931 SignalBlocker blocker (*this, "backend_changed");
932 string backend_name = backend_combo.get_active_text();
933 boost::shared_ptr<ARDOUR::AudioBackend> backend;
935 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
936 /* eh? setting the backend failed... how ? */
937 /* A: stale config contains a backend that does not exist in current build */
941 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
943 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
946 setup_midi_tab_for_backend ();
947 _midi_devices.clear();
949 if (backend->requires_driver_selection()) {
950 if (set_driver_popdown_strings ()) {
954 /* this will change the device text which will cause a call to
955 * device changed which will set up parameters
960 update_midi_options ();
962 connect_disconnect_button.hide();
964 midi_option_changed();
966 started_at_least_once = false;
968 /* changing the backend implies stopping the engine
969 * ARDOUR::AudioEngine() may or may not emit this signal
970 * depending on previous engine state
972 engine_stopped (); // set "active/inactive"
974 if (!ignore_changes) {
975 maybe_display_saved_state ();
980 EngineControl::update_midi_options ()
982 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
983 vector<string> midi_options = backend->enumerate_midi_options();
985 if (midi_options.size() == 1) {
986 /* only contains the "none" option */
987 midi_option_combo.set_sensitive (false);
990 set_popdown_strings (midi_option_combo, midi_options);
991 midi_option_combo.set_active_text (midi_options.front());
992 midi_option_combo.set_sensitive (true);
994 midi_option_combo.set_sensitive (false);
1000 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1002 if (ARDOUR::Profile->get_mixbus()) {
1006 uint32_t cnt = (uint32_t) sb->get_value();
1008 sb->set_text (_("all available channels"));
1011 snprintf (buf, sizeof (buf), "%d", cnt);
1017 // @return true if there are drivers available
1019 EngineControl::set_driver_popdown_strings ()
1021 DEBUG_ECONTROL ("set_driver_popdown_strings");
1022 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1023 vector<string> drivers = backend->enumerate_drivers();
1025 if (drivers.empty ()) {
1026 // This is an error...?
1030 string current_driver = backend->driver_name ();
1032 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1034 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1037 current_driver = drivers.front ();
1040 set_popdown_strings (driver_combo, drivers);
1042 string_compose ("driver_combo.set_active_text: %1", current_driver));
1043 driver_combo.set_active_text (current_driver);
1047 // @return true if there are devices available
1049 EngineControl::set_device_popdown_strings ()
1051 DEBUG_ECONTROL ("set_device_popdown_strings");
1052 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1053 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1055 /* NOTE: Ardour currently does not display the "available" field of the
1058 * Doing so would require a different GUI widget than the combo
1059 * box/popdown that we currently use, since it has no way to list
1060 * items that are not selectable. Something more like a popup menu,
1061 * which could have unselectable items, would be appropriate.
1064 vector<string> available_devices;
1066 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1067 available_devices.push_back (i->name);
1070 if (available_devices.empty ()) {
1074 string current_device = backend->device_name ();
1076 // Make sure that backend->device_name () is a valid
1077 // device, the backend may not return a valid device if it hasn't
1079 if (std::find (available_devices.begin (),
1080 available_devices.end (),
1081 current_device) == available_devices.end ()) {
1083 current_device = available_devices.front ();
1086 set_popdown_strings (device_combo, available_devices);
1088 string_compose ("set device_combo active text: %1", current_device));
1090 device_combo.set_active_text (current_device);
1094 // @return true if there are input devices available
1096 EngineControl::set_input_device_popdown_strings ()
1098 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1099 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1100 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1102 vector<string> available_devices;
1104 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1105 available_devices.push_back (i->name);
1108 if (available_devices.empty()) {
1112 string current_device = backend->input_device_name ();
1114 // Make sure that backend->input_device_name () is a valid
1115 // device, the backend may not return a valid device if it hasn't
1117 if (std::find (available_devices.begin (),
1118 available_devices.end (),
1119 current_device) == available_devices.end ()) {
1121 current_device = available_devices.front ();
1124 set_popdown_strings (input_device_combo, available_devices);
1127 string_compose ("set input_device_combo active text: %1", current_device));
1128 input_device_combo.set_active_text (current_device);
1132 // @return true if there are output devices available
1134 EngineControl::set_output_device_popdown_strings ()
1136 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1137 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1138 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1140 vector<string> available_devices;
1142 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1143 available_devices.push_back (i->name);
1146 if (available_devices.empty()) {
1150 string current_device = backend->output_device_name ();
1152 // Make sure that backend->output_device_name () is a valid
1153 // device, the backend may not return a valid device if it hasn't
1155 if (std::find (available_devices.begin (),
1156 available_devices.end (),
1157 current_device) == available_devices.end ()) {
1159 current_device = available_devices.front ();
1162 set_popdown_strings (output_device_combo, available_devices);
1165 string_compose ("set output_device_combo active text: %1", current_device));
1166 output_device_combo.set_active_text (current_device);
1171 EngineControl::list_devices ()
1173 DEBUG_ECONTROL ("list_devices");
1174 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1177 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1179 bool devices_available = false;
1181 if (backend->use_separate_input_and_output_devices ()) {
1182 bool input_devices_available = set_input_device_popdown_strings ();
1183 bool output_devices_available = set_output_device_popdown_strings ();
1184 devices_available = input_devices_available || output_devices_available;
1186 devices_available = set_device_popdown_strings ();
1189 if (devices_available) {
1192 device_combo.clear();
1193 input_device_combo.clear();
1194 output_device_combo.clear();
1196 update_sensitivity ();
1200 EngineControl::driver_changed ()
1202 SignalBlocker blocker (*this, "driver_changed");
1203 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1206 backend->set_driver (driver_combo.get_active_text());
1209 if (!ignore_changes) {
1210 maybe_display_saved_state ();
1215 EngineControl::get_sample_rates_for_all_devices ()
1217 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1218 ARDOUR::AudioEngine::instance ()->current_backend ();
1219 vector<float> all_rates;
1221 if (backend->use_separate_input_and_output_devices ()) {
1222 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1224 all_rates = backend->available_sample_rates (get_device_name ());
1230 EngineControl::get_default_sample_rates ()
1232 vector<float> rates;
1233 rates.push_back (8000.0f);
1234 rates.push_back (16000.0f);
1235 rates.push_back (32000.0f);
1236 rates.push_back (44100.0f);
1237 rates.push_back (48000.0f);
1238 rates.push_back (88200.0f);
1239 rates.push_back (96000.0f);
1240 rates.push_back (192000.0f);
1241 rates.push_back (384000.0f);
1246 EngineControl::set_samplerate_popdown_strings ()
1248 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1249 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1254 if (_have_control) {
1255 sr = get_sample_rates_for_all_devices ();
1257 sr = get_default_sample_rates ();
1260 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1261 s.push_back (rate_as_string (*x));
1262 if (*x == _desired_sample_rate) {
1267 set_popdown_strings (sample_rate_combo, s);
1270 if (desired.empty ()) {
1271 float new_active_sr = backend->default_sample_rate ();
1273 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1274 new_active_sr = sr.front ();
1277 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1279 sample_rate_combo.set_active_text (desired);
1283 update_sensitivity ();
1287 EngineControl::get_buffer_sizes_for_all_devices ()
1289 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1290 ARDOUR::AudioEngine::instance ()->current_backend ();
1291 vector<uint32_t> all_sizes;
1293 if (backend->use_separate_input_and_output_devices ()) {
1294 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1296 all_sizes = backend->available_buffer_sizes (get_device_name ());
1302 EngineControl::get_default_buffer_sizes ()
1304 vector<uint32_t> sizes;
1305 sizes.push_back (8);
1306 sizes.push_back (16);
1307 sizes.push_back (32);
1308 sizes.push_back (64);
1309 sizes.push_back (128);
1310 sizes.push_back (256);
1311 sizes.push_back (512);
1312 sizes.push_back (1024);
1313 sizes.push_back (2048);
1314 sizes.push_back (4096);
1315 sizes.push_back (8192);
1320 EngineControl::set_buffersize_popdown_strings ()
1322 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1323 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1324 vector<uint32_t> bs;
1327 if (_have_control) {
1328 bs = get_buffer_sizes_for_all_devices ();
1329 } else if (backend->can_change_buffer_size_when_running()) {
1330 bs = get_default_buffer_sizes ();
1333 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1334 s.push_back (bufsize_as_string (*x));
1337 set_popdown_strings (buffer_size_combo, s);
1340 buffer_size_combo.set_active_text (s.front());
1342 uint32_t period = backend->buffer_size();
1343 if (0 == period && backend->use_separate_input_and_output_devices ()) {
1344 period = backend->default_buffer_size (get_input_device_name ());
1346 if (0 == period && backend->use_separate_input_and_output_devices ()) {
1347 period = backend->default_buffer_size (get_output_device_name ());
1349 if (0 == period && !backend->use_separate_input_and_output_devices ()) {
1350 period = backend->default_buffer_size (get_device_name ());
1353 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1354 show_buffer_duration ();
1356 update_sensitivity ();
1360 EngineControl::device_changed ()
1362 SignalBlocker blocker (*this, "device_changed");
1363 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1366 string device_name_in;
1367 string device_name_out; // only used if backend support separate I/O devices
1369 if (backend->use_separate_input_and_output_devices()) {
1370 device_name_in = get_input_device_name ();
1371 device_name_out = get_output_device_name ();
1373 device_name_in = get_device_name ();
1376 /* we set the backend-device to query various device related intormation.
1377 * This has the side effect that backend->device_name() will match
1378 * the device_name and 'change_device' will never be true.
1379 * so work around this by setting...
1381 if (backend->use_separate_input_and_output_devices()) {
1382 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1383 queue_device_changed = true;
1386 if (device_name_in != backend->device_name()) {
1387 queue_device_changed = true;
1391 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1392 if (backend->use_separate_input_and_output_devices()) {
1393 backend->set_input_device_name (device_name_in);
1394 backend->set_output_device_name (device_name_out);
1396 backend->set_device_name(device_name_in);
1400 /* don't allow programmatic change to combos to cause a
1401 recursive call to this method.
1403 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1405 set_samplerate_popdown_strings ();
1406 set_buffersize_popdown_strings ();
1408 /* TODO set min + max channel counts here */
1410 manage_control_app_sensitivity ();
1413 /* pick up any saved state for this device */
1415 if (!ignore_changes) {
1416 maybe_display_saved_state ();
1421 EngineControl::input_device_changed ()
1423 DEBUG_ECONTROL ("input_device_changed");
1428 EngineControl::output_device_changed ()
1430 DEBUG_ECONTROL ("output_device_changed");
1435 EngineControl::bufsize_as_string (uint32_t sz)
1437 /* Translators: "samples" is always plural here, so no
1438 need for plural+singular forms.
1441 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1446 EngineControl::sample_rate_changed ()
1448 DEBUG_ECONTROL ("sample_rate_changed");
1449 /* reset the strings for buffer size to show the correct msec value
1450 (reflecting the new sample rate).
1453 show_buffer_duration ();
1458 EngineControl::buffer_size_changed ()
1460 DEBUG_ECONTROL ("buffer_size_changed");
1461 show_buffer_duration ();
1465 EngineControl::show_buffer_duration ()
1467 DEBUG_ECONTROL ("show_buffer_duration");
1468 /* buffer sizes - convert from just samples to samples + msecs for
1469 * the displayed string
1472 string bs_text = buffer_size_combo.get_active_text ();
1473 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1474 uint32_t rate = get_rate();
1476 /* Developers: note the hard-coding of a double buffered model
1477 in the (2 * samples) computation of latency. we always start
1478 the audiobackend in this configuration.
1480 /* note to jack1 developers: ardour also always starts the engine
1481 * in async mode (no jack2 --sync option) which adds an extra cycle
1482 * of latency with jack2 (and *3 would be correct)
1483 * The value can also be wrong if jackd is started externally..
1485 * At the time of writing the ALSA backend always uses double-buffering *2,
1486 * The Dummy backend *1, and who knows what ASIO really does :)
1488 * So just display the period size, that's also what
1489 * ARDOUR_UI::update_sample_rate() does for the status bar.
1490 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1491 * but still, that's the buffer period, not [round-trip] latency)
1494 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1495 buffer_size_duration_label.set_text (buf);
1499 EngineControl::midi_option_changed ()
1501 DEBUG_ECONTROL ("midi_option_changed");
1502 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1505 backend->set_midi_option (get_midi_option());
1507 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1509 //_midi_devices.clear(); // TODO merge with state-saved settings..
1510 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1511 std::vector<MidiDeviceSettings> new_devices;
1513 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1514 MidiDeviceSettings mds = find_midi_device (i->name);
1515 if (i->available && !mds) {
1516 uint32_t input_latency = 0;
1517 uint32_t output_latency = 0;
1518 if (_can_set_midi_latencies) {
1519 input_latency = backend->systemic_midi_input_latency (i->name);
1520 output_latency = backend->systemic_midi_output_latency (i->name);
1522 bool enabled = backend->midi_device_enabled (i->name);
1523 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1524 new_devices.push_back (ptr);
1525 } else if (i->available) {
1526 new_devices.push_back (mds);
1529 _midi_devices = new_devices;
1531 if (_midi_devices.empty()) {
1532 midi_devices_button.set_sensitive (false);
1534 midi_devices_button.set_sensitive (true);
1539 EngineControl::parameter_changed ()
1543 EngineControl::State
1544 EngineControl::get_matching_state (
1545 const string& backend,
1546 const string& driver,
1547 const string& device)
1549 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1550 if ((*i)->backend == backend &&
1551 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1559 EngineControl::State
1560 EngineControl::get_matching_state (
1561 const string& backend,
1562 const string& driver,
1563 const string& input_device,
1564 const string& output_device)
1566 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1567 if ((*i)->backend == backend &&
1568 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1576 EngineControl::State
1577 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1579 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1582 if (backend->use_separate_input_and_output_devices ()) {
1583 return get_matching_state (backend_combo.get_active_text(),
1584 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1585 input_device_combo.get_active_text(),
1586 output_device_combo.get_active_text());
1588 return get_matching_state (backend_combo.get_active_text(),
1589 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1590 device_combo.get_active_text());
1594 return get_matching_state (backend_combo.get_active_text(),
1596 device_combo.get_active_text());
1599 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1600 const EngineControl::State& state2)
1602 if (state1->backend == state2->backend &&
1603 state1->driver == state2->driver &&
1604 state1->device == state2->device &&
1605 state1->input_device == state2->input_device &&
1606 state1->output_device == state2->output_device) {
1612 EngineControl::State
1613 EngineControl::save_state ()
1617 if (!_have_control) {
1618 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1622 state.reset(new StateStruct);
1623 state->backend = get_backend ();
1625 state.reset(new StateStruct);
1626 store_state (state);
1629 for (StateList::iterator i = states.begin(); i != states.end();) {
1630 if (equivalent_states (*i, state)) {
1631 i = states.erase(i);
1637 states.push_back (state);
1643 EngineControl::store_state (State state)
1645 state->backend = get_backend ();
1646 state->driver = get_driver ();
1647 state->device = get_device_name ();
1648 state->input_device = get_input_device_name ();
1649 state->output_device = get_output_device_name ();
1650 state->sample_rate = get_rate ();
1651 state->buffer_size = get_buffer_size ();
1652 state->input_latency = get_input_latency ();
1653 state->output_latency = get_output_latency ();
1654 state->input_channels = get_input_channels ();
1655 state->output_channels = get_output_channels ();
1656 state->midi_option = get_midi_option ();
1657 state->midi_devices = _midi_devices;
1661 EngineControl::maybe_display_saved_state ()
1663 if (!_have_control) {
1667 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1670 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1672 if (!_desired_sample_rate) {
1673 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1675 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1676 /* call this explicitly because we're ignoring changes to
1677 the controls at this point.
1679 show_buffer_duration ();
1680 input_latency.set_value (state->input_latency);
1681 output_latency.set_value (state->output_latency);
1683 if (!state->midi_option.empty()) {
1684 midi_option_combo.set_active_text (state->midi_option);
1685 _midi_devices = state->midi_devices;
1691 EngineControl::get_state ()
1693 LocaleGuard lg (X_("C"));
1695 XMLNode* root = new XMLNode ("AudioMIDISetup");
1698 if (!states.empty()) {
1699 XMLNode* state_nodes = new XMLNode ("EngineStates");
1701 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1703 XMLNode* node = new XMLNode ("State");
1705 node->add_property ("backend", (*i)->backend);
1706 node->add_property ("driver", (*i)->driver);
1707 node->add_property ("device", (*i)->device);
1708 node->add_property ("input-device", (*i)->input_device);
1709 node->add_property ("output-device", (*i)->output_device);
1710 node->add_property ("sample-rate", (*i)->sample_rate);
1711 node->add_property ("buffer-size", (*i)->buffer_size);
1712 node->add_property ("input-latency", (*i)->input_latency);
1713 node->add_property ("output-latency", (*i)->output_latency);
1714 node->add_property ("input-channels", (*i)->input_channels);
1715 node->add_property ("output-channels", (*i)->output_channels);
1716 node->add_property ("active", (*i)->active ? "yes" : "no");
1717 node->add_property ("midi-option", (*i)->midi_option);
1719 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1720 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1721 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1722 midi_device_stuff->add_property (X_("name"), (*p)->name);
1723 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1724 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1725 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1726 midi_devices->add_child_nocopy (*midi_device_stuff);
1728 node->add_child_nocopy (*midi_devices);
1730 state_nodes->add_child_nocopy (*node);
1733 root->add_child_nocopy (*state_nodes);
1740 EngineControl::set_default_state ()
1742 vector<string> backend_names;
1743 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1745 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1746 backend_names.push_back ((*b)->name);
1748 backend_combo.set_active_text (backend_names.front());
1750 // We could set default backends per platform etc here
1756 EngineControl::set_state (const XMLNode& root)
1758 XMLNodeList clist, cclist;
1759 XMLNodeConstIterator citer, cciter;
1761 XMLNode* grandchild;
1762 XMLProperty* prop = NULL;
1764 fprintf (stderr, "EngineControl::set_state\n");
1766 if (root.name() != "AudioMIDISetup") {
1770 clist = root.children();
1774 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1778 if (child->name() != "EngineStates") {
1782 cclist = child->children();
1784 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1785 State state (new StateStruct);
1787 grandchild = *cciter;
1789 if (grandchild->name() != "State") {
1793 if ((prop = grandchild->property ("backend")) == 0) {
1796 state->backend = prop->value ();
1798 if ((prop = grandchild->property ("driver")) == 0) {
1801 state->driver = prop->value ();
1803 if ((prop = grandchild->property ("device")) == 0) {
1806 state->device = prop->value ();
1808 if ((prop = grandchild->property ("input-device")) == 0) {
1811 state->input_device = prop->value ();
1813 if ((prop = grandchild->property ("output-device")) == 0) {
1816 state->output_device = prop->value ();
1818 if ((prop = grandchild->property ("sample-rate")) == 0) {
1821 state->sample_rate = atof (prop->value ());
1823 if ((prop = grandchild->property ("buffer-size")) == 0) {
1826 state->buffer_size = atoi (prop->value ());
1828 if ((prop = grandchild->property ("input-latency")) == 0) {
1831 state->input_latency = atoi (prop->value ());
1833 if ((prop = grandchild->property ("output-latency")) == 0) {
1836 state->output_latency = atoi (prop->value ());
1838 if ((prop = grandchild->property ("input-channels")) == 0) {
1841 state->input_channels = atoi (prop->value ());
1843 if ((prop = grandchild->property ("output-channels")) == 0) {
1846 state->output_channels = atoi (prop->value ());
1848 if ((prop = grandchild->property ("active")) == 0) {
1851 state->active = string_is_affirmative (prop->value ());
1853 if ((prop = grandchild->property ("midi-option")) == 0) {
1856 state->midi_option = prop->value ();
1858 state->midi_devices.clear();
1860 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1861 const XMLNodeList mnc = midinode->children();
1862 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1863 if ((*n)->property (X_("name")) == 0
1864 || (*n)->property (X_("enabled")) == 0
1865 || (*n)->property (X_("input-latency")) == 0
1866 || (*n)->property (X_("output-latency")) == 0
1871 MidiDeviceSettings ptr (new MidiDeviceSetting(
1872 (*n)->property (X_("name"))->value (),
1873 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1874 atoi ((*n)->property (X_("input-latency"))->value ()),
1875 atoi ((*n)->property (X_("output-latency"))->value ())
1877 state->midi_devices.push_back (ptr);
1882 /* remove accumulated duplicates (due to bug in ealier version)
1883 * this can be removed again before release
1885 for (StateList::iterator i = states.begin(); i != states.end();) {
1886 if ((*i)->backend == state->backend &&
1887 (*i)->driver == state->driver &&
1888 (*i)->device == state->device) {
1889 i = states.erase(i);
1896 states.push_back (state);
1900 /* now see if there was an active state and switch the setup to it */
1902 // purge states of backend that are not available in this built
1903 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1904 vector<std::string> backend_names;
1906 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1907 backend_names.push_back((*i)->name);
1909 for (StateList::iterator i = states.begin(); i != states.end();) {
1910 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1911 i = states.erase(i);
1917 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1920 return set_current_state (*i);
1927 EngineControl::set_current_state (const State& state)
1929 DEBUG_ECONTROL ("set_current_state");
1931 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1933 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1934 state->backend, "ardour", ""))) {
1935 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1936 // this shouldn't happen as the invalid backend names should have been
1937 // removed from the list of states.
1941 // now reflect the change in the backend in the GUI so backend_changed will
1942 // do the right thing
1943 backend_combo.set_active_text (state->backend);
1945 if (!state->driver.empty ()) {
1946 if (!backend->requires_driver_selection ()) {
1947 DEBUG_ECONTROL ("Backend should require driver selection");
1948 // A backend has changed from having driver selection to not having
1949 // it or someone has been manually editing a config file and messed
1954 if (backend->set_driver (state->driver) != 0) {
1955 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
1956 // Driver names for a backend have changed and the name in the
1957 // config file is now invalid or support for driver is no longer
1958 // included in the backend
1961 // no need to set the driver_combo as backend_changed will use
1962 // backend->driver_name to set the active driver
1965 if (!state->device.empty ()) {
1966 if (backend->set_device_name (state->device) != 0) {
1968 string_compose ("Unable to set device name %1", state->device));
1969 // device is no longer available on the system
1972 // no need to set active device as it will be picked up in
1973 // via backend_changed ()/set_device_popdown_strings
1976 // backend supports separate input/output devices
1977 if (backend->set_input_device_name (state->input_device) != 0) {
1978 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
1979 state->input_device));
1980 // input device is no longer available on the system
1984 if (backend->set_output_device_name (state->output_device) != 0) {
1985 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
1986 state->input_device));
1987 // output device is no longer available on the system
1990 // no need to set active devices as it will be picked up in via
1991 // backend_changed ()/set_*_device_popdown_strings
1996 // Now restore the state of the rest of the controls
1998 // We don't use a SignalBlocker as set_current_state is currently only
1999 // called from set_state before any signals are connected. If at some point
2000 // a more general named state mechanism is implemented and
2001 // set_current_state is called while signals are connected then a
2002 // SignalBlocker will need to be instantiated before setting these.
2004 device_combo.set_active_text (state->device);
2005 input_device_combo.set_active_text (state->input_device);
2006 output_device_combo.set_active_text (state->output_device);
2007 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2008 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2009 input_latency.set_value (state->input_latency);
2010 output_latency.set_value (state->output_latency);
2011 midi_option_combo.set_active_text (state->midi_option);
2016 EngineControl::push_state_to_backend (bool start)
2018 DEBUG_ECONTROL ("push_state_to_backend");
2019 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2025 /* figure out what is going to change */
2027 bool restart_required = false;
2028 bool was_running = ARDOUR::AudioEngine::instance()->running();
2029 bool change_driver = false;
2030 bool change_device = false;
2031 bool change_rate = false;
2032 bool change_bufsize = false;
2033 bool change_latency = false;
2034 bool change_channels = false;
2035 bool change_midi = false;
2037 uint32_t ochan = get_output_channels ();
2038 uint32_t ichan = get_input_channels ();
2040 if (_have_control) {
2042 if (started_at_least_once) {
2044 /* we can control the backend */
2046 if (backend->requires_driver_selection()) {
2047 if (get_driver() != backend->driver_name()) {
2048 change_driver = true;
2052 if (backend->use_separate_input_and_output_devices()) {
2053 if (get_input_device_name() != backend->input_device_name()) {
2054 change_device = true;
2056 if (get_output_device_name() != backend->output_device_name()) {
2057 change_device = true;
2060 if (get_device_name() != backend->device_name()) {
2061 change_device = true;
2065 if (queue_device_changed) {
2066 change_device = true;
2069 if (get_rate() != backend->sample_rate()) {
2073 if (get_buffer_size() != backend->buffer_size()) {
2074 change_bufsize = true;
2077 if (get_midi_option() != backend->midi_option()) {
2081 /* zero-requested channels means "all available" */
2084 ichan = backend->input_channels();
2088 ochan = backend->output_channels();
2091 if (ichan != backend->input_channels()) {
2092 change_channels = true;
2095 if (ochan != backend->output_channels()) {
2096 change_channels = true;
2099 if (get_input_latency() != backend->systemic_input_latency() ||
2100 get_output_latency() != backend->systemic_output_latency()) {
2101 change_latency = true;
2104 /* backend never started, so we have to force a group
2107 change_device = true;
2108 if (backend->requires_driver_selection()) {
2109 change_driver = true;
2112 change_bufsize = true;
2113 change_channels = true;
2114 change_latency = true;
2120 /* we have no control over the backend, meaning that we can
2121 * only possibly change sample rate and buffer size.
2125 if (get_rate() != backend->sample_rate()) {
2126 change_bufsize = true;
2129 if (get_buffer_size() != backend->buffer_size()) {
2130 change_bufsize = true;
2134 queue_device_changed = false;
2136 if (!_have_control) {
2138 /* We do not have control over the backend, so the best we can
2139 * do is try to change the sample rate and/or bufsize and get
2143 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2147 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2152 backend->set_sample_rate (get_rate());
2155 if (change_bufsize) {
2156 backend->set_buffer_size (get_buffer_size());
2160 if (ARDOUR::AudioEngine::instance()->start ()) {
2161 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2171 /* determine if we need to stop the backend before changing parameters */
2173 if (change_driver || change_device || change_channels || change_latency ||
2174 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2176 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2177 restart_required = true;
2179 restart_required = false;
2184 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2185 /* no changes in any parameters that absolutely require a
2186 * restart, so check those that might be changeable without a
2190 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2191 /* can't do this while running ... */
2192 restart_required = true;
2195 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2196 /* can't do this while running ... */
2197 restart_required = true;
2203 if (restart_required) {
2204 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2211 if (change_driver && backend->set_driver (get_driver())) {
2212 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2215 if (backend->use_separate_input_and_output_devices()) {
2216 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2217 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2220 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2221 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2225 if (change_device && backend->set_device_name (get_device_name())) {
2226 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2230 if (change_rate && backend->set_sample_rate (get_rate())) {
2231 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2234 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2235 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2239 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2240 if (backend->set_input_channels (get_input_channels())) {
2241 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2244 if (backend->set_output_channels (get_output_channels())) {
2245 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2249 if (change_latency) {
2250 if (backend->set_systemic_input_latency (get_input_latency())) {
2251 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2254 if (backend->set_systemic_output_latency (get_output_latency())) {
2255 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2261 backend->set_midi_option (get_midi_option());
2265 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2266 if (_measure_midi) {
2267 if (*p == _measure_midi) {
2268 backend->set_midi_device_enabled ((*p)->name, true);
2270 backend->set_midi_device_enabled ((*p)->name, false);
2274 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2275 if (backend->can_set_systemic_midi_latencies()) {
2276 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2277 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2282 if (start || (was_running && restart_required)) {
2283 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2294 EngineControl::post_push ()
2296 /* get a pointer to the current state object, creating one if
2300 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2303 state = save_state ();
2311 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2312 (*i)->active = false;
2315 /* mark this one active (to be used next time the dialog is
2319 state->active = true;
2321 if (_have_control) { // XXX
2322 manage_control_app_sensitivity ();
2325 /* schedule a redisplay of MIDI ports */
2326 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2331 EngineControl::get_rate () const
2333 float r = atof (sample_rate_combo.get_active_text ());
2334 /* the string may have been translated with an abbreviation for
2335 * thousands, so use a crude heuristic to fix this.
2345 EngineControl::get_buffer_size () const
2347 string txt = buffer_size_combo.get_active_text ();
2350 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2351 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2352 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2360 EngineControl::get_midi_option () const
2362 return midi_option_combo.get_active_text();
2366 EngineControl::get_input_channels() const
2368 if (ARDOUR::Profile->get_mixbus()) {
2369 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2370 if (!backend) return 0;
2371 return backend->input_channels();
2373 return (uint32_t) input_channels_adjustment.get_value();
2377 EngineControl::get_output_channels() const
2379 if (ARDOUR::Profile->get_mixbus()) {
2380 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2381 if (!backend) return 0;
2382 return backend->input_channels();
2384 return (uint32_t) output_channels_adjustment.get_value();
2388 EngineControl::get_input_latency() const
2390 return (uint32_t) input_latency_adjustment.get_value();
2394 EngineControl::get_output_latency() const
2396 return (uint32_t) output_latency_adjustment.get_value();
2400 EngineControl::get_backend () const
2402 return backend_combo.get_active_text ();
2406 EngineControl::get_driver () const
2408 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2409 return driver_combo.get_active_text ();
2416 EngineControl::get_device_name () const
2418 return device_combo.get_active_text ();
2422 EngineControl::get_input_device_name () const
2424 return input_device_combo.get_active_text ();
2428 EngineControl::get_output_device_name () const
2430 return output_device_combo.get_active_text ();
2434 EngineControl::control_app_button_clicked ()
2436 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2442 backend->launch_control_app ();
2446 EngineControl::stop_engine_button_clicked ()
2448 ARDOUR::AudioEngine::instance()->stop ();
2452 EngineControl::manage_control_app_sensitivity ()
2454 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2460 string appname = backend->control_app_name();
2462 if (appname.empty()) {
2463 control_app_button.set_sensitive (false);
2465 control_app_button.set_sensitive (true);
2470 EngineControl::set_desired_sample_rate (uint32_t sr)
2472 _desired_sample_rate = sr;
2477 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2479 if (page_num == 0) {
2480 cancel_button->set_sensitive (true);
2481 _measure_midi.reset();
2482 update_sensitivity ();
2484 cancel_button->set_sensitive (false);
2485 ok_button->set_sensitive (false);
2486 apply_button->set_sensitive (false);
2489 if (page_num == midi_tab) {
2491 refresh_midi_display ();
2494 if (page_num == latency_tab) {
2497 if (ARDOUR::AudioEngine::instance()->running()) {
2498 // TODO - mark as 'stopped for latency
2499 ARDOUR_UI::instance()->disconnect_from_engine ();
2503 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2505 /* save any existing latency values */
2507 uint32_t il = (uint32_t) input_latency.get_value ();
2508 uint32_t ol = (uint32_t) input_latency.get_value ();
2510 /* reset to zero so that our new test instance
2511 will be clean of any existing latency measures.
2513 NB. this should really be done by the backend
2514 when stated for latency measurement.
2517 input_latency.set_value (0);
2518 output_latency.set_value (0);
2520 push_state_to_backend (false);
2524 input_latency.set_value (il);
2525 output_latency.set_value (ol);
2528 // This should be done in push_state_to_backend()
2529 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2530 disable_latency_tab ();
2533 enable_latency_tab ();
2537 end_latency_detection ();
2538 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2543 /* latency measurement */
2546 EngineControl::check_audio_latency_measurement ()
2548 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2550 if (mtdm->resolve () < 0) {
2551 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2555 if (mtdm->err () > 0.3) {
2561 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2563 if (sample_rate == 0) {
2564 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2565 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2569 int frames_total = mtdm->del();
2570 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2572 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2573 _("Detected roundtrip latency: "),
2574 frames_total, frames_total * 1000.0f/sample_rate,
2575 _("Systemic latency: "),
2576 extra, extra * 1000.0f/sample_rate);
2580 if (mtdm->err () > 0.2) {
2582 strcat (buf, _("(signal detection error)"));
2588 strcat (buf, _("(inverted - bad wiring)"));
2592 lm_results.set_markup (string_compose (results_markup, buf));
2595 have_lm_results = true;
2596 end_latency_detection ();
2597 lm_use_button.set_sensitive (true);
2605 EngineControl::check_midi_latency_measurement ()
2607 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2609 if (!mididm->have_signal () || mididm->latency () == 0) {
2610 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2615 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2617 if (sample_rate == 0) {
2618 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2619 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2623 ARDOUR::framecnt_t frames_total = mididm->latency();
2624 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2625 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2626 _("Detected roundtrip latency: "),
2627 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2628 _("Systemic latency: "),
2629 extra, extra * 1000.0f / sample_rate);
2633 if (!mididm->ok ()) {
2635 strcat (buf, _("(averaging)"));
2639 if (mididm->deviation () > 50.0) {
2641 strcat (buf, _("(too large jitter)"));
2643 } else if (mididm->deviation () > 10.0) {
2645 strcat (buf, _("(large jitter)"));
2649 have_lm_results = true;
2650 end_latency_detection ();
2651 lm_use_button.set_sensitive (true);
2652 lm_results.set_markup (string_compose (results_markup, buf));
2654 } else if (mididm->processed () > 400) {
2655 have_lm_results = false;
2656 end_latency_detection ();
2657 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2661 lm_results.set_markup (string_compose (results_markup, buf));
2667 EngineControl::start_latency_detection ()
2669 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2670 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2672 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2673 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2674 if (_measure_midi) {
2675 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2677 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2679 lm_measure_label.set_text (_("Cancel"));
2680 have_lm_results = false;
2681 lm_use_button.set_sensitive (false);
2682 lm_input_channel_combo.set_sensitive (false);
2683 lm_output_channel_combo.set_sensitive (false);
2689 EngineControl::end_latency_detection ()
2691 latency_timeout.disconnect ();
2692 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2693 lm_measure_label.set_text (_("Measure"));
2694 if (!have_lm_results) {
2695 lm_use_button.set_sensitive (false);
2697 lm_input_channel_combo.set_sensitive (true);
2698 lm_output_channel_combo.set_sensitive (true);
2703 EngineControl::latency_button_clicked ()
2706 start_latency_detection ();
2708 end_latency_detection ();
2713 EngineControl::use_latency_button_clicked ()
2715 if (_measure_midi) {
2716 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2720 ARDOUR::framecnt_t frames_total = mididm->latency();
2721 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2722 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2723 _measure_midi->input_latency = one_way;
2724 _measure_midi->output_latency = one_way;
2725 notebook.set_current_page (midi_tab);
2727 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2733 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2734 one_way = std::max (0., one_way);
2736 input_latency_adjustment.set_value (one_way);
2737 output_latency_adjustment.set_value (one_way);
2739 /* back to settings page */
2740 notebook.set_current_page (0);
2746 EngineControl::on_delete_event (GdkEventAny* ev)
2748 if (notebook.get_current_page() == 2) {
2749 /* currently on latency tab - be sure to clean up */
2750 end_latency_detection ();
2752 return ArdourDialog::on_delete_event (ev);
2756 EngineControl::engine_running ()
2758 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2761 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2762 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2764 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2765 connect_disconnect_button.show();
2767 started_at_least_once = true;
2768 if (_have_control) {
2769 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2771 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2773 update_sensitivity();
2777 EngineControl::engine_stopped ()
2779 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2782 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2783 connect_disconnect_button.show();
2785 engine_status.set_markup(X_(""));
2786 update_sensitivity();
2790 EngineControl::device_list_changed ()
2792 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2794 midi_option_changed();
2798 EngineControl::connect_disconnect_click()
2800 if (ARDOUR::AudioEngine::instance()->running()) {
2801 ARDOUR_UI::instance()->disconnect_from_engine ();
2803 ARDOUR_UI::instance()->reconnect_to_engine ();
2808 EngineControl::calibrate_audio_latency ()
2810 _measure_midi.reset ();
2811 have_lm_results = false;
2812 lm_use_button.set_sensitive (false);
2813 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2814 notebook.set_current_page (latency_tab);
2818 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2821 have_lm_results = false;
2822 lm_use_button.set_sensitive (false);
2823 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2824 notebook.set_current_page (latency_tab);
2828 EngineControl::configure_midi_devices ()
2830 notebook.set_current_page (midi_tab);