2 Copyright (C) 2010 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <boost/scoped_ptr.hpp>
28 #include <gtkmm/messagedialog.h>
30 #include "pbd/error.h"
31 #include "pbd/xml++.h"
32 #include "pbd/unwind.h"
33 #include "pbd/failed_constructor.h"
35 #include <gtkmm/alignment.h>
36 #include <gtkmm/stock.h>
37 #include <gtkmm/notebook.h>
38 #include <gtkmm2ext/utils.h>
40 #include "ardour/audio_backend.h"
41 #include "ardour/audioengine.h"
42 #include "ardour/mtdm.h"
43 #include "ardour/mididm.h"
44 #include "ardour/rc_configuration.h"
45 #include "ardour/types.h"
46 #include "ardour/profile.h"
48 #include "pbd/convert.h"
49 #include "pbd/error.h"
53 #include "ardour_ui.h"
54 #include "engine_dialog.h"
55 #include "gui_thread.h"
61 using namespace Gtkmm2ext;
64 using namespace ARDOUR_UI_UTILS;
66 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
68 static const unsigned int midi_tab = 2;
69 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
71 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
73 EngineControl::EngineControl ()
74 : ArdourDialog (_("Audio/MIDI Setup"))
77 , input_latency_adjustment (0, 0, 99999, 1)
78 , input_latency (input_latency_adjustment)
79 , output_latency_adjustment (0, 0, 99999, 1)
80 , output_latency (output_latency_adjustment)
81 , input_channels_adjustment (0, 0, 256, 1)
82 , input_channels (input_channels_adjustment)
83 , output_channels_adjustment (0, 0, 256, 1)
84 , output_channels (output_channels_adjustment)
85 , ports_adjustment (128, 8, 1024, 1, 16)
86 , ports_spinner (ports_adjustment)
87 , control_app_button (_("Device Control Panel"))
88 , midi_devices_button (_("Midi Device Setup"))
89 , stop_engine_button (_("Stop (Reconfigure)"))
90 , lm_measure_label (_("Measure"))
91 , lm_use_button (_("Use results"))
92 , lm_back_button (_("Back to settings ... (ignore results)"))
93 , lm_button_audio (_("Calibrate Audio"))
95 , have_lm_results (false)
97 , midi_back_button (_("Back to settings"))
99 , _desired_sample_rate (0)
100 , started_at_least_once (false)
101 , queue_device_changed (false)
104 using namespace Notebook_Helpers;
105 vector<string> backend_names;
107 AttachOptions xopt = AttachOptions (FILL|EXPAND);
110 set_name (X_("AudioMIDISetup"));
112 /* the backend combo is the one thing that is ALWAYS visible */
114 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
116 if (backends.empty()) {
117 MessageDialog msg (string_compose (_("No audio/MIDI backends detected. %1 cannot run\n\n(This is a build/packaging/system error. It should never happen.)"), PROGRAM_NAME));
119 throw failed_constructor ();
122 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
123 backend_names.push_back ((*b)->name);
126 set_popdown_strings (backend_combo, backend_names);
128 /* setup basic packing characteristics for the table used on the main
129 * tab of the notebook
132 basic_packer.set_spacings (6);
133 basic_packer.set_border_width (12);
134 basic_packer.set_homogeneous (false);
138 basic_hbox.pack_start (basic_packer, false, false);
140 /* latency measurement tab */
142 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
145 lm_table.set_row_spacings (12);
146 lm_table.set_col_spacings (6);
147 lm_table.set_homogeneous (false);
149 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
152 lm_preamble.set_width_chars (60);
153 lm_preamble.set_line_wrap (true);
154 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
156 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
159 Gtk::Label* preamble;
160 preamble = manage (new Label);
161 preamble->set_width_chars (60);
162 preamble->set_line_wrap (true);
163 preamble->set_markup (_("Select two channels below and connect them using a cable."));
165 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
168 label = manage (new Label (_("Output channel")));
169 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
171 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
172 misc_align->add (lm_output_channel_combo);
173 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
176 label = manage (new Label (_("Input channel")));
177 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
179 misc_align = manage (new Alignment (0.0, 0.5));
180 misc_align->add (lm_input_channel_combo);
181 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
184 lm_measure_label.set_padding (10, 10);
185 lm_measure_button.add (lm_measure_label);
186 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
187 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
188 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
190 lm_use_button.set_sensitive (false);
192 /* Increase the default spacing around the labels of these three
198 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
199 l->set_padding (10, 10);
202 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
203 l->set_padding (10, 10);
206 preamble = manage (new Label);
207 preamble->set_width_chars (60);
208 preamble->set_line_wrap (true);
209 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
210 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
213 preamble = manage (new Label);
214 preamble->set_width_chars (60);
215 preamble->set_line_wrap (true);
216 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
217 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
219 ++row; // skip a row in the table
220 ++row; // skip a row in the table
222 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
224 ++row; // skip a row in the table
225 ++row; // skip a row in the table
227 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
228 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
229 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
231 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
233 lm_vbox.set_border_width (12);
234 lm_vbox.pack_start (lm_table, false, false);
236 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
240 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
241 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
242 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
243 notebook.set_border_width (12);
245 notebook.set_show_tabs (false);
246 notebook.show_all ();
248 notebook.set_name ("SettingsNotebook");
250 /* packup the notebook */
252 get_vbox()->set_border_width (12);
253 get_vbox()->pack_start (notebook);
255 /* need a special function to print "all available channels" when the
256 * channel counts hit zero.
259 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
260 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
262 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
263 midi_devices_button.set_sensitive (false);
264 midi_devices_button.set_name ("generic button");
265 midi_devices_button.set_can_focus(true);
267 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
268 control_app_button.set_name ("generic button");
269 control_app_button.set_can_focus(true);
270 manage_control_app_sensitivity ();
272 stop_engine_button.signal_clicked.connect (mem_fun (*this, &EngineControl::stop_engine_button_clicked));
273 stop_engine_button.set_sensitive (false);
274 stop_engine_button.set_name ("generic button");
275 stop_engine_button.set_can_focus(true);
277 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
278 apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
279 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
281 /* Pick up any existing audio setup configuration, if appropriate */
283 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
285 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
286 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
287 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
288 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
291 if (!set_state (*audio_setup)) {
292 set_default_state ();
295 set_default_state ();
298 connect_changed_signals ();
300 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
302 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
303 connect_disconnect_button.set_no_show_all();
308 EngineControl::connect_changed_signals ()
310 backend_combo_connection = backend_combo.signal_changed ().connect (
311 sigc::mem_fun (*this, &EngineControl::backend_changed));
312 driver_combo_connection = driver_combo.signal_changed ().connect (
313 sigc::mem_fun (*this, &EngineControl::driver_changed));
314 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
315 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
316 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
317 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
318 device_combo_connection = device_combo.signal_changed ().connect (
319 sigc::mem_fun (*this, &EngineControl::device_changed));
320 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
321 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
323 input_device_combo_connection = input_device_combo.signal_changed ().connect (
324 sigc::mem_fun (*this, &EngineControl::input_device_changed));
325 output_device_combo_connection = output_device_combo.signal_changed ().connect (
326 sigc::mem_fun (*this, &EngineControl::output_device_changed));
328 input_latency_connection = input_latency.signal_changed ().connect (
329 sigc::mem_fun (*this, &EngineControl::parameter_changed));
330 output_latency_connection = output_latency.signal_changed ().connect (
331 sigc::mem_fun (*this, &EngineControl::parameter_changed));
332 input_channels_connection = input_channels.signal_changed ().connect (
333 sigc::mem_fun (*this, &EngineControl::parameter_changed));
334 output_channels_connection = output_channels.signal_changed ().connect (
335 sigc::mem_fun (*this, &EngineControl::parameter_changed));
339 EngineControl::block_changed_signals ()
341 if (block_signals++ == 0) {
342 DEBUG_ECONTROL ("Blocking changed signals");
343 backend_combo_connection.block ();
344 driver_combo_connection.block ();
345 sample_rate_combo_connection.block ();
346 buffer_size_combo_connection.block ();
347 device_combo_connection.block ();
348 input_device_combo_connection.block ();
349 output_device_combo_connection.block ();
350 midi_option_combo_connection.block ();
351 input_latency_connection.block ();
352 output_latency_connection.block ();
353 input_channels_connection.block ();
354 output_channels_connection.block ();
359 EngineControl::unblock_changed_signals ()
361 if (--block_signals == 0) {
362 DEBUG_ECONTROL ("Unblocking changed signals");
363 backend_combo_connection.unblock ();
364 driver_combo_connection.unblock ();
365 sample_rate_combo_connection.unblock ();
366 buffer_size_combo_connection.unblock ();
367 device_combo_connection.unblock ();
368 input_device_combo_connection.unblock ();
369 output_device_combo_connection.unblock ();
370 midi_option_combo_connection.unblock ();
371 input_latency_connection.unblock ();
372 output_latency_connection.unblock ();
373 input_channels_connection.unblock ();
374 output_channels_connection.unblock ();
378 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
379 const std::string& reason)
380 : ec (engine_control)
383 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
384 ec.block_changed_signals ();
387 EngineControl::SignalBlocker::~SignalBlocker ()
389 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
390 ec.unblock_changed_signals ();
394 EngineControl::on_show ()
396 ArdourDialog::on_show ();
397 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
398 // re-check _have_control (jackd running) see #6041
402 ok_button->grab_focus();
406 EngineControl::on_response (int response_id)
408 ArdourDialog::on_response (response_id);
410 switch (response_id) {
412 push_state_to_backend (true);
415 #ifdef PLATFORM_WINDOWS
416 // For some reason we don't understand, 'hide()'
417 // needs to get called first in Windows
420 // But if there's no session open, this can produce
421 // a long gap when nothing appears to be happening.
422 // Let's show the splash image while we're waiting.
423 if ( !ARDOUR_COMMAND_LINE::no_splash ) {
424 if ( ARDOUR_UI::instance() ) {
425 if ( !ARDOUR_UI::instance()->session_loaded ) {
426 ARDOUR_UI::instance()->show_splash();
430 push_state_to_backend (true);
433 push_state_to_backend (true);
437 case RESPONSE_DELETE_EVENT:
440 ev.type = GDK_BUTTON_PRESS;
442 on_delete_event ((GdkEventAny*) &ev);
451 EngineControl::build_notebook ()
454 AttachOptions xopt = AttachOptions (FILL|EXPAND);
456 /* clear the table */
458 Gtkmm2ext::container_clear (basic_vbox);
459 Gtkmm2ext::container_clear (basic_packer);
461 if (control_app_button.get_parent()) {
462 control_app_button.get_parent()->remove (control_app_button);
465 label = manage (left_aligned_label (_("Audio System:")));
466 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
467 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
469 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
470 engine_status.show();
472 basic_packer.attach (stop_engine_button, 3, 4, 0, 1, xopt, xopt);
474 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
475 lm_button_audio.set_name ("generic button");
476 lm_button_audio.set_can_focus(true);
479 build_full_control_notebook ();
481 build_no_control_notebook ();
484 basic_vbox.pack_start (basic_hbox, false, false);
487 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
488 basic_vbox.show_all ();
493 EngineControl::build_full_control_notebook ()
495 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
498 using namespace Notebook_Helpers;
500 vector<string> strings;
501 AttachOptions xopt = AttachOptions (FILL|EXPAND);
502 int row = 1; // row zero == backend combo
504 /* start packing it up */
506 if (backend->requires_driver_selection()) {
507 label = manage (left_aligned_label (_("Driver:")));
508 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
509 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
513 if (backend->use_separate_input_and_output_devices()) {
514 label = manage (left_aligned_label (_("Input Device:")));
515 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
516 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
518 label = manage (left_aligned_label (_("Output Device:")));
519 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
520 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
522 // reset so it isn't used in state comparisons
523 device_combo.set_active_text ("");
525 label = manage (left_aligned_label (_("Device:")));
526 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
527 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
529 // reset these so they don't get used in state comparisons
530 input_device_combo.set_active_text ("");
531 output_device_combo.set_active_text ("");
534 label = manage (left_aligned_label (_("Sample rate:")));
535 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
536 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
540 label = manage (left_aligned_label (_("Buffer size:")));
541 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
542 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
543 buffer_size_duration_label.set_alignment (0.0); /* left-align */
544 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
546 /* button spans 2 rows */
548 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
551 input_channels.set_name ("InputChannels");
552 input_channels.set_flags (Gtk::CAN_FOCUS);
553 input_channels.set_digits (0);
554 input_channels.set_wrap (false);
555 output_channels.set_editable (true);
557 if (!ARDOUR::Profile->get_mixbus()) {
558 label = manage (left_aligned_label (_("Input Channels:")));
559 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
560 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
564 output_channels.set_name ("OutputChannels");
565 output_channels.set_flags (Gtk::CAN_FOCUS);
566 output_channels.set_digits (0);
567 output_channels.set_wrap (false);
568 output_channels.set_editable (true);
570 if (!ARDOUR::Profile->get_mixbus()) {
571 label = manage (left_aligned_label (_("Output Channels:")));
572 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
573 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
577 input_latency.set_name ("InputLatency");
578 input_latency.set_flags (Gtk::CAN_FOCUS);
579 input_latency.set_digits (0);
580 input_latency.set_wrap (false);
581 input_latency.set_editable (true);
583 label = manage (left_aligned_label (_("Hardware input latency:")));
584 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
585 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
586 label = manage (left_aligned_label (_("samples")));
587 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
590 output_latency.set_name ("OutputLatency");
591 output_latency.set_flags (Gtk::CAN_FOCUS);
592 output_latency.set_digits (0);
593 output_latency.set_wrap (false);
594 output_latency.set_editable (true);
596 label = manage (left_aligned_label (_("Hardware output latency:")));
597 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
598 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
599 label = manage (left_aligned_label (_("samples")));
600 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
602 /* button spans 2 rows */
604 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
607 label = manage (left_aligned_label (_("MIDI System:")));
608 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
609 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
610 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
615 EngineControl::build_no_control_notebook ()
617 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
620 using namespace Notebook_Helpers;
622 vector<string> strings;
623 AttachOptions xopt = AttachOptions (FILL|EXPAND);
624 int row = 1; // row zero == backend combo
625 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
627 label = manage (new Label);
628 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
629 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
632 if (backend->can_change_sample_rate_when_running()) {
633 label = manage (left_aligned_label (_("Sample rate:")));
634 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
635 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
639 if (backend->can_change_buffer_size_when_running()) {
640 label = manage (left_aligned_label (_("Buffer size:")));
641 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
642 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
643 buffer_size_duration_label.set_alignment (0.0); /* left-align */
644 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
648 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
652 EngineControl::~EngineControl ()
654 ignore_changes = true;
658 EngineControl::disable_latency_tab ()
660 vector<string> empty;
661 set_popdown_strings (lm_output_channel_combo, empty);
662 set_popdown_strings (lm_input_channel_combo, empty);
663 lm_measure_button.set_sensitive (false);
664 lm_use_button.set_sensitive (false);
668 EngineControl::enable_latency_tab ()
670 vector<string> outputs;
671 vector<string> inputs;
673 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
674 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
675 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
677 if (!ARDOUR::AudioEngine::instance()->running()) {
678 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
679 notebook.set_current_page (0);
683 else if (inputs.empty() || outputs.empty()) {
684 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
685 notebook.set_current_page (0);
690 lm_back_button_signal.disconnect();
692 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
695 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
699 set_popdown_strings (lm_output_channel_combo, outputs);
700 lm_output_channel_combo.set_active_text (outputs.front());
701 lm_output_channel_combo.set_sensitive (true);
703 set_popdown_strings (lm_input_channel_combo, inputs);
704 lm_input_channel_combo.set_active_text (inputs.front());
705 lm_input_channel_combo.set_sensitive (true);
707 lm_measure_button.set_sensitive (true);
711 EngineControl::setup_midi_tab_for_backend ()
713 string backend = backend_combo.get_active_text ();
715 Gtkmm2ext::container_clear (midi_vbox);
717 midi_vbox.set_border_width (12);
718 midi_device_table.set_border_width (12);
720 if (backend == "JACK") {
721 setup_midi_tab_for_jack ();
724 midi_vbox.pack_start (midi_device_table, true, true);
725 midi_vbox.pack_start (midi_back_button, false, false);
726 midi_vbox.show_all ();
730 EngineControl::update_sensitivity ()
732 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
734 ok_button->set_sensitive (false);
735 apply_button->set_sensitive (false);
736 stop_engine_button.set_sensitive (false);
741 size_t devices_available = 0;
743 if (backend->use_separate_input_and_output_devices ()) {
744 devices_available += get_popdown_string_count (input_device_combo);
745 devices_available += get_popdown_string_count (output_device_combo);
747 devices_available += get_popdown_string_count (device_combo);
750 if (devices_available == 0) {
752 input_latency.set_sensitive (false);
753 output_latency.set_sensitive (false);
754 input_channels.set_sensitive (false);
755 output_channels.set_sensitive (false);
757 input_latency.set_sensitive (true);
758 output_latency.set_sensitive (true);
759 input_channels.set_sensitive (true);
760 output_channels.set_sensitive (true);
763 if (get_popdown_string_count (buffer_size_combo) > 0) {
764 if (!ARDOUR::AudioEngine::instance()->running()) {
765 buffer_size_combo.set_sensitive (valid);
766 } else if (backend->can_change_sample_rate_when_running()) {
767 buffer_size_combo.set_sensitive (valid || !_have_control);
771 * Currently there is no way to manually stop the
772 * engine in order to re-configure it.
773 * This needs to remain sensitive for now.
775 * (it's also handy to implicily
776 * re-start the engine)
778 buffer_size_combo.set_sensitive (true);
780 buffer_size_combo.set_sensitive (false);
784 buffer_size_combo.set_sensitive (false);
788 if (get_popdown_string_count (sample_rate_combo) > 0) {
789 if (!ARDOUR::AudioEngine::instance()->running()) {
790 sample_rate_combo.set_sensitive (true);
792 sample_rate_combo.set_sensitive (false);
795 sample_rate_combo.set_sensitive (false);
799 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
800 input_device_combo.set_sensitive (false);
801 output_device_combo.set_sensitive (false);
802 device_combo.set_sensitive (false);
803 stop_engine_button.set_sensitive (true);
804 stop_engine_button.show ();
806 input_device_combo.set_sensitive (true);
807 output_device_combo.set_sensitive (true);
808 device_combo.set_sensitive (true);
809 stop_engine_button.set_sensitive (false);
810 stop_engine_button.hide ();
813 if (valid || !_have_control) {
814 ok_button->set_sensitive (true);
815 apply_button->set_sensitive (true);
817 ok_button->set_sensitive (false);
818 apply_button->set_sensitive (false);
823 EngineControl::setup_midi_tab_for_jack ()
828 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
830 device->input_latency = a->get_value();
832 device->output_latency = a->get_value();
837 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
838 b->set_active (!b->get_active());
839 device->enabled = b->get_active();
840 refresh_midi_display(device->name);
844 EngineControl::refresh_midi_display (std::string focus)
846 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
850 AttachOptions xopt = AttachOptions (FILL|EXPAND);
853 Gtkmm2ext::container_clear (midi_device_table);
855 midi_device_table.set_spacings (6);
857 l = manage (new Label);
858 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
859 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
860 l->set_alignment (0.5, 0.5);
864 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
865 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
866 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
867 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
869 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
870 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
871 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
872 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
875 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
880 bool enabled = (*p)->enabled;
882 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
883 m->set_name ("midi device");
884 m->set_can_focus (Gtk::CAN_FOCUS);
885 m->add_events (Gdk::BUTTON_RELEASE_MASK);
886 m->set_active (enabled);
887 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
888 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
889 if ((*p)->name == focus) {
893 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
894 s = manage (new Gtk::SpinButton (*a));
895 a->set_value ((*p)->input_latency);
896 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
897 s->set_sensitive (_can_set_midi_latencies && enabled);
898 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
900 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
901 s = manage (new Gtk::SpinButton (*a));
902 a->set_value ((*p)->output_latency);
903 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
904 s->set_sensitive (_can_set_midi_latencies && enabled);
905 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
907 b = manage (new Button (_("Calibrate")));
908 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
909 b->set_sensitive (_can_set_midi_latencies && enabled);
910 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
917 EngineControl::backend_changed ()
919 SignalBlocker blocker (*this, "backend_changed");
920 string backend_name = backend_combo.get_active_text();
921 boost::shared_ptr<ARDOUR::AudioBackend> backend;
923 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
924 /* eh? setting the backend failed... how ? */
925 /* A: stale config contains a backend that does not exist in current build */
929 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
931 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
934 setup_midi_tab_for_backend ();
935 _midi_devices.clear();
937 if (backend->requires_driver_selection()) {
938 if (set_driver_popdown_strings ()) {
939 driver_combo.set_sensitive (true);
944 driver_combo.set_sensitive (false);
945 /* this will change the device text which will cause a call to
946 * device changed which will set up parameters
951 update_midi_options ();
953 connect_disconnect_button.hide();
955 midi_option_changed();
957 started_at_least_once = false;
959 /* changing the backend implies stopping the engine
960 * ARDOUR::AudioEngine() may or may not emit this signal
961 * depending on previous engine state
963 engine_stopped (); // set "active/inactive"
965 if (!ignore_changes) {
966 maybe_display_saved_state ();
971 EngineControl::update_midi_options ()
973 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
974 vector<string> midi_options = backend->enumerate_midi_options();
976 if (midi_options.size() == 1) {
977 /* only contains the "none" option */
978 midi_option_combo.set_sensitive (false);
981 set_popdown_strings (midi_option_combo, midi_options);
982 midi_option_combo.set_active_text (midi_options.front());
983 midi_option_combo.set_sensitive (true);
985 midi_option_combo.set_sensitive (false);
991 EngineControl::print_channel_count (Gtk::SpinButton* sb)
993 if (ARDOUR::Profile->get_mixbus()) {
997 uint32_t cnt = (uint32_t) sb->get_value();
999 sb->set_text (_("all available channels"));
1002 snprintf (buf, sizeof (buf), "%d", cnt);
1008 // @return true if there are drivers available
1010 EngineControl::set_driver_popdown_strings ()
1012 DEBUG_ECONTROL ("set_driver_popdown_strings");
1013 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1014 vector<string> drivers = backend->enumerate_drivers();
1016 if (drivers.empty ()) {
1017 // This is an error...?
1021 string current_driver = backend->driver_name ();
1023 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1025 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1028 current_driver = drivers.front ();
1031 set_popdown_strings (driver_combo, drivers);
1033 string_compose ("driver_combo.set_active_text: %1", current_driver));
1034 driver_combo.set_active_text (current_driver);
1038 // @return true if there are devices available
1040 EngineControl::set_device_popdown_strings ()
1042 DEBUG_ECONTROL ("set_device_popdown_strings");
1043 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1044 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1046 /* NOTE: Ardour currently does not display the "available" field of the
1049 * Doing so would require a different GUI widget than the combo
1050 * box/popdown that we currently use, since it has no way to list
1051 * items that are not selectable. Something more like a popup menu,
1052 * which could have unselectable items, would be appropriate.
1055 vector<string> available_devices;
1057 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1058 available_devices.push_back (i->name);
1061 if (available_devices.empty ()) {
1065 string current_device = backend->device_name ();
1067 // Make sure that backend->device_name () is a valid
1068 // device, the backend may not return a valid device if it hasn't
1070 if (std::find (available_devices.begin (),
1071 available_devices.end (),
1072 current_device) == available_devices.end ()) {
1074 current_device = available_devices.front ();
1077 set_popdown_strings (device_combo, available_devices);
1079 string_compose ("set device_combo active text: %1", current_device));
1081 device_combo.set_active_text (current_device);
1085 // @return true if there are input devices available
1087 EngineControl::set_input_device_popdown_strings ()
1089 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1090 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1091 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1093 vector<string> available_devices;
1095 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1096 available_devices.push_back (i->name);
1099 if (available_devices.empty()) {
1103 string current_device = backend->input_device_name ();
1105 // Make sure that backend->input_device_name () is a valid
1106 // device, the backend may not return a valid device if it hasn't
1108 if (std::find (available_devices.begin (),
1109 available_devices.end (),
1110 current_device) == available_devices.end ()) {
1112 current_device = available_devices.front ();
1115 set_popdown_strings (input_device_combo, available_devices);
1118 string_compose ("set input_device_combo active text: %1", current_device));
1119 input_device_combo.set_active_text (current_device);
1123 // @return true if there are output devices available
1125 EngineControl::set_output_device_popdown_strings ()
1127 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1128 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1129 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1131 vector<string> available_devices;
1133 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1134 available_devices.push_back (i->name);
1137 if (available_devices.empty()) {
1141 string current_device = backend->output_device_name ();
1143 // Make sure that backend->output_device_name () is a valid
1144 // device, the backend may not return a valid device if it hasn't
1146 if (std::find (available_devices.begin (),
1147 available_devices.end (),
1148 current_device) == available_devices.end ()) {
1150 current_device = available_devices.front ();
1153 set_popdown_strings (output_device_combo, available_devices);
1156 string_compose ("set output_device_combo active text: %1", current_device));
1157 output_device_combo.set_active_text (current_device);
1162 EngineControl::list_devices ()
1164 DEBUG_ECONTROL ("list_devices");
1165 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1168 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1170 bool devices_available = false;
1172 if (backend->use_separate_input_and_output_devices ()) {
1173 bool input_devices_available = set_input_device_popdown_strings ();
1174 bool output_devices_available = set_output_device_popdown_strings ();
1175 devices_available = input_devices_available || output_devices_available;
1177 devices_available = set_device_popdown_strings ();
1180 if (devices_available) {
1183 device_combo.clear();
1184 input_device_combo.clear();
1185 output_device_combo.clear();
1187 update_sensitivity ();
1191 EngineControl::driver_changed ()
1193 SignalBlocker blocker (*this, "driver_changed");
1194 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1197 backend->set_driver (driver_combo.get_active_text());
1200 if (!ignore_changes) {
1201 maybe_display_saved_state ();
1206 EngineControl::get_sample_rates_for_all_devices ()
1208 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1209 ARDOUR::AudioEngine::instance ()->current_backend ();
1210 vector<float> all_rates;
1212 if (backend->use_separate_input_and_output_devices ()) {
1213 all_rates = backend->available_sample_rates (get_input_device_name (), get_output_device_name ());
1215 all_rates = backend->available_sample_rates (get_device_name ());
1221 EngineControl::get_default_sample_rates ()
1223 vector<float> rates;
1224 rates.push_back (8000.0f);
1225 rates.push_back (16000.0f);
1226 rates.push_back (32000.0f);
1227 rates.push_back (44100.0f);
1228 rates.push_back (48000.0f);
1229 rates.push_back (88200.0f);
1230 rates.push_back (96000.0f);
1231 rates.push_back (192000.0f);
1232 rates.push_back (384000.0f);
1237 EngineControl::set_samplerate_popdown_strings ()
1239 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1240 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1245 if (_have_control) {
1246 sr = get_sample_rates_for_all_devices ();
1248 sr = get_default_sample_rates ();
1251 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1252 s.push_back (rate_as_string (*x));
1253 if (*x == _desired_sample_rate) {
1258 set_popdown_strings (sample_rate_combo, s);
1261 if (desired.empty ()) {
1262 float new_active_sr = backend->default_sample_rate ();
1264 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1265 new_active_sr = sr.front ();
1268 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1270 sample_rate_combo.set_active_text (desired);
1274 update_sensitivity ();
1278 EngineControl::get_buffer_sizes_for_all_devices ()
1280 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1281 ARDOUR::AudioEngine::instance ()->current_backend ();
1282 vector<uint32_t> all_sizes;
1284 if (backend->use_separate_input_and_output_devices ()) {
1285 all_sizes = backend->available_buffer_sizes (get_input_device_name (), get_output_device_name ());
1287 all_sizes = backend->available_buffer_sizes (get_device_name ());
1293 EngineControl::get_default_buffer_sizes ()
1295 vector<uint32_t> sizes;
1296 sizes.push_back (8);
1297 sizes.push_back (16);
1298 sizes.push_back (32);
1299 sizes.push_back (64);
1300 sizes.push_back (128);
1301 sizes.push_back (256);
1302 sizes.push_back (512);
1303 sizes.push_back (1024);
1304 sizes.push_back (2048);
1305 sizes.push_back (4096);
1306 sizes.push_back (8192);
1311 EngineControl::set_buffersize_popdown_strings ()
1313 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1314 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1315 vector<uint32_t> bs;
1318 if (_have_control) {
1319 bs = get_buffer_sizes_for_all_devices ();
1320 } else if (backend->can_change_buffer_size_when_running()) {
1321 bs = get_default_buffer_sizes ();
1324 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1325 s.push_back (bufsize_as_string (*x));
1328 set_popdown_strings (buffer_size_combo, s);
1331 buffer_size_combo.set_active_text (s.front());
1333 uint32_t period = backend->buffer_size();
1334 if (0 == period && backend->use_separate_input_and_output_devices ()) {
1335 period = backend->default_buffer_size (get_input_device_name ());
1337 if (0 == period && backend->use_separate_input_and_output_devices ()) {
1338 period = backend->default_buffer_size (get_output_device_name ());
1340 if (0 == period && !backend->use_separate_input_and_output_devices ()) {
1341 period = backend->default_buffer_size (get_device_name ());
1344 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1345 show_buffer_duration ();
1347 update_sensitivity ();
1351 EngineControl::device_changed ()
1353 SignalBlocker blocker (*this, "device_changed");
1354 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1357 string device_name_in;
1358 string device_name_out; // only used if backend support separate I/O devices
1360 if (backend->use_separate_input_and_output_devices()) {
1361 device_name_in = get_input_device_name ();
1362 device_name_out = get_output_device_name ();
1364 device_name_in = get_device_name ();
1367 /* we set the backend-device to query various device related intormation.
1368 * This has the side effect that backend->device_name() will match
1369 * the device_name and 'change_device' will never be true.
1370 * so work around this by setting...
1372 if (backend->use_separate_input_and_output_devices()) {
1373 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1374 queue_device_changed = true;
1377 if (device_name_in != backend->device_name()) {
1378 queue_device_changed = true;
1382 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1383 if (backend->use_separate_input_and_output_devices()) {
1384 backend->set_input_device_name (device_name_in);
1385 backend->set_output_device_name (device_name_out);
1387 backend->set_device_name(device_name_in);
1391 /* don't allow programmatic change to combos to cause a
1392 recursive call to this method.
1394 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1396 set_samplerate_popdown_strings ();
1397 set_buffersize_popdown_strings ();
1399 /* TODO set min + max channel counts here */
1401 manage_control_app_sensitivity ();
1404 /* pick up any saved state for this device */
1406 if (!ignore_changes) {
1407 maybe_display_saved_state ();
1412 EngineControl::input_device_changed ()
1414 DEBUG_ECONTROL ("input_device_changed");
1419 EngineControl::output_device_changed ()
1421 DEBUG_ECONTROL ("output_device_changed");
1426 EngineControl::bufsize_as_string (uint32_t sz)
1428 /* Translators: "samples" is always plural here, so no
1429 need for plural+singular forms.
1432 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1437 EngineControl::sample_rate_changed ()
1439 DEBUG_ECONTROL ("sample_rate_changed");
1440 /* reset the strings for buffer size to show the correct msec value
1441 (reflecting the new sample rate).
1444 show_buffer_duration ();
1449 EngineControl::buffer_size_changed ()
1451 DEBUG_ECONTROL ("buffer_size_changed");
1452 show_buffer_duration ();
1456 EngineControl::show_buffer_duration ()
1458 DEBUG_ECONTROL ("show_buffer_duration");
1459 /* buffer sizes - convert from just samples to samples + msecs for
1460 * the displayed string
1463 string bs_text = buffer_size_combo.get_active_text ();
1464 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1465 uint32_t rate = get_rate();
1467 /* Developers: note the hard-coding of a double buffered model
1468 in the (2 * samples) computation of latency. we always start
1469 the audiobackend in this configuration.
1471 /* note to jack1 developers: ardour also always starts the engine
1472 * in async mode (no jack2 --sync option) which adds an extra cycle
1473 * of latency with jack2 (and *3 would be correct)
1474 * The value can also be wrong if jackd is started externally..
1476 * At the time of writing the ALSA backend always uses double-buffering *2,
1477 * The Dummy backend *1, and who knows what ASIO really does :)
1479 * So just display the period size, that's also what
1480 * ARDOUR_UI::update_sample_rate() does for the status bar.
1481 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1482 * but still, that's the buffer period, not [round-trip] latency)
1485 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1486 buffer_size_duration_label.set_text (buf);
1490 EngineControl::midi_option_changed ()
1492 DEBUG_ECONTROL ("midi_option_changed");
1493 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1496 backend->set_midi_option (get_midi_option());
1498 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1500 //_midi_devices.clear(); // TODO merge with state-saved settings..
1501 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1502 std::vector<MidiDeviceSettings> new_devices;
1504 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1505 MidiDeviceSettings mds = find_midi_device (i->name);
1506 if (i->available && !mds) {
1507 uint32_t input_latency = 0;
1508 uint32_t output_latency = 0;
1509 if (_can_set_midi_latencies) {
1510 input_latency = backend->systemic_midi_input_latency (i->name);
1511 output_latency = backend->systemic_midi_output_latency (i->name);
1513 bool enabled = backend->midi_device_enabled (i->name);
1514 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1515 new_devices.push_back (ptr);
1516 } else if (i->available) {
1517 new_devices.push_back (mds);
1520 _midi_devices = new_devices;
1522 if (_midi_devices.empty()) {
1523 midi_devices_button.set_sensitive (false);
1525 midi_devices_button.set_sensitive (true);
1530 EngineControl::parameter_changed ()
1534 EngineControl::State
1535 EngineControl::get_matching_state (
1536 const string& backend,
1537 const string& driver,
1538 const string& device)
1540 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1541 if ((*i)->backend == backend &&
1542 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1550 EngineControl::State
1551 EngineControl::get_matching_state (
1552 const string& backend,
1553 const string& driver,
1554 const string& input_device,
1555 const string& output_device)
1557 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1558 if ((*i)->backend == backend &&
1559 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1567 EngineControl::State
1568 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1570 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1573 if (backend->use_separate_input_and_output_devices ()) {
1574 return get_matching_state (backend_combo.get_active_text(),
1575 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1576 input_device_combo.get_active_text(),
1577 output_device_combo.get_active_text());
1579 return get_matching_state (backend_combo.get_active_text(),
1580 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1581 device_combo.get_active_text());
1585 return get_matching_state (backend_combo.get_active_text(),
1587 device_combo.get_active_text());
1590 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1591 const EngineControl::State& state2)
1593 if (state1->backend == state2->backend &&
1594 state1->driver == state2->driver &&
1595 state1->device == state2->device &&
1596 state1->input_device == state2->input_device &&
1597 state1->output_device == state2->output_device) {
1603 EngineControl::State
1604 EngineControl::save_state ()
1608 if (!_have_control) {
1609 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1613 state.reset(new StateStruct);
1614 state->backend = get_backend ();
1616 state.reset(new StateStruct);
1617 store_state (state);
1620 for (StateList::iterator i = states.begin(); i != states.end();) {
1621 if (equivalent_states (*i, state)) {
1622 i = states.erase(i);
1628 states.push_back (state);
1634 EngineControl::store_state (State state)
1636 state->backend = get_backend ();
1637 state->driver = get_driver ();
1638 state->device = get_device_name ();
1639 state->input_device = get_input_device_name ();
1640 state->output_device = get_output_device_name ();
1641 state->sample_rate = get_rate ();
1642 state->buffer_size = get_buffer_size ();
1643 state->input_latency = get_input_latency ();
1644 state->output_latency = get_output_latency ();
1645 state->input_channels = get_input_channels ();
1646 state->output_channels = get_output_channels ();
1647 state->midi_option = get_midi_option ();
1648 state->midi_devices = _midi_devices;
1652 EngineControl::maybe_display_saved_state ()
1654 if (!_have_control) {
1658 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1661 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1663 if (!_desired_sample_rate) {
1664 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1666 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1667 /* call this explicitly because we're ignoring changes to
1668 the controls at this point.
1670 show_buffer_duration ();
1671 input_latency.set_value (state->input_latency);
1672 output_latency.set_value (state->output_latency);
1674 if (!state->midi_option.empty()) {
1675 midi_option_combo.set_active_text (state->midi_option);
1676 _midi_devices = state->midi_devices;
1682 EngineControl::get_state ()
1684 LocaleGuard lg (X_("C"));
1686 XMLNode* root = new XMLNode ("AudioMIDISetup");
1689 if (!states.empty()) {
1690 XMLNode* state_nodes = new XMLNode ("EngineStates");
1692 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1694 XMLNode* node = new XMLNode ("State");
1696 node->add_property ("backend", (*i)->backend);
1697 node->add_property ("driver", (*i)->driver);
1698 node->add_property ("device", (*i)->device);
1699 node->add_property ("input-device", (*i)->input_device);
1700 node->add_property ("output-device", (*i)->output_device);
1701 node->add_property ("sample-rate", (*i)->sample_rate);
1702 node->add_property ("buffer-size", (*i)->buffer_size);
1703 node->add_property ("input-latency", (*i)->input_latency);
1704 node->add_property ("output-latency", (*i)->output_latency);
1705 node->add_property ("input-channels", (*i)->input_channels);
1706 node->add_property ("output-channels", (*i)->output_channels);
1707 node->add_property ("active", (*i)->active ? "yes" : "no");
1708 node->add_property ("midi-option", (*i)->midi_option);
1710 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1711 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1712 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1713 midi_device_stuff->add_property (X_("name"), (*p)->name);
1714 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1715 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1716 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1717 midi_devices->add_child_nocopy (*midi_device_stuff);
1719 node->add_child_nocopy (*midi_devices);
1721 state_nodes->add_child_nocopy (*node);
1724 root->add_child_nocopy (*state_nodes);
1731 EngineControl::set_default_state ()
1733 vector<string> backend_names;
1734 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1736 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1737 backend_names.push_back ((*b)->name);
1739 backend_combo.set_active_text (backend_names.front());
1741 // We could set default backends per platform etc here
1747 EngineControl::set_state (const XMLNode& root)
1749 XMLNodeList clist, cclist;
1750 XMLNodeConstIterator citer, cciter;
1752 XMLNode* grandchild;
1753 XMLProperty* prop = NULL;
1755 fprintf (stderr, "EngineControl::set_state\n");
1757 if (root.name() != "AudioMIDISetup") {
1761 clist = root.children();
1765 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1769 if (child->name() != "EngineStates") {
1773 cclist = child->children();
1775 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1776 State state (new StateStruct);
1778 grandchild = *cciter;
1780 if (grandchild->name() != "State") {
1784 if ((prop = grandchild->property ("backend")) == 0) {
1787 state->backend = prop->value ();
1789 if ((prop = grandchild->property ("driver")) == 0) {
1792 state->driver = prop->value ();
1794 if ((prop = grandchild->property ("device")) == 0) {
1797 state->device = prop->value ();
1799 if ((prop = grandchild->property ("input-device")) == 0) {
1802 state->input_device = prop->value ();
1804 if ((prop = grandchild->property ("output-device")) == 0) {
1807 state->output_device = prop->value ();
1809 if ((prop = grandchild->property ("sample-rate")) == 0) {
1812 state->sample_rate = atof (prop->value ());
1814 if ((prop = grandchild->property ("buffer-size")) == 0) {
1817 state->buffer_size = atoi (prop->value ());
1819 if ((prop = grandchild->property ("input-latency")) == 0) {
1822 state->input_latency = atoi (prop->value ());
1824 if ((prop = grandchild->property ("output-latency")) == 0) {
1827 state->output_latency = atoi (prop->value ());
1829 if ((prop = grandchild->property ("input-channels")) == 0) {
1832 state->input_channels = atoi (prop->value ());
1834 if ((prop = grandchild->property ("output-channels")) == 0) {
1837 state->output_channels = atoi (prop->value ());
1839 if ((prop = grandchild->property ("active")) == 0) {
1842 state->active = string_is_affirmative (prop->value ());
1844 if ((prop = grandchild->property ("midi-option")) == 0) {
1847 state->midi_option = prop->value ();
1849 state->midi_devices.clear();
1851 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1852 const XMLNodeList mnc = midinode->children();
1853 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1854 if ((*n)->property (X_("name")) == 0
1855 || (*n)->property (X_("enabled")) == 0
1856 || (*n)->property (X_("input-latency")) == 0
1857 || (*n)->property (X_("output-latency")) == 0
1862 MidiDeviceSettings ptr (new MidiDeviceSetting(
1863 (*n)->property (X_("name"))->value (),
1864 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1865 atoi ((*n)->property (X_("input-latency"))->value ()),
1866 atoi ((*n)->property (X_("output-latency"))->value ())
1868 state->midi_devices.push_back (ptr);
1873 /* remove accumulated duplicates (due to bug in ealier version)
1874 * this can be removed again before release
1876 for (StateList::iterator i = states.begin(); i != states.end();) {
1877 if ((*i)->backend == state->backend &&
1878 (*i)->driver == state->driver &&
1879 (*i)->device == state->device) {
1880 i = states.erase(i);
1887 states.push_back (state);
1891 /* now see if there was an active state and switch the setup to it */
1893 // purge states of backend that are not available in this built
1894 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1895 vector<std::string> backend_names;
1897 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1898 backend_names.push_back((*i)->name);
1900 for (StateList::iterator i = states.begin(); i != states.end();) {
1901 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1902 i = states.erase(i);
1908 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1911 return set_current_state (*i);
1918 EngineControl::set_current_state (const State& state)
1920 DEBUG_ECONTROL ("set_current_state");
1922 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1924 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1925 state->backend, "ardour", ""))) {
1926 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1927 // this shouldn't happen as the invalid backend names should have been
1928 // removed from the list of states.
1932 // now reflect the change in the backend in the GUI so backend_changed will
1933 // do the right thing
1934 backend_combo.set_active_text (state->backend);
1936 if (!state->driver.empty ()) {
1937 if (!backend->requires_driver_selection ()) {
1938 DEBUG_ECONTROL ("Backend should require driver selection");
1939 // A backend has changed from having driver selection to not having
1940 // it or someone has been manually editing a config file and messed
1945 if (backend->set_driver (state->driver) != 0) {
1946 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
1947 // Driver names for a backend have changed and the name in the
1948 // config file is now invalid or support for driver is no longer
1949 // included in the backend
1952 // no need to set the driver_combo as backend_changed will use
1953 // backend->driver_name to set the active driver
1956 if (!state->device.empty ()) {
1957 if (backend->set_device_name (state->device) != 0) {
1959 string_compose ("Unable to set device name %1", state->device));
1960 // device is no longer available on the system
1963 // no need to set active device as it will be picked up in
1964 // via backend_changed ()/set_device_popdown_strings
1967 // backend supports separate input/output devices
1968 if (backend->set_input_device_name (state->input_device) != 0) {
1969 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
1970 state->input_device));
1971 // input device is no longer available on the system
1975 if (backend->set_output_device_name (state->output_device) != 0) {
1976 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
1977 state->input_device));
1978 // output device is no longer available on the system
1981 // no need to set active devices as it will be picked up in via
1982 // backend_changed ()/set_*_device_popdown_strings
1987 // Now restore the state of the rest of the controls
1989 // We don't use a SignalBlocker as set_current_state is currently only
1990 // called from set_state before any signals are connected. If at some point
1991 // a more general named state mechanism is implemented and
1992 // set_current_state is called while signals are connected then a
1993 // SignalBlocker will need to be instantiated before setting these.
1995 device_combo.set_active_text (state->device);
1996 input_device_combo.set_active_text (state->input_device);
1997 output_device_combo.set_active_text (state->output_device);
1998 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1999 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2000 input_latency.set_value (state->input_latency);
2001 output_latency.set_value (state->output_latency);
2002 midi_option_combo.set_active_text (state->midi_option);
2007 EngineControl::push_state_to_backend (bool start)
2009 DEBUG_ECONTROL ("push_state_to_backend");
2010 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2016 /* figure out what is going to change */
2018 bool restart_required = false;
2019 bool was_running = ARDOUR::AudioEngine::instance()->running();
2020 bool change_driver = false;
2021 bool change_device = false;
2022 bool change_rate = false;
2023 bool change_bufsize = false;
2024 bool change_latency = false;
2025 bool change_channels = false;
2026 bool change_midi = false;
2028 uint32_t ochan = get_output_channels ();
2029 uint32_t ichan = get_input_channels ();
2031 if (_have_control) {
2033 if (started_at_least_once) {
2035 /* we can control the backend */
2037 if (backend->requires_driver_selection()) {
2038 if (get_driver() != backend->driver_name()) {
2039 change_driver = true;
2043 if (backend->use_separate_input_and_output_devices()) {
2044 if (get_input_device_name() != backend->input_device_name()) {
2045 change_device = true;
2047 if (get_output_device_name() != backend->output_device_name()) {
2048 change_device = true;
2051 if (get_device_name() != backend->device_name()) {
2052 change_device = true;
2056 if (queue_device_changed) {
2057 change_device = true;
2060 if (get_rate() != backend->sample_rate()) {
2064 if (get_buffer_size() != backend->buffer_size()) {
2065 change_bufsize = true;
2068 if (get_midi_option() != backend->midi_option()) {
2072 /* zero-requested channels means "all available" */
2075 ichan = backend->input_channels();
2079 ochan = backend->output_channels();
2082 if (ichan != backend->input_channels()) {
2083 change_channels = true;
2086 if (ochan != backend->output_channels()) {
2087 change_channels = true;
2090 if (get_input_latency() != backend->systemic_input_latency() ||
2091 get_output_latency() != backend->systemic_output_latency()) {
2092 change_latency = true;
2095 /* backend never started, so we have to force a group
2098 change_device = true;
2099 if (backend->requires_driver_selection()) {
2100 change_driver = true;
2103 change_bufsize = true;
2104 change_channels = true;
2105 change_latency = true;
2111 /* we have no control over the backend, meaning that we can
2112 * only possibly change sample rate and buffer size.
2116 if (get_rate() != backend->sample_rate()) {
2117 change_bufsize = true;
2120 if (get_buffer_size() != backend->buffer_size()) {
2121 change_bufsize = true;
2125 queue_device_changed = false;
2127 if (!_have_control) {
2129 /* We do not have control over the backend, so the best we can
2130 * do is try to change the sample rate and/or bufsize and get
2134 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2138 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2143 backend->set_sample_rate (get_rate());
2146 if (change_bufsize) {
2147 backend->set_buffer_size (get_buffer_size());
2151 if (ARDOUR::AudioEngine::instance()->start ()) {
2152 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2162 /* determine if we need to stop the backend before changing parameters */
2164 if (change_driver || change_device || change_channels || change_latency ||
2165 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2167 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2168 restart_required = true;
2170 restart_required = false;
2175 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2176 /* no changes in any parameters that absolutely require a
2177 * restart, so check those that might be changeable without a
2181 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2182 /* can't do this while running ... */
2183 restart_required = true;
2186 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2187 /* can't do this while running ... */
2188 restart_required = true;
2194 if (restart_required) {
2195 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2202 if (change_driver && backend->set_driver (get_driver())) {
2203 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2206 if (backend->use_separate_input_and_output_devices()) {
2207 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2208 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2211 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2212 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2216 if (change_device && backend->set_device_name (get_device_name())) {
2217 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2221 if (change_rate && backend->set_sample_rate (get_rate())) {
2222 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2225 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2226 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2230 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2231 if (backend->set_input_channels (get_input_channels())) {
2232 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2235 if (backend->set_output_channels (get_output_channels())) {
2236 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2240 if (change_latency) {
2241 if (backend->set_systemic_input_latency (get_input_latency())) {
2242 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2245 if (backend->set_systemic_output_latency (get_output_latency())) {
2246 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2252 backend->set_midi_option (get_midi_option());
2256 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2257 if (_measure_midi) {
2258 if (*p == _measure_midi) {
2259 backend->set_midi_device_enabled ((*p)->name, true);
2261 backend->set_midi_device_enabled ((*p)->name, false);
2265 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2266 if (backend->can_set_systemic_midi_latencies()) {
2267 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2268 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2273 if (start || (was_running && restart_required)) {
2274 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2285 EngineControl::post_push ()
2287 /* get a pointer to the current state object, creating one if
2291 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2294 state = save_state ();
2302 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2303 (*i)->active = false;
2306 /* mark this one active (to be used next time the dialog is
2310 state->active = true;
2312 if (_have_control) { // XXX
2313 manage_control_app_sensitivity ();
2316 /* schedule a redisplay of MIDI ports */
2317 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2322 EngineControl::get_rate () const
2324 float r = atof (sample_rate_combo.get_active_text ());
2325 /* the string may have been translated with an abbreviation for
2326 * thousands, so use a crude heuristic to fix this.
2336 EngineControl::get_buffer_size () const
2338 string txt = buffer_size_combo.get_active_text ();
2341 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2342 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2343 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2351 EngineControl::get_midi_option () const
2353 return midi_option_combo.get_active_text();
2357 EngineControl::get_input_channels() const
2359 if (ARDOUR::Profile->get_mixbus()) {
2360 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2361 if (!backend) return 0;
2362 return backend->input_channels();
2364 return (uint32_t) input_channels_adjustment.get_value();
2368 EngineControl::get_output_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) output_channels_adjustment.get_value();
2379 EngineControl::get_input_latency() const
2381 return (uint32_t) input_latency_adjustment.get_value();
2385 EngineControl::get_output_latency() const
2387 return (uint32_t) output_latency_adjustment.get_value();
2391 EngineControl::get_backend () const
2393 return backend_combo.get_active_text ();
2397 EngineControl::get_driver () const
2399 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2400 return driver_combo.get_active_text ();
2407 EngineControl::get_device_name () const
2409 return device_combo.get_active_text ();
2413 EngineControl::get_input_device_name () const
2415 return input_device_combo.get_active_text ();
2419 EngineControl::get_output_device_name () const
2421 return output_device_combo.get_active_text ();
2425 EngineControl::control_app_button_clicked ()
2427 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2433 backend->launch_control_app ();
2437 EngineControl::stop_engine_button_clicked ()
2439 ARDOUR::AudioEngine::instance()->stop ();
2443 EngineControl::manage_control_app_sensitivity ()
2445 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2451 string appname = backend->control_app_name();
2453 if (appname.empty()) {
2454 control_app_button.set_sensitive (false);
2456 control_app_button.set_sensitive (true);
2461 EngineControl::set_desired_sample_rate (uint32_t sr)
2463 _desired_sample_rate = sr;
2468 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2470 if (page_num == 0) {
2471 cancel_button->set_sensitive (true);
2472 _measure_midi.reset();
2473 update_sensitivity ();
2475 cancel_button->set_sensitive (false);
2476 ok_button->set_sensitive (false);
2477 apply_button->set_sensitive (false);
2480 if (page_num == midi_tab) {
2482 refresh_midi_display ();
2485 if (page_num == latency_tab) {
2488 if (ARDOUR::AudioEngine::instance()->running()) {
2489 // TODO - mark as 'stopped for latency
2490 ARDOUR_UI::instance()->disconnect_from_engine ();
2494 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2496 /* save any existing latency values */
2498 uint32_t il = (uint32_t) input_latency.get_value ();
2499 uint32_t ol = (uint32_t) input_latency.get_value ();
2501 /* reset to zero so that our new test instance
2502 will be clean of any existing latency measures.
2504 NB. this should really be done by the backend
2505 when stated for latency measurement.
2508 input_latency.set_value (0);
2509 output_latency.set_value (0);
2511 push_state_to_backend (false);
2515 input_latency.set_value (il);
2516 output_latency.set_value (ol);
2519 // This should be done in push_state_to_backend()
2520 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2521 disable_latency_tab ();
2524 enable_latency_tab ();
2528 end_latency_detection ();
2529 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2534 /* latency measurement */
2537 EngineControl::check_audio_latency_measurement ()
2539 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2541 if (mtdm->resolve () < 0) {
2542 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2546 if (mtdm->err () > 0.3) {
2552 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2554 if (sample_rate == 0) {
2555 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2556 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2560 int frames_total = mtdm->del();
2561 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2563 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2564 _("Detected roundtrip latency: "),
2565 frames_total, frames_total * 1000.0f/sample_rate,
2566 _("Systemic latency: "),
2567 extra, extra * 1000.0f/sample_rate);
2571 if (mtdm->err () > 0.2) {
2573 strcat (buf, _("(signal detection error)"));
2579 strcat (buf, _("(inverted - bad wiring)"));
2583 lm_results.set_markup (string_compose (results_markup, buf));
2586 have_lm_results = true;
2587 end_latency_detection ();
2588 lm_use_button.set_sensitive (true);
2596 EngineControl::check_midi_latency_measurement ()
2598 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2600 if (!mididm->have_signal () || mididm->latency () == 0) {
2601 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2606 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2608 if (sample_rate == 0) {
2609 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2610 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2614 ARDOUR::framecnt_t frames_total = mididm->latency();
2615 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2616 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2617 _("Detected roundtrip latency: "),
2618 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2619 _("Systemic latency: "),
2620 extra, extra * 1000.0f / sample_rate);
2624 if (!mididm->ok ()) {
2626 strcat (buf, _("(averaging)"));
2630 if (mididm->deviation () > 50.0) {
2632 strcat (buf, _("(too large jitter)"));
2634 } else if (mididm->deviation () > 10.0) {
2636 strcat (buf, _("(large jitter)"));
2640 have_lm_results = true;
2641 end_latency_detection ();
2642 lm_use_button.set_sensitive (true);
2643 lm_results.set_markup (string_compose (results_markup, buf));
2645 } else if (mididm->processed () > 400) {
2646 have_lm_results = false;
2647 end_latency_detection ();
2648 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2652 lm_results.set_markup (string_compose (results_markup, buf));
2658 EngineControl::start_latency_detection ()
2660 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2661 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2663 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2664 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2665 if (_measure_midi) {
2666 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2668 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2670 lm_measure_label.set_text (_("Cancel"));
2671 have_lm_results = false;
2672 lm_use_button.set_sensitive (false);
2673 lm_input_channel_combo.set_sensitive (false);
2674 lm_output_channel_combo.set_sensitive (false);
2680 EngineControl::end_latency_detection ()
2682 latency_timeout.disconnect ();
2683 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2684 lm_measure_label.set_text (_("Measure"));
2685 if (!have_lm_results) {
2686 lm_use_button.set_sensitive (false);
2688 lm_input_channel_combo.set_sensitive (true);
2689 lm_output_channel_combo.set_sensitive (true);
2694 EngineControl::latency_button_clicked ()
2697 start_latency_detection ();
2699 end_latency_detection ();
2704 EngineControl::use_latency_button_clicked ()
2706 if (_measure_midi) {
2707 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2711 ARDOUR::framecnt_t frames_total = mididm->latency();
2712 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2713 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2714 _measure_midi->input_latency = one_way;
2715 _measure_midi->output_latency = one_way;
2716 notebook.set_current_page (midi_tab);
2718 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2724 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2725 one_way = std::max (0., one_way);
2727 input_latency_adjustment.set_value (one_way);
2728 output_latency_adjustment.set_value (one_way);
2730 /* back to settings page */
2731 notebook.set_current_page (0);
2737 EngineControl::on_delete_event (GdkEventAny* ev)
2739 if (notebook.get_current_page() == 2) {
2740 /* currently on latency tab - be sure to clean up */
2741 end_latency_detection ();
2743 return ArdourDialog::on_delete_event (ev);
2747 EngineControl::engine_running ()
2749 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2752 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2753 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2755 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2756 connect_disconnect_button.show();
2758 started_at_least_once = true;
2759 if (_have_control) {
2760 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2762 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2764 update_sensitivity();
2768 EngineControl::engine_stopped ()
2770 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2773 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2774 connect_disconnect_button.show();
2776 engine_status.set_markup(X_(""));
2777 update_sensitivity();
2781 EngineControl::device_list_changed ()
2783 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2785 midi_option_changed();
2789 EngineControl::connect_disconnect_click()
2791 if (ARDOUR::AudioEngine::instance()->running()) {
2792 ARDOUR_UI::instance()->disconnect_from_engine ();
2794 ARDOUR_UI::instance()->reconnect_to_engine ();
2799 EngineControl::calibrate_audio_latency ()
2801 _measure_midi.reset ();
2802 have_lm_results = false;
2803 lm_use_button.set_sensitive (false);
2804 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2805 notebook.set_current_page (latency_tab);
2809 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2812 have_lm_results = false;
2813 lm_use_button.set_sensitive (false);
2814 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2815 notebook.set_current_page (latency_tab);
2819 EngineControl::configure_midi_devices ()
2821 notebook.set_current_page (midi_tab);