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