NO-OP whitespace (updated GH PR #357)
[ardour.git] / gtk2_ardour / engine_dialog.cc
1 /*
2     Copyright (C) 2010 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #include <exception>
21 #include <vector>
22 #include <cmath>
23 #include <map>
24
25 #include <boost/scoped_ptr.hpp>
26
27 #include <gtkmm/messagedialog.h>
28
29 #include "pbd/error.h"
30 #include "pbd/locale_guard.h"
31 #include "pbd/xml++.h"
32 #include "pbd/unwind.h"
33 #include "pbd/failed_constructor.h"
34
35 #include <gtkmm/alignment.h>
36 #include <gtkmm/stock.h>
37 #include <gtkmm/notebook.h>
38 #include <gtkmm2ext/utils.h>
39
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"
47
48 #include "pbd/convert.h"
49 #include "pbd/error.h"
50
51 #include "opts.h"
52 #include "debug.h"
53 #include "ardour_ui.h"
54 #include "engine_dialog.h"
55 #include "gui_thread.h"
56 #include "ui_config.h"
57 #include "public_editor.h"
58 #include "utils.h"
59 #include "pbd/i18n.h"
60 #include "splash.h"
61
62 using namespace std;
63 using namespace Gtk;
64 using namespace Gtkmm2ext;
65 using namespace PBD;
66 using namespace Glib;
67 using namespace ARDOUR_UI_UTILS;
68
69 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
70
71 static const unsigned int midi_tab = 2;
72 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
73
74 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
75
76 EngineControl::EngineControl ()
77         : ArdourDialog (_("Audio/MIDI Setup"))
78         , engine_status ("")
79         , basic_packer (9, 4)
80         , input_latency_adjustment (0, 0, 99999, 1)
81         , input_latency (input_latency_adjustment)
82         , output_latency_adjustment (0, 0, 99999, 1)
83         , output_latency (output_latency_adjustment)
84         , input_channels_adjustment (0, 0, 256, 1)
85         , input_channels (input_channels_adjustment)
86         , output_channels_adjustment (0, 0, 256, 1)
87         , output_channels (output_channels_adjustment)
88         , ports_adjustment (128, 8, 1024, 1, 16)
89         , ports_spinner (ports_adjustment)
90         , control_app_button (_("Device Control Panel"))
91         , midi_devices_button (_("Midi Device Setup"))
92         , start_stop_button (_("Stop"))
93         , update_devices_button (_("Refresh Devices"))
94         , use_buffered_io_button (_("Use Buffered I/O"), ArdourButton::led_default_elements)
95         , lm_measure_label (_("Measure"))
96         , lm_use_button (_("Use results"))
97         , lm_back_button (_("Back to settings ... (ignore results)"))
98         , lm_button_audio (_("Calibrate Audio"))
99         , lm_table (12, 3)
100         , have_lm_results (false)
101         , lm_running (false)
102         , midi_back_button (_("Back to settings"))
103         , ignore_changes (0)
104         , ignore_device_changes (0)
105         , _desired_sample_rate (0)
106         , started_at_least_once (false)
107         , queue_device_changed (false)
108         , _have_control (true)
109         , block_signals(0)
110 {
111         using namespace Notebook_Helpers;
112         vector<string> backend_names;
113         Label* label;
114         AttachOptions xopt = AttachOptions (FILL|EXPAND);
115         int row;
116
117         set_name (X_("AudioMIDISetup"));
118
119         /* the backend combo is the one thing that is ALWAYS visible */
120
121         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
122
123         if (backends.empty()) {
124                 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));
125                 msg.run ();
126                 throw failed_constructor ();
127         }
128
129         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
130                 backend_names.push_back ((*b)->name);
131         }
132
133         set_popdown_strings (backend_combo, backend_names);
134
135         /* setup basic packing characteristics for the table used on the main
136          * tab of the notebook
137          */
138
139         basic_packer.set_spacings (6);
140         basic_packer.set_border_width (12);
141         basic_packer.set_homogeneous (false);
142
143         /* pack it in */
144
145         basic_hbox.pack_start (basic_packer, false, false);
146
147         /* latency measurement tab */
148
149         lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
150
151         row = 0;
152         lm_table.set_row_spacings (12);
153         lm_table.set_col_spacings (6);
154         lm_table.set_homogeneous (false);
155
156         lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
157         row++;
158
159         lm_preamble.set_width_chars (60);
160         lm_preamble.set_line_wrap (true);
161         lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
162
163         lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
164         row++;
165
166         Gtk::Label* preamble;
167         preamble = manage (new Label);
168         preamble->set_width_chars (60);
169         preamble->set_line_wrap (true);
170         preamble->set_markup (_("Select two channels below and connect them using a cable."));
171
172         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
173         row++;
174
175         label = manage (new Label (_("Output channel")));
176         lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
177
178         Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
179         misc_align->add (lm_output_channel_combo);
180         lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
181         ++row;
182
183         label = manage (new Label (_("Input channel")));
184         lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
185
186         misc_align = manage (new Alignment (0.0, 0.5));
187         misc_align->add (lm_input_channel_combo);
188         lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
189         ++row;
190
191         lm_measure_label.set_padding (10, 10);
192         lm_measure_button.add (lm_measure_label);
193         lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
194         lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
195         lm_back_button_signal = lm_back_button.signal_clicked().connect(
196             sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
197
198         lm_use_button.set_sensitive (false);
199
200         /* Increase the default spacing around the labels of these three
201          * buttons
202          */
203
204         Gtk::Misc* l;
205
206         if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
207                 l->set_padding (10, 10);
208         }
209
210         if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
211                 l->set_padding (10, 10);
212         }
213
214         preamble = manage (new Label);
215         preamble->set_width_chars (60);
216         preamble->set_line_wrap (true);
217         preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
218         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
219         row++;
220
221         preamble = manage (new Label);
222         preamble->set_width_chars (60);
223         preamble->set_line_wrap (true);
224         preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
225         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
226
227         ++row; // skip a row in the table
228         ++row; // skip a row in the table
229
230         lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
231
232         ++row; // skip a row in the table
233         ++row; // skip a row in the table
234
235         lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
236         lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
237         lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
238
239         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
240
241         lm_vbox.set_border_width (12);
242         lm_vbox.pack_start (lm_table, false, false);
243
244         midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
245
246         /* pack it all up */
247
248         notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
249         notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
250         notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
251         notebook.set_border_width (12);
252
253         notebook.set_show_tabs (false);
254         notebook.show_all ();
255
256         notebook.set_name ("SettingsNotebook");
257
258         /* packup the notebook */
259
260         get_vbox()->set_border_width (12);
261         get_vbox()->pack_start (notebook);
262
263         /* need a special function to print "all available channels" when the
264          * channel counts hit zero.
265          */
266
267         input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
268         output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
269
270         midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
271         midi_devices_button.set_name ("generic button");
272         midi_devices_button.set_can_focus(true);
273
274         control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
275         control_app_button.set_name ("generic button");
276         control_app_button.set_can_focus(true);
277         manage_control_app_sensitivity ();
278
279         start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
280         start_stop_button.set_sensitive (false);
281         start_stop_button.set_name ("generic button");
282         start_stop_button.set_can_focus(true);
283         start_stop_button.set_can_default(true);
284         start_stop_button.set_act_on_release (false);
285
286         update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
287         update_devices_button.set_sensitive (false);
288         update_devices_button.set_name ("generic button");
289         update_devices_button.set_can_focus(true);
290
291         use_buffered_io_button.signal_clicked.connect (mem_fun (*this, &EngineControl::use_buffered_io_button_clicked));
292         use_buffered_io_button.set_sensitive (false);
293         use_buffered_io_button.set_name ("generic button");
294         use_buffered_io_button.set_can_focus(true);
295
296         /* Pick up any existing audio setup configuration, if appropriate */
297
298         XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
299
300         ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
301         ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
302         ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
303         ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
304
305         if (audio_setup) {
306                 if (!set_state (*audio_setup)) {
307                         set_default_state ();
308                 }
309         } else {
310                 set_default_state ();
311         }
312
313         update_sensitivity ();
314         connect_changed_signals ();
315
316         notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
317
318         connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
319
320         connect_disconnect_button.set_no_show_all();
321         use_buffered_io_button.set_no_show_all();
322         update_devices_button.set_no_show_all();
323         start_stop_button.set_no_show_all();
324         midi_devices_button.set_no_show_all();
325 }
326
327 void
328 EngineControl::connect_changed_signals ()
329 {
330         backend_combo_connection = backend_combo.signal_changed ().connect (
331             sigc::mem_fun (*this, &EngineControl::backend_changed));
332         driver_combo_connection = driver_combo.signal_changed ().connect (
333             sigc::mem_fun (*this, &EngineControl::driver_changed));
334         sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
335             sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
336         buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
337             sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
338         nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
339             sigc::mem_fun (*this, &EngineControl::nperiods_changed));
340         device_combo_connection = device_combo.signal_changed ().connect (
341             sigc::mem_fun (*this, &EngineControl::device_changed));
342         midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
343             sigc::mem_fun (*this, &EngineControl::midi_option_changed));
344
345         input_device_combo_connection = input_device_combo.signal_changed ().connect (
346             sigc::mem_fun (*this, &EngineControl::input_device_changed));
347         output_device_combo_connection = output_device_combo.signal_changed ().connect (
348             sigc::mem_fun (*this, &EngineControl::output_device_changed));
349
350         input_latency_connection = input_latency.signal_changed ().connect (
351             sigc::mem_fun (*this, &EngineControl::parameter_changed));
352         output_latency_connection = output_latency.signal_changed ().connect (
353             sigc::mem_fun (*this, &EngineControl::parameter_changed));
354         input_channels_connection = input_channels.signal_changed ().connect (
355             sigc::mem_fun (*this, &EngineControl::parameter_changed));
356         output_channels_connection = output_channels.signal_changed ().connect (
357             sigc::mem_fun (*this, &EngineControl::parameter_changed));
358 }
359
360 void
361 EngineControl::block_changed_signals ()
362 {
363         if (block_signals++ == 0) {
364                 DEBUG_ECONTROL ("Blocking changed signals");
365                 backend_combo_connection.block ();
366                 driver_combo_connection.block ();
367                 sample_rate_combo_connection.block ();
368                 buffer_size_combo_connection.block ();
369                 nperiods_combo_connection.block ();
370                 device_combo_connection.block ();
371                 input_device_combo_connection.block ();
372                 output_device_combo_connection.block ();
373                 midi_option_combo_connection.block ();
374                 input_latency_connection.block ();
375                 output_latency_connection.block ();
376                 input_channels_connection.block ();
377                 output_channels_connection.block ();
378         }
379 }
380
381 void
382 EngineControl::unblock_changed_signals ()
383 {
384         if (--block_signals == 0) {
385                 DEBUG_ECONTROL ("Unblocking changed signals");
386                 backend_combo_connection.unblock ();
387                 driver_combo_connection.unblock ();
388                 sample_rate_combo_connection.unblock ();
389                 buffer_size_combo_connection.unblock ();
390                 nperiods_combo_connection.unblock ();
391                 device_combo_connection.unblock ();
392                 input_device_combo_connection.unblock ();
393                 output_device_combo_connection.unblock ();
394                 midi_option_combo_connection.unblock ();
395                 input_latency_connection.unblock ();
396                 output_latency_connection.unblock ();
397                 input_channels_connection.unblock ();
398                 output_channels_connection.unblock ();
399         }
400 }
401
402 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
403                                              const std::string& reason)
404         : ec (engine_control)
405         , m_reason (reason)
406 {
407         DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
408         ec.block_changed_signals ();
409 }
410
411 EngineControl::SignalBlocker::~SignalBlocker ()
412 {
413         DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
414         ec.unblock_changed_signals ();
415 }
416
417 void
418 EngineControl::on_show ()
419 {
420         ArdourDialog::on_show ();
421         if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
422                 // re-check _have_control (jackd running) see #6041
423                 backend_changed ();
424         }
425         device_changed ();
426         start_stop_button.grab_focus();
427 }
428
429 void
430 EngineControl::on_map ()
431 {
432         if (!ARDOUR_UI::instance()->session_loaded && !PublicEditor::_instance) {
433                 set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
434         } else if (UIConfiguration::instance().get_all_floating_windows_are_dialogs()) {
435                 set_type_hint (Gdk::WINDOW_TYPE_HINT_DIALOG);
436         } else {
437                 set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY);
438         }
439         ArdourDialog::on_map ();
440 }
441
442 bool
443 EngineControl::try_autostart ()
444 {
445         if (!start_stop_button.get_sensitive()) {
446                 return false;
447         }
448         if (ARDOUR::AudioEngine::instance()->running()) {
449                 return true;
450         }
451         return start_engine ();
452 }
453
454 bool
455 EngineControl::start_engine ()
456 {
457         if (push_state_to_backend(true) != 0) {
458                 MessageDialog msg(*this,
459                                   ARDOUR::AudioEngine::instance()->get_last_backend_error());
460                 msg.run();
461                 return false;
462         }
463         return true;
464 }
465
466 bool
467 EngineControl::stop_engine (bool for_latency)
468 {
469         if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
470                 MessageDialog msg(*this,
471                                   ARDOUR::AudioEngine::instance()->get_last_backend_error());
472                 msg.run();
473                 return false;
474         }
475         return true;
476 }
477
478 void
479 EngineControl::build_notebook ()
480 {
481         Label* label;
482         AttachOptions xopt = AttachOptions (FILL|EXPAND);
483
484         /* clear the table */
485
486         Gtkmm2ext::container_clear (basic_vbox);
487         Gtkmm2ext::container_clear (basic_packer);
488
489         if (control_app_button.get_parent()) {
490                 control_app_button.get_parent()->remove (control_app_button);
491         }
492
493         label = manage (left_aligned_label (_("Audio System:")));
494         basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
495         basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
496
497         basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
498         engine_status.show();
499
500         basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
501         basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
502         basic_packer.attach (use_buffered_io_button, 3, 4, 2, 3, xopt, xopt);
503
504         lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
505         lm_button_audio.set_name ("generic button");
506         lm_button_audio.set_can_focus(true);
507
508         if (_have_control) {
509                 build_full_control_notebook ();
510         } else {
511                 build_no_control_notebook ();
512         }
513
514         basic_vbox.pack_start (basic_hbox, false, false);
515
516         {
517                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
518                 basic_vbox.show_all ();
519         }
520 }
521
522 void
523 EngineControl::build_full_control_notebook ()
524 {
525         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
526         assert (backend);
527
528         using namespace Notebook_Helpers;
529         Label* label;
530         vector<string> strings;
531         AttachOptions xopt = AttachOptions (FILL|EXPAND);
532         int row = 1; // row zero == backend combo
533
534         /* start packing it up */
535
536         if (backend->requires_driver_selection()) {
537                 label = manage (left_aligned_label (_("Driver:")));
538                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
539                 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
540                 row++;
541         }
542
543         if (backend->use_separate_input_and_output_devices()) {
544                 label = manage (left_aligned_label (_("Input Device:")));
545                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
546                 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
547                 row++;
548                 label = manage (left_aligned_label (_("Output Device:")));
549                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
550                 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
551                 row++;
552                 // reset so it isn't used in state comparisons
553                 device_combo.set_active_text ("");
554         } else {
555                 label = manage (left_aligned_label (_("Device:")));
556                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
557                 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
558                 row++;
559                 // reset these so they don't get used in state comparisons
560                 input_device_combo.set_active_text ("");
561                 output_device_combo.set_active_text ("");
562         }
563
564         label = manage (left_aligned_label (_("Sample rate:")));
565         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
566         basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
567         row++;
568
569
570         label = manage (left_aligned_label (_("Buffer size:")));
571         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
572         basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
573         buffer_size_duration_label.set_alignment (0.0); /* left-align */
574         basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
575
576         int ctrl_btn_span = 1;
577         if (backend->can_set_period_size ()) {
578                 row++;
579                 label = manage (left_aligned_label (_("Periods:")));
580                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
581                 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
582                 ++ctrl_btn_span;
583         }
584
585         /* button spans 2 or 3 rows */
586
587         basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
588         row++;
589
590         input_channels.set_name ("InputChannels");
591         input_channels.set_flags (Gtk::CAN_FOCUS);
592         input_channels.set_digits (0);
593         input_channels.set_wrap (false);
594         output_channels.set_editable (true);
595
596         if (!ARDOUR::Profile->get_mixbus()) {
597                 label = manage (left_aligned_label (_("Input Channels:")));
598                 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
599                 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
600                 ++row;
601         }
602
603         output_channels.set_name ("OutputChannels");
604         output_channels.set_flags (Gtk::CAN_FOCUS);
605         output_channels.set_digits (0);
606         output_channels.set_wrap (false);
607         output_channels.set_editable (true);
608
609         if (!ARDOUR::Profile->get_mixbus()) {
610                 label = manage (left_aligned_label (_("Output Channels:")));
611                 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
612                 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
613                 ++row;
614         }
615
616         input_latency.set_name ("InputLatency");
617         input_latency.set_flags (Gtk::CAN_FOCUS);
618         input_latency.set_digits (0);
619         input_latency.set_wrap (false);
620         input_latency.set_editable (true);
621
622         label = manage (left_aligned_label (_("Hardware input latency:")));
623         basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
624         basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
625         label = manage (left_aligned_label (_("samples")));
626         basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
627         ++row;
628
629         output_latency.set_name ("OutputLatency");
630         output_latency.set_flags (Gtk::CAN_FOCUS);
631         output_latency.set_digits (0);
632         output_latency.set_wrap (false);
633         output_latency.set_editable (true);
634
635         label = manage (left_aligned_label (_("Hardware output latency:")));
636         basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
637         basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
638         label = manage (left_aligned_label (_("samples")));
639         basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
640
641         /* button spans 2 rows */
642
643         basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
644         ++row;
645
646         label = manage (left_aligned_label (_("MIDI System:")));
647         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
648         basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
649         basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
650         row++;
651 }
652
653 void
654 EngineControl::build_no_control_notebook ()
655 {
656         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
657         assert (backend);
658
659         using namespace Notebook_Helpers;
660         Label* label;
661         vector<string> strings;
662         AttachOptions xopt = AttachOptions (FILL|EXPAND);
663         int row = 1; // row zero == backend combo
664         const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
665
666         label = manage (new Label);
667         label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
668         basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
669         row++;
670
671         if (backend->can_change_sample_rate_when_running()) {
672                 label = manage (left_aligned_label (_("Sample rate:")));
673                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
674                 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
675                 row++;
676         }
677
678         if (backend->can_change_buffer_size_when_running()) {
679                 label = manage (left_aligned_label (_("Buffer size:")));
680                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
681                 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
682                 buffer_size_duration_label.set_alignment (0.0); /* left-align */
683                 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
684                 row++;
685         }
686
687         basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
688         row++;
689 }
690
691 EngineControl::~EngineControl ()
692 {
693         ignore_changes = true;
694 }
695
696 void
697 EngineControl::disable_latency_tab ()
698 {
699         vector<string> empty;
700         set_popdown_strings (lm_output_channel_combo, empty);
701         set_popdown_strings (lm_input_channel_combo, empty);
702         lm_measure_button.set_sensitive (false);
703         lm_use_button.set_sensitive (false);
704 }
705
706 void
707 EngineControl::enable_latency_tab ()
708 {
709         vector<string> outputs;
710         vector<string> inputs;
711
712         ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
713         ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
714         ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
715
716         if (!ARDOUR::AudioEngine::instance()->running()) {
717                 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
718                 notebook.set_current_page (0);
719                 msg.run ();
720                 return;
721         }
722         else if (inputs.empty() || outputs.empty()) {
723                 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
724                 notebook.set_current_page (0);
725                 msg.run ();
726                 return;
727         }
728
729         lm_back_button_signal.disconnect();
730         if (_measure_midi) {
731                 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
732                 lm_preamble.hide ();
733         } else {
734                 lm_back_button_signal = lm_back_button.signal_clicked().connect(
735                     sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
736                 lm_preamble.show ();
737         }
738
739         set_popdown_strings (lm_output_channel_combo, outputs);
740         lm_output_channel_combo.set_active_text (outputs.front());
741         lm_output_channel_combo.set_sensitive (true);
742
743         set_popdown_strings (lm_input_channel_combo, inputs);
744         lm_input_channel_combo.set_active_text (inputs.front());
745         lm_input_channel_combo.set_sensitive (true);
746
747         lm_measure_button.set_sensitive (true);
748 }
749
750 void
751 EngineControl::setup_midi_tab_for_backend ()
752 {
753         string backend = backend_combo.get_active_text ();
754
755         Gtkmm2ext::container_clear (midi_vbox);
756
757         midi_vbox.set_border_width (12);
758         midi_device_table.set_border_width (12);
759
760         if (backend == "JACK") {
761                 setup_midi_tab_for_jack ();
762         }
763
764         midi_vbox.pack_start (midi_device_table, true, true);
765         midi_vbox.pack_start (midi_back_button, false, false);
766         midi_vbox.show_all ();
767 }
768
769 void
770 EngineControl::update_sensitivity ()
771 {
772         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
773         if (!backend) {
774                 start_stop_button.set_sensitive (false);
775                 return;
776         }
777
778         bool valid = true;
779         size_t devices_available = 0;
780         bool engine_running = ARDOUR::AudioEngine::instance()->running();
781
782         if (backend->use_separate_input_and_output_devices ()) {
783                 devices_available += get_popdown_string_count (input_device_combo);
784                 devices_available += get_popdown_string_count (output_device_combo);
785         } else {
786                 devices_available += get_popdown_string_count (device_combo);
787         }
788
789         if (devices_available == 0) {
790                 valid = false;
791                 input_latency.set_sensitive (false);
792                 output_latency.set_sensitive (false);
793                 input_channels.set_sensitive (false);
794                 output_channels.set_sensitive (false);
795         } else {
796                 input_latency.set_sensitive (true);
797                 output_latency.set_sensitive (true);
798                 input_channels.set_sensitive (!engine_running);
799                 output_channels.set_sensitive (!engine_running);
800         }
801
802         if (get_popdown_string_count (buffer_size_combo) > 0) {
803                 if (!engine_running) {
804                         buffer_size_combo.set_sensitive (valid);
805                 } else if (backend->can_change_sample_rate_when_running()) {
806                         buffer_size_combo.set_sensitive (valid || !_have_control);
807                 } else {
808 #if 1
809                         /* TODO
810                          * Currently there is no way to manually stop the
811                          * engine in order to re-configure it.
812                          * This needs to remain sensitive for now.
813                          *
814                          * (it's also handy to implicily
815                          * re-start the engine)
816                          */
817                         buffer_size_combo.set_sensitive (true);
818 #else
819                         buffer_size_combo.set_sensitive (false);
820 #endif
821                 }
822         } else {
823                 buffer_size_combo.set_sensitive (false);
824                 valid = false;
825         }
826
827         if (get_popdown_string_count (sample_rate_combo) > 0) {
828                 bool allow_to_set_rate = false;
829                 if (!engine_running) {
830                         if (!ARDOUR_UI::instance()->session_loaded) {
831                                 // engine is not running, no session loaded -> anything goes.
832                                 allow_to_set_rate = true;
833                         } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
834                                 // only allow to change if the current setting is not the native session rate.
835                                 allow_to_set_rate = true;
836                         }
837                 }
838                 sample_rate_combo.set_sensitive (allow_to_set_rate);
839         } else {
840                 sample_rate_combo.set_sensitive (false);
841                 valid = false;
842         }
843
844         if (get_popdown_string_count (nperiods_combo) > 0) {
845                 if (!engine_running) {
846                         nperiods_combo.set_sensitive (true);
847                 } else {
848                         nperiods_combo.set_sensitive (false);
849                 }
850         } else {
851                 nperiods_combo.set_sensitive (false);
852         }
853
854         if (_have_control) {
855                 start_stop_button.set_sensitive(true);
856                 start_stop_button.show();
857                 if (engine_running) {
858                         start_stop_button.set_text("Stop");
859                         update_devices_button.set_sensitive(false);
860                         use_buffered_io_button.set_sensitive(false);
861                 } else {
862                         if (backend->can_request_update_devices()) {
863                                 update_devices_button.show();
864                         } else {
865                                 update_devices_button.hide();
866                         }
867                         if (backend->can_use_buffered_io()) {
868                                 use_buffered_io_button.show();
869                         } else {
870                                 use_buffered_io_button.hide();
871                         }
872                         start_stop_button.set_text("Start");
873                         update_devices_button.set_sensitive(true);
874                         use_buffered_io_button.set_sensitive(true);
875                 }
876         } else {
877                 update_devices_button.set_sensitive(false);
878                 update_devices_button.hide();
879                 use_buffered_io_button.set_sensitive(false);
880                 use_buffered_io_button.hide();
881                 start_stop_button.set_sensitive(false);
882                 start_stop_button.hide();
883         }
884
885         if (engine_running && _have_control) {
886                 input_device_combo.set_sensitive (false);
887                 output_device_combo.set_sensitive (false);
888                 device_combo.set_sensitive (false);
889                 driver_combo.set_sensitive (false);
890         } else {
891                 input_device_combo.set_sensitive (true);
892                 output_device_combo.set_sensitive (true);
893                 device_combo.set_sensitive (true);
894                 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
895                         driver_combo.set_sensitive (true);
896                 } else {
897                         driver_combo.set_sensitive (false);
898                 }
899         }
900
901         midi_option_combo.set_sensitive (!engine_running);
902 }
903
904 void
905 EngineControl::setup_midi_tab_for_jack ()
906 {
907 }
908
909 void
910 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
911         if (for_input) {
912                 device->input_latency = a->get_value();
913         } else {
914                 device->output_latency = a->get_value();
915         }
916 }
917
918 void
919 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
920         b->set_active (!b->get_active());
921         device->enabled = b->get_active();
922         refresh_midi_display(device->name);
923 }
924
925 void
926 EngineControl::refresh_midi_display (std::string focus)
927 {
928         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
929         assert (backend);
930
931         int row  = 0;
932         AttachOptions xopt = AttachOptions (FILL|EXPAND);
933         Gtk::Label* l;
934
935         Gtkmm2ext::container_clear (midi_device_table);
936
937         midi_device_table.set_spacings (6);
938
939         l = manage (new Label);
940         l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
941         midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
942         l->set_alignment (0.5, 0.5);
943         row++;
944         l->show ();
945
946         l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
947         midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
948         l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
949         midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
950         row++;
951         l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
952         midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
953         l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
954         midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
955         row++;
956
957         for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
958                 ArdourButton *m;
959                 Gtk::Button* b;
960                 Gtk::Adjustment *a;
961                 Gtk::SpinButton *s;
962                 bool enabled = (*p)->enabled;
963
964                 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
965                 m->set_name ("midi device");
966                 m->set_can_focus (Gtk::CAN_FOCUS);
967                 m->add_events (Gdk::BUTTON_RELEASE_MASK);
968                 m->set_active (enabled);
969                 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
970                 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
971                 if ((*p)->name == focus) {
972                         m->grab_focus();
973                 }
974
975                 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
976                 s = manage (new Gtk::SpinButton (*a));
977                 a->set_value ((*p)->input_latency);
978                 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
979                 s->set_sensitive (_can_set_midi_latencies && enabled);
980                 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
981
982                 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
983                 s = manage (new Gtk::SpinButton (*a));
984                 a->set_value ((*p)->output_latency);
985                 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
986                 s->set_sensitive (_can_set_midi_latencies && enabled);
987                 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
988
989                 b = manage (new Button (_("Calibrate")));
990                 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
991                 b->set_sensitive (_can_set_midi_latencies && enabled);
992                 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
993
994                 row++;
995         }
996 }
997
998 void
999 EngineControl::backend_changed ()
1000 {
1001         SignalBlocker blocker (*this, "backend_changed");
1002         string backend_name = backend_combo.get_active_text();
1003         boost::shared_ptr<ARDOUR::AudioBackend> backend;
1004
1005         if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1006                 /* eh? setting the backend failed... how ? */
1007                 /* A: stale config contains a backend that does not exist in current build */
1008                 return;
1009         }
1010
1011         DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1012
1013         _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1014
1015         build_notebook ();
1016         setup_midi_tab_for_backend ();
1017         _midi_devices.clear();
1018
1019         if (backend->requires_driver_selection()) {
1020                 if (set_driver_popdown_strings ()) {
1021                         driver_changed ();
1022                 }
1023         } else {
1024                 /* this will change the device text which will cause a call to
1025                  * device changed which will set up parameters
1026                  */
1027                 list_devices ();
1028         }
1029
1030         update_midi_options ();
1031
1032         connect_disconnect_button.hide();
1033
1034         midi_option_changed();
1035
1036         started_at_least_once = false;
1037
1038         /* changing the backend implies stopping the engine
1039          * ARDOUR::AudioEngine() may or may not emit this signal
1040          * depending on previous engine state
1041          */
1042         engine_stopped (); // set "active/inactive"
1043
1044         if (!_have_control) {
1045                 // set settings from backend that we do have control over
1046                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1047         }
1048
1049         if (_have_control && !ignore_changes) {
1050                 // set driver & devices
1051                 State state = get_matching_state (backend_combo.get_active_text());
1052                 if (state) {
1053                         DEBUG_ECONTROL ("backend-changed(): found prior state for backend");
1054                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1055                         set_current_state (state);
1056                 } else {
1057                         DEBUG_ECONTROL ("backend-changed(): no prior state for backend");
1058                 }
1059         } else {
1060                 DEBUG_ECONTROL (string_compose ("backend-changed(): _have_control=%1 ignore_changes=%2", _have_control, ignore_changes));
1061         }
1062
1063         if (!ignore_changes) {
1064                 maybe_display_saved_state ();
1065         }
1066 }
1067
1068 void
1069 EngineControl::update_midi_options ()
1070 {
1071         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1072         vector<string> midi_options = backend->enumerate_midi_options();
1073
1074         if (midi_options.size() == 1) {
1075                 /* only contains the "none" option */
1076                 midi_option_combo.set_sensitive (false);
1077         } else {
1078                 if (_have_control) {
1079                         set_popdown_strings (midi_option_combo, midi_options);
1080                         midi_option_combo.set_active_text (midi_options.front());
1081                         midi_option_combo.set_sensitive (true);
1082                 } else {
1083                         midi_option_combo.set_sensitive (false);
1084                 }
1085         }
1086 }
1087
1088 bool
1089 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1090 {
1091         if (ARDOUR::Profile->get_mixbus()) {
1092                 return true;
1093         }
1094
1095         uint32_t cnt = (uint32_t) sb->get_value();
1096         if (cnt == 0) {
1097                 sb->set_text (_("all available channels"));
1098         } else {
1099                 char buf[32];
1100                 snprintf (buf, sizeof (buf), "%d", cnt);
1101                 sb->set_text (buf);
1102         }
1103         return true;
1104 }
1105
1106 // @return true if there are drivers available
1107 bool
1108 EngineControl::set_driver_popdown_strings ()
1109 {
1110         DEBUG_ECONTROL ("set_driver_popdown_strings");
1111         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1112         vector<string> drivers = backend->enumerate_drivers();
1113
1114         if (drivers.empty ()) {
1115                 // This is an error...?
1116                 return false;
1117         }
1118
1119         string current_driver = backend->driver_name ();
1120
1121         DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1122
1123         if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1124             drivers.end ()) {
1125
1126                 current_driver = drivers.front ();
1127         }
1128
1129         set_popdown_strings (driver_combo, drivers);
1130         DEBUG_ECONTROL (
1131             string_compose ("driver_combo.set_active_text: %1", current_driver));
1132         driver_combo.set_active_text (current_driver);
1133         return true;
1134 }
1135
1136 std::string
1137 EngineControl::get_default_device(const string& current_device_name,
1138                                   const vector<string>& available_devices)
1139 {
1140         // If the current device is available, use it as default
1141         if (std::find (available_devices.begin (),
1142                        available_devices.end (),
1143                        current_device_name) != available_devices.end ()) {
1144
1145                 return current_device_name;
1146         }
1147
1148         using namespace ARDOUR;
1149
1150         string default_device_name =
1151             AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1152
1153         vector<string>::const_iterator i;
1154
1155         // If there is a "Default" device available, use it
1156         for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1157                 if (*i == default_device_name) {
1158                         return *i;
1159                 }
1160         }
1161
1162         string none_device_name =
1163             AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1164
1165         // Use the first device that isn't "None"
1166         for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1167                 if (*i != none_device_name) {
1168                         return *i;
1169                 }
1170         }
1171
1172         // Use "None" if there are no other available
1173         return available_devices.front();
1174 }
1175
1176 // @return true if there are devices available
1177 bool
1178 EngineControl::set_device_popdown_strings ()
1179 {
1180         DEBUG_ECONTROL ("set_device_popdown_strings");
1181         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1182         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1183
1184         /* NOTE: Ardour currently does not display the "available" field of the
1185          * returned devices.
1186          *
1187          * Doing so would require a different GUI widget than the combo
1188          * box/popdown that we currently use, since it has no way to list
1189          * items that are not selectable. Something more like a popup menu,
1190          * which could have unselectable items, would be appropriate.
1191          */
1192
1193         vector<string> available_devices;
1194
1195         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1196                 available_devices.push_back (i->name);
1197         }
1198
1199         if (available_devices.empty ()) {
1200                 return false;
1201         }
1202
1203         set_popdown_strings (device_combo, available_devices);
1204
1205         std::string default_device =
1206             get_default_device(backend->device_name(), available_devices);
1207
1208         DEBUG_ECONTROL (
1209             string_compose ("set device_combo active text: %1", default_device));
1210
1211         device_combo.set_active_text(default_device);
1212         return true;
1213 }
1214
1215 // @return true if there are input devices available
1216 bool
1217 EngineControl::set_input_device_popdown_strings ()
1218 {
1219         DEBUG_ECONTROL ("set_input_device_popdown_strings");
1220         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1221         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1222
1223         vector<string> available_devices;
1224
1225         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1226                 available_devices.push_back (i->name);
1227         }
1228
1229         if (available_devices.empty()) {
1230                 return false;
1231         }
1232
1233         set_popdown_strings (input_device_combo, available_devices);
1234
1235         std::string default_device =
1236             get_default_device(backend->input_device_name(), available_devices);
1237
1238         DEBUG_ECONTROL (
1239             string_compose ("set input_device_combo active text: %1", default_device));
1240         input_device_combo.set_active_text(default_device);
1241         return true;
1242 }
1243
1244 // @return true if there are output devices available
1245 bool
1246 EngineControl::set_output_device_popdown_strings ()
1247 {
1248         DEBUG_ECONTROL ("set_output_device_popdown_strings");
1249         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1250         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1251
1252         vector<string> available_devices;
1253
1254         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1255                 available_devices.push_back (i->name);
1256         }
1257
1258         if (available_devices.empty()) {
1259                 return false;
1260         }
1261
1262         set_popdown_strings (output_device_combo, available_devices);
1263
1264         std::string default_device =
1265             get_default_device(backend->output_device_name(), available_devices);
1266
1267         DEBUG_ECONTROL (
1268             string_compose ("set output_device_combo active text: %1", default_device));
1269         output_device_combo.set_active_text(default_device);
1270         return true;
1271 }
1272
1273 void
1274 EngineControl::list_devices ()
1275 {
1276         DEBUG_ECONTROL ("list_devices");
1277         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1278         assert (backend);
1279
1280         /* now fill out devices, mark sample rates, buffer sizes insensitive */
1281
1282         bool devices_available = false;
1283
1284         if (backend->use_separate_input_and_output_devices ()) {
1285                 bool input_devices_available = set_input_device_popdown_strings ();
1286                 bool output_devices_available = set_output_device_popdown_strings ();
1287                 devices_available = input_devices_available || output_devices_available;
1288         } else {
1289                 devices_available = set_device_popdown_strings ();
1290         }
1291
1292         if (devices_available) {
1293                 device_changed ();
1294         } else {
1295                 device_combo.clear();
1296                 input_device_combo.clear();
1297                 output_device_combo.clear();
1298         }
1299         update_sensitivity ();
1300 }
1301
1302 void
1303 EngineControl::driver_changed ()
1304 {
1305         SignalBlocker blocker (*this, "driver_changed");
1306         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1307         assert (backend);
1308
1309         backend->set_driver (driver_combo.get_active_text());
1310         list_devices ();
1311
1312         // TODO load LRU device(s) for backend + driver combo
1313
1314         if (!ignore_changes) {
1315                 maybe_display_saved_state ();
1316         }
1317 }
1318
1319 vector<float>
1320 EngineControl::get_sample_rates_for_all_devices ()
1321 {
1322         boost::shared_ptr<ARDOUR::AudioBackend> backend =
1323             ARDOUR::AudioEngine::instance ()->current_backend ();
1324         vector<float> all_rates;
1325
1326         if (backend->use_separate_input_and_output_devices ()) {
1327                 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1328         } else {
1329                 all_rates = backend->available_sample_rates (get_device_name ());
1330         }
1331         return all_rates;
1332 }
1333
1334 vector<float>
1335 EngineControl::get_default_sample_rates ()
1336 {
1337         vector<float> rates;
1338         rates.push_back (8000.0f);
1339         rates.push_back (16000.0f);
1340         rates.push_back (32000.0f);
1341         rates.push_back (44100.0f);
1342         rates.push_back (48000.0f);
1343         rates.push_back (88200.0f);
1344         rates.push_back (96000.0f);
1345         rates.push_back (192000.0f);
1346         rates.push_back (384000.0f);
1347         return rates;
1348 }
1349
1350 void
1351 EngineControl::set_samplerate_popdown_strings ()
1352 {
1353         DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1354         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1355         string desired;
1356         vector<float> sr;
1357         vector<string> s;
1358
1359         if (_have_control) {
1360                 sr = get_sample_rates_for_all_devices ();
1361         } else {
1362                 sr = get_default_sample_rates ();
1363         }
1364
1365         for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1366                 s.push_back (rate_as_string (*x));
1367                 if (*x == _desired_sample_rate) {
1368                         desired = s.back();
1369                 }
1370         }
1371
1372         set_popdown_strings (sample_rate_combo, s);
1373
1374         if (!s.empty()) {
1375                 if (ARDOUR::AudioEngine::instance()->running()) {
1376                         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1377                 }
1378                 else if (desired.empty ()) {
1379                         float new_active_sr = backend->default_sample_rate ();
1380
1381                         if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1382                                 new_active_sr = sr.front ();
1383                         }
1384
1385                         sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1386                 } else {
1387                         sample_rate_combo.set_active_text (desired);
1388                 }
1389
1390         }
1391         update_sensitivity ();
1392 }
1393
1394 vector<uint32_t>
1395 EngineControl::get_buffer_sizes_for_all_devices ()
1396 {
1397         boost::shared_ptr<ARDOUR::AudioBackend> backend =
1398             ARDOUR::AudioEngine::instance ()->current_backend ();
1399         vector<uint32_t> all_sizes;
1400
1401         if (backend->use_separate_input_and_output_devices ()) {
1402                 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1403         } else {
1404                 all_sizes = backend->available_buffer_sizes (get_device_name ());
1405         }
1406         return all_sizes;
1407 }
1408
1409 vector<uint32_t>
1410 EngineControl::get_default_buffer_sizes ()
1411 {
1412         vector<uint32_t> sizes;
1413         sizes.push_back (8);
1414         sizes.push_back (16);
1415         sizes.push_back (32);
1416         sizes.push_back (64);
1417         sizes.push_back (128);
1418         sizes.push_back (256);
1419         sizes.push_back (512);
1420         sizes.push_back (1024);
1421         sizes.push_back (2048);
1422         sizes.push_back (4096);
1423         sizes.push_back (8192);
1424         return sizes;
1425 }
1426
1427 void
1428 EngineControl::set_buffersize_popdown_strings ()
1429 {
1430         DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1431         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1432         vector<uint32_t> bs;
1433         vector<string> s;
1434
1435         if (_have_control) {
1436                 bs = get_buffer_sizes_for_all_devices ();
1437         } else if (backend->can_change_buffer_size_when_running()) {
1438                 bs = get_default_buffer_sizes ();
1439         }
1440
1441         for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1442                 s.push_back (bufsize_as_string (*x));
1443         }
1444
1445         uint32_t previous_size = 0;
1446         if (!buffer_size_combo.get_active_text().empty()) {
1447                 previous_size = get_buffer_size ();
1448         }
1449
1450         set_popdown_strings (buffer_size_combo, s);
1451
1452         if (!s.empty()) {
1453
1454                 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1455                         buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1456                 } else {
1457
1458                         buffer_size_combo.set_active_text(s.front());
1459
1460                         uint32_t period = backend->buffer_size();
1461                         if (0 == period && backend->use_separate_input_and_output_devices()) {
1462                                 period = backend->default_buffer_size(get_input_device_name());
1463                         }
1464                         if (0 == period && backend->use_separate_input_and_output_devices()) {
1465                                 period = backend->default_buffer_size(get_output_device_name());
1466                         }
1467                         if (0 == period && !backend->use_separate_input_and_output_devices()) {
1468                                 period = backend->default_buffer_size(get_device_name());
1469                         }
1470
1471                         set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1472                 }
1473                 show_buffer_duration ();
1474         }
1475         update_sensitivity ();
1476 }
1477
1478 void
1479 EngineControl::set_nperiods_popdown_strings ()
1480 {
1481         DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1482         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1483         vector<uint32_t> np;
1484         vector<string> s;
1485
1486         if (backend->can_set_period_size()) {
1487                 np = backend->available_period_sizes (get_driver());
1488         }
1489
1490         for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1491                 s.push_back (to_string (*x));
1492         }
1493
1494         set_popdown_strings (nperiods_combo, s);
1495
1496         if (!s.empty()) {
1497                 set_active_text_if_present (nperiods_combo, to_string (backend->period_size())); // XXX
1498         }
1499
1500         update_sensitivity ();
1501 }
1502
1503 void
1504 EngineControl::device_changed ()
1505 {
1506         SignalBlocker blocker (*this, "device_changed");
1507         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1508         assert (backend);
1509
1510         string device_name_in;
1511         string device_name_out; // only used if backend support separate I/O devices
1512
1513         if (backend->use_separate_input_and_output_devices()) {
1514                 device_name_in  = get_input_device_name ();
1515                 device_name_out = get_output_device_name ();
1516         } else {
1517                 device_name_in = get_device_name ();
1518         }
1519
1520         /* we set the backend-device to query various device related intormation.
1521          * This has the side effect that backend->device_name() will match
1522          * the device_name and  'change_device' will never be true.
1523          * so work around this by setting...
1524          */
1525         if (backend->use_separate_input_and_output_devices()) {
1526                 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1527                         queue_device_changed = true;
1528                 }
1529         } else {
1530                 if (device_name_in != backend->device_name()) {
1531                         queue_device_changed = true;
1532                 }
1533         }
1534
1535         //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1536         if (backend->use_separate_input_and_output_devices()) {
1537                 backend->set_input_device_name (device_name_in);
1538                 backend->set_output_device_name (device_name_out);
1539         } else {
1540                 backend->set_device_name(device_name_in);
1541         }
1542
1543         {
1544                 /* don't allow programmatic change to combos to cause a
1545                    recursive call to this method.
1546                  */
1547                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1548
1549                 set_samplerate_popdown_strings ();
1550                 set_buffersize_popdown_strings ();
1551                 set_nperiods_popdown_strings ();
1552
1553                 /* TODO set min + max channel counts here */
1554
1555                 manage_control_app_sensitivity ();
1556         }
1557
1558         /* pick up any saved state for this device */
1559
1560         if (!ignore_changes) {
1561                 maybe_display_saved_state ();
1562         }
1563 }
1564
1565 void
1566 EngineControl::input_device_changed ()
1567 {
1568         DEBUG_ECONTROL ("input_device_changed");
1569
1570         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1571         if (backend && backend->match_input_output_devices_or_none ()) {
1572                 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1573
1574                 if (get_output_device_name () != dev_none
1575                                 && get_input_device_name () != dev_none
1576                                 && get_input_device_name () != get_output_device_name ()) {
1577                         block_changed_signals ();
1578                         if (contains_value (output_device_combo, get_input_device_name ())) {
1579                                 output_device_combo.set_active_text (get_input_device_name ());
1580                         } else {
1581                                 assert (contains_value (output_device_combo, dev_none));
1582                                 output_device_combo.set_active_text (dev_none);
1583                         }
1584                         unblock_changed_signals ();
1585                 }
1586         }
1587         device_changed ();
1588 }
1589
1590 void
1591 EngineControl::output_device_changed ()
1592 {
1593         DEBUG_ECONTROL ("output_device_changed");
1594         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1595         if (backend && backend->match_input_output_devices_or_none ()) {
1596                 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1597
1598                 if (get_input_device_name () != dev_none
1599                                 && get_input_device_name () != dev_none
1600                                 && get_input_device_name () != get_output_device_name ()) {
1601                         block_changed_signals ();
1602                         if (contains_value (input_device_combo, get_output_device_name ())) {
1603                                 input_device_combo.set_active_text (get_output_device_name ());
1604                         } else {
1605                                 assert (contains_value (input_device_combo, dev_none));
1606                                 input_device_combo.set_active_text (dev_none);
1607                         }
1608                         unblock_changed_signals ();
1609                 }
1610         }
1611         device_changed ();
1612 }
1613
1614 string
1615 EngineControl::bufsize_as_string (uint32_t sz)
1616 {
1617         return string_compose (P_("%1 sample", "%1 samples", sz), to_string(sz));
1618 }
1619
1620 void
1621 EngineControl::sample_rate_changed ()
1622 {
1623         DEBUG_ECONTROL ("sample_rate_changed");
1624         /* reset the strings for buffer size to show the correct msec value
1625            (reflecting the new sample rate).
1626          */
1627
1628         show_buffer_duration ();
1629
1630 }
1631
1632 void
1633 EngineControl::buffer_size_changed ()
1634 {
1635         DEBUG_ECONTROL ("buffer_size_changed");
1636         show_buffer_duration ();
1637 }
1638
1639 void
1640 EngineControl::nperiods_changed ()
1641 {
1642         DEBUG_ECONTROL ("nperiods_changed");
1643         show_buffer_duration ();
1644 }
1645
1646 void
1647 EngineControl::show_buffer_duration ()
1648 {
1649         DEBUG_ECONTROL ("show_buffer_duration");
1650         /* buffer sizes  - convert from just samples to samples + msecs for
1651          * the displayed string
1652          */
1653
1654         string bs_text = buffer_size_combo.get_active_text ();
1655         uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1656         uint32_t rate = get_rate();
1657
1658         /* Except for ALSA and Dummy backends, we don't know the number of periods
1659          * per cycle and settings.
1660          *
1661          * jack1 vs jack2 have different default latencies since jack2 start
1662          * in async-mode unless --sync is given which adds an extra cycle
1663          * of latency. The value is not known if jackd is started externally..
1664          *
1665          * So just display the period size, that's also what
1666          * ARDOUR_UI::update_sample_rate() does for the status bar.
1667          * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1668          * but still, that's the buffer period, not [round-trip] latency)
1669          */
1670         char buf[32];
1671         snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1672         buffer_size_duration_label.set_text (buf);
1673 }
1674
1675 void
1676 EngineControl::midi_option_changed ()
1677 {
1678         DEBUG_ECONTROL ("midi_option_changed");
1679         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1680         assert (backend);
1681
1682         backend->set_midi_option (get_midi_option());
1683
1684         vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1685
1686         //_midi_devices.clear(); // TODO merge with state-saved settings..
1687         _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1688         std::vector<MidiDeviceSettings> new_devices;
1689
1690         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1691                 MidiDeviceSettings mds = find_midi_device (i->name);
1692                 if (i->available && !mds) {
1693                         uint32_t input_latency = 0;
1694                         uint32_t output_latency = 0;
1695                         if (_can_set_midi_latencies) {
1696                                 input_latency = backend->systemic_midi_input_latency (i->name);
1697                                 output_latency = backend->systemic_midi_output_latency (i->name);
1698                         }
1699                         bool enabled = backend->midi_device_enabled (i->name);
1700                         MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1701                         new_devices.push_back (ptr);
1702                 } else if (i->available) {
1703                         new_devices.push_back (mds);
1704                 }
1705         }
1706         _midi_devices = new_devices;
1707
1708         if (_midi_devices.empty()) {
1709                 midi_devices_button.hide ();
1710         } else {
1711                 midi_devices_button.show ();
1712         }
1713 }
1714
1715 void
1716 EngineControl::parameter_changed ()
1717 {
1718 }
1719
1720 EngineControl::State
1721 EngineControl::get_matching_state (const string& backend)
1722 {
1723         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1724                 if ((*i)->backend == backend) {
1725                         return (*i);
1726                 }
1727         }
1728         return State();
1729 }
1730
1731 EngineControl::State
1732 EngineControl::get_matching_state (
1733                 const string& backend,
1734                 const string& driver,
1735                 const string& device)
1736 {
1737         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1738                 if ((*i)->backend == backend &&
1739                                 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1740                 {
1741                         return (*i);
1742                 }
1743         }
1744         return State();
1745 }
1746
1747 EngineControl::State
1748 EngineControl::get_matching_state (
1749                 const string& backend,
1750                 const string& driver,
1751                 const string& input_device,
1752                 const string& output_device)
1753 {
1754         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1755                 if ((*i)->backend == backend &&
1756                                 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1757                 {
1758                         return (*i);
1759                 }
1760         }
1761         return State();
1762 }
1763
1764 EngineControl::State
1765 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1766 {
1767         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1768
1769         if (backend) {
1770                 if (backend->use_separate_input_and_output_devices ()) {
1771                         return get_matching_state (backend_combo.get_active_text(),
1772                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1773                                         input_device_combo.get_active_text(),
1774                                         output_device_combo.get_active_text());
1775                 } else {
1776                         return get_matching_state (backend_combo.get_active_text(),
1777                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1778                                         device_combo.get_active_text());
1779                 }
1780         }
1781
1782         return get_matching_state (backend_combo.get_active_text(),
1783                         string(),
1784                         device_combo.get_active_text());
1785 }
1786
1787 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1788                                        const EngineControl::State& state2)
1789 {
1790         if (state1->backend == state2->backend &&
1791                         state1->driver == state2->driver &&
1792                         state1->device == state2->device &&
1793                         state1->input_device == state2->input_device &&
1794                         state1->output_device == state2->output_device) {
1795                 return true;
1796         }
1797         return false;
1798 }
1799
1800 // sort active first, then most recently used to the beginning of the list
1801 bool
1802 EngineControl::state_sort_cmp (const State &a, const State &b) {
1803         if (a->active) {
1804                 return true;
1805         }
1806         else if (b->active) {
1807                 return false;
1808         }
1809         else {
1810                 return a->lru > b->lru;
1811         }
1812 }
1813
1814 EngineControl::State
1815 EngineControl::save_state ()
1816 {
1817         State state;
1818
1819         if (!_have_control) {
1820                 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1821                 if (state) {
1822                         state->lru = time (NULL) ;
1823                         return state;
1824                 }
1825                 state.reset(new StateStruct);
1826                 state->backend = get_backend ();
1827         } else {
1828                 state.reset(new StateStruct);
1829                 store_state (state);
1830         }
1831
1832         for (StateList::iterator i = states.begin(); i != states.end();) {
1833                 if (equivalent_states (*i, state)) {
1834                         i =  states.erase(i);
1835                 } else {
1836                         ++i;
1837                 }
1838         }
1839
1840         states.push_back (state);
1841
1842         states.sort (state_sort_cmp);
1843
1844         return state;
1845 }
1846
1847 void
1848 EngineControl::store_state (State state)
1849 {
1850         state->backend = get_backend ();
1851         state->driver = get_driver ();
1852         state->device = get_device_name ();
1853         state->input_device = get_input_device_name ();
1854         state->output_device = get_output_device_name ();
1855         state->sample_rate = get_rate ();
1856         state->buffer_size = get_buffer_size ();
1857         state->n_periods = get_nperiods ();
1858         state->input_latency = get_input_latency ();
1859         state->output_latency = get_output_latency ();
1860         state->input_channels = get_input_channels ();
1861         state->output_channels = get_output_channels ();
1862         state->midi_option = get_midi_option ();
1863         state->midi_devices = _midi_devices;
1864         state->use_buffered_io = get_use_buffered_io ();
1865         state->lru = time (NULL) ;
1866 }
1867
1868 void
1869 EngineControl::maybe_display_saved_state ()
1870 {
1871         if (!_have_control) {
1872                 return;
1873         }
1874
1875         State state = get_saved_state_for_currently_displayed_backend_and_device ();
1876
1877         if (state) {
1878                 DEBUG_ECONTROL ("Restoring saved state");
1879                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1880
1881                 if (!_desired_sample_rate) {
1882                         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1883                 }
1884                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1885
1886                 set_active_text_if_present (nperiods_combo, to_string(state->n_periods));
1887                 /* call this explicitly because we're ignoring changes to
1888                    the controls at this point.
1889                  */
1890                 show_buffer_duration ();
1891                 input_latency.set_value (state->input_latency);
1892                 output_latency.set_value (state->output_latency);
1893
1894                 use_buffered_io_button.set_active (state->use_buffered_io);
1895
1896                 if (!state->midi_option.empty()) {
1897                         midi_option_combo.set_active_text (state->midi_option);
1898                         _midi_devices = state->midi_devices;
1899                 }
1900         } else {
1901                 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1902         }
1903 }
1904
1905 XMLNode&
1906 EngineControl::get_state ()
1907 {
1908         LocaleGuard lg;
1909
1910         XMLNode* root = new XMLNode ("AudioMIDISetup");
1911         std::string path;
1912
1913         if (!states.empty()) {
1914                 XMLNode* state_nodes = new XMLNode ("EngineStates");
1915
1916                 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1917
1918                         XMLNode* node = new XMLNode ("State");
1919
1920                         node->set_property ("backend", (*i)->backend);
1921                         node->set_property ("driver", (*i)->driver);
1922                         node->set_property ("device", (*i)->device);
1923                         node->set_property ("input-device", (*i)->input_device);
1924                         node->set_property ("output-device", (*i)->output_device);
1925                         node->set_property ("sample-rate", (*i)->sample_rate);
1926                         node->set_property ("buffer-size", (*i)->buffer_size);
1927                         node->set_property ("n-periods", (*i)->n_periods);
1928                         node->set_property ("input-latency", (*i)->input_latency);
1929                         node->set_property ("output-latency", (*i)->output_latency);
1930                         node->set_property ("input-channels", (*i)->input_channels);
1931                         node->set_property ("output-channels", (*i)->output_channels);
1932                         node->set_property ("active", (*i)->active);
1933                         node->set_property ("use-buffered-io", (*i)->use_buffered_io);
1934                         node->set_property ("midi-option", (*i)->midi_option);
1935                         int32_t lru_val = (*i)->active ? time (NULL) : (*i)->lru;
1936                         node->set_property ("lru", lru_val );
1937
1938                         XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1939                         for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1940                                 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1941                                 midi_device_stuff->set_property (X_("name"), (*p)->name);
1942                                 midi_device_stuff->set_property (X_("enabled"), (*p)->enabled);
1943                                 midi_device_stuff->set_property (X_("input-latency"), (*p)->input_latency);
1944                                 midi_device_stuff->set_property (X_("output-latency"), (*p)->output_latency);
1945                                 midi_devices->add_child_nocopy (*midi_device_stuff);
1946                         }
1947                         node->add_child_nocopy (*midi_devices);
1948
1949                         state_nodes->add_child_nocopy (*node);
1950                 }
1951
1952                 root->add_child_nocopy (*state_nodes);
1953         }
1954
1955         return *root;
1956 }
1957
1958 void
1959 EngineControl::set_default_state ()
1960 {
1961         vector<string> backend_names;
1962         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1963
1964         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1965                 backend_names.push_back ((*b)->name);
1966         }
1967         backend_combo.set_active_text (backend_names.front());
1968
1969         // We could set default backends per platform etc here
1970
1971         backend_changed ();
1972 }
1973
1974 bool
1975 EngineControl::set_state (const XMLNode& root)
1976 {
1977         XMLNodeList          clist, cclist;
1978         XMLNodeConstIterator citer, cciter;
1979         XMLNode const * child;
1980         XMLNode const * grandchild;
1981
1982         if (root.name() != "AudioMIDISetup") {
1983                 return false;
1984         }
1985
1986         clist = root.children();
1987
1988         states.clear ();
1989
1990         for (citer = clist.begin(); citer != clist.end(); ++citer) {
1991
1992                 child = *citer;
1993
1994                 if (child->name() != "EngineStates") {
1995                         continue;
1996                 }
1997
1998                 cclist = child->children();
1999
2000                 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2001                         State state (new StateStruct);
2002
2003                         grandchild = *cciter;
2004
2005                         if (grandchild->name() != "State") {
2006                                 continue;
2007                         }
2008
2009                         if (!grandchild->get_property ("backend", state->backend)) {
2010                                 continue;
2011                         }
2012
2013                         // If any of the required properties are not found in the state node
2014                         // then continue/skip to the next engine state
2015                         if (!grandchild->get_property ("driver", state->driver) ||
2016                             !grandchild->get_property ("device", state->device) ||
2017                             !grandchild->get_property ("input-device", state->input_device) ||
2018                             !grandchild->get_property ("output-device", state->output_device) ||
2019                             !grandchild->get_property ("sample-rate", state->sample_rate) ||
2020                             !grandchild->get_property ("buffer-size", state->buffer_size) ||
2021                             !grandchild->get_property ("input-latency", state->input_latency) ||
2022                             !grandchild->get_property ("output-latency", state->output_latency) ||
2023                             !grandchild->get_property ("input-channels", state->input_channels) ||
2024                             !grandchild->get_property ("output-channels", state->output_channels) ||
2025                             !grandchild->get_property ("active", state->active) ||
2026                             !grandchild->get_property ("use-buffered-io", state->use_buffered_io) ||
2027                             !grandchild->get_property ("midi-option", state->midi_option)) {
2028                                 continue;
2029                         }
2030
2031                         if (!grandchild->get_property ("n-periods", state->n_periods)) {
2032                                 // optional (new value in 4.5)
2033                                 state->n_periods = 0;
2034                         }
2035
2036                         state->midi_devices.clear();
2037                         XMLNode* midinode;
2038                         if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2039                                 const XMLNodeList mnc = midinode->children();
2040                                 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2041                                         std::string name;
2042                                         bool enabled;
2043                                         uint32_t input_latency;
2044                                         uint32_t output_latency;
2045
2046                                         if (!(*n)->get_property (X_("name"), name) ||
2047                                             !(*n)->get_property (X_("enabled"), enabled) ||
2048                                             !(*n)->get_property (X_("input-latency"), input_latency) ||
2049                                             !(*n)->get_property (X_("output-latency"), output_latency)) {
2050                                                 continue;
2051                                         }
2052
2053                                         MidiDeviceSettings ptr (
2054                                             new MidiDeviceSetting (name, enabled, input_latency, output_latency));
2055                                         state->midi_devices.push_back (ptr);
2056                                 }
2057                         }
2058
2059                         int32_t lru_val;
2060                         if (grandchild->get_property ("lru", lru_val)) {
2061                                 state->lru = lru_val;
2062                         }
2063
2064                         states.push_back (state);
2065                 }
2066         }
2067
2068         /* now see if there was an active state and switch the setup to it */
2069
2070         /* purge states of backend that are not available in this built */
2071         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2072         vector<std::string> backend_names;
2073
2074         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2075                 backend_names.push_back((*i)->name);
2076         }
2077         for (StateList::iterator i = states.begin(); i != states.end();) {
2078                 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2079                         i = states.erase(i);
2080                 } else {
2081                         ++i;
2082                 }
2083         }
2084
2085         states.sort (state_sort_cmp);
2086
2087         /* purge old states referring to the same backend */
2088         const time_t now = time (NULL);
2089         for (vector<std::string>::const_iterator bi = backend_names.begin(); bi != backend_names.end(); ++bi) {
2090                 bool first = true;
2091                 for (StateList::iterator i = states.begin(); i != states.end();) {
2092                         if ((*i)->backend != *bi) {
2093                                 ++i; continue;
2094                         }
2095                         // keep at latest one for every audio-system
2096                         if (first) {
2097                                 first = false;
2098                                 ++i; continue;
2099                         }
2100                         // also keep states used in the last 90 days.
2101                         if ((now - (*i)->lru) < 86400 * 90) {
2102                                 ++i; continue;
2103                         }
2104                         assert (!(*i)->active);
2105                         i = states.erase(i);
2106                 }
2107         }
2108
2109         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2110
2111                 if ((*i)->active) {
2112                         return set_current_state (*i);
2113                 }
2114         }
2115         return false;
2116 }
2117
2118 bool
2119 EngineControl::set_current_state (const State& state)
2120 {
2121         DEBUG_ECONTROL ("set_current_state");
2122
2123         boost::shared_ptr<ARDOUR::AudioBackend> backend;
2124
2125         if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2126                   state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2127                 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2128                 // this shouldn't happen as the invalid backend names should have been
2129                 // removed from the list of states.
2130                 return false;
2131         }
2132
2133         // now reflect the change in the backend in the GUI so backend_changed will
2134         // do the right thing
2135         backend_combo.set_active_text (state->backend);
2136
2137         if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2138                 backend_changed ();
2139                 // we don't have control don't restore state
2140                 return true;
2141         }
2142
2143
2144         if (!state->driver.empty ()) {
2145                 if (!backend->requires_driver_selection ()) {
2146                         DEBUG_ECONTROL ("Backend should require driver selection");
2147                         // A backend has changed from having driver selection to not having
2148                         // it or someone has been manually editing a config file and messed
2149                         // it up
2150                         return false;
2151                 }
2152
2153                 if (backend->set_driver (state->driver) != 0) {
2154                         DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2155                         // Driver names for a backend have changed and the name in the
2156                         // config file is now invalid or support for driver is no longer
2157                         // included in the backend
2158                         return false;
2159                 }
2160                 // no need to set the driver_combo as backend_changed will use
2161                 // backend->driver_name to set the active driver
2162         }
2163
2164         if (!state->device.empty ()) {
2165                 if (backend->set_device_name (state->device) != 0) {
2166                         DEBUG_ECONTROL (
2167                             string_compose ("Unable to set device name %1", state->device));
2168                         // device is no longer available on the system
2169                         return false;
2170                 }
2171                 // no need to set active device as it will be picked up in
2172                 // via backend_changed ()/set_device_popdown_strings
2173
2174         } else {
2175                 // backend supports separate input/output devices
2176                 if (backend->set_input_device_name (state->input_device) != 0) {
2177                         DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2178                                                         state->input_device));
2179                         // input device is no longer available on the system
2180                         return false;
2181                 }
2182
2183                 if (backend->set_output_device_name (state->output_device) != 0) {
2184                         DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2185                                                         state->input_device));
2186                         // output device is no longer available on the system
2187                         return false;
2188                 }
2189                 // no need to set active devices as it will be picked up in via
2190                 // backend_changed ()/set_*_device_popdown_strings
2191         }
2192
2193         backend_changed ();
2194
2195         // Now restore the state of the rest of the controls
2196
2197         // We don't use a SignalBlocker as set_current_state is currently only
2198         // called from set_state before any signals are connected. If at some point
2199         // a more general named state mechanism is implemented and
2200         // set_current_state is called while signals are connected then a
2201         // SignalBlocker will need to be instantiated before setting these.
2202
2203         device_combo.set_active_text (state->device);
2204         input_device_combo.set_active_text (state->input_device);
2205         output_device_combo.set_active_text (state->output_device);
2206         if (!_desired_sample_rate) {
2207                 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2208         }
2209         set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2210         set_active_text_if_present (nperiods_combo, to_string (state->n_periods));
2211         input_latency.set_value (state->input_latency);
2212         output_latency.set_value (state->output_latency);
2213         midi_option_combo.set_active_text (state->midi_option);
2214         use_buffered_io_button.set_active (state->use_buffered_io);
2215         return true;
2216 }
2217
2218 int
2219 EngineControl::push_state_to_backend (bool start)
2220 {
2221         DEBUG_ECONTROL ("push_state_to_backend");
2222         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2223         PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2224
2225         if (!backend) {
2226                 return 0;
2227         }
2228
2229         /* figure out what is going to change */
2230
2231         bool restart_required = false;
2232         bool was_running = ARDOUR::AudioEngine::instance()->running();
2233         bool change_driver = false;
2234         bool change_device = false;
2235         bool change_rate = false;
2236         bool change_bufsize = false;
2237         bool change_nperiods = false;
2238         bool change_latency = false;
2239         bool change_channels = false;
2240         bool change_midi = false;
2241         bool change_buffered_io = false;
2242
2243         uint32_t ochan = get_output_channels ();
2244         uint32_t ichan = get_input_channels ();
2245
2246         if (_have_control) {
2247
2248                 if (started_at_least_once) {
2249
2250                         /* we can control the backend */
2251
2252                         if (backend->requires_driver_selection()) {
2253                                 if (get_driver() != backend->driver_name()) {
2254                                         change_driver = true;
2255                                 }
2256                         }
2257
2258                         if (backend->use_separate_input_and_output_devices()) {
2259                                 if (get_input_device_name() != backend->input_device_name()) {
2260                                         change_device = true;
2261                                 }
2262                                 if (get_output_device_name() != backend->output_device_name()) {
2263                                         change_device = true;
2264                                 }
2265                         } else {
2266                                 if (get_device_name() != backend->device_name()) {
2267                                         change_device = true;
2268                                 }
2269                         }
2270
2271                         if (queue_device_changed) {
2272                                 change_device = true;
2273                         }
2274
2275                         if (get_rate() != backend->sample_rate()) {
2276                                 change_rate = true;
2277                         }
2278
2279                         if (get_buffer_size() != backend->buffer_size()) {
2280                                 change_bufsize = true;
2281                         }
2282
2283                         if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2284                                         && get_nperiods() != backend->period_size()) {
2285                                 change_nperiods = true;
2286                         }
2287
2288                         if (get_midi_option() != backend->midi_option()) {
2289                                 change_midi = true;
2290                         }
2291
2292                         if (backend->can_use_buffered_io()) {
2293                                 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2294                                         change_buffered_io = true;
2295                                 }
2296                         }
2297
2298                         /* zero-requested channels means "all available" */
2299
2300                         if (ichan == 0) {
2301                                 ichan = backend->input_channels();
2302                         }
2303
2304                         if (ochan == 0) {
2305                                 ochan = backend->output_channels();
2306                         }
2307
2308                         if (ichan != backend->input_channels()) {
2309                                 change_channels = true;
2310                         }
2311
2312                         if (ochan != backend->output_channels()) {
2313                                 change_channels = true;
2314                         }
2315
2316                         if (get_input_latency() != backend->systemic_input_latency() ||
2317                                         get_output_latency() != backend->systemic_output_latency()) {
2318                                 change_latency = true;
2319                         }
2320                 } else {
2321                         /* backend never started, so we have to force a group
2322                            of settings.
2323                          */
2324                         change_device = true;
2325                         if (backend->requires_driver_selection()) {
2326                                 change_driver = true;
2327                         }
2328                         change_rate = true;
2329                         change_bufsize = true;
2330                         change_channels = true;
2331                         change_latency = true;
2332                         change_midi = true;
2333                         change_buffered_io = backend->can_use_buffered_io();
2334                         change_channels = true;
2335                         change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2336                 }
2337
2338         } else {
2339
2340                 /* we have no control over the backend, meaning that we can
2341                  * only possibly change sample rate and buffer size.
2342                  */
2343
2344
2345                 if (get_rate() != backend->sample_rate()) {
2346                         change_bufsize = true;
2347                 }
2348
2349                 if (get_buffer_size() != backend->buffer_size()) {
2350                         change_bufsize = true;
2351                 }
2352         }
2353
2354         queue_device_changed = false;
2355
2356         if (!_have_control) {
2357
2358                 /* We do not have control over the backend, so the best we can
2359                  * do is try to change the sample rate and/or bufsize and get
2360                  * out of here.
2361                  */
2362
2363                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2364                         return 1;
2365                 }
2366
2367                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2368                         return 1;
2369                 }
2370
2371                 if (change_rate) {
2372                         backend->set_sample_rate (get_rate());
2373                 }
2374
2375                 if (change_bufsize) {
2376                         backend->set_buffer_size (get_buffer_size());
2377                 }
2378
2379                 if (start) {
2380                         if (ARDOUR::AudioEngine::instance()->start ()) {
2381                                 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2382                                 return -1;
2383                         }
2384                 }
2385
2386                 post_push ();
2387
2388                 return 0;
2389         }
2390
2391         /* determine if we need to stop the backend before changing parameters */
2392
2393         if (change_driver || change_device || change_channels || change_nperiods ||
2394                         (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2395                         (change_rate && !backend->can_change_sample_rate_when_running()) ||
2396                         change_midi || change_buffered_io ||
2397                         (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2398                 restart_required = true;
2399         } else {
2400                 restart_required = false;
2401         }
2402
2403
2404         if (was_running) {
2405                 if (restart_required) {
2406                         if (ARDOUR::AudioEngine::instance()->stop()) {
2407                                 return -1;
2408                         }
2409                 }
2410         }
2411
2412         if (change_driver && backend->set_driver (get_driver())) {
2413                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2414                 return -1;
2415         }
2416         if (backend->use_separate_input_and_output_devices()) {
2417                 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2418                         error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2419                         return -1;
2420                 }
2421                 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2422                         error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2423                         return -1;
2424                 }
2425         } else {
2426                 if (change_device && backend->set_device_name (get_device_name())) {
2427                         error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2428                         return -1;
2429                 }
2430         }
2431         if (change_rate && backend->set_sample_rate (get_rate())) {
2432                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2433                 return -1;
2434         }
2435         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2436                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2437                 return -1;
2438         }
2439         if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2440                 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2441                 return -1;
2442         }
2443
2444         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2445                 if (backend->set_input_channels (get_input_channels())) {
2446                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2447                         return -1;
2448                 }
2449                 if (backend->set_output_channels (get_output_channels())) {
2450                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2451                         return -1;
2452                 }
2453         }
2454         if (change_latency) {
2455                 if (backend->set_systemic_input_latency (get_input_latency())) {
2456                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2457                         return -1;
2458                 }
2459                 if (backend->set_systemic_output_latency (get_output_latency())) {
2460                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2461                         return -1;
2462                 }
2463         }
2464
2465         if (change_midi) {
2466                 backend->set_midi_option (get_midi_option());
2467         }
2468
2469         if (change_buffered_io) {
2470                 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2471         }
2472
2473         if (1 /* TODO */) {
2474                 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2475                         if (_measure_midi) {
2476                                 if (*p == _measure_midi) {
2477                                         backend->set_midi_device_enabled ((*p)->name, true);
2478                                 } else {
2479                                         backend->set_midi_device_enabled ((*p)->name, false);
2480                                 }
2481                                 if (backend->can_change_systemic_latency_when_running ()) {
2482                                         backend->set_systemic_midi_input_latency ((*p)->name, 0);
2483                                         backend->set_systemic_midi_output_latency ((*p)->name, 0);
2484                                 }
2485                                 continue;
2486                         }
2487                         backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2488                         if (backend->can_set_systemic_midi_latencies()) {
2489                                 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2490                                 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2491                         }
2492                 }
2493         }
2494
2495         if (start || (was_running && restart_required)) {
2496                 if (ARDOUR::AudioEngine::instance()->start()) {
2497                         return -1;
2498                 }
2499         }
2500
2501         post_push ();
2502
2503         return 0;
2504 }
2505
2506 void
2507 EngineControl::post_push ()
2508 {
2509         /* get a pointer to the current state object, creating one if
2510          * necessary
2511          */
2512
2513         State state = get_saved_state_for_currently_displayed_backend_and_device ();
2514
2515         if (!state) {
2516                 state = save_state ();
2517                 assert (state);
2518         } else {
2519                 store_state(state);
2520         }
2521
2522         states.sort (state_sort_cmp);
2523
2524         /* all off */
2525
2526         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2527                 (*i)->active = false;
2528         }
2529
2530         /* mark this one active (to be used next time the dialog is
2531          * shown)
2532          */
2533
2534         state->active = true;
2535
2536         if (_have_control) { // XXX
2537                 manage_control_app_sensitivity ();
2538         }
2539
2540         /* schedule a redisplay of MIDI ports */
2541         //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2542 }
2543
2544
2545 float
2546 EngineControl::get_rate () const
2547 {
2548         float r = atof (sample_rate_combo.get_active_text ());
2549         /* the string may have been translated with an abbreviation for
2550          * thousands, so use a crude heuristic to fix this.
2551          */
2552         if (r < 1000.0) {
2553                 r *= 1000.0;
2554         }
2555         return r;
2556 }
2557
2558
2559 uint32_t
2560 EngineControl::get_buffer_size () const
2561 {
2562         string txt = buffer_size_combo.get_active_text ();
2563         uint32_t samples;
2564
2565         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2566                 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2567                 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2568                 throw exception ();
2569         }
2570
2571         return samples;
2572 }
2573
2574 uint32_t
2575 EngineControl::get_nperiods () const
2576 {
2577         string txt = nperiods_combo.get_active_text ();
2578         return atoi (txt.c_str());
2579 }
2580
2581 string
2582 EngineControl::get_midi_option () const
2583 {
2584         return midi_option_combo.get_active_text();
2585 }
2586
2587 bool
2588 EngineControl::get_use_buffered_io () const
2589 {
2590         return use_buffered_io_button.get_active();
2591 }
2592
2593 uint32_t
2594 EngineControl::get_input_channels() const
2595 {
2596         if (ARDOUR::Profile->get_mixbus()) {
2597                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2598                 if (!backend) return 0;
2599                 return backend->input_channels();
2600         }
2601         return (uint32_t) input_channels_adjustment.get_value();
2602 }
2603
2604 uint32_t
2605 EngineControl::get_output_channels() const
2606 {
2607         if (ARDOUR::Profile->get_mixbus()) {
2608                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2609                 if (!backend) return 0;
2610                 return backend->input_channels();
2611         }
2612         return (uint32_t) output_channels_adjustment.get_value();
2613 }
2614
2615 uint32_t
2616 EngineControl::get_input_latency() const
2617 {
2618         return (uint32_t) input_latency_adjustment.get_value();
2619 }
2620
2621 uint32_t
2622 EngineControl::get_output_latency() const
2623 {
2624         return (uint32_t) output_latency_adjustment.get_value();
2625 }
2626
2627 string
2628 EngineControl::get_backend () const
2629 {
2630         return backend_combo.get_active_text ();
2631 }
2632
2633 string
2634 EngineControl::get_driver () const
2635 {
2636         if (driver_combo.get_parent()) {
2637                 return driver_combo.get_active_text ();
2638         } else {
2639                 return "";
2640         }
2641 }
2642
2643 string
2644 EngineControl::get_device_name () const
2645 {
2646         return device_combo.get_active_text ();
2647 }
2648
2649 string
2650 EngineControl::get_input_device_name () const
2651 {
2652         return input_device_combo.get_active_text ();
2653 }
2654
2655 string
2656 EngineControl::get_output_device_name () const
2657 {
2658         return output_device_combo.get_active_text ();
2659 }
2660
2661 void
2662 EngineControl::control_app_button_clicked ()
2663 {
2664         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2665
2666         if (!backend) {
2667                 return;
2668         }
2669
2670         backend->launch_control_app ();
2671 }
2672
2673 void
2674 EngineControl::start_stop_button_clicked ()
2675 {
2676         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2677
2678         if (!backend) {
2679                 return;
2680         }
2681
2682         if (ARDOUR::AudioEngine::instance()->running()) {
2683                 ARDOUR::AudioEngine::instance()->stop ();
2684         } else {
2685                 if (!ARDOUR_UI::instance()->session_loaded) {
2686                         pop_splash ();
2687                         hide ();
2688                         ARDOUR::GUIIdle ();
2689                 }
2690                 start_engine ();
2691                 if (!ARDOUR_UI::instance()->session_loaded) {
2692                         ArdourDialog::on_response (RESPONSE_OK);
2693                 }
2694         }
2695 }
2696
2697 void
2698 EngineControl::update_devices_button_clicked ()
2699 {
2700         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2701
2702         if (!backend) {
2703                 return;
2704         }
2705
2706         if (backend->update_devices()) {
2707                 device_list_changed ();
2708         }
2709 }
2710
2711 void
2712 EngineControl::use_buffered_io_button_clicked ()
2713 {
2714         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2715
2716         if (!backend) {
2717                 return;
2718         }
2719
2720         bool set_buffered_io = !use_buffered_io_button.get_active();
2721         use_buffered_io_button.set_active (set_buffered_io);
2722         backend->set_use_buffered_io (set_buffered_io);
2723 }
2724
2725 void
2726 EngineControl::manage_control_app_sensitivity ()
2727 {
2728         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2729
2730         if (!backend) {
2731                 return;
2732         }
2733
2734         string appname = backend->control_app_name();
2735
2736         if (appname.empty()) {
2737                 control_app_button.set_sensitive (false);
2738         } else {
2739                 control_app_button.set_sensitive (true);
2740         }
2741 }
2742
2743 void
2744 EngineControl::set_desired_sample_rate (uint32_t sr)
2745 {
2746         _desired_sample_rate = sr;
2747         if (ARDOUR::AudioEngine::instance ()->running ()
2748                         && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2749                 stop_engine ();
2750         }
2751         device_changed ();
2752 }
2753
2754 void
2755 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2756 {
2757         if (page_num == 0) {
2758                 _measure_midi.reset();
2759                 update_sensitivity ();
2760         }
2761
2762         if (page_num == midi_tab) {
2763                 /* MIDI tab */
2764                 refresh_midi_display ();
2765         }
2766
2767         if (page_num == latency_tab) {
2768                 /* latency tab */
2769
2770                 if (ARDOUR::AudioEngine::instance()->running()) {
2771                         stop_engine (true);
2772                 }
2773
2774                 {
2775                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2776
2777                         /* save any existing latency values */
2778
2779                         uint32_t il = (uint32_t) input_latency.get_value ();
2780                         uint32_t ol = (uint32_t) input_latency.get_value ();
2781
2782                         /* reset to zero so that our new test instance
2783                            will be clean of any existing latency measures.
2784
2785                            NB. this should really be done by the backend
2786                            when stated for latency measurement.
2787                         */
2788
2789                         input_latency.set_value (0);
2790                         output_latency.set_value (0);
2791
2792                         push_state_to_backend (false);
2793
2794                         /* reset control */
2795
2796                         input_latency.set_value (il);
2797                         output_latency.set_value (ol);
2798
2799                 }
2800                 // This should be done in push_state_to_backend()
2801                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2802                         disable_latency_tab ();
2803                 }
2804
2805                 enable_latency_tab ();
2806
2807         } else {
2808                 if (lm_running) {
2809                         end_latency_detection ();
2810                         ARDOUR::AudioEngine::instance()->stop_latency_detection();
2811                 }
2812         }
2813 }
2814
2815 /* latency measurement */
2816
2817 bool
2818 EngineControl::check_audio_latency_measurement ()
2819 {
2820         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2821
2822         if (mtdm->resolve () < 0) {
2823                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2824                 return true;
2825         }
2826
2827         if (mtdm->get_peak () > 0.707f) {
2828                 // get_peak() resets the peak-hold in the detector.
2829                 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2830                 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2831                 return true;
2832         }
2833
2834         if (mtdm->err () > 0.3) {
2835                 mtdm->invert ();
2836                 mtdm->resolve ();
2837         }
2838
2839         char buf[256];
2840         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2841
2842         if (sample_rate == 0) {
2843                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2844                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2845                 return false;
2846         }
2847
2848         int frames_total = mtdm->del();
2849         int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2850
2851         snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2852                         _("Detected roundtrip latency: "),
2853                         frames_total, frames_total * 1000.0f/sample_rate,
2854                         _("Systemic latency: "),
2855                         extra, extra * 1000.0f/sample_rate);
2856
2857         bool solid = true;
2858
2859         if (mtdm->err () > 0.2) {
2860                 strcat (buf, " ");
2861                 strcat (buf, _("(signal detection error)"));
2862                 solid = false;
2863         }
2864
2865         if (mtdm->inv ()) {
2866                 strcat (buf, " ");
2867                 strcat (buf, _("(inverted - bad wiring)"));
2868                 solid = false;
2869         }
2870
2871         lm_results.set_markup (string_compose (results_markup, buf));
2872
2873         if (solid) {
2874                 have_lm_results = true;
2875                 end_latency_detection ();
2876                 lm_use_button.set_sensitive (true);
2877                 return false;
2878         }
2879
2880         return true;
2881 }
2882
2883 bool
2884 EngineControl::check_midi_latency_measurement ()
2885 {
2886         ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2887
2888         if (!mididm->have_signal () || mididm->latency () == 0) {
2889                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2890                 return true;
2891         }
2892
2893         char buf[256];
2894         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2895
2896         if (sample_rate == 0) {
2897                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2898                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2899                 return false;
2900         }
2901
2902         ARDOUR::framecnt_t frames_total = mididm->latency();
2903         ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2904         snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2905                         _("Detected roundtrip latency: "),
2906                         frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2907                         _("Systemic latency: "),
2908                         extra, extra * 1000.0f / sample_rate);
2909
2910         bool solid = true;
2911
2912         if (!mididm->ok ()) {
2913                 strcat (buf, " ");
2914                 strcat (buf, _("(averaging)"));
2915                 solid = false;
2916         }
2917
2918         if (mididm->deviation () > 50.0) {
2919                 strcat (buf, " ");
2920                 strcat (buf, _("(too large jitter)"));
2921                 solid = false;
2922         } else if (mididm->deviation () > 10.0) {
2923                 strcat (buf, " ");
2924                 strcat (buf, _("(large jitter)"));
2925         }
2926
2927         if (solid) {
2928                 have_lm_results = true;
2929                 end_latency_detection ();
2930                 lm_use_button.set_sensitive (true);
2931                 lm_results.set_markup (string_compose (results_markup, buf));
2932                 return false;
2933         } else if (mididm->processed () > 400) {
2934                 have_lm_results = false;
2935                 end_latency_detection ();
2936                 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2937                 return false;
2938         }
2939
2940         lm_results.set_markup (string_compose (results_markup, buf));
2941
2942         return true;
2943 }
2944
2945 void
2946 EngineControl::start_latency_detection ()
2947 {
2948         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2949         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2950
2951         if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2952                 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2953                 if (_measure_midi) {
2954                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2955                 } else {
2956                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2957                 }
2958                 lm_measure_label.set_text (_("Cancel"));
2959                 have_lm_results = false;
2960                 lm_use_button.set_sensitive (false);
2961                 lm_input_channel_combo.set_sensitive (false);
2962                 lm_output_channel_combo.set_sensitive (false);
2963                 lm_running = true;
2964         }
2965 }
2966
2967 void
2968 EngineControl::end_latency_detection ()
2969 {
2970         latency_timeout.disconnect ();
2971         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2972         lm_measure_label.set_text (_("Measure"));
2973         if (!have_lm_results) {
2974                 lm_use_button.set_sensitive (false);
2975         }
2976         lm_input_channel_combo.set_sensitive (true);
2977         lm_output_channel_combo.set_sensitive (true);
2978         lm_running = false;
2979 }
2980
2981 void
2982 EngineControl::latency_button_clicked ()
2983 {
2984         if (!lm_running) {
2985                 start_latency_detection ();
2986         } else {
2987                 end_latency_detection ();
2988         }
2989 }
2990
2991 void
2992 EngineControl::latency_back_button_clicked ()
2993 {
2994         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2995         notebook.set_current_page(0);
2996 }
2997
2998 void
2999 EngineControl::use_latency_button_clicked ()
3000 {
3001         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3002         if (_measure_midi) {
3003                 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3004                 if (!mididm) {
3005                         return;
3006                 }
3007                 ARDOUR::framecnt_t frames_total = mididm->latency();
3008                 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3009                 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3010                 _measure_midi->input_latency = one_way;
3011                 _measure_midi->output_latency = one_way;
3012                 if (backend->can_change_systemic_latency_when_running ()) {
3013                         backend->set_systemic_midi_input_latency (_measure_midi->name, one_way);
3014                         backend->set_systemic_midi_output_latency (_measure_midi->name, one_way);
3015                 }
3016                 notebook.set_current_page (midi_tab);
3017         } else {
3018                 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3019
3020                 if (!mtdm) {
3021                         return;
3022                 }
3023
3024                 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3025                 one_way = std::max (0., one_way);
3026
3027                 input_latency_adjustment.set_value (one_way);
3028                 output_latency_adjustment.set_value (one_way);
3029                 if (backend->can_change_systemic_latency_when_running ()) {
3030                         backend->set_systemic_input_latency (one_way);
3031                         backend->set_systemic_output_latency (one_way);
3032                 }
3033
3034                 /* back to settings page */
3035                 notebook.set_current_page (0);
3036         }
3037 }
3038
3039 bool
3040 EngineControl::on_delete_event (GdkEventAny* ev)
3041 {
3042         if (notebook.get_current_page() == 2) {
3043                 /* currently on latency tab - be sure to clean up */
3044                 end_latency_detection ();
3045         }
3046         return ArdourDialog::on_delete_event (ev);
3047 }
3048
3049 void
3050 EngineControl::engine_running ()
3051 {
3052         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3053         assert (backend);
3054
3055         set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3056         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3057
3058         if (backend->can_set_period_size ()) {
3059                 set_active_text_if_present (nperiods_combo, to_string (backend->period_size()));
3060         }
3061
3062         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3063         connect_disconnect_button.show();
3064
3065         started_at_least_once = true;
3066         if (_have_control) {
3067                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3068         } else {
3069                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3070         }
3071         update_sensitivity();
3072 }
3073
3074 void
3075 EngineControl::engine_stopped ()
3076 {
3077         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3078         assert (backend);
3079
3080         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3081         connect_disconnect_button.show();
3082
3083         if (_have_control) {
3084                 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3085         } else {
3086                 engine_status.set_markup(X_(""));
3087         }
3088
3089         update_sensitivity();
3090 }
3091
3092 void
3093 EngineControl::device_list_changed ()
3094 {
3095         if (ignore_device_changes) {
3096                 return;
3097         }
3098         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3099         list_devices ();
3100         midi_option_changed();
3101 }
3102
3103 void
3104 EngineControl::connect_disconnect_click()
3105 {
3106         if (ARDOUR::AudioEngine::instance()->running()) {
3107                 stop_engine ();
3108         } else {
3109                 if (!ARDOUR_UI::instance()->session_loaded) {
3110                         pop_splash ();
3111                         hide ();
3112                         ARDOUR::GUIIdle ();
3113                 }
3114                 start_engine ();
3115                 if (!ARDOUR_UI::instance()->session_loaded) {
3116                         ArdourDialog::on_response (RESPONSE_OK);
3117                 }
3118         }
3119 }
3120
3121 void
3122 EngineControl::calibrate_audio_latency ()
3123 {
3124         _measure_midi.reset ();
3125         have_lm_results = false;
3126         lm_use_button.set_sensitive (false);
3127         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3128         notebook.set_current_page (latency_tab);
3129 }
3130
3131 void
3132 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3133 {
3134         _measure_midi = s;
3135         have_lm_results = false;
3136         lm_use_button.set_sensitive (false);
3137         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3138         notebook.set_current_page (latency_tab);
3139 }
3140
3141 void
3142 EngineControl::configure_midi_devices ()
3143 {
3144         notebook.set_current_page (midi_tab);
3145 }