Compare the string returned by backend->driver_name() against driver names in EngineC...
[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 <fstream>
24 #include <map>
25
26 #include <boost/scoped_ptr.hpp>
27
28 #include <gtkmm/messagedialog.h>
29
30 #include "pbd/error.h"
31 #include "pbd/xml++.h"
32 #include "pbd/unwind.h"
33 #include "pbd/failed_constructor.h"
34
35 #include <gtkmm/alignment.h>
36 #include <gtkmm/stock.h>
37 #include <gtkmm/notebook.h>
38 #include <gtkmm2ext/utils.h>
39
40 #include "ardour/audio_backend.h"
41 #include "ardour/audioengine.h"
42 #include "ardour/mtdm.h"
43 #include "ardour/mididm.h"
44 #include "ardour/rc_configuration.h"
45 #include "ardour/types.h"
46 #include "ardour/profile.h"
47
48 #include "pbd/convert.h"
49 #include "pbd/error.h"
50
51 #include "opts.h"
52 #include "debug.h"
53 #include "ardour_ui.h"
54 #include "engine_dialog.h"
55 #include "gui_thread.h"
56 #include "utils.h"
57 #include "i18n.h"
58
59 using namespace std;
60 using namespace Gtk;
61 using namespace Gtkmm2ext;
62 using namespace PBD;
63 using namespace Glib;
64 using namespace ARDOUR_UI_UTILS;
65
66 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
67
68 static const unsigned int midi_tab = 2;
69 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
70
71 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
72
73 EngineControl::EngineControl ()
74         : ArdourDialog (_("Audio/MIDI Setup"))
75         , engine_status ("")
76         , basic_packer (9, 4)
77         , input_latency_adjustment (0, 0, 99999, 1)
78         , input_latency (input_latency_adjustment)
79         , output_latency_adjustment (0, 0, 99999, 1)
80         , output_latency (output_latency_adjustment)
81         , input_channels_adjustment (0, 0, 256, 1)
82         , input_channels (input_channels_adjustment)
83         , output_channels_adjustment (0, 0, 256, 1)
84         , output_channels (output_channels_adjustment)
85         , ports_adjustment (128, 8, 1024, 1, 16)
86         , ports_spinner (ports_adjustment)
87         , control_app_button (_("Device Control Panel"))
88         , midi_devices_button (_("Midi Device Setup"))
89         , lm_measure_label (_("Measure"))
90         , lm_use_button (_("Use results"))
91         , lm_back_button (_("Back to settings ... (ignore results)"))
92         , lm_button_audio (_("Calibrate Audio"))
93         , lm_table (12, 3)
94         , have_lm_results (false)
95         , lm_running (false)
96         , midi_back_button (_("Back to settings"))
97         , ignore_changes (0)
98         , _desired_sample_rate (0)
99         , started_at_least_once (false)
100         , queue_device_changed (false)
101         , block_signals(0)
102 {
103         using namespace Notebook_Helpers;
104         vector<string> backend_names;
105         Label* label;
106         AttachOptions xopt = AttachOptions (FILL|EXPAND);
107         int row;
108
109         set_name (X_("AudioMIDISetup"));
110
111         /* the backend combo is the one thing that is ALWAYS visible */
112
113         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
114
115         if (backends.empty()) {
116                 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));
117                 msg.run ();
118                 throw failed_constructor ();
119         }
120
121         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
122                 backend_names.push_back ((*b)->name);
123         }
124
125         set_popdown_strings (backend_combo, backend_names);
126
127         /* setup basic packing characteristics for the table used on the main
128          * tab of the notebook
129          */
130
131         basic_packer.set_spacings (6);
132         basic_packer.set_border_width (12);
133         basic_packer.set_homogeneous (false);
134
135         /* pack it in */
136
137         basic_hbox.pack_start (basic_packer, false, false);
138
139         /* latency measurement tab */
140
141         lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
142
143         row = 0;
144         lm_table.set_row_spacings (12);
145         lm_table.set_col_spacings (6);
146         lm_table.set_homogeneous (false);
147
148         lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
149         row++;
150
151         lm_preamble.set_width_chars (60);
152         lm_preamble.set_line_wrap (true);
153         lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
154
155         lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
156         row++;
157
158         Gtk::Label* preamble;
159         preamble = manage (new Label);
160         preamble->set_width_chars (60);
161         preamble->set_line_wrap (true);
162         preamble->set_markup (_("Select two channels below and connect them using a cable."));
163
164         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
165         row++;
166
167         label = manage (new Label (_("Output channel")));
168         lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
169
170         Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
171         misc_align->add (lm_output_channel_combo);
172         lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
173         ++row;
174
175         label = manage (new Label (_("Input channel")));
176         lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
177
178         misc_align = manage (new Alignment (0.0, 0.5));
179         misc_align->add (lm_input_channel_combo);
180         lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
181         ++row;
182
183         lm_measure_label.set_padding (10, 10);
184         lm_measure_button.add (lm_measure_label);
185         lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
186         lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
187         lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
188
189         lm_use_button.set_sensitive (false);
190
191         /* Increase the default spacing around the labels of these three
192          * buttons
193          */
194
195         Gtk::Misc* l;
196
197         if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
198                 l->set_padding (10, 10);
199         }
200
201         if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
202                 l->set_padding (10, 10);
203         }
204
205         preamble = manage (new Label);
206         preamble->set_width_chars (60);
207         preamble->set_line_wrap (true);
208         preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
209         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
210         row++;
211
212         preamble = manage (new Label);
213         preamble->set_width_chars (60);
214         preamble->set_line_wrap (true);
215         preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
216         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
217
218         ++row; // skip a row in the table
219         ++row; // skip a row in the table
220
221         lm_table.attach (lm_results, 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_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
227         lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
228         lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
229
230         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
231
232         lm_vbox.set_border_width (12);
233         lm_vbox.pack_start (lm_table, false, false);
234
235         midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
236
237         /* pack it all up */
238
239         notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
240         notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
241         notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
242         notebook.set_border_width (12);
243
244         notebook.set_show_tabs (false);
245         notebook.show_all ();
246
247         notebook.set_name ("SettingsNotebook");
248
249         /* packup the notebook */
250
251         get_vbox()->set_border_width (12);
252         get_vbox()->pack_start (notebook);
253
254         get_action_area()->pack_start (engine_status);
255         engine_status.show();
256
257         /* need a special function to print "all available channels" when the
258          * channel counts hit zero.
259          */
260
261         input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
262         output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
263
264         midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
265         midi_devices_button.set_sensitive (false);
266         midi_devices_button.set_name ("generic button");
267         midi_devices_button.set_can_focus(true);
268
269         control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
270         manage_control_app_sensitivity ();
271
272         cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
273         apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
274         ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
275
276         /* Pick up any existing audio setup configuration, if appropriate */
277
278         XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
279
280         ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
281         ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
282         ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
283         ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
284
285         if (audio_setup) {
286                 set_state (*audio_setup);
287         }
288
289         if (backend_combo.get_active_text().empty()) {
290                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
291                 backend_combo.set_active_text (backend_names.front());
292         }
293
294         backend_changed ();
295
296         /* in case the setting the backend failed, e.g. stale config, from set_state(), try again */
297         if (0 == ARDOUR::AudioEngine::instance()->current_backend()) {
298                 backend_combo.set_active_text (backend_names.back());
299                 /* ignore: don't save state */
300                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
301                 backend_changed ();
302         }
303
304         connect_changed_signals ();
305
306         notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
307
308         connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
309         connect_disconnect_button.set_no_show_all();
310
311 }
312
313 void
314 EngineControl::connect_changed_signals ()
315 {
316         backend_combo_connection = backend_combo.signal_changed ().connect (
317             sigc::mem_fun (*this, &EngineControl::backend_changed));
318         driver_combo_connection = driver_combo.signal_changed ().connect (
319             sigc::mem_fun (*this, &EngineControl::driver_changed));
320         sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
321             sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
322         buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
323             sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
324         device_combo_connection = device_combo.signal_changed ().connect (
325             sigc::mem_fun (*this, &EngineControl::device_changed));
326         midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
327             sigc::mem_fun (*this, &EngineControl::midi_option_changed));
328
329         input_device_combo_connection = input_device_combo.signal_changed ().connect (
330             sigc::mem_fun (*this, &EngineControl::input_device_changed));
331         output_device_combo_connection = output_device_combo.signal_changed ().connect (
332             sigc::mem_fun (*this, &EngineControl::output_device_changed));
333
334         input_latency_connection = input_latency.signal_changed ().connect (
335             sigc::mem_fun (*this, &EngineControl::parameter_changed));
336         output_latency_connection = output_latency.signal_changed ().connect (
337             sigc::mem_fun (*this, &EngineControl::parameter_changed));
338         input_channels_connection = input_channels.signal_changed ().connect (
339             sigc::mem_fun (*this, &EngineControl::parameter_changed));
340         output_channels_connection = output_channels.signal_changed ().connect (
341             sigc::mem_fun (*this, &EngineControl::parameter_changed));
342 }
343
344 void
345 EngineControl::block_changed_signals ()
346 {
347         if (block_signals++ == 0) {
348                 DEBUG_ECONTROL ("Blocking changed signals");
349                 backend_combo_connection.block ();
350                 driver_combo_connection.block ();
351                 sample_rate_combo_connection.block ();
352                 buffer_size_combo_connection.block ();
353                 device_combo_connection.block ();
354                 input_device_combo_connection.block ();
355                 output_device_combo_connection.block ();
356                 midi_option_combo_connection.block ();
357                 input_latency_connection.block ();
358                 output_latency_connection.block ();
359                 input_channels_connection.block ();
360                 output_channels_connection.block ();
361         }
362 }
363
364 void
365 EngineControl::unblock_changed_signals ()
366 {
367         if (--block_signals == 0) {
368                 DEBUG_ECONTROL ("Unblocking changed signals");
369                 backend_combo_connection.unblock ();
370                 driver_combo_connection.unblock ();
371                 sample_rate_combo_connection.unblock ();
372                 buffer_size_combo_connection.unblock ();
373                 device_combo_connection.unblock ();
374                 input_device_combo_connection.unblock ();
375                 output_device_combo_connection.unblock ();
376                 midi_option_combo_connection.unblock ();
377                 input_latency_connection.unblock ();
378                 output_latency_connection.unblock ();
379                 input_channels_connection.unblock ();
380                 output_channels_connection.unblock ();
381         }
382 }
383
384 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
385                                              const std::string& reason)
386     : ec (engine_control)
387     , m_reason (reason)
388 {
389         DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
390         ec.block_changed_signals ();
391 }
392
393 EngineControl::SignalBlocker::~SignalBlocker ()
394 {
395         DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
396         ec.unblock_changed_signals ();
397 }
398
399 void
400 EngineControl::on_show ()
401 {
402         ArdourDialog::on_show ();
403         if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
404                 // re-check _have_control (jackd running) see #6041
405                 backend_changed ();
406         }
407         device_changed ();
408         ok_button->grab_focus();
409 }
410
411 void
412 EngineControl::on_response (int response_id)
413 {
414         ArdourDialog::on_response (response_id);
415
416         switch (response_id) {
417                 case RESPONSE_APPLY:
418                         push_state_to_backend (true);
419                         break;
420                 case RESPONSE_OK:
421 #ifdef PLATFORM_WINDOWS
422                         // For some reason we don't understand, 'hide()'
423                         // needs to get called first in Windows
424                         hide ();
425
426                         // But if there's no session open, this can produce
427                         // a long gap when nothing appears to be happening.
428                         // Let's show the splash image while we're waiting.
429                         if ( !ARDOUR_COMMAND_LINE::no_splash ) {
430                                 if ( ARDOUR_UI::instance() ) {
431                                         if ( !ARDOUR_UI::instance()->session_loaded ) {
432                                                 ARDOUR_UI::instance()->show_splash();
433                                         }
434                                 }
435                         }
436                         push_state_to_backend (true);
437                         break;
438 #else
439                         push_state_to_backend (true);
440                         hide ();
441                         break;
442 #endif
443                 case RESPONSE_DELETE_EVENT:
444                         {
445                                 GdkEventButton ev;
446                                 ev.type = GDK_BUTTON_PRESS;
447                                 ev.button = 1;
448                                 on_delete_event ((GdkEventAny*) &ev);
449                                 break;
450                         }
451                 default:
452                         hide ();
453         }
454 }
455
456 void
457 EngineControl::build_notebook ()
458 {
459         Label* label;
460         AttachOptions xopt = AttachOptions (FILL|EXPAND);
461
462         /* clear the table */
463
464         Gtkmm2ext::container_clear (basic_vbox);
465         Gtkmm2ext::container_clear (basic_packer);
466
467         if (control_app_button.get_parent()) {
468                 control_app_button.get_parent()->remove (control_app_button);
469         }
470
471         label = manage (left_aligned_label (_("Audio System:")));
472         basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
473         basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
474
475         lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
476         lm_button_audio.set_name ("generic button");
477         lm_button_audio.set_can_focus(true);
478
479         if (_have_control) {
480                 build_full_control_notebook ();
481         } else {
482                 build_no_control_notebook ();
483         }
484
485         basic_vbox.pack_start (basic_hbox, false, false);
486
487         {
488                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
489                 basic_vbox.show_all ();
490         }
491 }
492
493 void
494 EngineControl::build_full_control_notebook ()
495 {
496         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
497         assert (backend);
498
499         using namespace Notebook_Helpers;
500         Label* label;
501         vector<string> strings;
502         AttachOptions xopt = AttachOptions (FILL|EXPAND);
503         int row = 1; // row zero == backend combo
504
505         /* start packing it up */
506
507         if (backend->requires_driver_selection()) {
508                 label = manage (left_aligned_label (_("Driver:")));
509                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
510                 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
511                 row++;
512         }
513
514         if (backend->use_separate_input_and_output_devices()) {
515                 label = manage (left_aligned_label (_("Input Device:")));
516                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
517                 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
518                 row++;
519                 label = manage (left_aligned_label (_("Output Device:")));
520                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
521                 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
522                 row++;
523                 // reset so it isn't used in state comparisons
524                 device_combo.set_active_text ("");
525         } else {
526                 label = manage (left_aligned_label (_("Device:")));
527                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
528                 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
529                 row++;
530                 // reset these so they don't get used in state comparisons
531                 input_device_combo.set_active_text ("");
532                 output_device_combo.set_active_text ("");
533         }
534
535         label = manage (left_aligned_label (_("Sample rate:")));
536         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
537         basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
538         row++;
539
540
541         label = manage (left_aligned_label (_("Buffer size:")));
542         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
543         basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
544         buffer_size_duration_label.set_alignment (0.0); /* left-align */
545         basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
546
547         /* button spans 2 rows */
548
549         basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
550         row++;
551
552         input_channels.set_name ("InputChannels");
553         input_channels.set_flags (Gtk::CAN_FOCUS);
554         input_channels.set_digits (0);
555         input_channels.set_wrap (false);
556         output_channels.set_editable (true);
557
558         if (!ARDOUR::Profile->get_mixbus()) {
559                 label = manage (left_aligned_label (_("Input Channels:")));
560                 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
561                 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
562                 ++row;
563         }
564         
565         output_channels.set_name ("OutputChannels");
566         output_channels.set_flags (Gtk::CAN_FOCUS);
567         output_channels.set_digits (0);
568         output_channels.set_wrap (false);
569         output_channels.set_editable (true);
570
571         if (!ARDOUR::Profile->get_mixbus()) {
572                 label = manage (left_aligned_label (_("Output Channels:")));
573                 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
574                 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
575                 ++row;
576         }
577         
578         input_latency.set_name ("InputLatency");
579         input_latency.set_flags (Gtk::CAN_FOCUS);
580         input_latency.set_digits (0);
581         input_latency.set_wrap (false);
582         input_latency.set_editable (true);
583
584         label = manage (left_aligned_label (_("Hardware input latency:")));
585         basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
586         basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
587         label = manage (left_aligned_label (_("samples")));
588         basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
589         ++row;
590
591         output_latency.set_name ("OutputLatency");
592         output_latency.set_flags (Gtk::CAN_FOCUS);
593         output_latency.set_digits (0);
594         output_latency.set_wrap (false);
595         output_latency.set_editable (true);
596
597         label = manage (left_aligned_label (_("Hardware output latency:")));
598         basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
599         basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
600         label = manage (left_aligned_label (_("samples")));
601         basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
602
603         /* button spans 2 rows */
604
605         basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
606         ++row;
607
608         label = manage (left_aligned_label (_("MIDI System:")));
609         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
610         basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
611         basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
612         row++;
613 }
614
615 void
616 EngineControl::build_no_control_notebook ()
617 {
618         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
619         assert (backend);
620
621         using namespace Notebook_Helpers;
622         Label* label;
623         vector<string> strings;
624         AttachOptions xopt = AttachOptions (FILL|EXPAND);
625         int row = 1; // row zero == backend combo
626         const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
627
628         label = manage (new Label);
629         label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
630         basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
631         row++;
632
633         if (backend->can_change_sample_rate_when_running()) {
634                 label = manage (left_aligned_label (_("Sample rate:")));
635                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
636                 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
637                 row++;
638         }
639
640         if (backend->can_change_buffer_size_when_running()) {
641                 label = manage (left_aligned_label (_("Buffer size:")));
642                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
643                 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
644                 buffer_size_duration_label.set_alignment (0.0); /* left-align */
645                 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
646                 row++;
647         }
648
649         basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
650         row++;
651 }
652
653 EngineControl::~EngineControl ()
654 {
655         ignore_changes = true;
656 }
657
658 void
659 EngineControl::disable_latency_tab ()
660 {
661         vector<string> empty;
662         set_popdown_strings (lm_output_channel_combo, empty);
663         set_popdown_strings (lm_input_channel_combo, empty);
664         lm_measure_button.set_sensitive (false);
665         lm_use_button.set_sensitive (false);
666 }
667
668 void
669 EngineControl::enable_latency_tab ()
670 {
671         vector<string> outputs;
672         vector<string> inputs;
673
674         ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
675         ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
676         ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
677
678         if (!ARDOUR::AudioEngine::instance()->running()) {
679                 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
680                 notebook.set_current_page (0);
681                 msg.run ();
682                 return;
683         }
684         else if (inputs.empty() || outputs.empty()) {
685                 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
686                 notebook.set_current_page (0);
687                 msg.run ();
688                 return;
689         }
690
691         lm_back_button_signal.disconnect();
692         if (_measure_midi) {
693                 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
694                 lm_preamble.hide ();
695         } else {
696                 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
697                 lm_preamble.show ();
698         }
699
700         set_popdown_strings (lm_output_channel_combo, outputs);
701         lm_output_channel_combo.set_active_text (outputs.front());
702         lm_output_channel_combo.set_sensitive (true);
703
704         set_popdown_strings (lm_input_channel_combo, inputs);
705         lm_input_channel_combo.set_active_text (inputs.front());
706         lm_input_channel_combo.set_sensitive (true);
707
708         lm_measure_button.set_sensitive (true);
709 }
710
711 void
712 EngineControl::setup_midi_tab_for_backend ()
713 {
714         string backend = backend_combo.get_active_text ();
715
716         Gtkmm2ext::container_clear (midi_vbox);
717
718         midi_vbox.set_border_width (12);
719         midi_device_table.set_border_width (12);
720
721         if (backend == "JACK") {
722                 setup_midi_tab_for_jack ();
723         }
724
725         midi_vbox.pack_start (midi_device_table, true, true);
726         midi_vbox.pack_start (midi_back_button, false, false);
727         midi_vbox.show_all ();
728 }
729
730 void
731 EngineControl::setup_midi_tab_for_jack ()
732 {
733 }
734
735 void
736 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
737         if (for_input) {
738                 device->input_latency = a->get_value();
739         } else {
740                 device->output_latency = a->get_value();
741         }
742 }
743
744 void
745 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
746         b->set_active (!b->get_active());
747         device->enabled = b->get_active();
748         refresh_midi_display(device->name);
749 }
750
751 void
752 EngineControl::refresh_midi_display (std::string focus)
753 {
754         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
755         assert (backend);
756
757         int row  = 0;
758         AttachOptions xopt = AttachOptions (FILL|EXPAND);
759         Gtk::Label* l;
760
761         Gtkmm2ext::container_clear (midi_device_table);
762
763         midi_device_table.set_spacings (6);
764
765         l = manage (new Label);
766         l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
767         midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
768         l->set_alignment (0.5, 0.5);
769         row++;
770         l->show ();
771
772         l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
773         midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
774         l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
775         midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
776         row++;
777         l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
778         midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
779         l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
780         midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
781         row++;
782
783         for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
784                 ArdourButton *m;
785                 Gtk::Button* b;
786                 Gtk::Adjustment *a;
787                 Gtk::SpinButton *s;
788                 bool enabled = (*p)->enabled;
789
790                 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
791                 m->set_name ("midi device");
792                 m->set_can_focus (Gtk::CAN_FOCUS);
793                 m->add_events (Gdk::BUTTON_RELEASE_MASK);
794                 m->set_active (enabled);
795                 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
796                 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
797                 if ((*p)->name == focus) {
798                         m->grab_focus();
799                 }
800
801                 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
802                 s = manage (new Gtk::SpinButton (*a));
803                 a->set_value ((*p)->input_latency);
804                 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
805                 s->set_sensitive (_can_set_midi_latencies && enabled);
806                 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
807
808                 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
809                 s = manage (new Gtk::SpinButton (*a));
810                 a->set_value ((*p)->output_latency);
811                 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
812                 s->set_sensitive (_can_set_midi_latencies && enabled);
813                 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
814
815                 b = manage (new Button (_("Calibrate")));
816                 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
817                 b->set_sensitive (_can_set_midi_latencies && enabled);
818                 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
819
820                 row++;
821         }
822 }
823
824 void
825 EngineControl::backend_changed ()
826 {
827         SignalBlocker blocker (*this, "backend_changed");
828         string backend_name = backend_combo.get_active_text();
829         boost::shared_ptr<ARDOUR::AudioBackend> backend;
830
831         if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
832                 /* eh? setting the backend failed... how ? */
833                 /* A: stale config contains a backend that does not exist in current build */
834                 return;
835         }
836
837         DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
838
839         _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
840
841         build_notebook ();
842         setup_midi_tab_for_backend ();
843         _midi_devices.clear();
844
845         if (backend->requires_driver_selection()) {
846                 if (set_driver_popdown_strings ()) {
847                         driver_combo.set_sensitive (true);
848                         driver_changed ();
849                 }
850
851         } else {
852                 driver_combo.set_sensitive (false);
853                 /* this will change the device text which will cause a call to
854                  * device changed which will set up parameters
855                  */
856                 list_devices ();
857         }
858
859         update_midi_options ();
860
861         connect_disconnect_button.hide();
862
863         midi_option_changed();
864
865         started_at_least_once = false;
866
867         if (!ignore_changes) {
868                 maybe_display_saved_state ();
869         }
870 }
871
872 void
873 EngineControl::update_midi_options ()
874 {
875         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
876         vector<string> midi_options = backend->enumerate_midi_options();
877
878         if (midi_options.size() == 1) {
879                 /* only contains the "none" option */
880                 midi_option_combo.set_sensitive (false);
881         } else {
882                 if (_have_control) {
883                         set_popdown_strings (midi_option_combo, midi_options);
884                         midi_option_combo.set_active_text (midi_options.front());
885                         midi_option_combo.set_sensitive (true);
886                 } else {
887                         midi_option_combo.set_sensitive (false);
888                 }
889         }
890 }
891
892 bool
893 EngineControl::print_channel_count (Gtk::SpinButton* sb)
894 {
895         if (ARDOUR::Profile->get_mixbus()) {
896                 return true;
897         }
898         
899         uint32_t cnt = (uint32_t) sb->get_value();
900         if (cnt == 0) {
901                 sb->set_text (_("all available channels"));
902         } else {
903                 char buf[32];
904                 snprintf (buf, sizeof (buf), "%d", cnt);
905                 sb->set_text (buf);
906         }
907         return true;
908 }
909
910 // @return true if there are drivers available
911 bool
912 EngineControl::set_driver_popdown_strings ()
913 {
914         DEBUG_ECONTROL ("set_driver_popdown_strings");
915         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
916         vector<string> drivers = backend->enumerate_drivers();
917
918         if (drivers.empty ()) {
919                 // This is an error...?
920                 return false;
921         }
922
923         string current_driver = backend->driver_name ();
924
925         DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
926
927         if (std::find (drivers.begin (), drivers.end (), current_driver) ==
928             drivers.end ()) {
929
930                 current_driver = drivers.front ();
931         }
932
933         set_popdown_strings (driver_combo, drivers);
934         DEBUG_ECONTROL (
935             string_compose ("driver_combo.set_active_text: %1", current_driver));
936         driver_combo.set_active_text (current_driver);
937         return true;
938 }
939
940 // @return true if there are devices available
941 bool
942 EngineControl::set_device_popdown_strings ()
943 {
944         DEBUG_ECONTROL ("set_device_popdown_strings");
945         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
946         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
947
948         /* NOTE: Ardour currently does not display the "available" field of the
949          * returned devices.
950          *
951          * Doing so would require a different GUI widget than the combo
952          * box/popdown that we currently use, since it has no way to list
953          * items that are not selectable. Something more like a popup menu,
954          * which could have unselectable items, would be appropriate.
955          */
956
957         vector<string> available_devices;
958
959         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
960                 available_devices.push_back (i->name);
961         }
962
963
964         if (!available_devices.empty()) {
965
966                 {
967                         string current_device, found_device;
968                         current_device = device_combo.get_active_text ();
969                         if (current_device == "") {
970                                 current_device = backend->device_name ();
971                         }
972
973                         // Make sure that the active text is still relevant for this
974                         // device (it might only be relevant to the previous device!!)
975                         for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
976                                 if (*i == current_device)
977                                         found_device = current_device;
978                         }
979                         if (found_device == "")
980                                 // device has never been set (or was not relevant
981                                 // for this backend) Let's make sure it's not blank
982                                 current_device = available_devices.front ();
983
984                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
985                         set_popdown_strings (device_combo, available_devices);
986                         DEBUG_ECONTROL (string_compose ("set device_combo active text: %1", current_device));
987
988                         device_combo.set_active_text (current_device);
989                 }
990                 return true;
991         }
992         return false;
993 }
994
995 // @return true if there are input devices available
996 bool
997 EngineControl::set_input_device_popdown_strings ()
998 {
999         DEBUG_ECONTROL ("set_input_device_popdown_strings");
1000         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1001         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1002
1003         vector<string> available_devices;
1004
1005         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1006                 available_devices.push_back (i->name);
1007         }
1008
1009         if (!available_devices.empty()) {
1010
1011                 {
1012                         string current_device, found_device;
1013                         current_device = input_device_combo.get_active_text ();
1014                         if (current_device == "") {
1015                                 current_device = backend->input_device_name ();
1016                         }
1017
1018                         // Make sure that the active text is still relevant for this
1019                         // device (it might only be relevant to the previous device!!)
1020                         for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
1021                                 if (*i == current_device)
1022                                         found_device = current_device;
1023                         }
1024                         if (found_device == "")
1025                                 // device has never been set (or was not relevant
1026                                 // for this backend) Let's make sure it's not blank
1027                                 current_device = available_devices.front ();
1028
1029                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1030                         set_popdown_strings (input_device_combo, available_devices);
1031
1032                         DEBUG_ECONTROL (string_compose ("set input_device_combo active text: %1", current_device));
1033                         input_device_combo.set_active_text (current_device);
1034                 }
1035                 return true;
1036         }
1037
1038         return false;
1039 }
1040
1041 // @return true if there are output devices available
1042 bool
1043 EngineControl::set_output_device_popdown_strings ()
1044 {
1045         DEBUG_ECONTROL ("set_output_device_popdown_strings");
1046         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1047         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1048
1049         vector<string> available_devices;
1050
1051         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1052                 available_devices.push_back (i->name);
1053         }
1054
1055         if (!available_devices.empty()) {
1056
1057                 {
1058                         string current_device, found_device;
1059                         current_device = output_device_combo.get_active_text ();
1060                         if (current_device == "") {
1061                                 current_device = backend->output_device_name ();
1062                         }
1063
1064                         // Make sure that the active text is still relevant for this
1065                         // device (it might only be relevant to the previous device!!)
1066                         for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
1067                                 if (*i == current_device)
1068                                         found_device = current_device;
1069                         }
1070                         if (found_device == "")
1071                                 // device has never been set (or was not relevant
1072                                 // for this backend) Let's make sure it's not blank
1073                                 current_device = available_devices.front ();
1074
1075                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1076                         set_popdown_strings (output_device_combo, available_devices);
1077
1078                         DEBUG_ECONTROL (string_compose ("set input_device_combo active text: %1", current_device));
1079                         output_device_combo.set_active_text (current_device);
1080                 }
1081                 return true;
1082         }
1083
1084         return false;
1085 }
1086
1087 void
1088 EngineControl::list_devices ()
1089 {
1090         DEBUG_ECONTROL ("list_devices");
1091         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1092         assert (backend);
1093
1094         /* now fill out devices, mark sample rates, buffer sizes insensitive */
1095
1096         bool devices_available = false;
1097
1098         if (backend->use_separate_input_and_output_devices ()) {
1099                 bool input_devices_available = set_input_device_popdown_strings ();
1100                 bool output_devices_available = set_output_device_popdown_strings ();
1101                 devices_available = input_devices_available || output_devices_available;
1102         } else {
1103                 devices_available = set_device_popdown_strings ();
1104         }
1105
1106         if (devices_available) {
1107                 device_changed ();
1108
1109                 input_latency.set_sensitive (true);
1110                 output_latency.set_sensitive (true);
1111                 input_channels.set_sensitive (true);
1112                 output_channels.set_sensitive (true);
1113
1114                 ok_button->set_sensitive (true);
1115                 apply_button->set_sensitive (true);
1116
1117         } else {
1118                 device_combo.clear();
1119                 input_device_combo.clear();
1120                 output_device_combo.clear();
1121                 sample_rate_combo.set_sensitive (false);
1122                 buffer_size_combo.set_sensitive (false);
1123                 input_latency.set_sensitive (false);
1124                 output_latency.set_sensitive (false);
1125                 input_channels.set_sensitive (false);
1126                 output_channels.set_sensitive (false);
1127                 if (_have_control) {
1128                         ok_button->set_sensitive (false);
1129                         apply_button->set_sensitive (false);
1130                 } else {
1131                         ok_button->set_sensitive (true);
1132                         apply_button->set_sensitive (true);
1133                         if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
1134                                 sample_rate_combo.set_sensitive (true);
1135                         }
1136                         if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
1137                                 buffer_size_combo.set_sensitive (true);
1138                         }
1139
1140                 }
1141         }
1142 }
1143
1144 void
1145 EngineControl::driver_changed ()
1146 {
1147         SignalBlocker blocker (*this, "driver_changed");
1148         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1149         assert (backend);
1150
1151         backend->set_driver (driver_combo.get_active_text());
1152         list_devices ();
1153
1154         if (!ignore_changes) {
1155                 maybe_display_saved_state ();
1156         }
1157 }
1158
1159 void
1160 EngineControl::set_samplerate_popdown_strings (const std::string& device_name)
1161 {
1162         DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1163         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1164         string desired;
1165         vector<float> sr;
1166         vector<string> s;
1167
1168         if (_have_control) {
1169                 sr = backend->available_sample_rates (device_name);
1170         } else {
1171
1172                 sr.push_back (8000.0f);
1173                 sr.push_back (16000.0f);
1174                 sr.push_back (32000.0f);
1175                 sr.push_back (44100.0f);
1176                 sr.push_back (48000.0f);
1177                 sr.push_back (88200.0f);
1178                 sr.push_back (96000.0f);
1179                 sr.push_back (192000.0f);
1180                 sr.push_back (384000.0f);
1181         }
1182
1183         for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1184                 s.push_back (rate_as_string (*x));
1185                 if (*x == _desired_sample_rate) {
1186                         desired = s.back();
1187                 }
1188         }
1189
1190         if (!s.empty()) {
1191                 sample_rate_combo.set_sensitive (true);
1192                 set_popdown_strings (sample_rate_combo, s);
1193
1194                 if (desired.empty()) {
1195                         sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
1196                 } else {
1197                         sample_rate_combo.set_active_text (desired);
1198                 }
1199
1200         } else {
1201                 sample_rate_combo.set_sensitive (false);
1202         }
1203 }
1204
1205 void
1206 EngineControl::set_buffersize_popdown_strings (const std::string& device_name)
1207 {
1208         DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1209         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1210         vector<uint32_t> bs;
1211         vector<string> s;
1212
1213         if (_have_control) {
1214                 bs = backend->available_buffer_sizes (device_name);
1215         } else if (backend->can_change_buffer_size_when_running()) {
1216                 bs.push_back (8);
1217                 bs.push_back (16);
1218                 bs.push_back (32);
1219                 bs.push_back (64);
1220                 bs.push_back (128);
1221                 bs.push_back (256);
1222                 bs.push_back (512);
1223                 bs.push_back (1024);
1224                 bs.push_back (2048);
1225                 bs.push_back (4096);
1226                 bs.push_back (8192);
1227         }
1228         s.clear ();
1229         for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1230                 s.push_back (bufsize_as_string (*x));
1231         }
1232
1233         if (!s.empty()) {
1234                 buffer_size_combo.set_sensitive (true);
1235                 set_popdown_strings (buffer_size_combo, s);
1236                 buffer_size_combo.set_active_text (s.front());
1237
1238                 uint32_t period = backend->buffer_size();
1239                 if (0 == period) {
1240                         period = backend->default_buffer_size(device_name);
1241                 }
1242                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1243                 show_buffer_duration ();
1244         } else {
1245                 buffer_size_combo.set_sensitive (false);
1246         }
1247 }
1248
1249 void
1250 EngineControl::device_changed ()
1251 {
1252         SignalBlocker blocker (*this, "device_changed");
1253         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1254         assert (backend);
1255
1256         string device_name_in;
1257         string device_name_out; // only used if backend support separate I/O devices
1258
1259         if (backend->use_separate_input_and_output_devices()) {
1260                 device_name_in  = get_input_device_name ();
1261                 device_name_out = get_output_device_name ();
1262         } else {
1263                 device_name_in = get_device_name ();
1264         }
1265
1266         /* we set the backend-device to query various device related intormation.
1267          * This has the side effect that backend->device_name() will match
1268          * the device_name and  'change_device' will never be true.
1269          * so work around this by setting...
1270          */
1271         if (backend->use_separate_input_and_output_devices()) {
1272                 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1273                         queue_device_changed = true;
1274                 }
1275         } else {
1276                 if (device_name_in != backend->device_name()) {
1277                         queue_device_changed = true;
1278                 }
1279         }
1280         
1281         //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1282         if (backend->use_separate_input_and_output_devices()) {
1283                 backend->set_input_device_name (device_name_in);
1284                 backend->set_output_device_name (device_name_out);
1285         } else {
1286                 backend->set_device_name(device_name_in);
1287         }
1288
1289         {
1290                 /* don't allow programmatic change to combos to cause a
1291                    recursive call to this method.
1292                  */
1293                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1294
1295                 /* backends that support separate devices, need to ignore
1296                  * the device-name - and use the devies set above
1297                  */
1298                 set_samplerate_popdown_strings (device_name_in);
1299                 set_buffersize_popdown_strings (device_name_in);
1300                 /* XXX theoretically need to set min + max channel counts here
1301                 */
1302
1303                 manage_control_app_sensitivity ();
1304         }
1305
1306         /* pick up any saved state for this device */
1307
1308         if (!ignore_changes) {
1309                 maybe_display_saved_state ();
1310         }
1311 }
1312
1313 void
1314 EngineControl::input_device_changed ()
1315 {
1316         DEBUG_ECONTROL ("input_device_changed");
1317         device_changed ();
1318 }
1319
1320 void
1321 EngineControl::output_device_changed ()
1322 {
1323         DEBUG_ECONTROL ("output_device_changed");
1324         device_changed ();
1325 }
1326
1327 string
1328 EngineControl::bufsize_as_string (uint32_t sz)
1329 {
1330         /* Translators: "samples" is always plural here, so no
1331            need for plural+singular forms.
1332          */
1333         char buf[64];
1334         snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1335         return buf;
1336 }
1337
1338 void
1339 EngineControl::sample_rate_changed ()
1340 {
1341         DEBUG_ECONTROL ("sample_rate_changed");
1342         /* reset the strings for buffer size to show the correct msec value
1343            (reflecting the new sample rate).
1344          */
1345
1346         show_buffer_duration ();
1347
1348 }
1349
1350 void
1351 EngineControl::buffer_size_changed ()
1352 {
1353         DEBUG_ECONTROL ("buffer_size_changed");
1354         show_buffer_duration ();
1355 }
1356
1357 void
1358 EngineControl::show_buffer_duration ()
1359 {
1360         DEBUG_ECONTROL ("show_buffer_duration");
1361         /* buffer sizes  - convert from just samples to samples + msecs for
1362          * the displayed string
1363          */
1364
1365         string bs_text = buffer_size_combo.get_active_text ();
1366         uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1367         uint32_t rate = get_rate();
1368
1369         /* Developers: note the hard-coding of a double buffered model
1370            in the (2 * samples) computation of latency. we always start
1371            the audiobackend in this configuration.
1372          */
1373         /* note to jack1 developers: ardour also always starts the engine
1374          * in async mode (no jack2 --sync option) which adds an extra cycle
1375          * of latency with jack2 (and *3 would be correct)
1376          * The value can also be wrong if jackd is started externally..
1377          *
1378          * At the time of writing the ALSA backend always uses double-buffering *2,
1379          * The Dummy backend *1, and who knows what ASIO really does :)
1380          *
1381          * So just display the period size, that's also what
1382          * ARDOUR_UI::update_sample_rate() does for the status bar.
1383          * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1384          * but still, that's the buffer period, not [round-trip] latency)
1385          */
1386         char buf[32];
1387         snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1388         buffer_size_duration_label.set_text (buf);
1389 }
1390
1391 void
1392 EngineControl::midi_option_changed ()
1393 {
1394         DEBUG_ECONTROL ("midi_option_changed");
1395         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1396         assert (backend);
1397
1398         backend->set_midi_option (get_midi_option());
1399
1400         vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1401
1402         //_midi_devices.clear(); // TODO merge with state-saved settings..
1403         _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1404         std::vector<MidiDeviceSettings> new_devices;
1405
1406         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1407                 MidiDeviceSettings mds = find_midi_device (i->name);
1408                 if (i->available && !mds) {
1409                         uint32_t input_latency = 0;
1410                         uint32_t output_latency = 0;
1411                         if (_can_set_midi_latencies) {
1412                                 input_latency = backend->systemic_midi_input_latency (i->name);
1413                                 output_latency = backend->systemic_midi_output_latency (i->name);
1414                         }
1415                         bool enabled = backend->midi_device_enabled (i->name);
1416                         MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1417                         new_devices.push_back (ptr);
1418                 } else if (i->available) {
1419                         new_devices.push_back (mds);
1420                 }
1421         }
1422         _midi_devices = new_devices;
1423
1424         if (_midi_devices.empty()) {
1425                 midi_devices_button.set_sensitive (false);
1426         } else {
1427                 midi_devices_button.set_sensitive (true);
1428         }
1429 }
1430
1431 void
1432 EngineControl::parameter_changed ()
1433 {
1434 }
1435
1436 EngineControl::State
1437 EngineControl::get_matching_state (
1438                 const string& backend,
1439                 const string& driver,
1440                 const string& device)
1441 {
1442         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1443                 if ((*i)->backend == backend &&
1444                                 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1445                 {
1446                         return (*i);
1447                 }
1448         }
1449         return State();
1450 }
1451
1452 EngineControl::State
1453 EngineControl::get_matching_state (
1454                 const string& backend,
1455                 const string& driver,
1456                 const string& input_device,
1457                 const string& output_device)
1458 {
1459         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1460                 if ((*i)->backend == backend &&
1461                                 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1462                 {
1463                         return (*i);
1464                 }
1465         }
1466         return State();
1467 }
1468
1469 EngineControl::State
1470 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1471 {
1472         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1473
1474         if (backend) {
1475                 if (backend->use_separate_input_and_output_devices ()) {
1476                         return get_matching_state (backend_combo.get_active_text(),
1477                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1478                                         input_device_combo.get_active_text(),
1479                                         output_device_combo.get_active_text());
1480                 } else {
1481                         return get_matching_state (backend_combo.get_active_text(),
1482                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1483                                         device_combo.get_active_text());
1484                 }
1485         }
1486
1487         return get_matching_state (backend_combo.get_active_text(),
1488                         string(),
1489                         device_combo.get_active_text());
1490 }
1491
1492 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1493                                        const EngineControl::State& state2)
1494 {
1495         if (state1->backend == state2->backend &&
1496                         state1->driver == state2->driver &&
1497                         state1->device == state2->device &&
1498                         state1->input_device == state2->input_device &&
1499                         state1->output_device == state2->output_device) {
1500                 return true;
1501         }
1502         return false;
1503 }
1504
1505 EngineControl::State
1506 EngineControl::save_state ()
1507 {
1508         State state;
1509
1510         if (!_have_control) {
1511                 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1512                 if (state) {
1513                         return state;
1514                 }
1515                 state.reset(new StateStruct);
1516                 state->backend = get_backend ();
1517         } else {
1518                 state.reset(new StateStruct);
1519                 store_state (state);
1520         }
1521
1522         for (StateList::iterator i = states.begin(); i != states.end();) {
1523                 if (equivalent_states (*i, state)) {
1524                         i =  states.erase(i);
1525                 } else {
1526                         ++i;
1527                 }
1528         }
1529
1530         states.push_back (state);
1531
1532         return state;
1533 }
1534
1535 void
1536 EngineControl::store_state (State state)
1537 {
1538         state->backend = get_backend ();
1539         state->driver = get_driver ();
1540         state->device = get_device_name ();
1541         state->input_device = get_input_device_name ();
1542         state->output_device = get_output_device_name ();
1543         state->sample_rate = get_rate ();
1544         state->buffer_size = get_buffer_size ();
1545         state->input_latency = get_input_latency ();
1546         state->output_latency = get_output_latency ();
1547         state->input_channels = get_input_channels ();
1548         state->output_channels = get_output_channels ();
1549         state->midi_option = get_midi_option ();
1550         state->midi_devices = _midi_devices;
1551 }
1552
1553 void
1554 EngineControl::maybe_display_saved_state ()
1555 {
1556         if (!_have_control) {
1557                 return;
1558         }
1559
1560         State state = get_saved_state_for_currently_displayed_backend_and_device ();
1561
1562         if (state) {
1563                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1564
1565                 if (!_desired_sample_rate) {
1566                         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1567                 }
1568                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1569                 /* call this explicitly because we're ignoring changes to
1570                    the controls at this point.
1571                  */
1572                 show_buffer_duration ();
1573                 input_latency.set_value (state->input_latency);
1574                 output_latency.set_value (state->output_latency);
1575
1576                 if (!state->midi_option.empty()) {
1577                         midi_option_combo.set_active_text (state->midi_option);
1578                         _midi_devices = state->midi_devices;
1579                 }
1580         }
1581 }
1582
1583 XMLNode&
1584 EngineControl::get_state ()
1585 {
1586         LocaleGuard lg (X_("C"));
1587
1588         XMLNode* root = new XMLNode ("AudioMIDISetup");
1589         std::string path;
1590
1591         if (!states.empty()) {
1592                 XMLNode* state_nodes = new XMLNode ("EngineStates");
1593
1594                 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1595
1596                         XMLNode* node = new XMLNode ("State");
1597
1598                         node->add_property ("backend", (*i)->backend);
1599                         node->add_property ("driver", (*i)->driver);
1600                         node->add_property ("device", (*i)->device);
1601                         node->add_property ("input-device", (*i)->input_device);
1602                         node->add_property ("output-device", (*i)->output_device);
1603                         node->add_property ("sample-rate", (*i)->sample_rate);
1604                         node->add_property ("buffer-size", (*i)->buffer_size);
1605                         node->add_property ("input-latency", (*i)->input_latency);
1606                         node->add_property ("output-latency", (*i)->output_latency);
1607                         node->add_property ("input-channels", (*i)->input_channels);
1608                         node->add_property ("output-channels", (*i)->output_channels);
1609                         node->add_property ("active", (*i)->active ? "yes" : "no");
1610                         node->add_property ("midi-option", (*i)->midi_option);
1611
1612                         XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1613                         for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1614                                 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1615                                 midi_device_stuff->add_property (X_("name"), (*p)->name);
1616                                 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1617                                 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1618                                 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1619                                 midi_devices->add_child_nocopy (*midi_device_stuff);
1620                         }
1621                         node->add_child_nocopy (*midi_devices);
1622
1623                         state_nodes->add_child_nocopy (*node);
1624                 }
1625
1626                 root->add_child_nocopy (*state_nodes);
1627         }
1628
1629         return *root;
1630 }
1631
1632 void
1633 EngineControl::set_state (const XMLNode& root)
1634 {
1635         XMLNodeList          clist, cclist;
1636         XMLNodeConstIterator citer, cciter;
1637         XMLNode* child;
1638         XMLNode* grandchild;
1639         XMLProperty* prop = NULL;
1640
1641         fprintf (stderr, "EngineControl::set_state\n");
1642
1643         if (root.name() != "AudioMIDISetup") {
1644                 return;
1645         }
1646
1647         clist = root.children();
1648
1649         states.clear ();
1650
1651         for (citer = clist.begin(); citer != clist.end(); ++citer) {
1652
1653                 child = *citer;
1654
1655                 if (child->name() != "EngineStates") {
1656                         continue;
1657                 }
1658
1659                 cclist = child->children();
1660
1661                 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1662                         State state (new StateStruct);
1663
1664                         grandchild = *cciter;
1665
1666                         if (grandchild->name() != "State") {
1667                                 continue;
1668                         }
1669
1670                         if ((prop = grandchild->property ("backend")) == 0) {
1671                                 continue;
1672                         }
1673                         state->backend = prop->value ();
1674
1675                         if ((prop = grandchild->property ("driver")) == 0) {
1676                                 continue;
1677                         }
1678                         state->driver = prop->value ();
1679
1680                         if ((prop = grandchild->property ("device")) == 0) {
1681                                 continue;
1682                         }
1683                         state->device = prop->value ();
1684
1685                         if ((prop = grandchild->property ("input-device")) == 0) {
1686                                 continue;
1687                         }
1688                         state->input_device = prop->value ();
1689
1690                         if ((prop = grandchild->property ("output-device")) == 0) {
1691                                 continue;
1692                         }
1693                         state->output_device = prop->value ();
1694
1695                         if ((prop = grandchild->property ("sample-rate")) == 0) {
1696                                 continue;
1697                         }
1698                         state->sample_rate = atof (prop->value ());
1699
1700                         if ((prop = grandchild->property ("buffer-size")) == 0) {
1701                                 continue;
1702                         }
1703                         state->buffer_size = atoi (prop->value ());
1704
1705                         if ((prop = grandchild->property ("input-latency")) == 0) {
1706                                 continue;
1707                         }
1708                         state->input_latency = atoi (prop->value ());
1709
1710                         if ((prop = grandchild->property ("output-latency")) == 0) {
1711                                 continue;
1712                         }
1713                         state->output_latency = atoi (prop->value ());
1714
1715                         if ((prop = grandchild->property ("input-channels")) == 0) {
1716                                 continue;
1717                         }
1718                         state->input_channels = atoi (prop->value ());
1719
1720                         if ((prop = grandchild->property ("output-channels")) == 0) {
1721                                 continue;
1722                         }
1723                         state->output_channels = atoi (prop->value ());
1724
1725                         if ((prop = grandchild->property ("active")) == 0) {
1726                                 continue;
1727                         }
1728                         state->active = string_is_affirmative (prop->value ());
1729
1730                         if ((prop = grandchild->property ("midi-option")) == 0) {
1731                                 continue;
1732                         }
1733                         state->midi_option = prop->value ();
1734
1735                         state->midi_devices.clear();
1736                         XMLNode* midinode;
1737                         if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1738                                 const XMLNodeList mnc = midinode->children();
1739                                 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1740                                         if ((*n)->property (X_("name")) == 0
1741                                                         || (*n)->property (X_("enabled")) == 0
1742                                                         || (*n)->property (X_("input-latency")) == 0
1743                                                         || (*n)->property (X_("output-latency")) == 0
1744                                                  ) {
1745                                                 continue;
1746                                         }
1747
1748                                         MidiDeviceSettings ptr (new MidiDeviceSetting(
1749                                                                 (*n)->property (X_("name"))->value (),
1750                                                                 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1751                                                                 atoi ((*n)->property (X_("input-latency"))->value ()),
1752                                                                 atoi ((*n)->property (X_("output-latency"))->value ())
1753                                                                 ));
1754                                         state->midi_devices.push_back (ptr);
1755                                 }
1756                         }
1757
1758 #if 1
1759                         /* remove accumulated duplicates (due to bug in ealier version)
1760                          * this can be removed again before release
1761                          */
1762                         for (StateList::iterator i = states.begin(); i != states.end();) {
1763                                 if ((*i)->backend == state->backend &&
1764                                                 (*i)->driver == state->driver &&
1765                                                 (*i)->device == state->device) {
1766                                         i =  states.erase(i);
1767                                 } else {
1768                                         ++i;
1769                                 }
1770                         }
1771 #endif
1772
1773                         states.push_back (state);
1774                 }
1775         }
1776
1777         /* now see if there was an active state and switch the setup to it */
1778
1779         // purge states of backend that are not available in this built
1780         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1781         vector<std::string> backend_names;
1782
1783         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1784                 backend_names.push_back((*i)->name);
1785         }
1786         for (StateList::iterator i = states.begin(); i != states.end();) {
1787                 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1788                         i = states.erase(i);
1789                 } else {
1790                         ++i;
1791                 }
1792         }
1793
1794         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1795
1796                 if ((*i)->active) {
1797                         set_current_state (*i);
1798                         break;
1799                 }
1800         }
1801 }
1802
1803 void
1804 EngineControl::set_current_state (const State& state)
1805 {
1806         DEBUG_ECONTROL ("set_current_state");
1807         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1808         backend_combo.set_active_text (state->backend);
1809         driver_combo.set_active_text (state->driver);
1810         backend_changed ();
1811
1812         device_combo.set_active_text (state->device);
1813         input_device_combo.set_active_text (state->input_device);
1814         output_device_combo.set_active_text (state->output_device);
1815         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1816         set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1817         input_latency.set_value (state->input_latency);
1818         output_latency.set_value (state->output_latency);
1819         midi_option_combo.set_active_text (state->midi_option);
1820 }
1821
1822 int
1823 EngineControl::push_state_to_backend (bool start)
1824 {
1825         DEBUG_ECONTROL ("push_state_to_backend");
1826         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1827
1828         if (!backend) {
1829                 return 0;
1830         }
1831
1832         /* figure out what is going to change */
1833
1834         bool restart_required = false;
1835         bool was_running = ARDOUR::AudioEngine::instance()->running();
1836         bool change_driver = false;
1837         bool change_device = false;
1838         bool change_rate = false;
1839         bool change_bufsize = false;
1840         bool change_latency = false;
1841         bool change_channels = false;
1842         bool change_midi = false;
1843
1844         uint32_t ochan = get_output_channels ();
1845         uint32_t ichan = get_input_channels ();
1846
1847         if (_have_control) {
1848
1849                 if (started_at_least_once) {
1850
1851                         /* we can control the backend */
1852
1853                         if (backend->requires_driver_selection()) {
1854                                 if (get_driver() != backend->driver_name()) {
1855                                         change_driver = true;
1856                                 }
1857                         }
1858
1859                         if (backend->use_separate_input_and_output_devices()) {
1860                                 if (get_input_device_name() != backend->input_device_name()) {
1861                                         change_device = true;
1862                                 }
1863                                 if (get_output_device_name() != backend->output_device_name()) {
1864                                         change_device = true;
1865                                 }
1866                         } else {
1867                                 if (get_device_name() != backend->device_name()) {
1868                                         change_device = true;
1869                                 }
1870                         }
1871
1872                         if (queue_device_changed) {
1873                                 change_device = true;
1874                         }
1875
1876                         if (get_rate() != backend->sample_rate()) {
1877                                 change_rate = true;
1878                         }
1879
1880                         if (get_buffer_size() != backend->buffer_size()) {
1881                                 change_bufsize = true;
1882                         }
1883
1884                         if (get_midi_option() != backend->midi_option()) {
1885                                 change_midi = true;
1886                         }
1887
1888                         /* zero-requested channels means "all available" */
1889
1890                         if (ichan == 0) {
1891                                 ichan = backend->input_channels();
1892                         }
1893
1894                         if (ochan == 0) {
1895                                 ochan = backend->output_channels();
1896                         }
1897
1898                         if (ichan != backend->input_channels()) {
1899                                 change_channels = true;
1900                         }
1901
1902                         if (ochan != backend->output_channels()) {
1903                                 change_channels = true;
1904                         }
1905
1906                         if (get_input_latency() != backend->systemic_input_latency() ||
1907                                         get_output_latency() != backend->systemic_output_latency()) {
1908                                 change_latency = true;
1909                         }
1910                 } else {
1911                         /* backend never started, so we have to force a group
1912                            of settings.
1913                          */
1914                         change_device = true;
1915                         if (backend->requires_driver_selection()) {
1916                                 change_driver = true;
1917                         }
1918                         change_rate = true;
1919                         change_bufsize = true;
1920                         change_channels = true;
1921                         change_latency = true;
1922                         change_midi = true;
1923                 }
1924
1925         } else {
1926
1927                 /* we have no control over the backend, meaning that we can
1928                  * only possibly change sample rate and buffer size.
1929                  */
1930
1931
1932                 if (get_rate() != backend->sample_rate()) {
1933                         change_bufsize = true;
1934                 }
1935
1936                 if (get_buffer_size() != backend->buffer_size()) {
1937                         change_bufsize = true;
1938                 }
1939         }
1940
1941         queue_device_changed = false;
1942
1943         if (!_have_control) {
1944
1945                 /* We do not have control over the backend, so the best we can
1946                  * do is try to change the sample rate and/or bufsize and get
1947                  * out of here.
1948                  */
1949
1950                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1951                         return 1;
1952                 }
1953
1954                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1955                         return 1;
1956                 }
1957
1958                 if (change_rate) {
1959                         backend->set_sample_rate (get_rate());
1960                 }
1961
1962                 if (change_bufsize) {
1963                         backend->set_buffer_size (get_buffer_size());
1964                 }
1965
1966                 if (start) {
1967                         if (ARDOUR::AudioEngine::instance()->start ()) {
1968                                 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1969                                 return -1;
1970                         }
1971                 }
1972
1973                 post_push ();
1974
1975                 return 0;
1976         }
1977
1978         /* determine if we need to stop the backend before changing parameters */
1979
1980         if (change_driver || change_device || change_channels || change_latency ||
1981                         (change_rate && !backend->can_change_sample_rate_when_running()) ||
1982                         change_midi ||
1983                         (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1984                 restart_required = true;
1985         } else {
1986                 restart_required = false;
1987         }
1988
1989         if (was_running) {
1990
1991                 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1992                         /* no changes in any parameters that absolutely require a
1993                          * restart, so check those that might be changeable without a
1994                          * restart
1995                          */
1996
1997                         if (change_rate && !backend->can_change_sample_rate_when_running()) {
1998                                 /* can't do this while running ... */
1999                                 restart_required = true;
2000                         }
2001
2002                         if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2003                                 /* can't do this while running ... */
2004                                 restart_required = true;
2005                         }
2006                 }
2007         }
2008
2009         if (was_running) {
2010                 if (restart_required) {
2011                         if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2012                                 return -1;
2013                         }
2014                 }
2015         }
2016
2017
2018         if (change_driver && backend->set_driver (get_driver())) {
2019                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2020                 return -1;
2021         }
2022         if (backend->use_separate_input_and_output_devices()) {
2023                 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2024                         error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2025                         return -1;
2026                 }
2027                 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2028                         error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2029                         return -1;
2030                 }
2031         } else {
2032                 if (change_device && backend->set_device_name (get_device_name())) {
2033                         error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2034                         return -1;
2035                 }
2036         }
2037         if (change_rate && backend->set_sample_rate (get_rate())) {
2038                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2039                 return -1;
2040         }
2041         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2042                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2043                 return -1;
2044         }
2045
2046         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2047                 if (backend->set_input_channels (get_input_channels())) {
2048                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2049                         return -1;
2050                 }
2051                 if (backend->set_output_channels (get_output_channels())) {
2052                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2053                         return -1;
2054                 }
2055         }
2056         if (change_latency) {
2057                 if (backend->set_systemic_input_latency (get_input_latency())) {
2058                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2059                         return -1;
2060                 }
2061                 if (backend->set_systemic_output_latency (get_output_latency())) {
2062                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2063                         return -1;
2064                 }
2065         }
2066
2067         if (change_midi) {
2068                 backend->set_midi_option (get_midi_option());
2069         }
2070
2071         if (1 /* TODO */) {
2072                 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2073                         if (_measure_midi) {
2074                                 if (*p == _measure_midi) {
2075                                         backend->set_midi_device_enabled ((*p)->name, true);
2076                                 } else {
2077                                         backend->set_midi_device_enabled ((*p)->name, false);
2078                                 }
2079                                 continue;
2080                         }
2081                         backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2082                         if (backend->can_set_systemic_midi_latencies()) {
2083                                 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2084                                 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2085                         }
2086                 }
2087         }
2088
2089         if (start || (was_running && restart_required)) {
2090                 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2091                         return -1;
2092                 }
2093         }
2094
2095         post_push ();
2096
2097         return 0;
2098 }
2099
2100 void
2101 EngineControl::post_push ()
2102 {
2103         /* get a pointer to the current state object, creating one if
2104          * necessary
2105          */
2106
2107         State state = get_saved_state_for_currently_displayed_backend_and_device ();
2108
2109         if (!state) {
2110                 state = save_state ();
2111                 assert (state);
2112         } else {
2113                 store_state(state);
2114         }
2115
2116         /* all off */
2117
2118         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2119                 (*i)->active = false;
2120         }
2121
2122         /* mark this one active (to be used next time the dialog is
2123          * shown)
2124          */
2125
2126         state->active = true;
2127
2128         if (_have_control) { // XXX
2129                 manage_control_app_sensitivity ();
2130         }
2131
2132         /* schedule a redisplay of MIDI ports */
2133         //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2134 }
2135
2136
2137 float
2138 EngineControl::get_rate () const
2139 {
2140         float r = atof (sample_rate_combo.get_active_text ());
2141         /* the string may have been translated with an abbreviation for
2142          * thousands, so use a crude heuristic to fix this.
2143          */
2144         if (r < 1000.0) {
2145                 r *= 1000.0;
2146         }
2147         return r;
2148 }
2149
2150
2151 uint32_t
2152 EngineControl::get_buffer_size () const
2153 {
2154         string txt = buffer_size_combo.get_active_text ();
2155         uint32_t samples;
2156
2157         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2158                 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2159                 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2160                 throw exception ();
2161         }
2162
2163         return samples;
2164 }
2165
2166 string
2167 EngineControl::get_midi_option () const
2168 {
2169         return midi_option_combo.get_active_text();
2170 }
2171
2172 uint32_t
2173 EngineControl::get_input_channels() const
2174 {
2175         if (ARDOUR::Profile->get_mixbus()) {
2176                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2177                 if (!backend) return 0;
2178                 return backend->input_channels();
2179         }
2180         return (uint32_t) input_channels_adjustment.get_value();
2181 }
2182
2183 uint32_t
2184 EngineControl::get_output_channels() const
2185 {
2186         if (ARDOUR::Profile->get_mixbus()) {
2187                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2188                 if (!backend) return 0;
2189                 return backend->input_channels();
2190         }
2191         return (uint32_t) output_channels_adjustment.get_value();
2192 }
2193
2194 uint32_t
2195 EngineControl::get_input_latency() const
2196 {
2197         return (uint32_t) input_latency_adjustment.get_value();
2198 }
2199
2200 uint32_t
2201 EngineControl::get_output_latency() const
2202 {
2203         return (uint32_t) output_latency_adjustment.get_value();
2204 }
2205
2206 string
2207 EngineControl::get_backend () const
2208 {
2209         return backend_combo.get_active_text ();
2210 }
2211
2212 string
2213 EngineControl::get_driver () const
2214 {
2215         if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2216                 return driver_combo.get_active_text ();
2217         } else {
2218                 return "";
2219         }
2220 }
2221
2222 string
2223 EngineControl::get_device_name () const
2224 {
2225         return device_combo.get_active_text ();
2226 }
2227
2228 string
2229 EngineControl::get_input_device_name () const
2230 {
2231         return input_device_combo.get_active_text ();
2232 }
2233
2234 string
2235 EngineControl::get_output_device_name () const
2236 {
2237         return output_device_combo.get_active_text ();
2238 }
2239
2240 void
2241 EngineControl::control_app_button_clicked ()
2242 {
2243         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2244
2245         if (!backend) {
2246                 return;
2247         }
2248
2249         backend->launch_control_app ();
2250 }
2251
2252 void
2253 EngineControl::manage_control_app_sensitivity ()
2254 {
2255         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2256
2257         if (!backend) {
2258                 return;
2259         }
2260
2261         string appname = backend->control_app_name();
2262
2263         if (appname.empty()) {
2264                 control_app_button.set_sensitive (false);
2265         } else {
2266                 control_app_button.set_sensitive (true);
2267         }
2268 }
2269
2270 void
2271 EngineControl::set_desired_sample_rate (uint32_t sr)
2272 {
2273         _desired_sample_rate = sr;
2274         device_changed ();
2275 }
2276
2277 void
2278 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2279 {
2280         if (page_num == 0) {
2281                 cancel_button->set_sensitive (true);
2282                 ok_button->set_sensitive (true);
2283                 apply_button->set_sensitive (true);
2284                 _measure_midi.reset();
2285         } else {
2286                 cancel_button->set_sensitive (false);
2287                 ok_button->set_sensitive (false);
2288                 apply_button->set_sensitive (false);
2289         }
2290
2291         if (page_num == midi_tab) {
2292                 /* MIDI tab */
2293                 refresh_midi_display ();
2294         }
2295
2296         if (page_num == latency_tab) {
2297                 /* latency tab */
2298
2299                 if (ARDOUR::AudioEngine::instance()->running()) {
2300                         // TODO - mark as 'stopped for latency
2301                         ARDOUR_UI::instance()->disconnect_from_engine ();
2302                 }
2303
2304                 {
2305                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2306
2307                         /* save any existing latency values */
2308
2309                         uint32_t il = (uint32_t) input_latency.get_value ();
2310                         uint32_t ol = (uint32_t) input_latency.get_value ();
2311
2312                         /* reset to zero so that our new test instance
2313                            will be clean of any existing latency measures.
2314
2315                            NB. this should really be done by the backend
2316                            when stated for latency measurement.
2317                         */
2318
2319                         input_latency.set_value (0);
2320                         output_latency.set_value (0);
2321
2322                         push_state_to_backend (false);
2323
2324                         /* reset control */
2325
2326                         input_latency.set_value (il);
2327                         output_latency.set_value (ol);
2328
2329                 }
2330                 // This should be done in push_state_to_backend()
2331                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2332                         disable_latency_tab ();
2333                 }
2334
2335                 enable_latency_tab ();
2336
2337         } else {
2338                 if (lm_running) {
2339                         end_latency_detection ();
2340                         ARDOUR::AudioEngine::instance()->stop_latency_detection();
2341                 }
2342         }
2343 }
2344
2345 /* latency measurement */
2346
2347 bool
2348 EngineControl::check_audio_latency_measurement ()
2349 {
2350         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2351
2352         if (mtdm->resolve () < 0) {
2353                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2354                 return true;
2355         }
2356
2357         if (mtdm->err () > 0.3) {
2358                 mtdm->invert ();
2359                 mtdm->resolve ();
2360         }
2361
2362         char buf[256];
2363         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2364
2365         if (sample_rate == 0) {
2366                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2367                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2368                 return false;
2369         }
2370
2371         int frames_total = mtdm->del();
2372         int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2373
2374         snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2375                         _("Detected roundtrip latency: "),
2376                         frames_total, frames_total * 1000.0f/sample_rate,
2377                         _("Systemic latency: "),
2378                         extra, extra * 1000.0f/sample_rate);
2379
2380         bool solid = true;
2381
2382         if (mtdm->err () > 0.2) {
2383                 strcat (buf, " ");
2384                 strcat (buf, _("(signal detection error)"));
2385                 solid = false;
2386         }
2387
2388         if (mtdm->inv ()) {
2389                 strcat (buf, " ");
2390                 strcat (buf, _("(inverted - bad wiring)"));
2391                 solid = false;
2392         }
2393
2394         lm_results.set_markup (string_compose (results_markup, buf));
2395
2396         if (solid) {
2397                 have_lm_results = true;
2398                 end_latency_detection ();
2399                 lm_use_button.set_sensitive (true);
2400                 return false;
2401         }
2402
2403         return true;
2404 }
2405
2406 bool
2407 EngineControl::check_midi_latency_measurement ()
2408 {
2409         ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2410
2411         if (!mididm->have_signal () || mididm->latency () == 0) {
2412                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2413                 return true;
2414         }
2415
2416         char buf[256];
2417         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2418
2419         if (sample_rate == 0) {
2420                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2421                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2422                 return false;
2423         }
2424
2425         ARDOUR::framecnt_t frames_total = mididm->latency();
2426         ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2427         snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2428                         _("Detected roundtrip latency: "),
2429                         frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2430                         _("Systemic latency: "),
2431                         extra, extra * 1000.0f / sample_rate);
2432
2433         bool solid = true;
2434
2435         if (!mididm->ok ()) {
2436                 strcat (buf, " ");
2437                 strcat (buf, _("(averaging)"));
2438                 solid = false;
2439         }
2440
2441         if (mididm->deviation () > 50.0) {
2442                 strcat (buf, " ");
2443                 strcat (buf, _("(too large jitter)"));
2444                 solid = false;
2445         } else if (mididm->deviation () > 10.0) {
2446                 strcat (buf, " ");
2447                 strcat (buf, _("(large jitter)"));
2448         }
2449
2450         if (solid) {
2451                 have_lm_results = true;
2452                 end_latency_detection ();
2453                 lm_use_button.set_sensitive (true);
2454                 lm_results.set_markup (string_compose (results_markup, buf));
2455                 return false;
2456         } else if (mididm->processed () > 400) {
2457                 have_lm_results = false;
2458                 end_latency_detection ();
2459                 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2460                 return false;
2461         }
2462
2463         lm_results.set_markup (string_compose (results_markup, buf));
2464
2465         return true;
2466 }
2467
2468 void
2469 EngineControl::start_latency_detection ()
2470 {
2471         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2472         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2473
2474         if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2475                 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2476                 if (_measure_midi) {
2477                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2478                 } else {
2479                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2480                 }
2481                 lm_measure_label.set_text (_("Cancel"));
2482                 have_lm_results = false;
2483                 lm_use_button.set_sensitive (false);
2484                 lm_input_channel_combo.set_sensitive (false);
2485                 lm_output_channel_combo.set_sensitive (false);
2486                 lm_running = true;
2487         }
2488 }
2489
2490 void
2491 EngineControl::end_latency_detection ()
2492 {
2493         latency_timeout.disconnect ();
2494         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2495         lm_measure_label.set_text (_("Measure"));
2496         if (!have_lm_results) {
2497                 lm_use_button.set_sensitive (false);
2498         }
2499         lm_input_channel_combo.set_sensitive (true);
2500         lm_output_channel_combo.set_sensitive (true);
2501         lm_running = false;
2502 }
2503
2504 void
2505 EngineControl::latency_button_clicked ()
2506 {
2507         if (!lm_running) {
2508                 start_latency_detection ();
2509         } else {
2510                 end_latency_detection ();
2511         }
2512 }
2513
2514 void
2515 EngineControl::use_latency_button_clicked ()
2516 {
2517         if (_measure_midi) {
2518                 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2519                 if (!mididm) {
2520                         return;
2521                 }
2522                 ARDOUR::framecnt_t frames_total = mididm->latency();
2523                 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2524                 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2525                 _measure_midi->input_latency = one_way;
2526                 _measure_midi->output_latency = one_way;
2527                 notebook.set_current_page (midi_tab);
2528         } else {
2529                 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2530
2531                 if (!mtdm) {
2532                         return;
2533                 }
2534
2535                 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2536                 one_way = std::max (0., one_way);
2537
2538                 input_latency_adjustment.set_value (one_way);
2539                 output_latency_adjustment.set_value (one_way);
2540
2541                 /* back to settings page */
2542                 notebook.set_current_page (0);
2543 }
2544         }
2545
2546
2547 bool
2548 EngineControl::on_delete_event (GdkEventAny* ev)
2549 {
2550         if (notebook.get_current_page() == 2) {
2551                 /* currently on latency tab - be sure to clean up */
2552                 end_latency_detection ();
2553         }
2554         return ArdourDialog::on_delete_event (ev);
2555 }
2556
2557 void
2558 EngineControl::engine_running ()
2559 {
2560         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2561         assert (backend);
2562
2563         set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2564         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2565
2566         buffer_size_combo.set_sensitive (true);
2567         sample_rate_combo.set_sensitive (true);
2568
2569         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2570         connect_disconnect_button.show();
2571
2572         started_at_least_once = true;
2573         engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2574 }
2575
2576 void
2577 EngineControl::engine_stopped ()
2578 {
2579         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2580         assert (backend);
2581
2582         buffer_size_combo.set_sensitive (false);
2583         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2584         connect_disconnect_button.show();
2585
2586         sample_rate_combo.set_sensitive (true);
2587         buffer_size_combo.set_sensitive (true);
2588         engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2589 }
2590
2591 void
2592 EngineControl::device_list_changed ()
2593 {
2594         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2595         list_devices ();
2596         midi_option_changed();
2597 }
2598
2599 void
2600 EngineControl::connect_disconnect_click()
2601 {
2602         if (ARDOUR::AudioEngine::instance()->running()) {
2603                 ARDOUR_UI::instance()->disconnect_from_engine ();
2604         } else {
2605                 ARDOUR_UI::instance()->reconnect_to_engine ();
2606         }
2607 }
2608
2609 void
2610 EngineControl::calibrate_audio_latency ()
2611 {
2612         _measure_midi.reset ();
2613         have_lm_results = false;
2614         lm_use_button.set_sensitive (false);
2615         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2616         notebook.set_current_page (latency_tab);
2617 }
2618
2619 void
2620 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2621 {
2622         _measure_midi = s;
2623         have_lm_results = false;
2624         lm_use_button.set_sensitive (false);
2625         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2626         notebook.set_current_page (latency_tab);
2627 }
2628
2629 void
2630 EngineControl::configure_midi_devices ()
2631 {
2632         notebook.set_current_page (midi_tab);
2633 }