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