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