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 DEBUG_ECONTROL ("Restoring saved state");
1673 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1675 if (!_desired_sample_rate) {
1676 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1678 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1679 /* call this explicitly because we're ignoring changes to
1680 the controls at this point.
1682 show_buffer_duration ();
1683 input_latency.set_value (state->input_latency);
1684 output_latency.set_value (state->output_latency);
1686 if (!state->midi_option.empty()) {
1687 midi_option_combo.set_active_text (state->midi_option);
1688 _midi_devices = state->midi_devices;
1691 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1696 EngineControl::get_state ()
1698 LocaleGuard lg (X_("C"));
1700 XMLNode* root = new XMLNode ("AudioMIDISetup");
1703 if (!states.empty()) {
1704 XMLNode* state_nodes = new XMLNode ("EngineStates");
1706 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1708 XMLNode* node = new XMLNode ("State");
1710 node->add_property ("backend", (*i)->backend);
1711 node->add_property ("driver", (*i)->driver);
1712 node->add_property ("device", (*i)->device);
1713 node->add_property ("input-device", (*i)->input_device);
1714 node->add_property ("output-device", (*i)->output_device);
1715 node->add_property ("sample-rate", (*i)->sample_rate);
1716 node->add_property ("buffer-size", (*i)->buffer_size);
1717 node->add_property ("input-latency", (*i)->input_latency);
1718 node->add_property ("output-latency", (*i)->output_latency);
1719 node->add_property ("input-channels", (*i)->input_channels);
1720 node->add_property ("output-channels", (*i)->output_channels);
1721 node->add_property ("active", (*i)->active ? "yes" : "no");
1722 node->add_property ("midi-option", (*i)->midi_option);
1724 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1725 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1726 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1727 midi_device_stuff->add_property (X_("name"), (*p)->name);
1728 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1729 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1730 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1731 midi_devices->add_child_nocopy (*midi_device_stuff);
1733 node->add_child_nocopy (*midi_devices);
1735 state_nodes->add_child_nocopy (*node);
1738 root->add_child_nocopy (*state_nodes);
1745 EngineControl::set_default_state ()
1747 vector<string> backend_names;
1748 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1750 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1751 backend_names.push_back ((*b)->name);
1753 backend_combo.set_active_text (backend_names.front());
1755 // We could set default backends per platform etc here
1761 EngineControl::set_state (const XMLNode& root)
1763 XMLNodeList clist, cclist;
1764 XMLNodeConstIterator citer, cciter;
1766 XMLNode* grandchild;
1767 XMLProperty* prop = NULL;
1769 fprintf (stderr, "EngineControl::set_state\n");
1771 if (root.name() != "AudioMIDISetup") {
1775 clist = root.children();
1779 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1783 if (child->name() != "EngineStates") {
1787 cclist = child->children();
1789 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1790 State state (new StateStruct);
1792 grandchild = *cciter;
1794 if (grandchild->name() != "State") {
1798 if ((prop = grandchild->property ("backend")) == 0) {
1801 state->backend = prop->value ();
1803 if ((prop = grandchild->property ("driver")) == 0) {
1806 state->driver = prop->value ();
1808 if ((prop = grandchild->property ("device")) == 0) {
1811 state->device = prop->value ();
1813 if ((prop = grandchild->property ("input-device")) == 0) {
1816 state->input_device = prop->value ();
1818 if ((prop = grandchild->property ("output-device")) == 0) {
1821 state->output_device = prop->value ();
1823 if ((prop = grandchild->property ("sample-rate")) == 0) {
1826 state->sample_rate = atof (prop->value ());
1828 if ((prop = grandchild->property ("buffer-size")) == 0) {
1831 state->buffer_size = atoi (prop->value ());
1833 if ((prop = grandchild->property ("input-latency")) == 0) {
1836 state->input_latency = atoi (prop->value ());
1838 if ((prop = grandchild->property ("output-latency")) == 0) {
1841 state->output_latency = atoi (prop->value ());
1843 if ((prop = grandchild->property ("input-channels")) == 0) {
1846 state->input_channels = atoi (prop->value ());
1848 if ((prop = grandchild->property ("output-channels")) == 0) {
1851 state->output_channels = atoi (prop->value ());
1853 if ((prop = grandchild->property ("active")) == 0) {
1856 state->active = string_is_affirmative (prop->value ());
1858 if ((prop = grandchild->property ("midi-option")) == 0) {
1861 state->midi_option = prop->value ();
1863 state->midi_devices.clear();
1865 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1866 const XMLNodeList mnc = midinode->children();
1867 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1868 if ((*n)->property (X_("name")) == 0
1869 || (*n)->property (X_("enabled")) == 0
1870 || (*n)->property (X_("input-latency")) == 0
1871 || (*n)->property (X_("output-latency")) == 0
1876 MidiDeviceSettings ptr (new MidiDeviceSetting(
1877 (*n)->property (X_("name"))->value (),
1878 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1879 atoi ((*n)->property (X_("input-latency"))->value ()),
1880 atoi ((*n)->property (X_("output-latency"))->value ())
1882 state->midi_devices.push_back (ptr);
1887 /* remove accumulated duplicates (due to bug in ealier version)
1888 * this can be removed again before release
1890 for (StateList::iterator i = states.begin(); i != states.end();) {
1891 if ((*i)->backend == state->backend &&
1892 (*i)->driver == state->driver &&
1893 (*i)->device == state->device) {
1894 i = states.erase(i);
1901 states.push_back (state);
1905 /* now see if there was an active state and switch the setup to it */
1907 // purge states of backend that are not available in this built
1908 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1909 vector<std::string> backend_names;
1911 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1912 backend_names.push_back((*i)->name);
1914 for (StateList::iterator i = states.begin(); i != states.end();) {
1915 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1916 i = states.erase(i);
1922 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1925 return set_current_state (*i);
1932 EngineControl::set_current_state (const State& state)
1934 DEBUG_ECONTROL ("set_current_state");
1936 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1938 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1939 state->backend, downcase (PROGRAM_NAME), ""))) {
1940 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1941 // this shouldn't happen as the invalid backend names should have been
1942 // removed from the list of states.
1946 // now reflect the change in the backend in the GUI so backend_changed will
1947 // do the right thing
1948 backend_combo.set_active_text (state->backend);
1950 if (!state->driver.empty ()) {
1951 if (!backend->requires_driver_selection ()) {
1952 DEBUG_ECONTROL ("Backend should require driver selection");
1953 // A backend has changed from having driver selection to not having
1954 // it or someone has been manually editing a config file and messed
1959 if (backend->set_driver (state->driver) != 0) {
1960 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
1961 // Driver names for a backend have changed and the name in the
1962 // config file is now invalid or support for driver is no longer
1963 // included in the backend
1966 // no need to set the driver_combo as backend_changed will use
1967 // backend->driver_name to set the active driver
1970 if (!state->device.empty ()) {
1971 if (backend->set_device_name (state->device) != 0) {
1973 string_compose ("Unable to set device name %1", state->device));
1974 // device is no longer available on the system
1977 // no need to set active device as it will be picked up in
1978 // via backend_changed ()/set_device_popdown_strings
1981 // backend supports separate input/output devices
1982 if (backend->set_input_device_name (state->input_device) != 0) {
1983 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
1984 state->input_device));
1985 // input device is no longer available on the system
1989 if (backend->set_output_device_name (state->output_device) != 0) {
1990 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
1991 state->input_device));
1992 // output device is no longer available on the system
1995 // no need to set active devices as it will be picked up in via
1996 // backend_changed ()/set_*_device_popdown_strings
2001 // Now restore the state of the rest of the controls
2003 // We don't use a SignalBlocker as set_current_state is currently only
2004 // called from set_state before any signals are connected. If at some point
2005 // a more general named state mechanism is implemented and
2006 // set_current_state is called while signals are connected then a
2007 // SignalBlocker will need to be instantiated before setting these.
2009 device_combo.set_active_text (state->device);
2010 input_device_combo.set_active_text (state->input_device);
2011 output_device_combo.set_active_text (state->output_device);
2012 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2013 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2014 input_latency.set_value (state->input_latency);
2015 output_latency.set_value (state->output_latency);
2016 midi_option_combo.set_active_text (state->midi_option);
2021 EngineControl::push_state_to_backend (bool start)
2023 DEBUG_ECONTROL ("push_state_to_backend");
2024 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2030 /* figure out what is going to change */
2032 bool restart_required = false;
2033 bool was_running = ARDOUR::AudioEngine::instance()->running();
2034 bool change_driver = false;
2035 bool change_device = false;
2036 bool change_rate = false;
2037 bool change_bufsize = false;
2038 bool change_latency = false;
2039 bool change_channels = false;
2040 bool change_midi = false;
2042 uint32_t ochan = get_output_channels ();
2043 uint32_t ichan = get_input_channels ();
2045 if (_have_control) {
2047 if (started_at_least_once) {
2049 /* we can control the backend */
2051 if (backend->requires_driver_selection()) {
2052 if (get_driver() != backend->driver_name()) {
2053 change_driver = true;
2057 if (backend->use_separate_input_and_output_devices()) {
2058 if (get_input_device_name() != backend->input_device_name()) {
2059 change_device = true;
2061 if (get_output_device_name() != backend->output_device_name()) {
2062 change_device = true;
2065 if (get_device_name() != backend->device_name()) {
2066 change_device = true;
2070 if (queue_device_changed) {
2071 change_device = true;
2074 if (get_rate() != backend->sample_rate()) {
2078 if (get_buffer_size() != backend->buffer_size()) {
2079 change_bufsize = true;
2082 if (get_midi_option() != backend->midi_option()) {
2086 /* zero-requested channels means "all available" */
2089 ichan = backend->input_channels();
2093 ochan = backend->output_channels();
2096 if (ichan != backend->input_channels()) {
2097 change_channels = true;
2100 if (ochan != backend->output_channels()) {
2101 change_channels = true;
2104 if (get_input_latency() != backend->systemic_input_latency() ||
2105 get_output_latency() != backend->systemic_output_latency()) {
2106 change_latency = true;
2109 /* backend never started, so we have to force a group
2112 change_device = true;
2113 if (backend->requires_driver_selection()) {
2114 change_driver = true;
2117 change_bufsize = true;
2118 change_channels = true;
2119 change_latency = true;
2125 /* we have no control over the backend, meaning that we can
2126 * only possibly change sample rate and buffer size.
2130 if (get_rate() != backend->sample_rate()) {
2131 change_bufsize = true;
2134 if (get_buffer_size() != backend->buffer_size()) {
2135 change_bufsize = true;
2139 queue_device_changed = false;
2141 if (!_have_control) {
2143 /* We do not have control over the backend, so the best we can
2144 * do is try to change the sample rate and/or bufsize and get
2148 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2152 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2157 backend->set_sample_rate (get_rate());
2160 if (change_bufsize) {
2161 backend->set_buffer_size (get_buffer_size());
2165 if (ARDOUR::AudioEngine::instance()->start ()) {
2166 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2176 /* determine if we need to stop the backend before changing parameters */
2178 if (change_driver || change_device || change_channels || change_latency ||
2179 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2181 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2182 restart_required = true;
2184 restart_required = false;
2189 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2190 /* no changes in any parameters that absolutely require a
2191 * restart, so check those that might be changeable without a
2195 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2196 /* can't do this while running ... */
2197 restart_required = true;
2200 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2201 /* can't do this while running ... */
2202 restart_required = true;
2208 if (restart_required) {
2209 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2216 if (change_driver && backend->set_driver (get_driver())) {
2217 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2220 if (backend->use_separate_input_and_output_devices()) {
2221 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2222 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2225 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2226 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2230 if (change_device && backend->set_device_name (get_device_name())) {
2231 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2235 if (change_rate && backend->set_sample_rate (get_rate())) {
2236 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2239 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2240 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2244 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2245 if (backend->set_input_channels (get_input_channels())) {
2246 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2249 if (backend->set_output_channels (get_output_channels())) {
2250 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2254 if (change_latency) {
2255 if (backend->set_systemic_input_latency (get_input_latency())) {
2256 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2259 if (backend->set_systemic_output_latency (get_output_latency())) {
2260 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2266 backend->set_midi_option (get_midi_option());
2270 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2271 if (_measure_midi) {
2272 if (*p == _measure_midi) {
2273 backend->set_midi_device_enabled ((*p)->name, true);
2275 backend->set_midi_device_enabled ((*p)->name, false);
2279 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2280 if (backend->can_set_systemic_midi_latencies()) {
2281 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2282 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2287 if (start || (was_running && restart_required)) {
2288 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2299 EngineControl::post_push ()
2301 /* get a pointer to the current state object, creating one if
2305 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2308 state = save_state ();
2316 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2317 (*i)->active = false;
2320 /* mark this one active (to be used next time the dialog is
2324 state->active = true;
2326 if (_have_control) { // XXX
2327 manage_control_app_sensitivity ();
2330 /* schedule a redisplay of MIDI ports */
2331 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2336 EngineControl::get_rate () const
2338 float r = atof (sample_rate_combo.get_active_text ());
2339 /* the string may have been translated with an abbreviation for
2340 * thousands, so use a crude heuristic to fix this.
2350 EngineControl::get_buffer_size () const
2352 string txt = buffer_size_combo.get_active_text ();
2355 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2356 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2357 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2365 EngineControl::get_midi_option () const
2367 return midi_option_combo.get_active_text();
2371 EngineControl::get_input_channels() const
2373 if (ARDOUR::Profile->get_mixbus()) {
2374 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2375 if (!backend) return 0;
2376 return backend->input_channels();
2378 return (uint32_t) input_channels_adjustment.get_value();
2382 EngineControl::get_output_channels() const
2384 if (ARDOUR::Profile->get_mixbus()) {
2385 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2386 if (!backend) return 0;
2387 return backend->input_channels();
2389 return (uint32_t) output_channels_adjustment.get_value();
2393 EngineControl::get_input_latency() const
2395 return (uint32_t) input_latency_adjustment.get_value();
2399 EngineControl::get_output_latency() const
2401 return (uint32_t) output_latency_adjustment.get_value();
2405 EngineControl::get_backend () const
2407 return backend_combo.get_active_text ();
2411 EngineControl::get_driver () const
2413 if (driver_combo.get_parent()) {
2414 return driver_combo.get_active_text ();
2421 EngineControl::get_device_name () const
2423 return device_combo.get_active_text ();
2427 EngineControl::get_input_device_name () const
2429 return input_device_combo.get_active_text ();
2433 EngineControl::get_output_device_name () const
2435 return output_device_combo.get_active_text ();
2439 EngineControl::control_app_button_clicked ()
2441 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2447 backend->launch_control_app ();
2451 EngineControl::start_stop_button_clicked ()
2453 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2459 if (ARDOUR::AudioEngine::instance()->running()) {
2460 ARDOUR::AudioEngine::instance()->stop ();
2462 push_state_to_backend (true);
2467 EngineControl::manage_control_app_sensitivity ()
2469 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2475 string appname = backend->control_app_name();
2477 if (appname.empty()) {
2478 control_app_button.set_sensitive (false);
2480 control_app_button.set_sensitive (true);
2485 EngineControl::set_desired_sample_rate (uint32_t sr)
2487 _desired_sample_rate = sr;
2492 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2494 if (page_num == 0) {
2495 cancel_button->set_sensitive (true);
2496 _measure_midi.reset();
2497 update_sensitivity ();
2499 cancel_button->set_sensitive (false);
2500 ok_button->set_sensitive (false);
2503 if (page_num == midi_tab) {
2505 refresh_midi_display ();
2508 if (page_num == latency_tab) {
2511 if (ARDOUR::AudioEngine::instance()->running()) {
2512 // TODO - mark as 'stopped for latency
2513 ARDOUR_UI::instance()->disconnect_from_engine ();
2517 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2519 /* save any existing latency values */
2521 uint32_t il = (uint32_t) input_latency.get_value ();
2522 uint32_t ol = (uint32_t) input_latency.get_value ();
2524 /* reset to zero so that our new test instance
2525 will be clean of any existing latency measures.
2527 NB. this should really be done by the backend
2528 when stated for latency measurement.
2531 input_latency.set_value (0);
2532 output_latency.set_value (0);
2534 push_state_to_backend (false);
2538 input_latency.set_value (il);
2539 output_latency.set_value (ol);
2542 // This should be done in push_state_to_backend()
2543 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2544 disable_latency_tab ();
2547 enable_latency_tab ();
2551 end_latency_detection ();
2552 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2557 /* latency measurement */
2560 EngineControl::check_audio_latency_measurement ()
2562 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2564 if (mtdm->resolve () < 0) {
2565 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2569 if (mtdm->err () > 0.3) {
2575 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2577 if (sample_rate == 0) {
2578 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2579 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2583 int frames_total = mtdm->del();
2584 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2586 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2587 _("Detected roundtrip latency: "),
2588 frames_total, frames_total * 1000.0f/sample_rate,
2589 _("Systemic latency: "),
2590 extra, extra * 1000.0f/sample_rate);
2594 if (mtdm->err () > 0.2) {
2596 strcat (buf, _("(signal detection error)"));
2602 strcat (buf, _("(inverted - bad wiring)"));
2606 lm_results.set_markup (string_compose (results_markup, buf));
2609 have_lm_results = true;
2610 end_latency_detection ();
2611 lm_use_button.set_sensitive (true);
2619 EngineControl::check_midi_latency_measurement ()
2621 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2623 if (!mididm->have_signal () || mididm->latency () == 0) {
2624 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2629 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2631 if (sample_rate == 0) {
2632 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2633 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2637 ARDOUR::framecnt_t frames_total = mididm->latency();
2638 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2639 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2640 _("Detected roundtrip latency: "),
2641 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2642 _("Systemic latency: "),
2643 extra, extra * 1000.0f / sample_rate);
2647 if (!mididm->ok ()) {
2649 strcat (buf, _("(averaging)"));
2653 if (mididm->deviation () > 50.0) {
2655 strcat (buf, _("(too large jitter)"));
2657 } else if (mididm->deviation () > 10.0) {
2659 strcat (buf, _("(large jitter)"));
2663 have_lm_results = true;
2664 end_latency_detection ();
2665 lm_use_button.set_sensitive (true);
2666 lm_results.set_markup (string_compose (results_markup, buf));
2668 } else if (mididm->processed () > 400) {
2669 have_lm_results = false;
2670 end_latency_detection ();
2671 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2675 lm_results.set_markup (string_compose (results_markup, buf));
2681 EngineControl::start_latency_detection ()
2683 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2684 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2686 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2687 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2688 if (_measure_midi) {
2689 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2691 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2693 lm_measure_label.set_text (_("Cancel"));
2694 have_lm_results = false;
2695 lm_use_button.set_sensitive (false);
2696 lm_input_channel_combo.set_sensitive (false);
2697 lm_output_channel_combo.set_sensitive (false);
2703 EngineControl::end_latency_detection ()
2705 latency_timeout.disconnect ();
2706 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2707 lm_measure_label.set_text (_("Measure"));
2708 if (!have_lm_results) {
2709 lm_use_button.set_sensitive (false);
2711 lm_input_channel_combo.set_sensitive (true);
2712 lm_output_channel_combo.set_sensitive (true);
2717 EngineControl::latency_button_clicked ()
2720 start_latency_detection ();
2722 end_latency_detection ();
2727 EngineControl::use_latency_button_clicked ()
2729 if (_measure_midi) {
2730 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2734 ARDOUR::framecnt_t frames_total = mididm->latency();
2735 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2736 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2737 _measure_midi->input_latency = one_way;
2738 _measure_midi->output_latency = one_way;
2739 notebook.set_current_page (midi_tab);
2741 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2747 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2748 one_way = std::max (0., one_way);
2750 input_latency_adjustment.set_value (one_way);
2751 output_latency_adjustment.set_value (one_way);
2753 /* back to settings page */
2754 notebook.set_current_page (0);
2760 EngineControl::on_delete_event (GdkEventAny* ev)
2762 if (notebook.get_current_page() == 2) {
2763 /* currently on latency tab - be sure to clean up */
2764 end_latency_detection ();
2766 return ArdourDialog::on_delete_event (ev);
2770 EngineControl::engine_running ()
2772 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2775 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2776 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2778 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2779 connect_disconnect_button.show();
2781 started_at_least_once = true;
2782 if (_have_control) {
2783 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2785 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2787 update_sensitivity();
2791 EngineControl::engine_stopped ()
2793 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2796 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2797 connect_disconnect_button.show();
2799 if (_have_control) {
2800 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
2802 engine_status.set_markup(X_(""));
2805 update_sensitivity();
2809 EngineControl::device_list_changed ()
2811 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2813 midi_option_changed();
2817 EngineControl::connect_disconnect_click()
2819 if (ARDOUR::AudioEngine::instance()->running()) {
2820 ARDOUR_UI::instance()->disconnect_from_engine ();
2822 ARDOUR_UI::instance()->reconnect_to_engine ();
2827 EngineControl::calibrate_audio_latency ()
2829 _measure_midi.reset ();
2830 have_lm_results = false;
2831 lm_use_button.set_sensitive (false);
2832 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2833 notebook.set_current_page (latency_tab);
2837 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2840 have_lm_results = false;
2841 lm_use_button.set_sensitive (false);
2842 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2843 notebook.set_current_page (latency_tab);
2847 EngineControl::configure_midi_devices ()
2849 notebook.set_current_page (midi_tab);