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