Fix inconsistent session-check
[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()->the_session () && !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()->the_session ()) {
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                 } else if (ARDOUR_UI::instance()->the_session ()) {
1368                         float active_sr = ARDOUR_UI::instance()->the_session()->nominal_sample_rate ();
1369
1370                         if (std::find (sr.begin (), sr.end (), active_sr) == sr.end ()) {
1371                                 active_sr = sr.front ();
1372                         }
1373
1374                         sample_rate_combo.set_active_text (rate_as_string (active_sr));
1375                 } else if (desired.empty ()) {
1376                         float new_active_sr = backend->default_sample_rate ();
1377
1378                         if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1379                                 new_active_sr = sr.front ();
1380                         }
1381
1382                         sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1383                 } else {
1384                         sample_rate_combo.set_active_text (desired);
1385                 }
1386         }
1387         update_sensitivity ();
1388 }
1389
1390 vector<uint32_t>
1391 EngineControl::get_buffer_sizes_for_all_devices ()
1392 {
1393         boost::shared_ptr<ARDOUR::AudioBackend> backend =
1394             ARDOUR::AudioEngine::instance ()->current_backend ();
1395         vector<uint32_t> all_sizes;
1396
1397         if (backend->use_separate_input_and_output_devices ()) {
1398                 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1399         } else {
1400                 all_sizes = backend->available_buffer_sizes (get_device_name ());
1401         }
1402         return all_sizes;
1403 }
1404
1405 vector<uint32_t>
1406 EngineControl::get_default_buffer_sizes ()
1407 {
1408         vector<uint32_t> sizes;
1409         sizes.push_back (8);
1410         sizes.push_back (16);
1411         sizes.push_back (32);
1412         sizes.push_back (64);
1413         sizes.push_back (128);
1414         sizes.push_back (256);
1415         sizes.push_back (512);
1416         sizes.push_back (1024);
1417         sizes.push_back (2048);
1418         sizes.push_back (4096);
1419         sizes.push_back (8192);
1420         return sizes;
1421 }
1422
1423 void
1424 EngineControl::set_buffersize_popdown_strings ()
1425 {
1426         DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1427         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1428         vector<uint32_t> bs;
1429         vector<string> s;
1430
1431         if (_have_control) {
1432                 bs = get_buffer_sizes_for_all_devices ();
1433         } else if (backend->can_change_buffer_size_when_running()) {
1434                 bs = get_default_buffer_sizes ();
1435         }
1436
1437         for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1438                 s.push_back (bufsize_as_string (*x));
1439         }
1440
1441         uint32_t previous_size = backend->buffer_size ();
1442         if (!buffer_size_combo.get_active_text().empty()) {
1443                 previous_size = get_buffer_size ();
1444         }
1445
1446         set_popdown_strings (buffer_size_combo, s);
1447
1448         if (!s.empty()) {
1449
1450                 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1451                         buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1452                 } else {
1453
1454                         buffer_size_combo.set_active_text(s.front());
1455
1456                         uint32_t period = backend->buffer_size();
1457                         if (0 == period && backend->use_separate_input_and_output_devices()) {
1458                                 period = backend->default_buffer_size(get_input_device_name());
1459                         }
1460                         if (0 == period && backend->use_separate_input_and_output_devices()) {
1461                                 period = backend->default_buffer_size(get_output_device_name());
1462                         }
1463                         if (0 == period && !backend->use_separate_input_and_output_devices()) {
1464                                 period = backend->default_buffer_size(get_device_name());
1465                         }
1466
1467                         set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1468                 }
1469                 show_buffer_duration ();
1470         }
1471         update_sensitivity ();
1472 }
1473
1474 void
1475 EngineControl::set_nperiods_popdown_strings ()
1476 {
1477         DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1478         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1479         vector<uint32_t> np;
1480         vector<string> s;
1481
1482         if (backend->can_set_period_size()) {
1483                 np = backend->available_period_sizes (get_driver());
1484         }
1485
1486         for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1487                 s.push_back (to_string (*x));
1488         }
1489
1490         set_popdown_strings (nperiods_combo, s);
1491
1492         if (!s.empty()) {
1493                 set_active_text_if_present (nperiods_combo, to_string (backend->period_size())); // XXX
1494         }
1495
1496         update_sensitivity ();
1497 }
1498
1499 void
1500 EngineControl::device_changed ()
1501 {
1502         SignalBlocker blocker (*this, "device_changed");
1503         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1504         assert (backend);
1505
1506         string device_name_in;
1507         string device_name_out; // only used if backend support separate I/O devices
1508
1509         if (backend->use_separate_input_and_output_devices()) {
1510                 device_name_in  = get_input_device_name ();
1511                 device_name_out = get_output_device_name ();
1512         } else {
1513                 device_name_in = get_device_name ();
1514         }
1515
1516         /* we set the backend-device to query various device related intormation.
1517          * This has the side effect that backend->device_name() will match
1518          * the device_name and  'change_device' will never be true.
1519          * so work around this by setting...
1520          */
1521         if (backend->use_separate_input_and_output_devices()) {
1522                 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1523                         queue_device_changed = true;
1524                 }
1525         } else {
1526                 if (device_name_in != backend->device_name()) {
1527                         queue_device_changed = true;
1528                 }
1529         }
1530
1531         //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1532         if (backend->use_separate_input_and_output_devices()) {
1533                 backend->set_input_device_name (device_name_in);
1534                 backend->set_output_device_name (device_name_out);
1535         } else {
1536                 backend->set_device_name(device_name_in);
1537         }
1538
1539         {
1540                 /* don't allow programmatic change to combos to cause a
1541                    recursive call to this method.
1542                  */
1543                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1544
1545                 set_samplerate_popdown_strings ();
1546                 set_buffersize_popdown_strings ();
1547                 set_nperiods_popdown_strings ();
1548
1549                 /* TODO set min + max channel counts here */
1550
1551                 manage_control_app_sensitivity ();
1552         }
1553
1554         /* pick up any saved state for this device */
1555
1556         if (!ignore_changes) {
1557                 maybe_display_saved_state ();
1558         }
1559 }
1560
1561 void
1562 EngineControl::input_device_changed ()
1563 {
1564         DEBUG_ECONTROL ("input_device_changed");
1565
1566         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1567         if (backend && backend->match_input_output_devices_or_none ()) {
1568                 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1569
1570                 if (get_output_device_name () != dev_none
1571                                 && get_input_device_name () != dev_none
1572                                 && get_input_device_name () != get_output_device_name ()) {
1573                         block_changed_signals ();
1574                         if (contains_value (output_device_combo, get_input_device_name ())) {
1575                                 output_device_combo.set_active_text (get_input_device_name ());
1576                         } else {
1577                                 assert (contains_value (output_device_combo, dev_none));
1578                                 output_device_combo.set_active_text (dev_none);
1579                         }
1580                         unblock_changed_signals ();
1581                 }
1582         }
1583         device_changed ();
1584 }
1585
1586 void
1587 EngineControl::output_device_changed ()
1588 {
1589         DEBUG_ECONTROL ("output_device_changed");
1590         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1591         if (backend && backend->match_input_output_devices_or_none ()) {
1592                 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1593
1594                 if (get_input_device_name () != dev_none
1595                                 && get_input_device_name () != dev_none
1596                                 && get_input_device_name () != get_output_device_name ()) {
1597                         block_changed_signals ();
1598                         if (contains_value (input_device_combo, get_output_device_name ())) {
1599                                 input_device_combo.set_active_text (get_output_device_name ());
1600                         } else {
1601                                 assert (contains_value (input_device_combo, dev_none));
1602                                 input_device_combo.set_active_text (dev_none);
1603                         }
1604                         unblock_changed_signals ();
1605                 }
1606         }
1607         device_changed ();
1608 }
1609
1610 string
1611 EngineControl::bufsize_as_string (uint32_t sz)
1612 {
1613         return string_compose (P_("%1 sample", "%1 samples", sz), to_string(sz));
1614 }
1615
1616 void
1617 EngineControl::sample_rate_changed ()
1618 {
1619         DEBUG_ECONTROL ("sample_rate_changed");
1620         /* reset the strings for buffer size to show the correct msec value
1621            (reflecting the new sample rate).
1622          */
1623
1624         show_buffer_duration ();
1625
1626 }
1627
1628 void
1629 EngineControl::buffer_size_changed ()
1630 {
1631         DEBUG_ECONTROL ("buffer_size_changed");
1632         if (ARDOUR::AudioEngine::instance()->running()) {
1633                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1634                 if (backend && backend->can_change_buffer_size_when_running ()) {
1635                         backend->set_buffer_size (get_buffer_size());
1636                 }
1637         }
1638         show_buffer_duration ();
1639 }
1640
1641 void
1642 EngineControl::nperiods_changed ()
1643 {
1644         DEBUG_ECONTROL ("nperiods_changed");
1645         show_buffer_duration ();
1646 }
1647
1648 void
1649 EngineControl::show_buffer_duration ()
1650 {
1651         DEBUG_ECONTROL ("show_buffer_duration");
1652         /* buffer sizes  - convert from just samples to samples + msecs for
1653          * the displayed string
1654          */
1655
1656         string bs_text = buffer_size_combo.get_active_text ();
1657         uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1658         uint32_t rate = get_rate();
1659
1660         /* Except for ALSA and Dummy backends, we don't know the number of periods
1661          * per cycle and settings.
1662          *
1663          * jack1 vs jack2 have different default latencies since jack2 start
1664          * in async-mode unless --sync is given which adds an extra cycle
1665          * of latency. The value is not known if jackd is started externally..
1666          *
1667          * So just display the period size, that's also what
1668          * ARDOUR_UI::update_sample_rate() does for the status bar.
1669          * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1670          * but still, that's the buffer period, not [round-trip] latency)
1671          */
1672         char buf[32];
1673         snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1674         buffer_size_duration_label.set_text (buf);
1675 }
1676
1677 void
1678 EngineControl::midi_option_changed ()
1679 {
1680         DEBUG_ECONTROL ("midi_option_changed");
1681         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1682         assert (backend);
1683
1684         backend->set_midi_option (get_midi_option());
1685
1686         vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1687
1688         //_midi_devices.clear(); // TODO merge with state-saved settings..
1689         _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1690         std::vector<MidiDeviceSettings> new_devices;
1691
1692         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1693                 MidiDeviceSettings mds = find_midi_device (i->name);
1694                 if (i->available && !mds) {
1695                         uint32_t input_latency = 0;
1696                         uint32_t output_latency = 0;
1697                         if (_can_set_midi_latencies) {
1698                                 input_latency = backend->systemic_midi_input_latency (i->name);
1699                                 output_latency = backend->systemic_midi_output_latency (i->name);
1700                         }
1701                         bool enabled = backend->midi_device_enabled (i->name);
1702                         MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1703                         new_devices.push_back (ptr);
1704                 } else if (i->available) {
1705                         new_devices.push_back (mds);
1706                 }
1707         }
1708         _midi_devices = new_devices;
1709
1710         if (_midi_devices.empty()) {
1711                 midi_devices_button.hide ();
1712         } else {
1713                 midi_devices_button.show ();
1714         }
1715 }
1716
1717 void
1718 EngineControl::parameter_changed ()
1719 {
1720 }
1721
1722 EngineControl::State
1723 EngineControl::get_matching_state (const string& backend)
1724 {
1725         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1726                 if ((*i)->backend == backend) {
1727                         return (*i);
1728                 }
1729         }
1730         return State();
1731 }
1732
1733 EngineControl::State
1734 EngineControl::get_matching_state (
1735                 const string& backend,
1736                 const string& driver,
1737                 const string& device)
1738 {
1739         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1740                 if ((*i)->backend == backend &&
1741                                 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1742                 {
1743                         return (*i);
1744                 }
1745         }
1746         return State();
1747 }
1748
1749 EngineControl::State
1750 EngineControl::get_matching_state (
1751                 const string& backend,
1752                 const string& driver,
1753                 const string& input_device,
1754                 const string& output_device)
1755 {
1756         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1757                 if ((*i)->backend == backend &&
1758                                 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1759                 {
1760                         return (*i);
1761                 }
1762         }
1763         return State();
1764 }
1765
1766 EngineControl::State
1767 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1768 {
1769         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1770
1771         if (backend) {
1772                 if (backend->use_separate_input_and_output_devices ()) {
1773                         return get_matching_state (backend_combo.get_active_text(),
1774                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1775                                         input_device_combo.get_active_text(),
1776                                         output_device_combo.get_active_text());
1777                 } else {
1778                         return get_matching_state (backend_combo.get_active_text(),
1779                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1780                                         device_combo.get_active_text());
1781                 }
1782         }
1783
1784         return get_matching_state (backend_combo.get_active_text(),
1785                         string(),
1786                         device_combo.get_active_text());
1787 }
1788
1789 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1790                                        const EngineControl::State& state2)
1791 {
1792         if (state1->backend == state2->backend &&
1793                         state1->driver == state2->driver &&
1794                         state1->device == state2->device &&
1795                         state1->input_device == state2->input_device &&
1796                         state1->output_device == state2->output_device) {
1797                 return true;
1798         }
1799         return false;
1800 }
1801
1802 // sort active first, then most recently used to the beginning of the list
1803 bool
1804 EngineControl::state_sort_cmp (const State &a, const State &b) {
1805         if (a->active) {
1806                 return true;
1807         }
1808         else if (b->active) {
1809                 return false;
1810         }
1811         else {
1812                 return a->lru > b->lru;
1813         }
1814 }
1815
1816 EngineControl::State
1817 EngineControl::save_state ()
1818 {
1819         State state;
1820
1821         if (!_have_control) {
1822                 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1823                 if (state) {
1824                         state->lru = time (NULL) ;
1825                         return state;
1826                 }
1827                 state.reset(new StateStruct);
1828                 state->backend = get_backend ();
1829         } else {
1830                 state.reset(new StateStruct);
1831                 store_state (state);
1832         }
1833
1834         for (StateList::iterator i = states.begin(); i != states.end();) {
1835                 if (equivalent_states (*i, state)) {
1836                         i =  states.erase(i);
1837                 } else {
1838                         ++i;
1839                 }
1840         }
1841
1842         states.push_back (state);
1843
1844         states.sort (state_sort_cmp);
1845
1846         return state;
1847 }
1848
1849 void
1850 EngineControl::store_state (State state)
1851 {
1852         state->backend = get_backend ();
1853         state->driver = get_driver ();
1854         state->device = get_device_name ();
1855         state->input_device = get_input_device_name ();
1856         state->output_device = get_output_device_name ();
1857         state->sample_rate = get_rate ();
1858         state->buffer_size = get_buffer_size ();
1859         state->n_periods = get_nperiods ();
1860         state->input_latency = get_input_latency ();
1861         state->output_latency = get_output_latency ();
1862         state->input_channels = get_input_channels ();
1863         state->output_channels = get_output_channels ();
1864         state->midi_option = get_midi_option ();
1865         state->midi_devices = _midi_devices;
1866         state->use_buffered_io = get_use_buffered_io ();
1867         state->lru = time (NULL) ;
1868 }
1869
1870 void
1871 EngineControl::maybe_display_saved_state ()
1872 {
1873         if (!_have_control || ARDOUR::AudioEngine::instance()->running ()) {
1874                 return;
1875         }
1876
1877         State state = get_saved_state_for_currently_displayed_backend_and_device ();
1878
1879         if (state) {
1880                 DEBUG_ECONTROL ("Restoring saved state");
1881                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1882
1883                 if (0 == _desired_sample_rate && sample_rate_combo.get_sensitive ()) {
1884                         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1885                 }
1886                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1887
1888                 set_active_text_if_present (nperiods_combo, to_string(state->n_periods));
1889                 /* call this explicitly because we're ignoring changes to
1890                    the controls at this point.
1891                  */
1892                 show_buffer_duration ();
1893                 input_latency.set_value (state->input_latency);
1894                 output_latency.set_value (state->output_latency);
1895
1896                 use_buffered_io_button.set_active (state->use_buffered_io);
1897
1898                 if (!state->midi_option.empty()) {
1899                         midi_option_combo.set_active_text (state->midi_option);
1900                         _midi_devices = state->midi_devices;
1901                 }
1902         } else {
1903                 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1904         }
1905 }
1906
1907 XMLNode&
1908 EngineControl::get_state ()
1909 {
1910         LocaleGuard lg;
1911
1912         XMLNode* root = new XMLNode ("AudioMIDISetup");
1913         std::string path;
1914
1915         if (!states.empty()) {
1916                 XMLNode* state_nodes = new XMLNode ("EngineStates");
1917
1918                 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1919
1920                         XMLNode* node = new XMLNode ("State");
1921
1922                         node->set_property ("backend", (*i)->backend);
1923                         node->set_property ("driver", (*i)->driver);
1924                         node->set_property ("device", (*i)->device);
1925                         node->set_property ("input-device", (*i)->input_device);
1926                         node->set_property ("output-device", (*i)->output_device);
1927                         node->set_property ("sample-rate", (*i)->sample_rate);
1928                         node->set_property ("buffer-size", (*i)->buffer_size);
1929                         node->set_property ("n-periods", (*i)->n_periods);
1930                         node->set_property ("input-latency", (*i)->input_latency);
1931                         node->set_property ("output-latency", (*i)->output_latency);
1932                         node->set_property ("input-channels", (*i)->input_channels);
1933                         node->set_property ("output-channels", (*i)->output_channels);
1934                         node->set_property ("active", (*i)->active);
1935                         node->set_property ("use-buffered-io", (*i)->use_buffered_io);
1936                         node->set_property ("midi-option", (*i)->midi_option);
1937                         int32_t lru_val = (*i)->active ? time (NULL) : (*i)->lru;
1938                         node->set_property ("lru", lru_val );
1939
1940                         XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1941                         for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1942                                 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1943                                 midi_device_stuff->set_property (X_("name"), (*p)->name);
1944                                 midi_device_stuff->set_property (X_("enabled"), (*p)->enabled);
1945                                 midi_device_stuff->set_property (X_("input-latency"), (*p)->input_latency);
1946                                 midi_device_stuff->set_property (X_("output-latency"), (*p)->output_latency);
1947                                 midi_devices->add_child_nocopy (*midi_device_stuff);
1948                         }
1949                         node->add_child_nocopy (*midi_devices);
1950
1951                         state_nodes->add_child_nocopy (*node);
1952                 }
1953
1954                 root->add_child_nocopy (*state_nodes);
1955         }
1956
1957         return *root;
1958 }
1959
1960 void
1961 EngineControl::set_default_state ()
1962 {
1963         vector<string> backend_names;
1964         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1965
1966         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1967                 backend_names.push_back ((*b)->name);
1968         }
1969         backend_combo.set_active_text (backend_names.front());
1970
1971         // We could set default backends per platform etc here
1972
1973         backend_changed ();
1974 }
1975
1976 bool
1977 EngineControl::set_state (const XMLNode& root)
1978 {
1979         XMLNodeList          clist, cclist;
1980         XMLNodeConstIterator citer, cciter;
1981         XMLNode const * child;
1982         XMLNode const * grandchild;
1983
1984         if (root.name() != "AudioMIDISetup") {
1985                 return false;
1986         }
1987
1988         clist = root.children();
1989
1990         states.clear ();
1991
1992         for (citer = clist.begin(); citer != clist.end(); ++citer) {
1993
1994                 child = *citer;
1995
1996                 if (child->name() != "EngineStates") {
1997                         continue;
1998                 }
1999
2000                 cclist = child->children();
2001
2002                 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2003                         State state (new StateStruct);
2004
2005                         grandchild = *cciter;
2006
2007                         if (grandchild->name() != "State") {
2008                                 continue;
2009                         }
2010
2011                         if (!grandchild->get_property ("backend", state->backend)) {
2012                                 continue;
2013                         }
2014
2015                         // If any of the required properties are not found in the state node
2016                         // then continue/skip to the next engine state
2017                         if (!grandchild->get_property ("driver", state->driver) ||
2018                             !grandchild->get_property ("device", state->device) ||
2019                             !grandchild->get_property ("input-device", state->input_device) ||
2020                             !grandchild->get_property ("output-device", state->output_device) ||
2021                             !grandchild->get_property ("sample-rate", state->sample_rate) ||
2022                             !grandchild->get_property ("buffer-size", state->buffer_size) ||
2023                             !grandchild->get_property ("input-latency", state->input_latency) ||
2024                             !grandchild->get_property ("output-latency", state->output_latency) ||
2025                             !grandchild->get_property ("input-channels", state->input_channels) ||
2026                             !grandchild->get_property ("output-channels", state->output_channels) ||
2027                             !grandchild->get_property ("active", state->active) ||
2028                             !grandchild->get_property ("use-buffered-io", state->use_buffered_io) ||
2029                             !grandchild->get_property ("midi-option", state->midi_option)) {
2030                                 continue;
2031                         }
2032
2033                         if (!grandchild->get_property ("n-periods", state->n_periods)) {
2034                                 // optional (new value in 4.5)
2035                                 state->n_periods = 0;
2036                         }
2037
2038                         state->midi_devices.clear();
2039                         XMLNode* midinode;
2040                         if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2041                                 const XMLNodeList mnc = midinode->children();
2042                                 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2043                                         std::string name;
2044                                         bool enabled;
2045                                         uint32_t input_latency;
2046                                         uint32_t output_latency;
2047
2048                                         if (!(*n)->get_property (X_("name"), name) ||
2049                                             !(*n)->get_property (X_("enabled"), enabled) ||
2050                                             !(*n)->get_property (X_("input-latency"), input_latency) ||
2051                                             !(*n)->get_property (X_("output-latency"), output_latency)) {
2052                                                 continue;
2053                                         }
2054
2055                                         MidiDeviceSettings ptr (
2056                                             new MidiDeviceSetting (name, enabled, input_latency, output_latency));
2057                                         state->midi_devices.push_back (ptr);
2058                                 }
2059                         }
2060
2061                         int32_t lru_val;
2062                         if (grandchild->get_property ("lru", lru_val)) {
2063                                 state->lru = lru_val;
2064                         }
2065
2066                         states.push_back (state);
2067                 }
2068         }
2069
2070         /* now see if there was an active state and switch the setup to it */
2071
2072         /* purge states of backend that are not available in this built */
2073         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2074         vector<std::string> backend_names;
2075
2076         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2077                 backend_names.push_back((*i)->name);
2078         }
2079         for (StateList::iterator i = states.begin(); i != states.end();) {
2080                 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2081                         i = states.erase(i);
2082                 } else {
2083                         ++i;
2084                 }
2085         }
2086
2087         states.sort (state_sort_cmp);
2088
2089         /* purge old states referring to the same backend */
2090         const time_t now = time (NULL);
2091         for (vector<std::string>::const_iterator bi = backend_names.begin(); bi != backend_names.end(); ++bi) {
2092                 bool first = true;
2093                 for (StateList::iterator i = states.begin(); i != states.end();) {
2094                         if ((*i)->backend != *bi) {
2095                                 ++i; continue;
2096                         }
2097                         // keep at latest one for every audio-system
2098                         if (first) {
2099                                 first = false;
2100                                 ++i; continue;
2101                         }
2102                         // also keep states used in the last 90 days.
2103                         if ((now - (*i)->lru) < 86400 * 90) {
2104                                 ++i; continue;
2105                         }
2106                         assert (!(*i)->active);
2107                         i = states.erase(i);
2108                 }
2109         }
2110
2111         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2112
2113                 if ((*i)->active) {
2114                         return set_current_state (*i);
2115                 }
2116         }
2117         return false;
2118 }
2119
2120 bool
2121 EngineControl::set_current_state (const State& state)
2122 {
2123         DEBUG_ECONTROL ("set_current_state");
2124
2125         boost::shared_ptr<ARDOUR::AudioBackend> backend;
2126
2127         if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2128                   state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2129                 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2130                 // this shouldn't happen as the invalid backend names should have been
2131                 // removed from the list of states.
2132                 return false;
2133         }
2134
2135         // now reflect the change in the backend in the GUI so backend_changed will
2136         // do the right thing
2137         backend_combo.set_active_text (state->backend);
2138
2139         if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2140                 backend_changed ();
2141                 // we don't have control don't restore state
2142                 return true;
2143         }
2144
2145
2146         if (!state->driver.empty ()) {
2147                 if (!backend->requires_driver_selection ()) {
2148                         DEBUG_ECONTROL ("Backend should require driver selection");
2149                         // A backend has changed from having driver selection to not having
2150                         // it or someone has been manually editing a config file and messed
2151                         // it up
2152                         return false;
2153                 }
2154
2155                 if (backend->set_driver (state->driver) != 0) {
2156                         DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2157                         // Driver names for a backend have changed and the name in the
2158                         // config file is now invalid or support for driver is no longer
2159                         // included in the backend
2160                         return false;
2161                 }
2162                 // no need to set the driver_combo as backend_changed will use
2163                 // backend->driver_name to set the active driver
2164         }
2165
2166         if (!state->device.empty ()) {
2167                 if (backend->set_device_name (state->device) != 0) {
2168                         DEBUG_ECONTROL (
2169                             string_compose ("Unable to set device name %1", state->device));
2170                         // device is no longer available on the system
2171                         return false;
2172                 }
2173                 // no need to set active device as it will be picked up in
2174                 // via backend_changed ()/set_device_popdown_strings
2175
2176         } else {
2177                 // backend supports separate input/output devices
2178                 if (backend->set_input_device_name (state->input_device) != 0) {
2179                         DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2180                                                         state->input_device));
2181                         // input device is no longer available on the system
2182                         return false;
2183                 }
2184
2185                 if (backend->set_output_device_name (state->output_device) != 0) {
2186                         DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2187                                                         state->input_device));
2188                         // output device is no longer available on the system
2189                         return false;
2190                 }
2191                 // no need to set active devices as it will be picked up in via
2192                 // backend_changed ()/set_*_device_popdown_strings
2193         }
2194
2195         backend_changed ();
2196
2197         // Now restore the state of the rest of the controls
2198
2199         // We don't use a SignalBlocker as set_current_state is currently only
2200         // called from set_state before any signals are connected. If at some point
2201         // a more general named state mechanism is implemented and
2202         // set_current_state is called while signals are connected then a
2203         // SignalBlocker will need to be instantiated before setting these.
2204
2205         device_combo.set_active_text (state->device);
2206         input_device_combo.set_active_text (state->input_device);
2207         output_device_combo.set_active_text (state->output_device);
2208         if (0 == _desired_sample_rate && sample_rate_combo.get_sensitive ()) {
2209                 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2210         }
2211         set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2212         set_active_text_if_present (nperiods_combo, to_string (state->n_periods));
2213         input_latency.set_value (state->input_latency);
2214         output_latency.set_value (state->output_latency);
2215         midi_option_combo.set_active_text (state->midi_option);
2216         use_buffered_io_button.set_active (state->use_buffered_io);
2217         return true;
2218 }
2219
2220 int
2221 EngineControl::push_state_to_backend (bool start)
2222 {
2223         DEBUG_ECONTROL ("push_state_to_backend");
2224         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2225         PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2226
2227         if (!backend) {
2228                 return 0;
2229         }
2230
2231         /* figure out what is going to change */
2232
2233         bool restart_required = false;
2234         bool was_running = ARDOUR::AudioEngine::instance()->running();
2235         bool change_driver = false;
2236         bool change_device = false;
2237         bool change_rate = false;
2238         bool change_bufsize = false;
2239         bool change_nperiods = false;
2240         bool change_latency = false;
2241         bool change_channels = false;
2242         bool change_midi = false;
2243         bool change_buffered_io = false;
2244
2245         uint32_t ochan = get_output_channels ();
2246         uint32_t ichan = get_input_channels ();
2247
2248         if (_have_control) {
2249
2250                 if (started_at_least_once) {
2251
2252                         /* we can control the backend */
2253
2254                         if (backend->requires_driver_selection()) {
2255                                 if (get_driver() != backend->driver_name()) {
2256                                         change_driver = true;
2257                                 }
2258                         }
2259
2260                         if (backend->use_separate_input_and_output_devices()) {
2261                                 if (get_input_device_name() != backend->input_device_name()) {
2262                                         change_device = true;
2263                                 }
2264                                 if (get_output_device_name() != backend->output_device_name()) {
2265                                         change_device = true;
2266                                 }
2267                         } else {
2268                                 if (get_device_name() != backend->device_name()) {
2269                                         change_device = true;
2270                                 }
2271                         }
2272
2273                         if (queue_device_changed) {
2274                                 change_device = true;
2275                         }
2276
2277                         if (get_rate() != backend->sample_rate()) {
2278                                 change_rate = true;
2279                         }
2280
2281                         if (get_buffer_size() != backend->buffer_size()) {
2282                                 change_bufsize = true;
2283                         }
2284
2285                         if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2286                                         && get_nperiods() != backend->period_size()) {
2287                                 change_nperiods = true;
2288                         }
2289
2290                         if (get_midi_option() != backend->midi_option()) {
2291                                 change_midi = true;
2292                         }
2293
2294                         if (backend->can_use_buffered_io()) {
2295                                 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2296                                         change_buffered_io = true;
2297                                 }
2298                         }
2299
2300                         /* zero-requested channels means "all available" */
2301
2302                         if (ichan == 0) {
2303                                 ichan = backend->input_channels();
2304                         }
2305
2306                         if (ochan == 0) {
2307                                 ochan = backend->output_channels();
2308                         }
2309
2310                         if (ichan != backend->input_channels()) {
2311                                 change_channels = true;
2312                         }
2313
2314                         if (ochan != backend->output_channels()) {
2315                                 change_channels = true;
2316                         }
2317
2318                         if (get_input_latency() != backend->systemic_input_latency() ||
2319                                         get_output_latency() != backend->systemic_output_latency()) {
2320                                 change_latency = true;
2321                         }
2322                 } else {
2323                         /* backend never started, so we have to force a group
2324                            of settings.
2325                          */
2326                         change_device = true;
2327                         if (backend->requires_driver_selection()) {
2328                                 change_driver = true;
2329                         }
2330                         change_rate = true;
2331                         change_bufsize = true;
2332                         change_channels = true;
2333                         change_latency = true;
2334                         change_midi = true;
2335                         change_buffered_io = backend->can_use_buffered_io();
2336                         change_channels = true;
2337                         change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2338                 }
2339
2340         } else {
2341
2342                 /* we have no control over the backend, meaning that we can
2343                  * only possibly change sample rate and buffer size.
2344                  */
2345
2346
2347                 if (get_rate() != backend->sample_rate()) {
2348                         change_bufsize = true;
2349                 }
2350
2351                 if (get_buffer_size() != backend->buffer_size()) {
2352                         change_bufsize = true;
2353                 }
2354         }
2355
2356         queue_device_changed = false;
2357
2358         if (!_have_control) {
2359
2360                 /* We do not have control over the backend, so the best we can
2361                  * do is try to change the sample rate and/or bufsize and get
2362                  * out of here.
2363                  */
2364
2365                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2366                         return 1;
2367                 }
2368
2369                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2370                         return 1;
2371                 }
2372
2373                 if (change_rate) {
2374                         backend->set_sample_rate (get_rate());
2375                 }
2376
2377                 if (change_bufsize) {
2378                         backend->set_buffer_size (get_buffer_size());
2379                 }
2380
2381                 if (start) {
2382                         if (ARDOUR::AudioEngine::instance()->start ()) {
2383                                 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2384                                 return -1;
2385                         }
2386                 }
2387
2388                 post_push ();
2389
2390                 return 0;
2391         }
2392
2393         /* determine if we need to stop the backend before changing parameters */
2394
2395         if (change_driver || change_device || change_channels || change_nperiods ||
2396                         (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2397                         (change_rate && !backend->can_change_sample_rate_when_running()) ||
2398                         change_midi || change_buffered_io ||
2399                         (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2400                 restart_required = true;
2401         } else {
2402                 restart_required = false;
2403         }
2404
2405
2406         if (was_running) {
2407                 if (restart_required) {
2408                         if (ARDOUR::AudioEngine::instance()->stop()) {
2409                                 return -1;
2410                         }
2411                 }
2412         }
2413
2414         if (change_driver && backend->set_driver (get_driver())) {
2415                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2416                 return -1;
2417         }
2418         if (backend->use_separate_input_and_output_devices()) {
2419                 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2420                         error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2421                         return -1;
2422                 }
2423                 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2424                         error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2425                         return -1;
2426                 }
2427         } else {
2428                 if (change_device && backend->set_device_name (get_device_name())) {
2429                         error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2430                         return -1;
2431                 }
2432         }
2433         if (change_rate && backend->set_sample_rate (get_rate())) {
2434                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2435                 return -1;
2436         }
2437         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2438                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2439                 return -1;
2440         }
2441         if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2442                 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2443                 return -1;
2444         }
2445
2446         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2447                 if (backend->set_input_channels (get_input_channels())) {
2448                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2449                         return -1;
2450                 }
2451                 if (backend->set_output_channels (get_output_channels())) {
2452                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2453                         return -1;
2454                 }
2455         }
2456         if (change_latency) {
2457                 if (backend->set_systemic_input_latency (get_input_latency())) {
2458                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2459                         return -1;
2460                 }
2461                 if (backend->set_systemic_output_latency (get_output_latency())) {
2462                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2463                         return -1;
2464                 }
2465         }
2466
2467         if (change_midi) {
2468                 backend->set_midi_option (get_midi_option());
2469         }
2470
2471         if (change_buffered_io) {
2472                 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2473         }
2474
2475         if (1 /* TODO */) {
2476                 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2477                         if (_measure_midi) {
2478                                 if (*p == _measure_midi) {
2479                                         backend->set_midi_device_enabled ((*p)->name, true);
2480                                 } else {
2481                                         backend->set_midi_device_enabled ((*p)->name, false);
2482                                 }
2483                                 if (backend->can_change_systemic_latency_when_running ()) {
2484                                         backend->set_systemic_midi_input_latency ((*p)->name, 0);
2485                                         backend->set_systemic_midi_output_latency ((*p)->name, 0);
2486                                 }
2487                                 continue;
2488                         }
2489                         backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2490                         if (backend->can_set_systemic_midi_latencies()) {
2491                                 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2492                                 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2493                         }
2494                 }
2495         }
2496
2497         if (start || (was_running && restart_required)) {
2498                 if (ARDOUR::AudioEngine::instance()->start()) {
2499                         return -1;
2500                 }
2501         }
2502
2503         post_push ();
2504
2505         return 0;
2506 }
2507
2508 void
2509 EngineControl::post_push ()
2510 {
2511         /* get a pointer to the current state object, creating one if
2512          * necessary
2513          */
2514
2515         State state = get_saved_state_for_currently_displayed_backend_and_device ();
2516
2517         if (!state) {
2518                 state = save_state ();
2519                 assert (state);
2520         } else {
2521                 store_state(state);
2522         }
2523
2524         states.sort (state_sort_cmp);
2525
2526         /* all off */
2527
2528         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2529                 (*i)->active = false;
2530         }
2531
2532         /* mark this one active (to be used next time the dialog is
2533          * shown)
2534          */
2535
2536         state->active = true;
2537
2538         if (_have_control) { // XXX
2539                 manage_control_app_sensitivity ();
2540         }
2541
2542         /* schedule a redisplay of MIDI ports */
2543         //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2544 }
2545
2546
2547 float
2548 EngineControl::get_rate () const
2549 {
2550         float r = atof (sample_rate_combo.get_active_text ());
2551         /* the string may have been translated with an abbreviation for
2552          * thousands, so use a crude heuristic to fix this.
2553          */
2554         if (r < 1000.0) {
2555                 r *= 1000.0;
2556         }
2557         return r;
2558 }
2559
2560
2561 uint32_t
2562 EngineControl::get_buffer_size () const
2563 {
2564         string txt = buffer_size_combo.get_active_text ();
2565         uint32_t samples;
2566
2567         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2568                 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2569                 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2570                 throw exception ();
2571         }
2572
2573         return samples;
2574 }
2575
2576 uint32_t
2577 EngineControl::get_nperiods () const
2578 {
2579         string txt = nperiods_combo.get_active_text ();
2580         return atoi (txt.c_str());
2581 }
2582
2583 string
2584 EngineControl::get_midi_option () const
2585 {
2586         return midi_option_combo.get_active_text();
2587 }
2588
2589 bool
2590 EngineControl::get_use_buffered_io () const
2591 {
2592         return use_buffered_io_button.get_active();
2593 }
2594
2595 uint32_t
2596 EngineControl::get_input_channels() const
2597 {
2598         if (ARDOUR::Profile->get_mixbus()) {
2599                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2600                 if (!backend) return 0;
2601                 return backend->input_channels();
2602         }
2603         return (uint32_t) input_channels_adjustment.get_value();
2604 }
2605
2606 uint32_t
2607 EngineControl::get_output_channels() const
2608 {
2609         if (ARDOUR::Profile->get_mixbus()) {
2610                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2611                 if (!backend) return 0;
2612                 return backend->input_channels();
2613         }
2614         return (uint32_t) output_channels_adjustment.get_value();
2615 }
2616
2617 uint32_t
2618 EngineControl::get_input_latency() const
2619 {
2620         return (uint32_t) input_latency_adjustment.get_value();
2621 }
2622
2623 uint32_t
2624 EngineControl::get_output_latency() const
2625 {
2626         return (uint32_t) output_latency_adjustment.get_value();
2627 }
2628
2629 string
2630 EngineControl::get_backend () const
2631 {
2632         return backend_combo.get_active_text ();
2633 }
2634
2635 string
2636 EngineControl::get_driver () const
2637 {
2638         if (driver_combo.get_parent()) {
2639                 return driver_combo.get_active_text ();
2640         } else {
2641                 return "";
2642         }
2643 }
2644
2645 string
2646 EngineControl::get_device_name () const
2647 {
2648         return device_combo.get_active_text ();
2649 }
2650
2651 string
2652 EngineControl::get_input_device_name () const
2653 {
2654         return input_device_combo.get_active_text ();
2655 }
2656
2657 string
2658 EngineControl::get_output_device_name () const
2659 {
2660         return output_device_combo.get_active_text ();
2661 }
2662
2663 void
2664 EngineControl::control_app_button_clicked ()
2665 {
2666         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2667
2668         if (!backend) {
2669                 return;
2670         }
2671
2672         backend->launch_control_app ();
2673 }
2674
2675 void
2676 EngineControl::start_stop_button_clicked ()
2677 {
2678         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2679
2680         if (!backend) {
2681                 return;
2682         }
2683
2684         if (ARDOUR::AudioEngine::instance()->running()) {
2685                 ARDOUR::AudioEngine::instance()->stop ();
2686         } else {
2687                 if (!ARDOUR_UI::instance()->the_session ()) {
2688                         pop_splash ();
2689                         hide ();
2690                         ARDOUR::GUIIdle ();
2691                 }
2692                 start_engine ();
2693                 if (!ARDOUR_UI::instance()->the_session ()) {
2694                         ArdourDialog::on_response (RESPONSE_OK);
2695                 }
2696         }
2697 }
2698
2699 void
2700 EngineControl::update_devices_button_clicked ()
2701 {
2702         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2703
2704         if (!backend) {
2705                 return;
2706         }
2707
2708         if (backend->update_devices()) {
2709                 device_list_changed ();
2710         }
2711 }
2712
2713 void
2714 EngineControl::use_buffered_io_button_clicked ()
2715 {
2716         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2717
2718         if (!backend) {
2719                 return;
2720         }
2721
2722         bool set_buffered_io = !use_buffered_io_button.get_active();
2723         use_buffered_io_button.set_active (set_buffered_io);
2724         backend->set_use_buffered_io (set_buffered_io);
2725 }
2726
2727 void
2728 EngineControl::manage_control_app_sensitivity ()
2729 {
2730         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2731
2732         if (!backend) {
2733                 return;
2734         }
2735
2736         string appname = backend->control_app_name();
2737
2738         if (appname.empty()) {
2739                 control_app_button.set_sensitive (false);
2740         } else {
2741                 control_app_button.set_sensitive (true);
2742         }
2743 }
2744
2745 void
2746 EngineControl::set_desired_sample_rate (uint32_t sr)
2747 {
2748         _desired_sample_rate = sr;
2749         if (ARDOUR::AudioEngine::instance ()->running ()
2750                         && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2751                 stop_engine ();
2752         }
2753         device_changed ();
2754 }
2755
2756 void
2757 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2758 {
2759         if (page_num == 0) {
2760                 _measure_midi.reset();
2761                 update_sensitivity ();
2762         }
2763
2764         if (page_num == midi_tab) {
2765                 /* MIDI tab */
2766                 refresh_midi_display ();
2767         }
2768
2769         if (page_num == latency_tab) {
2770                 /* latency tab */
2771
2772                 if (ARDOUR::AudioEngine::instance()->running()) {
2773                         stop_engine (true);
2774                 }
2775
2776                 {
2777                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2778
2779                         /* save any existing latency values */
2780
2781                         uint32_t il = (uint32_t) input_latency.get_value ();
2782                         uint32_t ol = (uint32_t) input_latency.get_value ();
2783
2784                         /* reset to zero so that our new test instance
2785                            will be clean of any existing latency measures.
2786
2787                            NB. this should really be done by the backend
2788                            when stated for latency measurement.
2789                         */
2790
2791                         input_latency.set_value (0);
2792                         output_latency.set_value (0);
2793
2794                         push_state_to_backend (false);
2795
2796                         /* reset control */
2797
2798                         input_latency.set_value (il);
2799                         output_latency.set_value (ol);
2800
2801                 }
2802                 // This should be done in push_state_to_backend()
2803                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2804                         disable_latency_tab ();
2805                 }
2806
2807                 enable_latency_tab ();
2808
2809         } else {
2810                 if (lm_running) {
2811                         end_latency_detection ();
2812                         ARDOUR::AudioEngine::instance()->stop_latency_detection();
2813                 }
2814         }
2815 }
2816
2817 /* latency measurement */
2818
2819 bool
2820 EngineControl::check_audio_latency_measurement ()
2821 {
2822         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2823
2824         if (mtdm->resolve () < 0) {
2825                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2826                 return true;
2827         }
2828
2829         if (mtdm->get_peak () > 0.707f) {
2830                 // get_peak() resets the peak-hold in the detector.
2831                 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2832                 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2833                 return true;
2834         }
2835
2836         if (mtdm->err () > 0.3) {
2837                 mtdm->invert ();
2838                 mtdm->resolve ();
2839         }
2840
2841         char buf[256];
2842         ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2843
2844         if (sample_rate == 0) {
2845                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2846                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2847                 return false;
2848         }
2849
2850         int samples_total = mtdm->del();
2851         int extra = samples_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2852
2853         snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2854                         _("Detected roundtrip latency: "),
2855                         samples_total, samples_total * 1000.0f/sample_rate,
2856                         _("Systemic latency: "),
2857                         extra, extra * 1000.0f/sample_rate);
2858
2859         bool solid = true;
2860
2861         if (mtdm->err () > 0.2) {
2862                 strcat (buf, " ");
2863                 strcat (buf, _("(signal detection error)"));
2864                 solid = false;
2865         }
2866
2867         if (mtdm->inv ()) {
2868                 strcat (buf, " ");
2869                 strcat (buf, _("(inverted - bad wiring)"));
2870                 solid = false;
2871         }
2872
2873         lm_results.set_markup (string_compose (results_markup, buf));
2874
2875         if (solid) {
2876                 have_lm_results = true;
2877                 end_latency_detection ();
2878                 lm_use_button.set_sensitive (true);
2879                 return false;
2880         }
2881
2882         return true;
2883 }
2884
2885 bool
2886 EngineControl::check_midi_latency_measurement ()
2887 {
2888         ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2889
2890         if (!mididm->have_signal () || mididm->latency () == 0) {
2891                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2892                 return true;
2893         }
2894
2895         char buf[256];
2896         ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2897
2898         if (sample_rate == 0) {
2899                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2900                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2901                 return false;
2902         }
2903
2904         ARDOUR::samplecnt_t samples_total = mididm->latency();
2905         ARDOUR::samplecnt_t extra = samples_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2906         snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2907                         _("Detected roundtrip latency: "),
2908                         samples_total, samples_total * 1000.0f / sample_rate, mididm->deviation (),
2909                         _("Systemic latency: "),
2910                         extra, extra * 1000.0f / sample_rate);
2911
2912         bool solid = true;
2913
2914         if (!mididm->ok ()) {
2915                 strcat (buf, " ");
2916                 strcat (buf, _("(averaging)"));
2917                 solid = false;
2918         }
2919
2920         if (mididm->deviation () > 50.0) {
2921                 strcat (buf, " ");
2922                 strcat (buf, _("(too large jitter)"));
2923                 solid = false;
2924         } else if (mididm->deviation () > 10.0) {
2925                 strcat (buf, " ");
2926                 strcat (buf, _("(large jitter)"));
2927         }
2928
2929         if (solid) {
2930                 have_lm_results = true;
2931                 end_latency_detection ();
2932                 lm_use_button.set_sensitive (true);
2933                 lm_results.set_markup (string_compose (results_markup, buf));
2934                 return false;
2935         } else if (mididm->processed () > 400) {
2936                 have_lm_results = false;
2937                 end_latency_detection ();
2938                 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2939                 return false;
2940         }
2941
2942         lm_results.set_markup (string_compose (results_markup, buf));
2943
2944         return true;
2945 }
2946
2947 void
2948 EngineControl::start_latency_detection ()
2949 {
2950         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2951         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2952
2953         if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2954                 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2955                 if (_measure_midi) {
2956                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2957                 } else {
2958                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2959                 }
2960                 lm_measure_label.set_text (_("Cancel"));
2961                 have_lm_results = false;
2962                 lm_use_button.set_sensitive (false);
2963                 lm_input_channel_combo.set_sensitive (false);
2964                 lm_output_channel_combo.set_sensitive (false);
2965                 lm_running = true;
2966         }
2967 }
2968
2969 void
2970 EngineControl::end_latency_detection ()
2971 {
2972         latency_timeout.disconnect ();
2973         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2974         lm_measure_label.set_text (_("Measure"));
2975         if (!have_lm_results) {
2976                 lm_use_button.set_sensitive (false);
2977         }
2978         lm_input_channel_combo.set_sensitive (true);
2979         lm_output_channel_combo.set_sensitive (true);
2980         lm_running = false;
2981 }
2982
2983 void
2984 EngineControl::latency_button_clicked ()
2985 {
2986         if (!lm_running) {
2987                 start_latency_detection ();
2988         } else {
2989                 end_latency_detection ();
2990         }
2991 }
2992
2993 void
2994 EngineControl::latency_back_button_clicked ()
2995 {
2996         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2997         notebook.set_current_page(0);
2998 }
2999
3000 void
3001 EngineControl::use_latency_button_clicked ()
3002 {
3003         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3004         if (_measure_midi) {
3005                 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3006                 if (!mididm) {
3007                         return;
3008                 }
3009                 ARDOUR::samplecnt_t samples_total = mididm->latency();
3010                 ARDOUR::samplecnt_t extra = samples_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3011                 uint32_t one_way = max ((ARDOUR::samplecnt_t) 0, extra / 2);
3012                 _measure_midi->input_latency = one_way;
3013                 _measure_midi->output_latency = one_way;
3014                 if (backend->can_change_systemic_latency_when_running ()) {
3015                         backend->set_systemic_midi_input_latency (_measure_midi->name, one_way);
3016                         backend->set_systemic_midi_output_latency (_measure_midi->name, one_way);
3017                 }
3018                 notebook.set_current_page (midi_tab);
3019         } else {
3020                 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3021
3022                 if (!mtdm) {
3023                         return;
3024                 }
3025
3026                 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3027                 one_way = std::max (0., one_way);
3028
3029                 input_latency_adjustment.set_value (one_way);
3030                 output_latency_adjustment.set_value (one_way);
3031                 if (backend->can_change_systemic_latency_when_running ()) {
3032                         backend->set_systemic_input_latency (one_way);
3033                         backend->set_systemic_output_latency (one_way);
3034                 }
3035
3036                 /* back to settings page */
3037                 notebook.set_current_page (0);
3038         }
3039 }
3040
3041 bool
3042 EngineControl::on_delete_event (GdkEventAny* ev)
3043 {
3044         if (notebook.get_current_page() == 2) {
3045                 /* currently on latency tab - be sure to clean up */
3046                 end_latency_detection ();
3047         }
3048         return ArdourDialog::on_delete_event (ev);
3049 }
3050
3051 void
3052 EngineControl::engine_running ()
3053 {
3054         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3055         assert (backend);
3056
3057         set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3058         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3059
3060         if (backend->can_set_period_size ()) {
3061                 set_active_text_if_present (nperiods_combo, to_string (backend->period_size()));
3062         }
3063
3064         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3065         connect_disconnect_button.show();
3066
3067         started_at_least_once = true;
3068         if (_have_control) {
3069                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3070         } else {
3071                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3072         }
3073         update_sensitivity();
3074 }
3075
3076 void
3077 EngineControl::engine_stopped ()
3078 {
3079         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3080         assert (backend);
3081
3082         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3083         connect_disconnect_button.show();
3084
3085         if (_have_control) {
3086                 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3087         } else {
3088                 engine_status.set_markup(X_(""));
3089         }
3090
3091         update_sensitivity();
3092 }
3093
3094 void
3095 EngineControl::device_list_changed ()
3096 {
3097         if (ignore_device_changes) {
3098                 return;
3099         }
3100         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3101         list_devices ();
3102         midi_option_changed();
3103 }
3104
3105 void
3106 EngineControl::connect_disconnect_click()
3107 {
3108         if (ARDOUR::AudioEngine::instance()->running()) {
3109                 stop_engine ();
3110         } else {
3111                 if (!ARDOUR_UI::instance()->the_session ()) {
3112                         pop_splash ();
3113                         hide ();
3114                         ARDOUR::GUIIdle ();
3115                 }
3116                 start_engine ();
3117                 if (!ARDOUR_UI::instance()->the_session ()) {
3118                         ArdourDialog::on_response (RESPONSE_OK);
3119                 }
3120         }
3121 }
3122
3123 void
3124 EngineControl::calibrate_audio_latency ()
3125 {
3126         _measure_midi.reset ();
3127         have_lm_results = false;
3128         lm_use_button.set_sensitive (false);
3129         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3130         notebook.set_current_page (latency_tab);
3131 }
3132
3133 void
3134 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3135 {
3136         _measure_midi = s;
3137         have_lm_results = false;
3138         lm_use_button.set_sensitive (false);
3139         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3140         notebook.set_current_page (latency_tab);
3141 }
3142
3143 void
3144 EngineControl::configure_midi_devices ()
3145 {
3146         notebook.set_current_page (midi_tab);
3147 }