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