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 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
280 /* Pick up any existing audio setup configuration, if appropriate */
282 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
284 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
285 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
286 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
287 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
290 if (!set_state (*audio_setup)) {
291 set_default_state ();
294 set_default_state ();
297 connect_changed_signals ();
299 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
301 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
302 connect_disconnect_button.set_no_show_all();
307 EngineControl::connect_changed_signals ()
309 backend_combo_connection = backend_combo.signal_changed ().connect (
310 sigc::mem_fun (*this, &EngineControl::backend_changed));
311 driver_combo_connection = driver_combo.signal_changed ().connect (
312 sigc::mem_fun (*this, &EngineControl::driver_changed));
313 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
314 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
315 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
316 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
317 device_combo_connection = device_combo.signal_changed ().connect (
318 sigc::mem_fun (*this, &EngineControl::device_changed));
319 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
320 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
322 input_device_combo_connection = input_device_combo.signal_changed ().connect (
323 sigc::mem_fun (*this, &EngineControl::input_device_changed));
324 output_device_combo_connection = output_device_combo.signal_changed ().connect (
325 sigc::mem_fun (*this, &EngineControl::output_device_changed));
327 input_latency_connection = input_latency.signal_changed ().connect (
328 sigc::mem_fun (*this, &EngineControl::parameter_changed));
329 output_latency_connection = output_latency.signal_changed ().connect (
330 sigc::mem_fun (*this, &EngineControl::parameter_changed));
331 input_channels_connection = input_channels.signal_changed ().connect (
332 sigc::mem_fun (*this, &EngineControl::parameter_changed));
333 output_channels_connection = output_channels.signal_changed ().connect (
334 sigc::mem_fun (*this, &EngineControl::parameter_changed));
338 EngineControl::block_changed_signals ()
340 if (block_signals++ == 0) {
341 DEBUG_ECONTROL ("Blocking changed signals");
342 backend_combo_connection.block ();
343 driver_combo_connection.block ();
344 sample_rate_combo_connection.block ();
345 buffer_size_combo_connection.block ();
346 device_combo_connection.block ();
347 input_device_combo_connection.block ();
348 output_device_combo_connection.block ();
349 midi_option_combo_connection.block ();
350 input_latency_connection.block ();
351 output_latency_connection.block ();
352 input_channels_connection.block ();
353 output_channels_connection.block ();
358 EngineControl::unblock_changed_signals ()
360 if (--block_signals == 0) {
361 DEBUG_ECONTROL ("Unblocking changed signals");
362 backend_combo_connection.unblock ();
363 driver_combo_connection.unblock ();
364 sample_rate_combo_connection.unblock ();
365 buffer_size_combo_connection.unblock ();
366 device_combo_connection.unblock ();
367 input_device_combo_connection.unblock ();
368 output_device_combo_connection.unblock ();
369 midi_option_combo_connection.unblock ();
370 input_latency_connection.unblock ();
371 output_latency_connection.unblock ();
372 input_channels_connection.unblock ();
373 output_channels_connection.unblock ();
377 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
378 const std::string& reason)
379 : ec (engine_control)
382 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
383 ec.block_changed_signals ();
386 EngineControl::SignalBlocker::~SignalBlocker ()
388 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
389 ec.unblock_changed_signals ();
393 EngineControl::on_show ()
395 ArdourDialog::on_show ();
396 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
397 // re-check _have_control (jackd running) see #6041
401 ok_button->grab_focus();
405 EngineControl::on_response (int response_id)
407 ArdourDialog::on_response (response_id);
409 switch (response_id) {
411 #ifdef PLATFORM_WINDOWS
412 // For some reason we don't understand, 'hide()'
413 // needs to get called first in Windows
416 // But if there's no session open, this can produce
417 // a long gap when nothing appears to be happening.
418 // Let's show the splash image while we're waiting.
419 if ( !ARDOUR_COMMAND_LINE::no_splash ) {
420 if ( ARDOUR_UI::instance() ) {
421 if ( !ARDOUR_UI::instance()->session_loaded ) {
422 ARDOUR_UI::instance()->show_splash();
426 push_state_to_backend (true);
429 push_state_to_backend (true);
433 case RESPONSE_DELETE_EVENT:
436 ev.type = GDK_BUTTON_PRESS;
438 on_delete_event ((GdkEventAny*) &ev);
447 EngineControl::build_notebook ()
450 AttachOptions xopt = AttachOptions (FILL|EXPAND);
452 /* clear the table */
454 Gtkmm2ext::container_clear (basic_vbox);
455 Gtkmm2ext::container_clear (basic_packer);
457 if (control_app_button.get_parent()) {
458 control_app_button.get_parent()->remove (control_app_button);
461 label = manage (left_aligned_label (_("Audio System:")));
462 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
463 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
465 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
466 engine_status.show();
468 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
470 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
471 lm_button_audio.set_name ("generic button");
472 lm_button_audio.set_can_focus(true);
475 build_full_control_notebook ();
477 build_no_control_notebook ();
480 basic_vbox.pack_start (basic_hbox, false, false);
483 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
484 basic_vbox.show_all ();
489 EngineControl::build_full_control_notebook ()
491 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
494 using namespace Notebook_Helpers;
496 vector<string> strings;
497 AttachOptions xopt = AttachOptions (FILL|EXPAND);
498 int row = 1; // row zero == backend combo
500 /* start packing it up */
502 if (backend->requires_driver_selection()) {
503 label = manage (left_aligned_label (_("Driver:")));
504 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
505 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
509 if (backend->use_separate_input_and_output_devices()) {
510 label = manage (left_aligned_label (_("Input Device:")));
511 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
512 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
514 label = manage (left_aligned_label (_("Output Device:")));
515 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
516 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
518 // reset so it isn't used in state comparisons
519 device_combo.set_active_text ("");
521 label = manage (left_aligned_label (_("Device:")));
522 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
523 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
525 // reset these so they don't get used in state comparisons
526 input_device_combo.set_active_text ("");
527 output_device_combo.set_active_text ("");
530 label = manage (left_aligned_label (_("Sample rate:")));
531 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
532 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
536 label = manage (left_aligned_label (_("Buffer size:")));
537 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
538 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
539 buffer_size_duration_label.set_alignment (0.0); /* left-align */
540 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
542 /* button spans 2 rows */
544 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
547 input_channels.set_name ("InputChannels");
548 input_channels.set_flags (Gtk::CAN_FOCUS);
549 input_channels.set_digits (0);
550 input_channels.set_wrap (false);
551 output_channels.set_editable (true);
553 if (!ARDOUR::Profile->get_mixbus()) {
554 label = manage (left_aligned_label (_("Input Channels:")));
555 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
556 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
560 output_channels.set_name ("OutputChannels");
561 output_channels.set_flags (Gtk::CAN_FOCUS);
562 output_channels.set_digits (0);
563 output_channels.set_wrap (false);
564 output_channels.set_editable (true);
566 if (!ARDOUR::Profile->get_mixbus()) {
567 label = manage (left_aligned_label (_("Output Channels:")));
568 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
569 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
573 input_latency.set_name ("InputLatency");
574 input_latency.set_flags (Gtk::CAN_FOCUS);
575 input_latency.set_digits (0);
576 input_latency.set_wrap (false);
577 input_latency.set_editable (true);
579 label = manage (left_aligned_label (_("Hardware input latency:")));
580 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
581 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
582 label = manage (left_aligned_label (_("samples")));
583 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
586 output_latency.set_name ("OutputLatency");
587 output_latency.set_flags (Gtk::CAN_FOCUS);
588 output_latency.set_digits (0);
589 output_latency.set_wrap (false);
590 output_latency.set_editable (true);
592 label = manage (left_aligned_label (_("Hardware output latency:")));
593 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
594 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
595 label = manage (left_aligned_label (_("samples")));
596 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
598 /* button spans 2 rows */
600 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
603 label = manage (left_aligned_label (_("MIDI System:")));
604 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
605 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
606 #if ! defined __APPLE__ && ! defined PLATFORM_WINDOWS // => linux, YAY
607 /* Currently the only backend with dedicated Midi setup is ALSA.
608 * lot of people complain that this is greyed out
609 * "I can't use MIDI, the setup is greyed out"
611 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
617 EngineControl::build_no_control_notebook ()
619 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
622 using namespace Notebook_Helpers;
624 vector<string> strings;
625 AttachOptions xopt = AttachOptions (FILL|EXPAND);
626 int row = 1; // row zero == backend combo
627 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
629 label = manage (new Label);
630 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
631 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
634 if (backend->can_change_sample_rate_when_running()) {
635 label = manage (left_aligned_label (_("Sample rate:")));
636 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
637 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
641 if (backend->can_change_buffer_size_when_running()) {
642 label = manage (left_aligned_label (_("Buffer size:")));
643 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
644 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
645 buffer_size_duration_label.set_alignment (0.0); /* left-align */
646 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
650 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
654 EngineControl::~EngineControl ()
656 ignore_changes = true;
660 EngineControl::disable_latency_tab ()
662 vector<string> empty;
663 set_popdown_strings (lm_output_channel_combo, empty);
664 set_popdown_strings (lm_input_channel_combo, empty);
665 lm_measure_button.set_sensitive (false);
666 lm_use_button.set_sensitive (false);
670 EngineControl::enable_latency_tab ()
672 vector<string> outputs;
673 vector<string> inputs;
675 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
676 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
677 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
679 if (!ARDOUR::AudioEngine::instance()->running()) {
680 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
681 notebook.set_current_page (0);
685 else if (inputs.empty() || outputs.empty()) {
686 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
687 notebook.set_current_page (0);
692 lm_back_button_signal.disconnect();
694 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
697 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
701 set_popdown_strings (lm_output_channel_combo, outputs);
702 lm_output_channel_combo.set_active_text (outputs.front());
703 lm_output_channel_combo.set_sensitive (true);
705 set_popdown_strings (lm_input_channel_combo, inputs);
706 lm_input_channel_combo.set_active_text (inputs.front());
707 lm_input_channel_combo.set_sensitive (true);
709 lm_measure_button.set_sensitive (true);
713 EngineControl::setup_midi_tab_for_backend ()
715 string backend = backend_combo.get_active_text ();
717 Gtkmm2ext::container_clear (midi_vbox);
719 midi_vbox.set_border_width (12);
720 midi_device_table.set_border_width (12);
722 if (backend == "JACK") {
723 setup_midi_tab_for_jack ();
726 midi_vbox.pack_start (midi_device_table, true, true);
727 midi_vbox.pack_start (midi_back_button, false, false);
728 midi_vbox.show_all ();
732 EngineControl::update_sensitivity ()
734 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
736 ok_button->set_sensitive (false);
737 start_stop_button.set_sensitive (false);
742 size_t devices_available = 0;
744 if (backend->use_separate_input_and_output_devices ()) {
745 devices_available += get_popdown_string_count (input_device_combo);
746 devices_available += get_popdown_string_count (output_device_combo);
748 devices_available += get_popdown_string_count (device_combo);
751 if (devices_available == 0) {
753 input_latency.set_sensitive (false);
754 output_latency.set_sensitive (false);
755 input_channels.set_sensitive (false);
756 output_channels.set_sensitive (false);
758 input_latency.set_sensitive (true);
759 output_latency.set_sensitive (true);
760 input_channels.set_sensitive (true);
761 output_channels.set_sensitive (true);
764 if (get_popdown_string_count (buffer_size_combo) > 0) {
765 if (!ARDOUR::AudioEngine::instance()->running()) {
766 buffer_size_combo.set_sensitive (valid);
767 } else if (backend->can_change_sample_rate_when_running()) {
768 buffer_size_combo.set_sensitive (valid || !_have_control);
772 * Currently there is no way to manually stop the
773 * engine in order to re-configure it.
774 * This needs to remain sensitive for now.
776 * (it's also handy to implicily
777 * re-start the engine)
779 buffer_size_combo.set_sensitive (true);
781 buffer_size_combo.set_sensitive (false);
785 buffer_size_combo.set_sensitive (false);
789 if (get_popdown_string_count (sample_rate_combo) > 0) {
790 if (!ARDOUR::AudioEngine::instance()->running()) {
791 sample_rate_combo.set_sensitive (true);
793 sample_rate_combo.set_sensitive (false);
796 sample_rate_combo.set_sensitive (false);
801 start_stop_button.set_sensitive(true);
802 start_stop_button.show();
803 if (ARDOUR::AudioEngine::instance()->running()) {
804 start_stop_button.set_text("Stop");
806 start_stop_button.set_text("Start");
809 start_stop_button.set_sensitive(false);
810 start_stop_button.hide();
813 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
814 input_device_combo.set_sensitive (false);
815 output_device_combo.set_sensitive (false);
816 device_combo.set_sensitive (false);
817 driver_combo.set_sensitive (false);
819 input_device_combo.set_sensitive (true);
820 output_device_combo.set_sensitive (true);
821 device_combo.set_sensitive (true);
822 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
823 driver_combo.set_sensitive (true);
825 driver_combo.set_sensitive (false);
829 if (valid || !_have_control) {
830 ok_button->set_sensitive (true);
832 ok_button->set_sensitive (false);
837 EngineControl::setup_midi_tab_for_jack ()
842 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
844 device->input_latency = a->get_value();
846 device->output_latency = a->get_value();
851 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
852 b->set_active (!b->get_active());
853 device->enabled = b->get_active();
854 refresh_midi_display(device->name);
858 EngineControl::refresh_midi_display (std::string focus)
860 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
864 AttachOptions xopt = AttachOptions (FILL|EXPAND);
867 Gtkmm2ext::container_clear (midi_device_table);
869 midi_device_table.set_spacings (6);
871 l = manage (new Label);
872 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
873 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
874 l->set_alignment (0.5, 0.5);
878 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
879 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
880 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
881 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
883 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
884 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
885 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
886 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
889 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
894 bool enabled = (*p)->enabled;
896 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
897 m->set_name ("midi device");
898 m->set_can_focus (Gtk::CAN_FOCUS);
899 m->add_events (Gdk::BUTTON_RELEASE_MASK);
900 m->set_active (enabled);
901 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
902 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
903 if ((*p)->name == focus) {
907 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
908 s = manage (new Gtk::SpinButton (*a));
909 a->set_value ((*p)->input_latency);
910 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
911 s->set_sensitive (_can_set_midi_latencies && enabled);
912 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
914 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
915 s = manage (new Gtk::SpinButton (*a));
916 a->set_value ((*p)->output_latency);
917 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
918 s->set_sensitive (_can_set_midi_latencies && enabled);
919 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
921 b = manage (new Button (_("Calibrate")));
922 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
923 b->set_sensitive (_can_set_midi_latencies && enabled);
924 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
931 EngineControl::backend_changed ()
933 SignalBlocker blocker (*this, "backend_changed");
934 string backend_name = backend_combo.get_active_text();
935 boost::shared_ptr<ARDOUR::AudioBackend> backend;
937 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (PROGRAM_NAME), ""))) {
938 /* eh? setting the backend failed... how ? */
939 /* A: stale config contains a backend that does not exist in current build */
943 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
945 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
948 setup_midi_tab_for_backend ();
949 _midi_devices.clear();
951 if (backend->requires_driver_selection()) {
952 if (set_driver_popdown_strings ()) {
956 /* this will change the device text which will cause a call to
957 * device changed which will set up parameters
962 update_midi_options ();
964 connect_disconnect_button.hide();
966 midi_option_changed();
968 started_at_least_once = false;
970 /* changing the backend implies stopping the engine
971 * ARDOUR::AudioEngine() may or may not emit this signal
972 * depending on previous engine state
974 engine_stopped (); // set "active/inactive"
976 if (!ignore_changes) {
977 maybe_display_saved_state ();
982 EngineControl::update_midi_options ()
984 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
985 vector<string> midi_options = backend->enumerate_midi_options();
987 if (midi_options.size() == 1) {
988 /* only contains the "none" option */
989 midi_option_combo.set_sensitive (false);
992 set_popdown_strings (midi_option_combo, midi_options);
993 midi_option_combo.set_active_text (midi_options.front());
994 midi_option_combo.set_sensitive (true);
996 midi_option_combo.set_sensitive (false);
1002 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1004 if (ARDOUR::Profile->get_mixbus()) {
1008 uint32_t cnt = (uint32_t) sb->get_value();
1010 sb->set_text (_("all available channels"));
1013 snprintf (buf, sizeof (buf), "%d", cnt);
1019 // @return true if there are drivers available
1021 EngineControl::set_driver_popdown_strings ()
1023 DEBUG_ECONTROL ("set_driver_popdown_strings");
1024 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1025 vector<string> drivers = backend->enumerate_drivers();
1027 if (drivers.empty ()) {
1028 // This is an error...?
1032 string current_driver = backend->driver_name ();
1034 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1036 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1039 current_driver = drivers.front ();
1042 set_popdown_strings (driver_combo, drivers);
1044 string_compose ("driver_combo.set_active_text: %1", current_driver));
1045 driver_combo.set_active_text (current_driver);
1049 // @return true if there are devices available
1051 EngineControl::set_device_popdown_strings ()
1053 DEBUG_ECONTROL ("set_device_popdown_strings");
1054 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1055 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1057 /* NOTE: Ardour currently does not display the "available" field of the
1060 * Doing so would require a different GUI widget than the combo
1061 * box/popdown that we currently use, since it has no way to list
1062 * items that are not selectable. Something more like a popup menu,
1063 * which could have unselectable items, would be appropriate.
1066 vector<string> available_devices;
1068 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1069 available_devices.push_back (i->name);
1072 if (available_devices.empty ()) {
1076 string current_device = backend->device_name ();
1078 // Make sure that backend->device_name () is a valid
1079 // device, the backend may not return a valid device if it hasn't
1081 if (std::find (available_devices.begin (),
1082 available_devices.end (),
1083 current_device) == available_devices.end ()) {
1085 current_device = available_devices.front ();
1088 set_popdown_strings (device_combo, available_devices);
1090 string_compose ("set device_combo active text: %1", current_device));
1092 device_combo.set_active_text (current_device);
1096 // @return true if there are input devices available
1098 EngineControl::set_input_device_popdown_strings ()
1100 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1101 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1102 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1104 vector<string> available_devices;
1106 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1107 available_devices.push_back (i->name);
1110 if (available_devices.empty()) {
1114 string current_device = backend->input_device_name ();
1116 // Make sure that backend->input_device_name () is a valid
1117 // device, the backend may not return a valid device if it hasn't
1119 if (std::find (available_devices.begin (),
1120 available_devices.end (),
1121 current_device) == available_devices.end ()) {
1123 current_device = available_devices.front ();
1126 set_popdown_strings (input_device_combo, available_devices);
1129 string_compose ("set input_device_combo active text: %1", current_device));
1130 input_device_combo.set_active_text (current_device);
1134 // @return true if there are output devices available
1136 EngineControl::set_output_device_popdown_strings ()
1138 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1139 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1140 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1142 vector<string> available_devices;
1144 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1145 available_devices.push_back (i->name);
1148 if (available_devices.empty()) {
1152 string current_device = backend->output_device_name ();
1154 // Make sure that backend->output_device_name () is a valid
1155 // device, the backend may not return a valid device if it hasn't
1157 if (std::find (available_devices.begin (),
1158 available_devices.end (),
1159 current_device) == available_devices.end ()) {
1161 current_device = available_devices.front ();
1164 set_popdown_strings (output_device_combo, available_devices);
1167 string_compose ("set output_device_combo active text: %1", current_device));
1168 output_device_combo.set_active_text (current_device);
1173 EngineControl::list_devices ()
1175 DEBUG_ECONTROL ("list_devices");
1176 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1179 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1181 bool devices_available = false;
1183 if (backend->use_separate_input_and_output_devices ()) {
1184 bool input_devices_available = set_input_device_popdown_strings ();
1185 bool output_devices_available = set_output_device_popdown_strings ();
1186 devices_available = input_devices_available || output_devices_available;
1188 devices_available = set_device_popdown_strings ();
1191 if (devices_available) {
1194 device_combo.clear();
1195 input_device_combo.clear();
1196 output_device_combo.clear();
1198 update_sensitivity ();
1202 EngineControl::driver_changed ()
1204 SignalBlocker blocker (*this, "driver_changed");
1205 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1208 backend->set_driver (driver_combo.get_active_text());
1211 if (!ignore_changes) {
1212 maybe_display_saved_state ();
1217 EngineControl::get_sample_rates_for_all_devices ()
1219 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1220 ARDOUR::AudioEngine::instance ()->current_backend ();
1221 vector<float> all_rates;
1223 if (backend->use_separate_input_and_output_devices ()) {
1224 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1226 all_rates = backend->available_sample_rates (get_device_name ());
1232 EngineControl::get_default_sample_rates ()
1234 vector<float> rates;
1235 rates.push_back (8000.0f);
1236 rates.push_back (16000.0f);
1237 rates.push_back (32000.0f);
1238 rates.push_back (44100.0f);
1239 rates.push_back (48000.0f);
1240 rates.push_back (88200.0f);
1241 rates.push_back (96000.0f);
1242 rates.push_back (192000.0f);
1243 rates.push_back (384000.0f);
1248 EngineControl::set_samplerate_popdown_strings ()
1250 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1251 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1256 if (_have_control) {
1257 sr = get_sample_rates_for_all_devices ();
1259 sr = get_default_sample_rates ();
1262 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1263 s.push_back (rate_as_string (*x));
1264 if (*x == _desired_sample_rate) {
1269 set_popdown_strings (sample_rate_combo, s);
1272 if (desired.empty ()) {
1273 float new_active_sr = backend->default_sample_rate ();
1275 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1276 new_active_sr = sr.front ();
1279 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1281 sample_rate_combo.set_active_text (desired);
1285 update_sensitivity ();
1289 EngineControl::get_buffer_sizes_for_all_devices ()
1291 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1292 ARDOUR::AudioEngine::instance ()->current_backend ();
1293 vector<uint32_t> all_sizes;
1295 if (backend->use_separate_input_and_output_devices ()) {
1296 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1298 all_sizes = backend->available_buffer_sizes (get_device_name ());
1304 EngineControl::get_default_buffer_sizes ()
1306 vector<uint32_t> sizes;
1307 sizes.push_back (8);
1308 sizes.push_back (16);
1309 sizes.push_back (32);
1310 sizes.push_back (64);
1311 sizes.push_back (128);
1312 sizes.push_back (256);
1313 sizes.push_back (512);
1314 sizes.push_back (1024);
1315 sizes.push_back (2048);
1316 sizes.push_back (4096);
1317 sizes.push_back (8192);
1322 EngineControl::set_buffersize_popdown_strings ()
1324 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1325 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1326 vector<uint32_t> bs;
1329 if (_have_control) {
1330 bs = get_buffer_sizes_for_all_devices ();
1331 } else if (backend->can_change_buffer_size_when_running()) {
1332 bs = get_default_buffer_sizes ();
1335 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1336 s.push_back (bufsize_as_string (*x));
1339 set_popdown_strings (buffer_size_combo, s);
1342 buffer_size_combo.set_active_text (s.front());
1344 uint32_t period = backend->buffer_size();
1345 if (0 == period && backend->use_separate_input_and_output_devices ()) {
1346 period = backend->default_buffer_size (get_input_device_name ());
1348 if (0 == period && backend->use_separate_input_and_output_devices ()) {
1349 period = backend->default_buffer_size (get_output_device_name ());
1351 if (0 == period && !backend->use_separate_input_and_output_devices ()) {
1352 period = backend->default_buffer_size (get_device_name ());
1355 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1356 show_buffer_duration ();
1358 update_sensitivity ();
1362 EngineControl::device_changed ()
1364 SignalBlocker blocker (*this, "device_changed");
1365 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1368 string device_name_in;
1369 string device_name_out; // only used if backend support separate I/O devices
1371 if (backend->use_separate_input_and_output_devices()) {
1372 device_name_in = get_input_device_name ();
1373 device_name_out = get_output_device_name ();
1375 device_name_in = get_device_name ();
1378 /* we set the backend-device to query various device related intormation.
1379 * This has the side effect that backend->device_name() will match
1380 * the device_name and 'change_device' will never be true.
1381 * so work around this by setting...
1383 if (backend->use_separate_input_and_output_devices()) {
1384 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1385 queue_device_changed = true;
1388 if (device_name_in != backend->device_name()) {
1389 queue_device_changed = true;
1393 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1394 if (backend->use_separate_input_and_output_devices()) {
1395 backend->set_input_device_name (device_name_in);
1396 backend->set_output_device_name (device_name_out);
1398 backend->set_device_name(device_name_in);
1402 /* don't allow programmatic change to combos to cause a
1403 recursive call to this method.
1405 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1407 set_samplerate_popdown_strings ();
1408 set_buffersize_popdown_strings ();
1410 /* TODO set min + max channel counts here */
1412 manage_control_app_sensitivity ();
1415 /* pick up any saved state for this device */
1417 if (!ignore_changes) {
1418 maybe_display_saved_state ();
1423 EngineControl::input_device_changed ()
1425 DEBUG_ECONTROL ("input_device_changed");
1430 EngineControl::output_device_changed ()
1432 DEBUG_ECONTROL ("output_device_changed");
1437 EngineControl::bufsize_as_string (uint32_t sz)
1439 /* Translators: "samples" is always plural here, so no
1440 need for plural+singular forms.
1443 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1448 EngineControl::sample_rate_changed ()
1450 DEBUG_ECONTROL ("sample_rate_changed");
1451 /* reset the strings for buffer size to show the correct msec value
1452 (reflecting the new sample rate).
1455 show_buffer_duration ();
1460 EngineControl::buffer_size_changed ()
1462 DEBUG_ECONTROL ("buffer_size_changed");
1463 show_buffer_duration ();
1467 EngineControl::show_buffer_duration ()
1469 DEBUG_ECONTROL ("show_buffer_duration");
1470 /* buffer sizes - convert from just samples to samples + msecs for
1471 * the displayed string
1474 string bs_text = buffer_size_combo.get_active_text ();
1475 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1476 uint32_t rate = get_rate();
1478 /* Developers: note the hard-coding of a double buffered model
1479 in the (2 * samples) computation of latency. we always start
1480 the audiobackend in this configuration.
1482 /* note to jack1 developers: ardour also always starts the engine
1483 * in async mode (no jack2 --sync option) which adds an extra cycle
1484 * of latency with jack2 (and *3 would be correct)
1485 * The value can also be wrong if jackd is started externally..
1487 * At the time of writing the ALSA backend always uses double-buffering *2,
1488 * The Dummy backend *1, and who knows what ASIO really does :)
1490 * So just display the period size, that's also what
1491 * ARDOUR_UI::update_sample_rate() does for the status bar.
1492 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1493 * but still, that's the buffer period, not [round-trip] latency)
1496 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1497 buffer_size_duration_label.set_text (buf);
1501 EngineControl::midi_option_changed ()
1503 DEBUG_ECONTROL ("midi_option_changed");
1504 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1507 backend->set_midi_option (get_midi_option());
1509 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1511 //_midi_devices.clear(); // TODO merge with state-saved settings..
1512 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1513 std::vector<MidiDeviceSettings> new_devices;
1515 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1516 MidiDeviceSettings mds = find_midi_device (i->name);
1517 if (i->available && !mds) {
1518 uint32_t input_latency = 0;
1519 uint32_t output_latency = 0;
1520 if (_can_set_midi_latencies) {
1521 input_latency = backend->systemic_midi_input_latency (i->name);
1522 output_latency = backend->systemic_midi_output_latency (i->name);
1524 bool enabled = backend->midi_device_enabled (i->name);
1525 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1526 new_devices.push_back (ptr);
1527 } else if (i->available) {
1528 new_devices.push_back (mds);
1531 _midi_devices = new_devices;
1533 if (_midi_devices.empty()) {
1534 midi_devices_button.set_sensitive (false);
1536 midi_devices_button.set_sensitive (true);
1541 EngineControl::parameter_changed ()
1545 EngineControl::State
1546 EngineControl::get_matching_state (
1547 const string& backend,
1548 const string& driver,
1549 const string& device)
1551 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1552 if ((*i)->backend == backend &&
1553 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1561 EngineControl::State
1562 EngineControl::get_matching_state (
1563 const string& backend,
1564 const string& driver,
1565 const string& input_device,
1566 const string& output_device)
1568 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1569 if ((*i)->backend == backend &&
1570 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1578 EngineControl::State
1579 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1581 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1584 if (backend->use_separate_input_and_output_devices ()) {
1585 return get_matching_state (backend_combo.get_active_text(),
1586 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1587 input_device_combo.get_active_text(),
1588 output_device_combo.get_active_text());
1590 return get_matching_state (backend_combo.get_active_text(),
1591 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1592 device_combo.get_active_text());
1596 return get_matching_state (backend_combo.get_active_text(),
1598 device_combo.get_active_text());
1601 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1602 const EngineControl::State& state2)
1604 if (state1->backend == state2->backend &&
1605 state1->driver == state2->driver &&
1606 state1->device == state2->device &&
1607 state1->input_device == state2->input_device &&
1608 state1->output_device == state2->output_device) {
1614 EngineControl::State
1615 EngineControl::save_state ()
1619 if (!_have_control) {
1620 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1624 state.reset(new StateStruct);
1625 state->backend = get_backend ();
1627 state.reset(new StateStruct);
1628 store_state (state);
1631 for (StateList::iterator i = states.begin(); i != states.end();) {
1632 if (equivalent_states (*i, state)) {
1633 i = states.erase(i);
1639 states.push_back (state);
1645 EngineControl::store_state (State state)
1647 state->backend = get_backend ();
1648 state->driver = get_driver ();
1649 state->device = get_device_name ();
1650 state->input_device = get_input_device_name ();
1651 state->output_device = get_output_device_name ();
1652 state->sample_rate = get_rate ();
1653 state->buffer_size = get_buffer_size ();
1654 state->input_latency = get_input_latency ();
1655 state->output_latency = get_output_latency ();
1656 state->input_channels = get_input_channels ();
1657 state->output_channels = get_output_channels ();
1658 state->midi_option = get_midi_option ();
1659 state->midi_devices = _midi_devices;
1663 EngineControl::maybe_display_saved_state ()
1665 if (!_have_control) {
1669 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1672 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1674 if (!_desired_sample_rate) {
1675 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1677 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1678 /* call this explicitly because we're ignoring changes to
1679 the controls at this point.
1681 show_buffer_duration ();
1682 input_latency.set_value (state->input_latency);
1683 output_latency.set_value (state->output_latency);
1685 if (!state->midi_option.empty()) {
1686 midi_option_combo.set_active_text (state->midi_option);
1687 _midi_devices = state->midi_devices;
1693 EngineControl::get_state ()
1695 LocaleGuard lg (X_("C"));
1697 XMLNode* root = new XMLNode ("AudioMIDISetup");
1700 if (!states.empty()) {
1701 XMLNode* state_nodes = new XMLNode ("EngineStates");
1703 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1705 XMLNode* node = new XMLNode ("State");
1707 node->add_property ("backend", (*i)->backend);
1708 node->add_property ("driver", (*i)->driver);
1709 node->add_property ("device", (*i)->device);
1710 node->add_property ("input-device", (*i)->input_device);
1711 node->add_property ("output-device", (*i)->output_device);
1712 node->add_property ("sample-rate", (*i)->sample_rate);
1713 node->add_property ("buffer-size", (*i)->buffer_size);
1714 node->add_property ("input-latency", (*i)->input_latency);
1715 node->add_property ("output-latency", (*i)->output_latency);
1716 node->add_property ("input-channels", (*i)->input_channels);
1717 node->add_property ("output-channels", (*i)->output_channels);
1718 node->add_property ("active", (*i)->active ? "yes" : "no");
1719 node->add_property ("midi-option", (*i)->midi_option);
1721 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1722 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1723 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1724 midi_device_stuff->add_property (X_("name"), (*p)->name);
1725 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1726 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1727 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1728 midi_devices->add_child_nocopy (*midi_device_stuff);
1730 node->add_child_nocopy (*midi_devices);
1732 state_nodes->add_child_nocopy (*node);
1735 root->add_child_nocopy (*state_nodes);
1742 EngineControl::set_default_state ()
1744 vector<string> backend_names;
1745 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1747 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1748 backend_names.push_back ((*b)->name);
1750 backend_combo.set_active_text (backend_names.front());
1752 // We could set default backends per platform etc here
1758 EngineControl::set_state (const XMLNode& root)
1760 XMLNodeList clist, cclist;
1761 XMLNodeConstIterator citer, cciter;
1763 XMLNode* grandchild;
1764 XMLProperty* prop = NULL;
1766 fprintf (stderr, "EngineControl::set_state\n");
1768 if (root.name() != "AudioMIDISetup") {
1772 clist = root.children();
1776 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1780 if (child->name() != "EngineStates") {
1784 cclist = child->children();
1786 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1787 State state (new StateStruct);
1789 grandchild = *cciter;
1791 if (grandchild->name() != "State") {
1795 if ((prop = grandchild->property ("backend")) == 0) {
1798 state->backend = prop->value ();
1800 if ((prop = grandchild->property ("driver")) == 0) {
1803 state->driver = prop->value ();
1805 if ((prop = grandchild->property ("device")) == 0) {
1808 state->device = prop->value ();
1810 if ((prop = grandchild->property ("input-device")) == 0) {
1813 state->input_device = prop->value ();
1815 if ((prop = grandchild->property ("output-device")) == 0) {
1818 state->output_device = prop->value ();
1820 if ((prop = grandchild->property ("sample-rate")) == 0) {
1823 state->sample_rate = atof (prop->value ());
1825 if ((prop = grandchild->property ("buffer-size")) == 0) {
1828 state->buffer_size = atoi (prop->value ());
1830 if ((prop = grandchild->property ("input-latency")) == 0) {
1833 state->input_latency = atoi (prop->value ());
1835 if ((prop = grandchild->property ("output-latency")) == 0) {
1838 state->output_latency = atoi (prop->value ());
1840 if ((prop = grandchild->property ("input-channels")) == 0) {
1843 state->input_channels = atoi (prop->value ());
1845 if ((prop = grandchild->property ("output-channels")) == 0) {
1848 state->output_channels = atoi (prop->value ());
1850 if ((prop = grandchild->property ("active")) == 0) {
1853 state->active = string_is_affirmative (prop->value ());
1855 if ((prop = grandchild->property ("midi-option")) == 0) {
1858 state->midi_option = prop->value ();
1860 state->midi_devices.clear();
1862 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1863 const XMLNodeList mnc = midinode->children();
1864 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1865 if ((*n)->property (X_("name")) == 0
1866 || (*n)->property (X_("enabled")) == 0
1867 || (*n)->property (X_("input-latency")) == 0
1868 || (*n)->property (X_("output-latency")) == 0
1873 MidiDeviceSettings ptr (new MidiDeviceSetting(
1874 (*n)->property (X_("name"))->value (),
1875 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1876 atoi ((*n)->property (X_("input-latency"))->value ()),
1877 atoi ((*n)->property (X_("output-latency"))->value ())
1879 state->midi_devices.push_back (ptr);
1884 /* remove accumulated duplicates (due to bug in ealier version)
1885 * this can be removed again before release
1887 for (StateList::iterator i = states.begin(); i != states.end();) {
1888 if ((*i)->backend == state->backend &&
1889 (*i)->driver == state->driver &&
1890 (*i)->device == state->device) {
1891 i = states.erase(i);
1898 states.push_back (state);
1902 /* now see if there was an active state and switch the setup to it */
1904 // purge states of backend that are not available in this built
1905 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1906 vector<std::string> backend_names;
1908 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1909 backend_names.push_back((*i)->name);
1911 for (StateList::iterator i = states.begin(); i != states.end();) {
1912 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1913 i = states.erase(i);
1919 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1922 return set_current_state (*i);
1929 EngineControl::set_current_state (const State& state)
1931 DEBUG_ECONTROL ("set_current_state");
1933 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1935 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1936 state->backend, downcase (PROGRAM_NAME), ""))) {
1937 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1938 // this shouldn't happen as the invalid backend names should have been
1939 // removed from the list of states.
1943 // now reflect the change in the backend in the GUI so backend_changed will
1944 // do the right thing
1945 backend_combo.set_active_text (state->backend);
1947 if (!state->driver.empty ()) {
1948 if (!backend->requires_driver_selection ()) {
1949 DEBUG_ECONTROL ("Backend should require driver selection");
1950 // A backend has changed from having driver selection to not having
1951 // it or someone has been manually editing a config file and messed
1956 if (backend->set_driver (state->driver) != 0) {
1957 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
1958 // Driver names for a backend have changed and the name in the
1959 // config file is now invalid or support for driver is no longer
1960 // included in the backend
1963 // no need to set the driver_combo as backend_changed will use
1964 // backend->driver_name to set the active driver
1967 if (!state->device.empty ()) {
1968 if (backend->set_device_name (state->device) != 0) {
1970 string_compose ("Unable to set device name %1", state->device));
1971 // device is no longer available on the system
1974 // no need to set active device as it will be picked up in
1975 // via backend_changed ()/set_device_popdown_strings
1978 // backend supports separate input/output devices
1979 if (backend->set_input_device_name (state->input_device) != 0) {
1980 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
1981 state->input_device));
1982 // input device is no longer available on the system
1986 if (backend->set_output_device_name (state->output_device) != 0) {
1987 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
1988 state->input_device));
1989 // output device is no longer available on the system
1992 // no need to set active devices as it will be picked up in via
1993 // backend_changed ()/set_*_device_popdown_strings
1998 // Now restore the state of the rest of the controls
2000 // We don't use a SignalBlocker as set_current_state is currently only
2001 // called from set_state before any signals are connected. If at some point
2002 // a more general named state mechanism is implemented and
2003 // set_current_state is called while signals are connected then a
2004 // SignalBlocker will need to be instantiated before setting these.
2006 device_combo.set_active_text (state->device);
2007 input_device_combo.set_active_text (state->input_device);
2008 output_device_combo.set_active_text (state->output_device);
2009 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2010 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2011 input_latency.set_value (state->input_latency);
2012 output_latency.set_value (state->output_latency);
2013 midi_option_combo.set_active_text (state->midi_option);
2018 EngineControl::push_state_to_backend (bool start)
2020 DEBUG_ECONTROL ("push_state_to_backend");
2021 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2027 /* figure out what is going to change */
2029 bool restart_required = false;
2030 bool was_running = ARDOUR::AudioEngine::instance()->running();
2031 bool change_driver = false;
2032 bool change_device = false;
2033 bool change_rate = false;
2034 bool change_bufsize = false;
2035 bool change_latency = false;
2036 bool change_channels = false;
2037 bool change_midi = false;
2039 uint32_t ochan = get_output_channels ();
2040 uint32_t ichan = get_input_channels ();
2042 if (_have_control) {
2044 if (started_at_least_once) {
2046 /* we can control the backend */
2048 if (backend->requires_driver_selection()) {
2049 if (get_driver() != backend->driver_name()) {
2050 change_driver = true;
2054 if (backend->use_separate_input_and_output_devices()) {
2055 if (get_input_device_name() != backend->input_device_name()) {
2056 change_device = true;
2058 if (get_output_device_name() != backend->output_device_name()) {
2059 change_device = true;
2062 if (get_device_name() != backend->device_name()) {
2063 change_device = true;
2067 if (queue_device_changed) {
2068 change_device = true;
2071 if (get_rate() != backend->sample_rate()) {
2075 if (get_buffer_size() != backend->buffer_size()) {
2076 change_bufsize = true;
2079 if (get_midi_option() != backend->midi_option()) {
2083 /* zero-requested channels means "all available" */
2086 ichan = backend->input_channels();
2090 ochan = backend->output_channels();
2093 if (ichan != backend->input_channels()) {
2094 change_channels = true;
2097 if (ochan != backend->output_channels()) {
2098 change_channels = true;
2101 if (get_input_latency() != backend->systemic_input_latency() ||
2102 get_output_latency() != backend->systemic_output_latency()) {
2103 change_latency = true;
2106 /* backend never started, so we have to force a group
2109 change_device = true;
2110 if (backend->requires_driver_selection()) {
2111 change_driver = true;
2114 change_bufsize = true;
2115 change_channels = true;
2116 change_latency = true;
2122 /* we have no control over the backend, meaning that we can
2123 * only possibly change sample rate and buffer size.
2127 if (get_rate() != backend->sample_rate()) {
2128 change_bufsize = true;
2131 if (get_buffer_size() != backend->buffer_size()) {
2132 change_bufsize = true;
2136 queue_device_changed = false;
2138 if (!_have_control) {
2140 /* We do not have control over the backend, so the best we can
2141 * do is try to change the sample rate and/or bufsize and get
2145 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2149 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2154 backend->set_sample_rate (get_rate());
2157 if (change_bufsize) {
2158 backend->set_buffer_size (get_buffer_size());
2162 if (ARDOUR::AudioEngine::instance()->start ()) {
2163 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2173 /* determine if we need to stop the backend before changing parameters */
2175 if (change_driver || change_device || change_channels || change_latency ||
2176 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2178 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2179 restart_required = true;
2181 restart_required = false;
2186 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2187 /* no changes in any parameters that absolutely require a
2188 * restart, so check those that might be changeable without a
2192 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2193 /* can't do this while running ... */
2194 restart_required = true;
2197 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2198 /* can't do this while running ... */
2199 restart_required = true;
2205 if (restart_required) {
2206 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2213 if (change_driver && backend->set_driver (get_driver())) {
2214 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2217 if (backend->use_separate_input_and_output_devices()) {
2218 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2219 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2222 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2223 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2227 if (change_device && backend->set_device_name (get_device_name())) {
2228 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2232 if (change_rate && backend->set_sample_rate (get_rate())) {
2233 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2236 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2237 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2241 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2242 if (backend->set_input_channels (get_input_channels())) {
2243 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2246 if (backend->set_output_channels (get_output_channels())) {
2247 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2251 if (change_latency) {
2252 if (backend->set_systemic_input_latency (get_input_latency())) {
2253 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2256 if (backend->set_systemic_output_latency (get_output_latency())) {
2257 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2263 backend->set_midi_option (get_midi_option());
2267 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2268 if (_measure_midi) {
2269 if (*p == _measure_midi) {
2270 backend->set_midi_device_enabled ((*p)->name, true);
2272 backend->set_midi_device_enabled ((*p)->name, false);
2276 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2277 if (backend->can_set_systemic_midi_latencies()) {
2278 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2279 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2284 if (start || (was_running && restart_required)) {
2285 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2296 EngineControl::post_push ()
2298 /* get a pointer to the current state object, creating one if
2302 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2305 state = save_state ();
2313 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2314 (*i)->active = false;
2317 /* mark this one active (to be used next time the dialog is
2321 state->active = true;
2323 if (_have_control) { // XXX
2324 manage_control_app_sensitivity ();
2327 /* schedule a redisplay of MIDI ports */
2328 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2333 EngineControl::get_rate () const
2335 float r = atof (sample_rate_combo.get_active_text ());
2336 /* the string may have been translated with an abbreviation for
2337 * thousands, so use a crude heuristic to fix this.
2347 EngineControl::get_buffer_size () const
2349 string txt = buffer_size_combo.get_active_text ();
2352 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2353 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2354 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2362 EngineControl::get_midi_option () const
2364 return midi_option_combo.get_active_text();
2368 EngineControl::get_input_channels() const
2370 if (ARDOUR::Profile->get_mixbus()) {
2371 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2372 if (!backend) return 0;
2373 return backend->input_channels();
2375 return (uint32_t) input_channels_adjustment.get_value();
2379 EngineControl::get_output_channels() const
2381 if (ARDOUR::Profile->get_mixbus()) {
2382 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2383 if (!backend) return 0;
2384 return backend->input_channels();
2386 return (uint32_t) output_channels_adjustment.get_value();
2390 EngineControl::get_input_latency() const
2392 return (uint32_t) input_latency_adjustment.get_value();
2396 EngineControl::get_output_latency() const
2398 return (uint32_t) output_latency_adjustment.get_value();
2402 EngineControl::get_backend () const
2404 return backend_combo.get_active_text ();
2408 EngineControl::get_driver () const
2410 if (driver_combo.get_parent()) {
2411 return driver_combo.get_active_text ();
2418 EngineControl::get_device_name () const
2420 return device_combo.get_active_text ();
2424 EngineControl::get_input_device_name () const
2426 return input_device_combo.get_active_text ();
2430 EngineControl::get_output_device_name () const
2432 return output_device_combo.get_active_text ();
2436 EngineControl::control_app_button_clicked ()
2438 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2444 backend->launch_control_app ();
2448 EngineControl::start_stop_button_clicked ()
2450 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2456 if (ARDOUR::AudioEngine::instance()->running()) {
2457 ARDOUR::AudioEngine::instance()->stop ();
2459 push_state_to_backend (true);
2464 EngineControl::manage_control_app_sensitivity ()
2466 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2472 string appname = backend->control_app_name();
2474 if (appname.empty()) {
2475 control_app_button.set_sensitive (false);
2477 control_app_button.set_sensitive (true);
2482 EngineControl::set_desired_sample_rate (uint32_t sr)
2484 _desired_sample_rate = sr;
2489 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2491 if (page_num == 0) {
2492 cancel_button->set_sensitive (true);
2493 _measure_midi.reset();
2494 update_sensitivity ();
2496 cancel_button->set_sensitive (false);
2497 ok_button->set_sensitive (false);
2500 if (page_num == midi_tab) {
2502 refresh_midi_display ();
2505 if (page_num == latency_tab) {
2508 if (ARDOUR::AudioEngine::instance()->running()) {
2509 // TODO - mark as 'stopped for latency
2510 ARDOUR_UI::instance()->disconnect_from_engine ();
2514 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2516 /* save any existing latency values */
2518 uint32_t il = (uint32_t) input_latency.get_value ();
2519 uint32_t ol = (uint32_t) input_latency.get_value ();
2521 /* reset to zero so that our new test instance
2522 will be clean of any existing latency measures.
2524 NB. this should really be done by the backend
2525 when stated for latency measurement.
2528 input_latency.set_value (0);
2529 output_latency.set_value (0);
2531 push_state_to_backend (false);
2535 input_latency.set_value (il);
2536 output_latency.set_value (ol);
2539 // This should be done in push_state_to_backend()
2540 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2541 disable_latency_tab ();
2544 enable_latency_tab ();
2548 end_latency_detection ();
2549 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2554 /* latency measurement */
2557 EngineControl::check_audio_latency_measurement ()
2559 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2561 if (mtdm->resolve () < 0) {
2562 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2566 if (mtdm->err () > 0.3) {
2572 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2574 if (sample_rate == 0) {
2575 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2576 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2580 int frames_total = mtdm->del();
2581 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2583 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2584 _("Detected roundtrip latency: "),
2585 frames_total, frames_total * 1000.0f/sample_rate,
2586 _("Systemic latency: "),
2587 extra, extra * 1000.0f/sample_rate);
2591 if (mtdm->err () > 0.2) {
2593 strcat (buf, _("(signal detection error)"));
2599 strcat (buf, _("(inverted - bad wiring)"));
2603 lm_results.set_markup (string_compose (results_markup, buf));
2606 have_lm_results = true;
2607 end_latency_detection ();
2608 lm_use_button.set_sensitive (true);
2616 EngineControl::check_midi_latency_measurement ()
2618 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2620 if (!mididm->have_signal () || mididm->latency () == 0) {
2621 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2626 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2628 if (sample_rate == 0) {
2629 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2630 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2634 ARDOUR::framecnt_t frames_total = mididm->latency();
2635 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2636 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2637 _("Detected roundtrip latency: "),
2638 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2639 _("Systemic latency: "),
2640 extra, extra * 1000.0f / sample_rate);
2644 if (!mididm->ok ()) {
2646 strcat (buf, _("(averaging)"));
2650 if (mididm->deviation () > 50.0) {
2652 strcat (buf, _("(too large jitter)"));
2654 } else if (mididm->deviation () > 10.0) {
2656 strcat (buf, _("(large jitter)"));
2660 have_lm_results = true;
2661 end_latency_detection ();
2662 lm_use_button.set_sensitive (true);
2663 lm_results.set_markup (string_compose (results_markup, buf));
2665 } else if (mididm->processed () > 400) {
2666 have_lm_results = false;
2667 end_latency_detection ();
2668 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2672 lm_results.set_markup (string_compose (results_markup, buf));
2678 EngineControl::start_latency_detection ()
2680 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2681 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2683 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2684 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2685 if (_measure_midi) {
2686 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2688 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2690 lm_measure_label.set_text (_("Cancel"));
2691 have_lm_results = false;
2692 lm_use_button.set_sensitive (false);
2693 lm_input_channel_combo.set_sensitive (false);
2694 lm_output_channel_combo.set_sensitive (false);
2700 EngineControl::end_latency_detection ()
2702 latency_timeout.disconnect ();
2703 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2704 lm_measure_label.set_text (_("Measure"));
2705 if (!have_lm_results) {
2706 lm_use_button.set_sensitive (false);
2708 lm_input_channel_combo.set_sensitive (true);
2709 lm_output_channel_combo.set_sensitive (true);
2714 EngineControl::latency_button_clicked ()
2717 start_latency_detection ();
2719 end_latency_detection ();
2724 EngineControl::use_latency_button_clicked ()
2726 if (_measure_midi) {
2727 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2731 ARDOUR::framecnt_t frames_total = mididm->latency();
2732 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2733 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2734 _measure_midi->input_latency = one_way;
2735 _measure_midi->output_latency = one_way;
2736 notebook.set_current_page (midi_tab);
2738 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2744 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2745 one_way = std::max (0., one_way);
2747 input_latency_adjustment.set_value (one_way);
2748 output_latency_adjustment.set_value (one_way);
2750 /* back to settings page */
2751 notebook.set_current_page (0);
2757 EngineControl::on_delete_event (GdkEventAny* ev)
2759 if (notebook.get_current_page() == 2) {
2760 /* currently on latency tab - be sure to clean up */
2761 end_latency_detection ();
2763 return ArdourDialog::on_delete_event (ev);
2767 EngineControl::engine_running ()
2769 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2772 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2773 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2775 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2776 connect_disconnect_button.show();
2778 started_at_least_once = true;
2779 if (_have_control) {
2780 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2782 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2784 update_sensitivity();
2788 EngineControl::engine_stopped ()
2790 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2793 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2794 connect_disconnect_button.show();
2796 if (_have_control) {
2797 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
2799 engine_status.set_markup(X_(""));
2802 update_sensitivity();
2806 EngineControl::device_list_changed ()
2808 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2810 midi_option_changed();
2814 EngineControl::connect_disconnect_click()
2816 if (ARDOUR::AudioEngine::instance()->running()) {
2817 ARDOUR_UI::instance()->disconnect_from_engine ();
2819 ARDOUR_UI::instance()->reconnect_to_engine ();
2824 EngineControl::calibrate_audio_latency ()
2826 _measure_midi.reset ();
2827 have_lm_results = false;
2828 lm_use_button.set_sensitive (false);
2829 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2830 notebook.set_current_page (latency_tab);
2834 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2837 have_lm_results = false;
2838 lm_use_button.set_sensitive (false);
2839 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2840 notebook.set_current_page (latency_tab);
2844 EngineControl::configure_midi_devices ()
2846 notebook.set_current_page (midi_tab);