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 driver_combo.set_sensitive (false);
804 stop_engine_button.set_sensitive (true);
805 stop_engine_button.show ();
807 input_device_combo.set_sensitive (true);
808 output_device_combo.set_sensitive (true);
809 device_combo.set_sensitive (true);
810 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
811 driver_combo.set_sensitive (true);
813 driver_combo.set_sensitive (false);
815 stop_engine_button.set_sensitive (false);
816 stop_engine_button.hide ();
819 if (valid || !_have_control) {
820 ok_button->set_sensitive (true);
821 apply_button->set_sensitive (true);
823 ok_button->set_sensitive (false);
824 apply_button->set_sensitive (false);
829 EngineControl::setup_midi_tab_for_jack ()
834 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
836 device->input_latency = a->get_value();
838 device->output_latency = a->get_value();
843 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
844 b->set_active (!b->get_active());
845 device->enabled = b->get_active();
846 refresh_midi_display(device->name);
850 EngineControl::refresh_midi_display (std::string focus)
852 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
856 AttachOptions xopt = AttachOptions (FILL|EXPAND);
859 Gtkmm2ext::container_clear (midi_device_table);
861 midi_device_table.set_spacings (6);
863 l = manage (new Label);
864 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
865 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
866 l->set_alignment (0.5, 0.5);
870 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
871 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
872 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
873 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
875 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
876 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
877 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
878 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
881 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
886 bool enabled = (*p)->enabled;
888 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
889 m->set_name ("midi device");
890 m->set_can_focus (Gtk::CAN_FOCUS);
891 m->add_events (Gdk::BUTTON_RELEASE_MASK);
892 m->set_active (enabled);
893 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
894 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
895 if ((*p)->name == focus) {
899 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
900 s = manage (new Gtk::SpinButton (*a));
901 a->set_value ((*p)->input_latency);
902 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
903 s->set_sensitive (_can_set_midi_latencies && enabled);
904 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
906 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
907 s = manage (new Gtk::SpinButton (*a));
908 a->set_value ((*p)->output_latency);
909 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
910 s->set_sensitive (_can_set_midi_latencies && enabled);
911 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
913 b = manage (new Button (_("Calibrate")));
914 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
915 b->set_sensitive (_can_set_midi_latencies && enabled);
916 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
923 EngineControl::backend_changed ()
925 SignalBlocker blocker (*this, "backend_changed");
926 string backend_name = backend_combo.get_active_text();
927 boost::shared_ptr<ARDOUR::AudioBackend> backend;
929 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
930 /* eh? setting the backend failed... how ? */
931 /* A: stale config contains a backend that does not exist in current build */
935 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
937 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
940 setup_midi_tab_for_backend ();
941 _midi_devices.clear();
943 if (backend->requires_driver_selection()) {
944 if (set_driver_popdown_strings ()) {
948 /* this will change the device text which will cause a call to
949 * device changed which will set up parameters
954 update_midi_options ();
956 connect_disconnect_button.hide();
958 midi_option_changed();
960 started_at_least_once = false;
962 /* changing the backend implies stopping the engine
963 * ARDOUR::AudioEngine() may or may not emit this signal
964 * depending on previous engine state
966 engine_stopped (); // set "active/inactive"
968 if (!ignore_changes) {
969 maybe_display_saved_state ();
974 EngineControl::update_midi_options ()
976 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
977 vector<string> midi_options = backend->enumerate_midi_options();
979 if (midi_options.size() == 1) {
980 /* only contains the "none" option */
981 midi_option_combo.set_sensitive (false);
984 set_popdown_strings (midi_option_combo, midi_options);
985 midi_option_combo.set_active_text (midi_options.front());
986 midi_option_combo.set_sensitive (true);
988 midi_option_combo.set_sensitive (false);
994 EngineControl::print_channel_count (Gtk::SpinButton* sb)
996 if (ARDOUR::Profile->get_mixbus()) {
1000 uint32_t cnt = (uint32_t) sb->get_value();
1002 sb->set_text (_("all available channels"));
1005 snprintf (buf, sizeof (buf), "%d", cnt);
1011 // @return true if there are drivers available
1013 EngineControl::set_driver_popdown_strings ()
1015 DEBUG_ECONTROL ("set_driver_popdown_strings");
1016 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1017 vector<string> drivers = backend->enumerate_drivers();
1019 if (drivers.empty ()) {
1020 // This is an error...?
1024 string current_driver = backend->driver_name ();
1026 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1028 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1031 current_driver = drivers.front ();
1034 set_popdown_strings (driver_combo, drivers);
1036 string_compose ("driver_combo.set_active_text: %1", current_driver));
1037 driver_combo.set_active_text (current_driver);
1041 // @return true if there are devices available
1043 EngineControl::set_device_popdown_strings ()
1045 DEBUG_ECONTROL ("set_device_popdown_strings");
1046 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1047 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1049 /* NOTE: Ardour currently does not display the "available" field of the
1052 * Doing so would require a different GUI widget than the combo
1053 * box/popdown that we currently use, since it has no way to list
1054 * items that are not selectable. Something more like a popup menu,
1055 * which could have unselectable items, would be appropriate.
1058 vector<string> available_devices;
1060 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1061 available_devices.push_back (i->name);
1064 if (available_devices.empty ()) {
1068 string current_device = backend->device_name ();
1070 // Make sure that backend->device_name () is a valid
1071 // device, the backend may not return a valid device if it hasn't
1073 if (std::find (available_devices.begin (),
1074 available_devices.end (),
1075 current_device) == available_devices.end ()) {
1077 current_device = available_devices.front ();
1080 set_popdown_strings (device_combo, available_devices);
1082 string_compose ("set device_combo active text: %1", current_device));
1084 device_combo.set_active_text (current_device);
1088 // @return true if there are input devices available
1090 EngineControl::set_input_device_popdown_strings ()
1092 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1093 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1094 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1096 vector<string> available_devices;
1098 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1099 available_devices.push_back (i->name);
1102 if (available_devices.empty()) {
1106 string current_device = backend->input_device_name ();
1108 // Make sure that backend->input_device_name () is a valid
1109 // device, the backend may not return a valid device if it hasn't
1111 if (std::find (available_devices.begin (),
1112 available_devices.end (),
1113 current_device) == available_devices.end ()) {
1115 current_device = available_devices.front ();
1118 set_popdown_strings (input_device_combo, available_devices);
1121 string_compose ("set input_device_combo active text: %1", current_device));
1122 input_device_combo.set_active_text (current_device);
1126 // @return true if there are output devices available
1128 EngineControl::set_output_device_popdown_strings ()
1130 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1131 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1132 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1134 vector<string> available_devices;
1136 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1137 available_devices.push_back (i->name);
1140 if (available_devices.empty()) {
1144 string current_device = backend->output_device_name ();
1146 // Make sure that backend->output_device_name () is a valid
1147 // device, the backend may not return a valid device if it hasn't
1149 if (std::find (available_devices.begin (),
1150 available_devices.end (),
1151 current_device) == available_devices.end ()) {
1153 current_device = available_devices.front ();
1156 set_popdown_strings (output_device_combo, available_devices);
1159 string_compose ("set output_device_combo active text: %1", current_device));
1160 output_device_combo.set_active_text (current_device);
1165 EngineControl::list_devices ()
1167 DEBUG_ECONTROL ("list_devices");
1168 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1171 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1173 bool devices_available = false;
1175 if (backend->use_separate_input_and_output_devices ()) {
1176 bool input_devices_available = set_input_device_popdown_strings ();
1177 bool output_devices_available = set_output_device_popdown_strings ();
1178 devices_available = input_devices_available || output_devices_available;
1180 devices_available = set_device_popdown_strings ();
1183 if (devices_available) {
1186 device_combo.clear();
1187 input_device_combo.clear();
1188 output_device_combo.clear();
1190 update_sensitivity ();
1194 EngineControl::driver_changed ()
1196 SignalBlocker blocker (*this, "driver_changed");
1197 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1200 backend->set_driver (driver_combo.get_active_text());
1203 if (!ignore_changes) {
1204 maybe_display_saved_state ();
1209 EngineControl::get_sample_rates_for_all_devices ()
1211 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1212 ARDOUR::AudioEngine::instance ()->current_backend ();
1213 vector<float> all_rates;
1215 if (backend->use_separate_input_and_output_devices ()) {
1216 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1218 all_rates = backend->available_sample_rates (get_device_name ());
1224 EngineControl::get_default_sample_rates ()
1226 vector<float> rates;
1227 rates.push_back (8000.0f);
1228 rates.push_back (16000.0f);
1229 rates.push_back (32000.0f);
1230 rates.push_back (44100.0f);
1231 rates.push_back (48000.0f);
1232 rates.push_back (88200.0f);
1233 rates.push_back (96000.0f);
1234 rates.push_back (192000.0f);
1235 rates.push_back (384000.0f);
1240 EngineControl::set_samplerate_popdown_strings ()
1242 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1243 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1248 if (_have_control) {
1249 sr = get_sample_rates_for_all_devices ();
1251 sr = get_default_sample_rates ();
1254 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1255 s.push_back (rate_as_string (*x));
1256 if (*x == _desired_sample_rate) {
1261 set_popdown_strings (sample_rate_combo, s);
1264 if (desired.empty ()) {
1265 float new_active_sr = backend->default_sample_rate ();
1267 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1268 new_active_sr = sr.front ();
1271 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1273 sample_rate_combo.set_active_text (desired);
1277 update_sensitivity ();
1281 EngineControl::get_buffer_sizes_for_all_devices ()
1283 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1284 ARDOUR::AudioEngine::instance ()->current_backend ();
1285 vector<uint32_t> all_sizes;
1287 if (backend->use_separate_input_and_output_devices ()) {
1288 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1290 all_sizes = backend->available_buffer_sizes (get_device_name ());
1296 EngineControl::get_default_buffer_sizes ()
1298 vector<uint32_t> sizes;
1299 sizes.push_back (8);
1300 sizes.push_back (16);
1301 sizes.push_back (32);
1302 sizes.push_back (64);
1303 sizes.push_back (128);
1304 sizes.push_back (256);
1305 sizes.push_back (512);
1306 sizes.push_back (1024);
1307 sizes.push_back (2048);
1308 sizes.push_back (4096);
1309 sizes.push_back (8192);
1314 EngineControl::set_buffersize_popdown_strings ()
1316 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1317 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1318 vector<uint32_t> bs;
1321 if (_have_control) {
1322 bs = get_buffer_sizes_for_all_devices ();
1323 } else if (backend->can_change_buffer_size_when_running()) {
1324 bs = get_default_buffer_sizes ();
1327 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1328 s.push_back (bufsize_as_string (*x));
1331 set_popdown_strings (buffer_size_combo, s);
1334 buffer_size_combo.set_active_text (s.front());
1336 uint32_t period = backend->buffer_size();
1337 if (0 == period && backend->use_separate_input_and_output_devices ()) {
1338 period = backend->default_buffer_size (get_input_device_name ());
1340 if (0 == period && backend->use_separate_input_and_output_devices ()) {
1341 period = backend->default_buffer_size (get_output_device_name ());
1343 if (0 == period && !backend->use_separate_input_and_output_devices ()) {
1344 period = backend->default_buffer_size (get_device_name ());
1347 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1348 show_buffer_duration ();
1350 update_sensitivity ();
1354 EngineControl::device_changed ()
1356 SignalBlocker blocker (*this, "device_changed");
1357 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1360 string device_name_in;
1361 string device_name_out; // only used if backend support separate I/O devices
1363 if (backend->use_separate_input_and_output_devices()) {
1364 device_name_in = get_input_device_name ();
1365 device_name_out = get_output_device_name ();
1367 device_name_in = get_device_name ();
1370 /* we set the backend-device to query various device related intormation.
1371 * This has the side effect that backend->device_name() will match
1372 * the device_name and 'change_device' will never be true.
1373 * so work around this by setting...
1375 if (backend->use_separate_input_and_output_devices()) {
1376 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1377 queue_device_changed = true;
1380 if (device_name_in != backend->device_name()) {
1381 queue_device_changed = true;
1385 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1386 if (backend->use_separate_input_and_output_devices()) {
1387 backend->set_input_device_name (device_name_in);
1388 backend->set_output_device_name (device_name_out);
1390 backend->set_device_name(device_name_in);
1394 /* don't allow programmatic change to combos to cause a
1395 recursive call to this method.
1397 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1399 set_samplerate_popdown_strings ();
1400 set_buffersize_popdown_strings ();
1402 /* TODO set min + max channel counts here */
1404 manage_control_app_sensitivity ();
1407 /* pick up any saved state for this device */
1409 if (!ignore_changes) {
1410 maybe_display_saved_state ();
1415 EngineControl::input_device_changed ()
1417 DEBUG_ECONTROL ("input_device_changed");
1422 EngineControl::output_device_changed ()
1424 DEBUG_ECONTROL ("output_device_changed");
1429 EngineControl::bufsize_as_string (uint32_t sz)
1431 /* Translators: "samples" is always plural here, so no
1432 need for plural+singular forms.
1435 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1440 EngineControl::sample_rate_changed ()
1442 DEBUG_ECONTROL ("sample_rate_changed");
1443 /* reset the strings for buffer size to show the correct msec value
1444 (reflecting the new sample rate).
1447 show_buffer_duration ();
1452 EngineControl::buffer_size_changed ()
1454 DEBUG_ECONTROL ("buffer_size_changed");
1455 show_buffer_duration ();
1459 EngineControl::show_buffer_duration ()
1461 DEBUG_ECONTROL ("show_buffer_duration");
1462 /* buffer sizes - convert from just samples to samples + msecs for
1463 * the displayed string
1466 string bs_text = buffer_size_combo.get_active_text ();
1467 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1468 uint32_t rate = get_rate();
1470 /* Developers: note the hard-coding of a double buffered model
1471 in the (2 * samples) computation of latency. we always start
1472 the audiobackend in this configuration.
1474 /* note to jack1 developers: ardour also always starts the engine
1475 * in async mode (no jack2 --sync option) which adds an extra cycle
1476 * of latency with jack2 (and *3 would be correct)
1477 * The value can also be wrong if jackd is started externally..
1479 * At the time of writing the ALSA backend always uses double-buffering *2,
1480 * The Dummy backend *1, and who knows what ASIO really does :)
1482 * So just display the period size, that's also what
1483 * ARDOUR_UI::update_sample_rate() does for the status bar.
1484 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1485 * but still, that's the buffer period, not [round-trip] latency)
1488 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1489 buffer_size_duration_label.set_text (buf);
1493 EngineControl::midi_option_changed ()
1495 DEBUG_ECONTROL ("midi_option_changed");
1496 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1499 backend->set_midi_option (get_midi_option());
1501 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1503 //_midi_devices.clear(); // TODO merge with state-saved settings..
1504 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1505 std::vector<MidiDeviceSettings> new_devices;
1507 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1508 MidiDeviceSettings mds = find_midi_device (i->name);
1509 if (i->available && !mds) {
1510 uint32_t input_latency = 0;
1511 uint32_t output_latency = 0;
1512 if (_can_set_midi_latencies) {
1513 input_latency = backend->systemic_midi_input_latency (i->name);
1514 output_latency = backend->systemic_midi_output_latency (i->name);
1516 bool enabled = backend->midi_device_enabled (i->name);
1517 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1518 new_devices.push_back (ptr);
1519 } else if (i->available) {
1520 new_devices.push_back (mds);
1523 _midi_devices = new_devices;
1525 if (_midi_devices.empty()) {
1526 midi_devices_button.set_sensitive (false);
1528 midi_devices_button.set_sensitive (true);
1533 EngineControl::parameter_changed ()
1537 EngineControl::State
1538 EngineControl::get_matching_state (
1539 const string& backend,
1540 const string& driver,
1541 const string& device)
1543 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1544 if ((*i)->backend == backend &&
1545 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1553 EngineControl::State
1554 EngineControl::get_matching_state (
1555 const string& backend,
1556 const string& driver,
1557 const string& input_device,
1558 const string& output_device)
1560 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1561 if ((*i)->backend == backend &&
1562 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1570 EngineControl::State
1571 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1573 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1576 if (backend->use_separate_input_and_output_devices ()) {
1577 return get_matching_state (backend_combo.get_active_text(),
1578 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1579 input_device_combo.get_active_text(),
1580 output_device_combo.get_active_text());
1582 return get_matching_state (backend_combo.get_active_text(),
1583 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1584 device_combo.get_active_text());
1588 return get_matching_state (backend_combo.get_active_text(),
1590 device_combo.get_active_text());
1593 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1594 const EngineControl::State& state2)
1596 if (state1->backend == state2->backend &&
1597 state1->driver == state2->driver &&
1598 state1->device == state2->device &&
1599 state1->input_device == state2->input_device &&
1600 state1->output_device == state2->output_device) {
1606 EngineControl::State
1607 EngineControl::save_state ()
1611 if (!_have_control) {
1612 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1616 state.reset(new StateStruct);
1617 state->backend = get_backend ();
1619 state.reset(new StateStruct);
1620 store_state (state);
1623 for (StateList::iterator i = states.begin(); i != states.end();) {
1624 if (equivalent_states (*i, state)) {
1625 i = states.erase(i);
1631 states.push_back (state);
1637 EngineControl::store_state (State state)
1639 state->backend = get_backend ();
1640 state->driver = get_driver ();
1641 state->device = get_device_name ();
1642 state->input_device = get_input_device_name ();
1643 state->output_device = get_output_device_name ();
1644 state->sample_rate = get_rate ();
1645 state->buffer_size = get_buffer_size ();
1646 state->input_latency = get_input_latency ();
1647 state->output_latency = get_output_latency ();
1648 state->input_channels = get_input_channels ();
1649 state->output_channels = get_output_channels ();
1650 state->midi_option = get_midi_option ();
1651 state->midi_devices = _midi_devices;
1655 EngineControl::maybe_display_saved_state ()
1657 if (!_have_control) {
1661 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1664 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1666 if (!_desired_sample_rate) {
1667 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1669 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1670 /* call this explicitly because we're ignoring changes to
1671 the controls at this point.
1673 show_buffer_duration ();
1674 input_latency.set_value (state->input_latency);
1675 output_latency.set_value (state->output_latency);
1677 if (!state->midi_option.empty()) {
1678 midi_option_combo.set_active_text (state->midi_option);
1679 _midi_devices = state->midi_devices;
1685 EngineControl::get_state ()
1687 LocaleGuard lg (X_("C"));
1689 XMLNode* root = new XMLNode ("AudioMIDISetup");
1692 if (!states.empty()) {
1693 XMLNode* state_nodes = new XMLNode ("EngineStates");
1695 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1697 XMLNode* node = new XMLNode ("State");
1699 node->add_property ("backend", (*i)->backend);
1700 node->add_property ("driver", (*i)->driver);
1701 node->add_property ("device", (*i)->device);
1702 node->add_property ("input-device", (*i)->input_device);
1703 node->add_property ("output-device", (*i)->output_device);
1704 node->add_property ("sample-rate", (*i)->sample_rate);
1705 node->add_property ("buffer-size", (*i)->buffer_size);
1706 node->add_property ("input-latency", (*i)->input_latency);
1707 node->add_property ("output-latency", (*i)->output_latency);
1708 node->add_property ("input-channels", (*i)->input_channels);
1709 node->add_property ("output-channels", (*i)->output_channels);
1710 node->add_property ("active", (*i)->active ? "yes" : "no");
1711 node->add_property ("midi-option", (*i)->midi_option);
1713 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1714 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1715 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1716 midi_device_stuff->add_property (X_("name"), (*p)->name);
1717 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1718 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1719 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1720 midi_devices->add_child_nocopy (*midi_device_stuff);
1722 node->add_child_nocopy (*midi_devices);
1724 state_nodes->add_child_nocopy (*node);
1727 root->add_child_nocopy (*state_nodes);
1734 EngineControl::set_default_state ()
1736 vector<string> backend_names;
1737 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1739 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1740 backend_names.push_back ((*b)->name);
1742 backend_combo.set_active_text (backend_names.front());
1744 // We could set default backends per platform etc here
1750 EngineControl::set_state (const XMLNode& root)
1752 XMLNodeList clist, cclist;
1753 XMLNodeConstIterator citer, cciter;
1755 XMLNode* grandchild;
1756 XMLProperty* prop = NULL;
1758 fprintf (stderr, "EngineControl::set_state\n");
1760 if (root.name() != "AudioMIDISetup") {
1764 clist = root.children();
1768 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1772 if (child->name() != "EngineStates") {
1776 cclist = child->children();
1778 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1779 State state (new StateStruct);
1781 grandchild = *cciter;
1783 if (grandchild->name() != "State") {
1787 if ((prop = grandchild->property ("backend")) == 0) {
1790 state->backend = prop->value ();
1792 if ((prop = grandchild->property ("driver")) == 0) {
1795 state->driver = prop->value ();
1797 if ((prop = grandchild->property ("device")) == 0) {
1800 state->device = prop->value ();
1802 if ((prop = grandchild->property ("input-device")) == 0) {
1805 state->input_device = prop->value ();
1807 if ((prop = grandchild->property ("output-device")) == 0) {
1810 state->output_device = prop->value ();
1812 if ((prop = grandchild->property ("sample-rate")) == 0) {
1815 state->sample_rate = atof (prop->value ());
1817 if ((prop = grandchild->property ("buffer-size")) == 0) {
1820 state->buffer_size = atoi (prop->value ());
1822 if ((prop = grandchild->property ("input-latency")) == 0) {
1825 state->input_latency = atoi (prop->value ());
1827 if ((prop = grandchild->property ("output-latency")) == 0) {
1830 state->output_latency = atoi (prop->value ());
1832 if ((prop = grandchild->property ("input-channels")) == 0) {
1835 state->input_channels = atoi (prop->value ());
1837 if ((prop = grandchild->property ("output-channels")) == 0) {
1840 state->output_channels = atoi (prop->value ());
1842 if ((prop = grandchild->property ("active")) == 0) {
1845 state->active = string_is_affirmative (prop->value ());
1847 if ((prop = grandchild->property ("midi-option")) == 0) {
1850 state->midi_option = prop->value ();
1852 state->midi_devices.clear();
1854 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1855 const XMLNodeList mnc = midinode->children();
1856 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1857 if ((*n)->property (X_("name")) == 0
1858 || (*n)->property (X_("enabled")) == 0
1859 || (*n)->property (X_("input-latency")) == 0
1860 || (*n)->property (X_("output-latency")) == 0
1865 MidiDeviceSettings ptr (new MidiDeviceSetting(
1866 (*n)->property (X_("name"))->value (),
1867 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1868 atoi ((*n)->property (X_("input-latency"))->value ()),
1869 atoi ((*n)->property (X_("output-latency"))->value ())
1871 state->midi_devices.push_back (ptr);
1876 /* remove accumulated duplicates (due to bug in ealier version)
1877 * this can be removed again before release
1879 for (StateList::iterator i = states.begin(); i != states.end();) {
1880 if ((*i)->backend == state->backend &&
1881 (*i)->driver == state->driver &&
1882 (*i)->device == state->device) {
1883 i = states.erase(i);
1890 states.push_back (state);
1894 /* now see if there was an active state and switch the setup to it */
1896 // purge states of backend that are not available in this built
1897 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1898 vector<std::string> backend_names;
1900 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1901 backend_names.push_back((*i)->name);
1903 for (StateList::iterator i = states.begin(); i != states.end();) {
1904 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1905 i = states.erase(i);
1911 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1914 return set_current_state (*i);
1921 EngineControl::set_current_state (const State& state)
1923 DEBUG_ECONTROL ("set_current_state");
1925 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1927 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1928 state->backend, "ardour", ""))) {
1929 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1930 // this shouldn't happen as the invalid backend names should have been
1931 // removed from the list of states.
1935 // now reflect the change in the backend in the GUI so backend_changed will
1936 // do the right thing
1937 backend_combo.set_active_text (state->backend);
1939 if (!state->driver.empty ()) {
1940 if (!backend->requires_driver_selection ()) {
1941 DEBUG_ECONTROL ("Backend should require driver selection");
1942 // A backend has changed from having driver selection to not having
1943 // it or someone has been manually editing a config file and messed
1948 if (backend->set_driver (state->driver) != 0) {
1949 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
1950 // Driver names for a backend have changed and the name in the
1951 // config file is now invalid or support for driver is no longer
1952 // included in the backend
1955 // no need to set the driver_combo as backend_changed will use
1956 // backend->driver_name to set the active driver
1959 if (!state->device.empty ()) {
1960 if (backend->set_device_name (state->device) != 0) {
1962 string_compose ("Unable to set device name %1", state->device));
1963 // device is no longer available on the system
1966 // no need to set active device as it will be picked up in
1967 // via backend_changed ()/set_device_popdown_strings
1970 // backend supports separate input/output devices
1971 if (backend->set_input_device_name (state->input_device) != 0) {
1972 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
1973 state->input_device));
1974 // input device is no longer available on the system
1978 if (backend->set_output_device_name (state->output_device) != 0) {
1979 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
1980 state->input_device));
1981 // output device is no longer available on the system
1984 // no need to set active devices as it will be picked up in via
1985 // backend_changed ()/set_*_device_popdown_strings
1990 // Now restore the state of the rest of the controls
1992 // We don't use a SignalBlocker as set_current_state is currently only
1993 // called from set_state before any signals are connected. If at some point
1994 // a more general named state mechanism is implemented and
1995 // set_current_state is called while signals are connected then a
1996 // SignalBlocker will need to be instantiated before setting these.
1998 device_combo.set_active_text (state->device);
1999 input_device_combo.set_active_text (state->input_device);
2000 output_device_combo.set_active_text (state->output_device);
2001 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2002 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2003 input_latency.set_value (state->input_latency);
2004 output_latency.set_value (state->output_latency);
2005 midi_option_combo.set_active_text (state->midi_option);
2010 EngineControl::push_state_to_backend (bool start)
2012 DEBUG_ECONTROL ("push_state_to_backend");
2013 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2019 /* figure out what is going to change */
2021 bool restart_required = false;
2022 bool was_running = ARDOUR::AudioEngine::instance()->running();
2023 bool change_driver = false;
2024 bool change_device = false;
2025 bool change_rate = false;
2026 bool change_bufsize = false;
2027 bool change_latency = false;
2028 bool change_channels = false;
2029 bool change_midi = false;
2031 uint32_t ochan = get_output_channels ();
2032 uint32_t ichan = get_input_channels ();
2034 if (_have_control) {
2036 if (started_at_least_once) {
2038 /* we can control the backend */
2040 if (backend->requires_driver_selection()) {
2041 if (get_driver() != backend->driver_name()) {
2042 change_driver = true;
2046 if (backend->use_separate_input_and_output_devices()) {
2047 if (get_input_device_name() != backend->input_device_name()) {
2048 change_device = true;
2050 if (get_output_device_name() != backend->output_device_name()) {
2051 change_device = true;
2054 if (get_device_name() != backend->device_name()) {
2055 change_device = true;
2059 if (queue_device_changed) {
2060 change_device = true;
2063 if (get_rate() != backend->sample_rate()) {
2067 if (get_buffer_size() != backend->buffer_size()) {
2068 change_bufsize = true;
2071 if (get_midi_option() != backend->midi_option()) {
2075 /* zero-requested channels means "all available" */
2078 ichan = backend->input_channels();
2082 ochan = backend->output_channels();
2085 if (ichan != backend->input_channels()) {
2086 change_channels = true;
2089 if (ochan != backend->output_channels()) {
2090 change_channels = true;
2093 if (get_input_latency() != backend->systemic_input_latency() ||
2094 get_output_latency() != backend->systemic_output_latency()) {
2095 change_latency = true;
2098 /* backend never started, so we have to force a group
2101 change_device = true;
2102 if (backend->requires_driver_selection()) {
2103 change_driver = true;
2106 change_bufsize = true;
2107 change_channels = true;
2108 change_latency = true;
2114 /* we have no control over the backend, meaning that we can
2115 * only possibly change sample rate and buffer size.
2119 if (get_rate() != backend->sample_rate()) {
2120 change_bufsize = true;
2123 if (get_buffer_size() != backend->buffer_size()) {
2124 change_bufsize = true;
2128 queue_device_changed = false;
2130 if (!_have_control) {
2132 /* We do not have control over the backend, so the best we can
2133 * do is try to change the sample rate and/or bufsize and get
2137 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2141 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2146 backend->set_sample_rate (get_rate());
2149 if (change_bufsize) {
2150 backend->set_buffer_size (get_buffer_size());
2154 if (ARDOUR::AudioEngine::instance()->start ()) {
2155 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2165 /* determine if we need to stop the backend before changing parameters */
2167 if (change_driver || change_device || change_channels || change_latency ||
2168 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2170 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2171 restart_required = true;
2173 restart_required = false;
2178 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2179 /* no changes in any parameters that absolutely require a
2180 * restart, so check those that might be changeable without a
2184 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2185 /* can't do this while running ... */
2186 restart_required = true;
2189 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2190 /* can't do this while running ... */
2191 restart_required = true;
2197 if (restart_required) {
2198 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2205 if (change_driver && backend->set_driver (get_driver())) {
2206 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2209 if (backend->use_separate_input_and_output_devices()) {
2210 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2211 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2214 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2215 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2219 if (change_device && backend->set_device_name (get_device_name())) {
2220 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2224 if (change_rate && backend->set_sample_rate (get_rate())) {
2225 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2228 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2229 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2233 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2234 if (backend->set_input_channels (get_input_channels())) {
2235 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2238 if (backend->set_output_channels (get_output_channels())) {
2239 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2243 if (change_latency) {
2244 if (backend->set_systemic_input_latency (get_input_latency())) {
2245 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2248 if (backend->set_systemic_output_latency (get_output_latency())) {
2249 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2255 backend->set_midi_option (get_midi_option());
2259 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2260 if (_measure_midi) {
2261 if (*p == _measure_midi) {
2262 backend->set_midi_device_enabled ((*p)->name, true);
2264 backend->set_midi_device_enabled ((*p)->name, false);
2268 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2269 if (backend->can_set_systemic_midi_latencies()) {
2270 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2271 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2276 if (start || (was_running && restart_required)) {
2277 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2288 EngineControl::post_push ()
2290 /* get a pointer to the current state object, creating one if
2294 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2297 state = save_state ();
2305 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2306 (*i)->active = false;
2309 /* mark this one active (to be used next time the dialog is
2313 state->active = true;
2315 if (_have_control) { // XXX
2316 manage_control_app_sensitivity ();
2319 /* schedule a redisplay of MIDI ports */
2320 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2325 EngineControl::get_rate () const
2327 float r = atof (sample_rate_combo.get_active_text ());
2328 /* the string may have been translated with an abbreviation for
2329 * thousands, so use a crude heuristic to fix this.
2339 EngineControl::get_buffer_size () const
2341 string txt = buffer_size_combo.get_active_text ();
2344 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2345 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2346 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2354 EngineControl::get_midi_option () const
2356 return midi_option_combo.get_active_text();
2360 EngineControl::get_input_channels() const
2362 if (ARDOUR::Profile->get_mixbus()) {
2363 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2364 if (!backend) return 0;
2365 return backend->input_channels();
2367 return (uint32_t) input_channels_adjustment.get_value();
2371 EngineControl::get_output_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) output_channels_adjustment.get_value();
2382 EngineControl::get_input_latency() const
2384 return (uint32_t) input_latency_adjustment.get_value();
2388 EngineControl::get_output_latency() const
2390 return (uint32_t) output_latency_adjustment.get_value();
2394 EngineControl::get_backend () const
2396 return backend_combo.get_active_text ();
2400 EngineControl::get_driver () const
2402 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2403 return driver_combo.get_active_text ();
2410 EngineControl::get_device_name () const
2412 return device_combo.get_active_text ();
2416 EngineControl::get_input_device_name () const
2418 return input_device_combo.get_active_text ();
2422 EngineControl::get_output_device_name () const
2424 return output_device_combo.get_active_text ();
2428 EngineControl::control_app_button_clicked ()
2430 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2436 backend->launch_control_app ();
2440 EngineControl::stop_engine_button_clicked ()
2442 ARDOUR::AudioEngine::instance()->stop ();
2446 EngineControl::manage_control_app_sensitivity ()
2448 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2454 string appname = backend->control_app_name();
2456 if (appname.empty()) {
2457 control_app_button.set_sensitive (false);
2459 control_app_button.set_sensitive (true);
2464 EngineControl::set_desired_sample_rate (uint32_t sr)
2466 _desired_sample_rate = sr;
2471 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2473 if (page_num == 0) {
2474 cancel_button->set_sensitive (true);
2475 _measure_midi.reset();
2476 update_sensitivity ();
2478 cancel_button->set_sensitive (false);
2479 ok_button->set_sensitive (false);
2480 apply_button->set_sensitive (false);
2483 if (page_num == midi_tab) {
2485 refresh_midi_display ();
2488 if (page_num == latency_tab) {
2491 if (ARDOUR::AudioEngine::instance()->running()) {
2492 // TODO - mark as 'stopped for latency
2493 ARDOUR_UI::instance()->disconnect_from_engine ();
2497 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2499 /* save any existing latency values */
2501 uint32_t il = (uint32_t) input_latency.get_value ();
2502 uint32_t ol = (uint32_t) input_latency.get_value ();
2504 /* reset to zero so that our new test instance
2505 will be clean of any existing latency measures.
2507 NB. this should really be done by the backend
2508 when stated for latency measurement.
2511 input_latency.set_value (0);
2512 output_latency.set_value (0);
2514 push_state_to_backend (false);
2518 input_latency.set_value (il);
2519 output_latency.set_value (ol);
2522 // This should be done in push_state_to_backend()
2523 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2524 disable_latency_tab ();
2527 enable_latency_tab ();
2531 end_latency_detection ();
2532 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2537 /* latency measurement */
2540 EngineControl::check_audio_latency_measurement ()
2542 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2544 if (mtdm->resolve () < 0) {
2545 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2549 if (mtdm->err () > 0.3) {
2555 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2557 if (sample_rate == 0) {
2558 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2559 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2563 int frames_total = mtdm->del();
2564 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2566 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2567 _("Detected roundtrip latency: "),
2568 frames_total, frames_total * 1000.0f/sample_rate,
2569 _("Systemic latency: "),
2570 extra, extra * 1000.0f/sample_rate);
2574 if (mtdm->err () > 0.2) {
2576 strcat (buf, _("(signal detection error)"));
2582 strcat (buf, _("(inverted - bad wiring)"));
2586 lm_results.set_markup (string_compose (results_markup, buf));
2589 have_lm_results = true;
2590 end_latency_detection ();
2591 lm_use_button.set_sensitive (true);
2599 EngineControl::check_midi_latency_measurement ()
2601 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2603 if (!mididm->have_signal () || mididm->latency () == 0) {
2604 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2609 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2611 if (sample_rate == 0) {
2612 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2613 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2617 ARDOUR::framecnt_t frames_total = mididm->latency();
2618 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2619 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2620 _("Detected roundtrip latency: "),
2621 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2622 _("Systemic latency: "),
2623 extra, extra * 1000.0f / sample_rate);
2627 if (!mididm->ok ()) {
2629 strcat (buf, _("(averaging)"));
2633 if (mididm->deviation () > 50.0) {
2635 strcat (buf, _("(too large jitter)"));
2637 } else if (mididm->deviation () > 10.0) {
2639 strcat (buf, _("(large jitter)"));
2643 have_lm_results = true;
2644 end_latency_detection ();
2645 lm_use_button.set_sensitive (true);
2646 lm_results.set_markup (string_compose (results_markup, buf));
2648 } else if (mididm->processed () > 400) {
2649 have_lm_results = false;
2650 end_latency_detection ();
2651 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2655 lm_results.set_markup (string_compose (results_markup, buf));
2661 EngineControl::start_latency_detection ()
2663 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2664 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2666 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2667 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2668 if (_measure_midi) {
2669 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2671 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2673 lm_measure_label.set_text (_("Cancel"));
2674 have_lm_results = false;
2675 lm_use_button.set_sensitive (false);
2676 lm_input_channel_combo.set_sensitive (false);
2677 lm_output_channel_combo.set_sensitive (false);
2683 EngineControl::end_latency_detection ()
2685 latency_timeout.disconnect ();
2686 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2687 lm_measure_label.set_text (_("Measure"));
2688 if (!have_lm_results) {
2689 lm_use_button.set_sensitive (false);
2691 lm_input_channel_combo.set_sensitive (true);
2692 lm_output_channel_combo.set_sensitive (true);
2697 EngineControl::latency_button_clicked ()
2700 start_latency_detection ();
2702 end_latency_detection ();
2707 EngineControl::use_latency_button_clicked ()
2709 if (_measure_midi) {
2710 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2714 ARDOUR::framecnt_t frames_total = mididm->latency();
2715 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2716 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2717 _measure_midi->input_latency = one_way;
2718 _measure_midi->output_latency = one_way;
2719 notebook.set_current_page (midi_tab);
2721 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2727 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2728 one_way = std::max (0., one_way);
2730 input_latency_adjustment.set_value (one_way);
2731 output_latency_adjustment.set_value (one_way);
2733 /* back to settings page */
2734 notebook.set_current_page (0);
2740 EngineControl::on_delete_event (GdkEventAny* ev)
2742 if (notebook.get_current_page() == 2) {
2743 /* currently on latency tab - be sure to clean up */
2744 end_latency_detection ();
2746 return ArdourDialog::on_delete_event (ev);
2750 EngineControl::engine_running ()
2752 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2755 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2756 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2758 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2759 connect_disconnect_button.show();
2761 started_at_least_once = true;
2762 if (_have_control) {
2763 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2765 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2767 update_sensitivity();
2771 EngineControl::engine_stopped ()
2773 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2776 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2777 connect_disconnect_button.show();
2779 engine_status.set_markup(X_(""));
2780 update_sensitivity();
2784 EngineControl::device_list_changed ()
2786 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2788 midi_option_changed();
2792 EngineControl::connect_disconnect_click()
2794 if (ARDOUR::AudioEngine::instance()->running()) {
2795 ARDOUR_UI::instance()->disconnect_from_engine ();
2797 ARDOUR_UI::instance()->reconnect_to_engine ();
2802 EngineControl::calibrate_audio_latency ()
2804 _measure_midi.reset ();
2805 have_lm_results = false;
2806 lm_use_button.set_sensitive (false);
2807 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2808 notebook.set_current_page (latency_tab);
2812 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2815 have_lm_results = false;
2816 lm_use_button.set_sensitive (false);
2817 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2818 notebook.set_current_page (latency_tab);
2822 EngineControl::configure_midi_devices ()
2824 notebook.set_current_page (midi_tab);