Reimplement method using code extracted from EngineDialog::backend_changed
[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;
924         current_driver = backend->driver_name ();
925
926         DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
927
928         // driver might not have been set yet
929         if (current_driver == "") {
930                 current_driver = driver_combo.get_active_text ();
931                 if (current_driver == "")
932                         // driver has never been set, make sure it's not blank
933                         current_driver = drivers.front ();
934         }
935
936         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
937         set_popdown_strings (driver_combo, drivers);
938         DEBUG_ECONTROL (
939                         string_compose ("driver_combo.set_active_text: %1", current_driver));
940         driver_combo.set_active_text (current_driver);
941         return true;
942 }
943
944 // @return true if there are devices available
945 bool
946 EngineControl::set_device_popdown_strings ()
947 {
948         DEBUG_ECONTROL ("set_device_popdown_strings");
949         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
950         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
951
952         /* NOTE: Ardour currently does not display the "available" field of the
953          * returned devices.
954          *
955          * Doing so would require a different GUI widget than the combo
956          * box/popdown that we currently use, since it has no way to list
957          * items that are not selectable. Something more like a popup menu,
958          * which could have unselectable items, would be appropriate.
959          */
960
961         vector<string> available_devices;
962
963         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
964                 available_devices.push_back (i->name);
965         }
966
967
968         if (!available_devices.empty()) {
969
970                 {
971                         string current_device, found_device;
972                         current_device = device_combo.get_active_text ();
973                         if (current_device == "") {
974                                 current_device = backend->device_name ();
975                         }
976
977                         // Make sure that the active text is still relevant for this
978                         // device (it might only be relevant to the previous device!!)
979                         for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
980                                 if (*i == current_device)
981                                         found_device = current_device;
982                         }
983                         if (found_device == "")
984                                 // device has never been set (or was not relevant
985                                 // for this backend) Let's make sure it's not blank
986                                 current_device = available_devices.front ();
987
988                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
989                         set_popdown_strings (device_combo, available_devices);
990                         DEBUG_ECONTROL (string_compose ("set device_combo active text: %1", current_device));
991
992                         device_combo.set_active_text (current_device);
993                 }
994                 return true;
995         }
996         return false;
997 }
998
999 // @return true if there are input devices available
1000 bool
1001 EngineControl::set_input_device_popdown_strings ()
1002 {
1003         DEBUG_ECONTROL ("set_input_device_popdown_strings");
1004         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1005         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1006
1007         vector<string> available_devices;
1008
1009         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1010                 available_devices.push_back (i->name);
1011         }
1012
1013         if (!available_devices.empty()) {
1014
1015                 {
1016                         string current_device, found_device;
1017                         current_device = input_device_combo.get_active_text ();
1018                         if (current_device == "") {
1019                                 current_device = backend->input_device_name ();
1020                         }
1021
1022                         // Make sure that the active text is still relevant for this
1023                         // device (it might only be relevant to the previous device!!)
1024                         for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
1025                                 if (*i == current_device)
1026                                         found_device = current_device;
1027                         }
1028                         if (found_device == "")
1029                                 // device has never been set (or was not relevant
1030                                 // for this backend) Let's make sure it's not blank
1031                                 current_device = available_devices.front ();
1032
1033                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1034                         set_popdown_strings (input_device_combo, available_devices);
1035
1036                         DEBUG_ECONTROL (string_compose ("set input_device_combo active text: %1", current_device));
1037                         input_device_combo.set_active_text (current_device);
1038                 }
1039                 return true;
1040         }
1041
1042         return false;
1043 }
1044
1045 // @return true if there are output devices available
1046 bool
1047 EngineControl::set_output_device_popdown_strings ()
1048 {
1049         DEBUG_ECONTROL ("set_output_device_popdown_strings");
1050         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1051         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1052
1053         vector<string> available_devices;
1054
1055         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1056                 available_devices.push_back (i->name);
1057         }
1058
1059         if (!available_devices.empty()) {
1060
1061                 {
1062                         string current_device, found_device;
1063                         current_device = output_device_combo.get_active_text ();
1064                         if (current_device == "") {
1065                                 current_device = backend->output_device_name ();
1066                         }
1067
1068                         // Make sure that the active text is still relevant for this
1069                         // device (it might only be relevant to the previous device!!)
1070                         for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
1071                                 if (*i == current_device)
1072                                         found_device = current_device;
1073                         }
1074                         if (found_device == "")
1075                                 // device has never been set (or was not relevant
1076                                 // for this backend) Let's make sure it's not blank
1077                                 current_device = available_devices.front ();
1078
1079                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1080                         set_popdown_strings (output_device_combo, available_devices);
1081
1082                         DEBUG_ECONTROL (string_compose ("set input_device_combo active text: %1", current_device));
1083                         output_device_combo.set_active_text (current_device);
1084                 }
1085                 return true;
1086         }
1087
1088         return false;
1089 }
1090
1091 void
1092 EngineControl::list_devices ()
1093 {
1094         DEBUG_ECONTROL ("list_devices");
1095         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1096         assert (backend);
1097
1098         /* now fill out devices, mark sample rates, buffer sizes insensitive */
1099
1100         bool devices_available = false;
1101
1102         if (backend->use_separate_input_and_output_devices ()) {
1103                 bool input_devices_available = set_input_device_popdown_strings ();
1104                 bool output_devices_available = set_output_device_popdown_strings ();
1105                 devices_available = input_devices_available || output_devices_available;
1106         } else {
1107                 devices_available = set_device_popdown_strings ();
1108         }
1109
1110         if (devices_available) {
1111                 device_changed ();
1112
1113                 input_latency.set_sensitive (true);
1114                 output_latency.set_sensitive (true);
1115                 input_channels.set_sensitive (true);
1116                 output_channels.set_sensitive (true);
1117
1118                 ok_button->set_sensitive (true);
1119                 apply_button->set_sensitive (true);
1120
1121         } else {
1122                 device_combo.clear();
1123                 input_device_combo.clear();
1124                 output_device_combo.clear();
1125                 sample_rate_combo.set_sensitive (false);
1126                 buffer_size_combo.set_sensitive (false);
1127                 input_latency.set_sensitive (false);
1128                 output_latency.set_sensitive (false);
1129                 input_channels.set_sensitive (false);
1130                 output_channels.set_sensitive (false);
1131                 if (_have_control) {
1132                         ok_button->set_sensitive (false);
1133                         apply_button->set_sensitive (false);
1134                 } else {
1135                         ok_button->set_sensitive (true);
1136                         apply_button->set_sensitive (true);
1137                         if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
1138                                 sample_rate_combo.set_sensitive (true);
1139                         }
1140                         if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
1141                                 buffer_size_combo.set_sensitive (true);
1142                         }
1143
1144                 }
1145         }
1146 }
1147
1148 void
1149 EngineControl::driver_changed ()
1150 {
1151         SignalBlocker blocker (*this, "driver_changed");
1152         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1153         assert (backend);
1154
1155         backend->set_driver (driver_combo.get_active_text());
1156         list_devices ();
1157
1158         if (!ignore_changes) {
1159                 maybe_display_saved_state ();
1160         }
1161 }
1162
1163 void
1164 EngineControl::set_samplerate_popdown_strings (const std::string& device_name)
1165 {
1166         DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1167         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1168         string desired;
1169         vector<float> sr;
1170         vector<string> s;
1171
1172         if (_have_control) {
1173                 sr = backend->available_sample_rates (device_name);
1174         } else {
1175
1176                 sr.push_back (8000.0f);
1177                 sr.push_back (16000.0f);
1178                 sr.push_back (32000.0f);
1179                 sr.push_back (44100.0f);
1180                 sr.push_back (48000.0f);
1181                 sr.push_back (88200.0f);
1182                 sr.push_back (96000.0f);
1183                 sr.push_back (192000.0f);
1184                 sr.push_back (384000.0f);
1185         }
1186
1187         for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1188                 s.push_back (rate_as_string (*x));
1189                 if (*x == _desired_sample_rate) {
1190                         desired = s.back();
1191                 }
1192         }
1193
1194         if (!s.empty()) {
1195                 sample_rate_combo.set_sensitive (true);
1196                 set_popdown_strings (sample_rate_combo, s);
1197
1198                 if (desired.empty()) {
1199                         sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
1200                 } else {
1201                         sample_rate_combo.set_active_text (desired);
1202                 }
1203
1204         } else {
1205                 sample_rate_combo.set_sensitive (false);
1206         }
1207 }
1208
1209 void
1210 EngineControl::set_buffersize_popdown_strings (const std::string& device_name)
1211 {
1212         DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1213         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1214         vector<uint32_t> bs;
1215         vector<string> s;
1216
1217         if (_have_control) {
1218                 bs = backend->available_buffer_sizes (device_name);
1219         } else if (backend->can_change_buffer_size_when_running()) {
1220                 bs.push_back (8);
1221                 bs.push_back (16);
1222                 bs.push_back (32);
1223                 bs.push_back (64);
1224                 bs.push_back (128);
1225                 bs.push_back (256);
1226                 bs.push_back (512);
1227                 bs.push_back (1024);
1228                 bs.push_back (2048);
1229                 bs.push_back (4096);
1230                 bs.push_back (8192);
1231         }
1232         s.clear ();
1233         for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1234                 s.push_back (bufsize_as_string (*x));
1235         }
1236
1237         if (!s.empty()) {
1238                 buffer_size_combo.set_sensitive (true);
1239                 set_popdown_strings (buffer_size_combo, s);
1240                 buffer_size_combo.set_active_text (s.front());
1241
1242                 uint32_t period = backend->buffer_size();
1243                 if (0 == period) {
1244                         period = backend->default_buffer_size(device_name);
1245                 }
1246                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1247                 show_buffer_duration ();
1248         } else {
1249                 buffer_size_combo.set_sensitive (false);
1250         }
1251 }
1252
1253 void
1254 EngineControl::device_changed ()
1255 {
1256         SignalBlocker blocker (*this, "device_changed");
1257         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1258         assert (backend);
1259
1260         string device_name_in;
1261         string device_name_out; // only used if backend support separate I/O devices
1262
1263         if (backend->use_separate_input_and_output_devices()) {
1264                 device_name_in  = get_input_device_name ();
1265                 device_name_out = get_output_device_name ();
1266         } else {
1267                 device_name_in = get_device_name ();
1268         }
1269
1270         /* we set the backend-device to query various device related intormation.
1271          * This has the side effect that backend->device_name() will match
1272          * the device_name and  'change_device' will never be true.
1273          * so work around this by setting...
1274          */
1275         if (backend->use_separate_input_and_output_devices()) {
1276                 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1277                         queue_device_changed = true;
1278                 }
1279         } else {
1280                 if (device_name_in != backend->device_name()) {
1281                         queue_device_changed = true;
1282                 }
1283         }
1284         
1285         //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1286         if (backend->use_separate_input_and_output_devices()) {
1287                 backend->set_input_device_name (device_name_in);
1288                 backend->set_output_device_name (device_name_out);
1289         } else {
1290                 backend->set_device_name(device_name_in);
1291         }
1292
1293         {
1294                 /* don't allow programmatic change to combos to cause a
1295                    recursive call to this method.
1296                  */
1297                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1298
1299                 /* backends that support separate devices, need to ignore
1300                  * the device-name - and use the devies set above
1301                  */
1302                 set_samplerate_popdown_strings (device_name_in);
1303                 set_buffersize_popdown_strings (device_name_in);
1304                 /* XXX theoretically need to set min + max channel counts here
1305                 */
1306
1307                 manage_control_app_sensitivity ();
1308         }
1309
1310         /* pick up any saved state for this device */
1311
1312         if (!ignore_changes) {
1313                 maybe_display_saved_state ();
1314         }
1315 }
1316
1317 void
1318 EngineControl::input_device_changed ()
1319 {
1320         DEBUG_ECONTROL ("input_device_changed");
1321         device_changed ();
1322 }
1323
1324 void
1325 EngineControl::output_device_changed ()
1326 {
1327         DEBUG_ECONTROL ("output_device_changed");
1328         device_changed ();
1329 }
1330
1331 string
1332 EngineControl::bufsize_as_string (uint32_t sz)
1333 {
1334         /* Translators: "samples" is always plural here, so no
1335            need for plural+singular forms.
1336          */
1337         char buf[64];
1338         snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1339         return buf;
1340 }
1341
1342 void
1343 EngineControl::sample_rate_changed ()
1344 {
1345         DEBUG_ECONTROL ("sample_rate_changed");
1346         /* reset the strings for buffer size to show the correct msec value
1347            (reflecting the new sample rate).
1348          */
1349
1350         show_buffer_duration ();
1351
1352 }
1353
1354 void
1355 EngineControl::buffer_size_changed ()
1356 {
1357         DEBUG_ECONTROL ("buffer_size_changed");
1358         show_buffer_duration ();
1359 }
1360
1361 void
1362 EngineControl::show_buffer_duration ()
1363 {
1364         DEBUG_ECONTROL ("show_buffer_duration");
1365         /* buffer sizes  - convert from just samples to samples + msecs for
1366          * the displayed string
1367          */
1368
1369         string bs_text = buffer_size_combo.get_active_text ();
1370         uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1371         uint32_t rate = get_rate();
1372
1373         /* Developers: note the hard-coding of a double buffered model
1374            in the (2 * samples) computation of latency. we always start
1375            the audiobackend in this configuration.
1376          */
1377         /* note to jack1 developers: ardour also always starts the engine
1378          * in async mode (no jack2 --sync option) which adds an extra cycle
1379          * of latency with jack2 (and *3 would be correct)
1380          * The value can also be wrong if jackd is started externally..
1381          *
1382          * At the time of writing the ALSA backend always uses double-buffering *2,
1383          * The Dummy backend *1, and who knows what ASIO really does :)
1384          *
1385          * So just display the period size, that's also what
1386          * ARDOUR_UI::update_sample_rate() does for the status bar.
1387          * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1388          * but still, that's the buffer period, not [round-trip] latency)
1389          */
1390         char buf[32];
1391         snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1392         buffer_size_duration_label.set_text (buf);
1393 }
1394
1395 void
1396 EngineControl::midi_option_changed ()
1397 {
1398         DEBUG_ECONTROL ("midi_option_changed");
1399         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1400         assert (backend);
1401
1402         backend->set_midi_option (get_midi_option());
1403
1404         vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1405
1406         //_midi_devices.clear(); // TODO merge with state-saved settings..
1407         _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1408         std::vector<MidiDeviceSettings> new_devices;
1409
1410         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1411                 MidiDeviceSettings mds = find_midi_device (i->name);
1412                 if (i->available && !mds) {
1413                         uint32_t input_latency = 0;
1414                         uint32_t output_latency = 0;
1415                         if (_can_set_midi_latencies) {
1416                                 input_latency = backend->systemic_midi_input_latency (i->name);
1417                                 output_latency = backend->systemic_midi_output_latency (i->name);
1418                         }
1419                         bool enabled = backend->midi_device_enabled (i->name);
1420                         MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1421                         new_devices.push_back (ptr);
1422                 } else if (i->available) {
1423                         new_devices.push_back (mds);
1424                 }
1425         }
1426         _midi_devices = new_devices;
1427
1428         if (_midi_devices.empty()) {
1429                 midi_devices_button.set_sensitive (false);
1430         } else {
1431                 midi_devices_button.set_sensitive (true);
1432         }
1433 }
1434
1435 void
1436 EngineControl::parameter_changed ()
1437 {
1438 }
1439
1440 EngineControl::State
1441 EngineControl::get_matching_state (
1442                 const string& backend,
1443                 const string& driver,
1444                 const string& device)
1445 {
1446         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1447                 if ((*i)->backend == backend &&
1448                                 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1449                 {
1450                         return (*i);
1451                 }
1452         }
1453         return State();
1454 }
1455
1456 EngineControl::State
1457 EngineControl::get_matching_state (
1458                 const string& backend,
1459                 const string& driver,
1460                 const string& input_device,
1461                 const string& output_device)
1462 {
1463         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1464                 if ((*i)->backend == backend &&
1465                                 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1466                 {
1467                         return (*i);
1468                 }
1469         }
1470         return State();
1471 }
1472
1473 EngineControl::State
1474 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1475 {
1476         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1477
1478         if (backend) {
1479                 if (backend->use_separate_input_and_output_devices ()) {
1480                         return get_matching_state (backend_combo.get_active_text(),
1481                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1482                                         input_device_combo.get_active_text(),
1483                                         output_device_combo.get_active_text());
1484                 } else {
1485                         return get_matching_state (backend_combo.get_active_text(),
1486                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1487                                         device_combo.get_active_text());
1488                 }
1489         }
1490
1491         return get_matching_state (backend_combo.get_active_text(),
1492                         string(),
1493                         device_combo.get_active_text());
1494 }
1495
1496 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1497                                        const EngineControl::State& state2)
1498 {
1499         if (state1->backend == state2->backend &&
1500                         state1->driver == state2->driver &&
1501                         state1->device == state2->device &&
1502                         state1->input_device == state2->input_device &&
1503                         state1->output_device == state2->output_device) {
1504                 return true;
1505         }
1506         return false;
1507 }
1508
1509 EngineControl::State
1510 EngineControl::save_state ()
1511 {
1512         State state;
1513
1514         if (!_have_control) {
1515                 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1516                 if (state) {
1517                         return state;
1518                 }
1519                 state.reset(new StateStruct);
1520                 state->backend = get_backend ();
1521         } else {
1522                 state.reset(new StateStruct);
1523                 store_state (state);
1524         }
1525
1526         for (StateList::iterator i = states.begin(); i != states.end();) {
1527                 if (equivalent_states (*i, state)) {
1528                         i =  states.erase(i);
1529                 } else {
1530                         ++i;
1531                 }
1532         }
1533
1534         states.push_back (state);
1535
1536         return state;
1537 }
1538
1539 void
1540 EngineControl::store_state (State state)
1541 {
1542         state->backend = get_backend ();
1543         state->driver = get_driver ();
1544         state->device = get_device_name ();
1545         state->input_device = get_input_device_name ();
1546         state->output_device = get_output_device_name ();
1547         state->sample_rate = get_rate ();
1548         state->buffer_size = get_buffer_size ();
1549         state->input_latency = get_input_latency ();
1550         state->output_latency = get_output_latency ();
1551         state->input_channels = get_input_channels ();
1552         state->output_channels = get_output_channels ();
1553         state->midi_option = get_midi_option ();
1554         state->midi_devices = _midi_devices;
1555 }
1556
1557 void
1558 EngineControl::maybe_display_saved_state ()
1559 {
1560         if (!_have_control) {
1561                 return;
1562         }
1563
1564         State state = get_saved_state_for_currently_displayed_backend_and_device ();
1565
1566         if (state) {
1567                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1568
1569                 if (!_desired_sample_rate) {
1570                         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1571                 }
1572                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1573                 /* call this explicitly because we're ignoring changes to
1574                    the controls at this point.
1575                  */
1576                 show_buffer_duration ();
1577                 input_latency.set_value (state->input_latency);
1578                 output_latency.set_value (state->output_latency);
1579
1580                 if (!state->midi_option.empty()) {
1581                         midi_option_combo.set_active_text (state->midi_option);
1582                         _midi_devices = state->midi_devices;
1583                 }
1584         }
1585 }
1586
1587 XMLNode&
1588 EngineControl::get_state ()
1589 {
1590         LocaleGuard lg (X_("C"));
1591
1592         XMLNode* root = new XMLNode ("AudioMIDISetup");
1593         std::string path;
1594
1595         if (!states.empty()) {
1596                 XMLNode* state_nodes = new XMLNode ("EngineStates");
1597
1598                 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1599
1600                         XMLNode* node = new XMLNode ("State");
1601
1602                         node->add_property ("backend", (*i)->backend);
1603                         node->add_property ("driver", (*i)->driver);
1604                         node->add_property ("device", (*i)->device);
1605                         node->add_property ("input-device", (*i)->input_device);
1606                         node->add_property ("output-device", (*i)->output_device);
1607                         node->add_property ("sample-rate", (*i)->sample_rate);
1608                         node->add_property ("buffer-size", (*i)->buffer_size);
1609                         node->add_property ("input-latency", (*i)->input_latency);
1610                         node->add_property ("output-latency", (*i)->output_latency);
1611                         node->add_property ("input-channels", (*i)->input_channels);
1612                         node->add_property ("output-channels", (*i)->output_channels);
1613                         node->add_property ("active", (*i)->active ? "yes" : "no");
1614                         node->add_property ("midi-option", (*i)->midi_option);
1615
1616                         XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1617                         for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1618                                 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1619                                 midi_device_stuff->add_property (X_("name"), (*p)->name);
1620                                 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1621                                 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1622                                 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1623                                 midi_devices->add_child_nocopy (*midi_device_stuff);
1624                         }
1625                         node->add_child_nocopy (*midi_devices);
1626
1627                         state_nodes->add_child_nocopy (*node);
1628                 }
1629
1630                 root->add_child_nocopy (*state_nodes);
1631         }
1632
1633         return *root;
1634 }
1635
1636 void
1637 EngineControl::set_state (const XMLNode& root)
1638 {
1639         XMLNodeList          clist, cclist;
1640         XMLNodeConstIterator citer, cciter;
1641         XMLNode* child;
1642         XMLNode* grandchild;
1643         XMLProperty* prop = NULL;
1644
1645         fprintf (stderr, "EngineControl::set_state\n");
1646
1647         if (root.name() != "AudioMIDISetup") {
1648                 return;
1649         }
1650
1651         clist = root.children();
1652
1653         states.clear ();
1654
1655         for (citer = clist.begin(); citer != clist.end(); ++citer) {
1656
1657                 child = *citer;
1658
1659                 if (child->name() != "EngineStates") {
1660                         continue;
1661                 }
1662
1663                 cclist = child->children();
1664
1665                 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1666                         State state (new StateStruct);
1667
1668                         grandchild = *cciter;
1669
1670                         if (grandchild->name() != "State") {
1671                                 continue;
1672                         }
1673
1674                         if ((prop = grandchild->property ("backend")) == 0) {
1675                                 continue;
1676                         }
1677                         state->backend = prop->value ();
1678
1679                         if ((prop = grandchild->property ("driver")) == 0) {
1680                                 continue;
1681                         }
1682                         state->driver = prop->value ();
1683
1684                         if ((prop = grandchild->property ("device")) == 0) {
1685                                 continue;
1686                         }
1687                         state->device = prop->value ();
1688
1689                         if ((prop = grandchild->property ("input-device")) == 0) {
1690                                 continue;
1691                         }
1692                         state->input_device = prop->value ();
1693
1694                         if ((prop = grandchild->property ("output-device")) == 0) {
1695                                 continue;
1696                         }
1697                         state->output_device = prop->value ();
1698
1699                         if ((prop = grandchild->property ("sample-rate")) == 0) {
1700                                 continue;
1701                         }
1702                         state->sample_rate = atof (prop->value ());
1703
1704                         if ((prop = grandchild->property ("buffer-size")) == 0) {
1705                                 continue;
1706                         }
1707                         state->buffer_size = atoi (prop->value ());
1708
1709                         if ((prop = grandchild->property ("input-latency")) == 0) {
1710                                 continue;
1711                         }
1712                         state->input_latency = atoi (prop->value ());
1713
1714                         if ((prop = grandchild->property ("output-latency")) == 0) {
1715                                 continue;
1716                         }
1717                         state->output_latency = atoi (prop->value ());
1718
1719                         if ((prop = grandchild->property ("input-channels")) == 0) {
1720                                 continue;
1721                         }
1722                         state->input_channels = atoi (prop->value ());
1723
1724                         if ((prop = grandchild->property ("output-channels")) == 0) {
1725                                 continue;
1726                         }
1727                         state->output_channels = atoi (prop->value ());
1728
1729                         if ((prop = grandchild->property ("active")) == 0) {
1730                                 continue;
1731                         }
1732                         state->active = string_is_affirmative (prop->value ());
1733
1734                         if ((prop = grandchild->property ("midi-option")) == 0) {
1735                                 continue;
1736                         }
1737                         state->midi_option = prop->value ();
1738
1739                         state->midi_devices.clear();
1740                         XMLNode* midinode;
1741                         if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1742                                 const XMLNodeList mnc = midinode->children();
1743                                 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1744                                         if ((*n)->property (X_("name")) == 0
1745                                                         || (*n)->property (X_("enabled")) == 0
1746                                                         || (*n)->property (X_("input-latency")) == 0
1747                                                         || (*n)->property (X_("output-latency")) == 0
1748                                                  ) {
1749                                                 continue;
1750                                         }
1751
1752                                         MidiDeviceSettings ptr (new MidiDeviceSetting(
1753                                                                 (*n)->property (X_("name"))->value (),
1754                                                                 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1755                                                                 atoi ((*n)->property (X_("input-latency"))->value ()),
1756                                                                 atoi ((*n)->property (X_("output-latency"))->value ())
1757                                                                 ));
1758                                         state->midi_devices.push_back (ptr);
1759                                 }
1760                         }
1761
1762 #if 1
1763                         /* remove accumulated duplicates (due to bug in ealier version)
1764                          * this can be removed again before release
1765                          */
1766                         for (StateList::iterator i = states.begin(); i != states.end();) {
1767                                 if ((*i)->backend == state->backend &&
1768                                                 (*i)->driver == state->driver &&
1769                                                 (*i)->device == state->device) {
1770                                         i =  states.erase(i);
1771                                 } else {
1772                                         ++i;
1773                                 }
1774                         }
1775 #endif
1776
1777                         states.push_back (state);
1778                 }
1779         }
1780
1781         /* now see if there was an active state and switch the setup to it */
1782
1783         // purge states of backend that are not available in this built
1784         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1785         vector<std::string> backend_names;
1786
1787         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1788                 backend_names.push_back((*i)->name);
1789         }
1790         for (StateList::iterator i = states.begin(); i != states.end();) {
1791                 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1792                         i = states.erase(i);
1793                 } else {
1794                         ++i;
1795                 }
1796         }
1797
1798         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1799
1800                 if ((*i)->active) {
1801                         set_current_state (*i);
1802                         break;
1803                 }
1804         }
1805 }
1806
1807 void
1808 EngineControl::set_current_state (const State& state)
1809 {
1810         DEBUG_ECONTROL ("set_current_state");
1811         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1812         backend_combo.set_active_text (state->backend);
1813         driver_combo.set_active_text (state->driver);
1814         backend_changed ();
1815
1816         device_combo.set_active_text (state->device);
1817         input_device_combo.set_active_text (state->input_device);
1818         output_device_combo.set_active_text (state->output_device);
1819         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1820         set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1821         input_latency.set_value (state->input_latency);
1822         output_latency.set_value (state->output_latency);
1823         midi_option_combo.set_active_text (state->midi_option);
1824 }
1825
1826 int
1827 EngineControl::push_state_to_backend (bool start)
1828 {
1829         DEBUG_ECONTROL ("push_state_to_backend");
1830         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1831
1832         if (!backend) {
1833                 return 0;
1834         }
1835
1836         /* figure out what is going to change */
1837
1838         bool restart_required = false;
1839         bool was_running = ARDOUR::AudioEngine::instance()->running();
1840         bool change_driver = false;
1841         bool change_device = false;
1842         bool change_rate = false;
1843         bool change_bufsize = false;
1844         bool change_latency = false;
1845         bool change_channels = false;
1846         bool change_midi = false;
1847
1848         uint32_t ochan = get_output_channels ();
1849         uint32_t ichan = get_input_channels ();
1850
1851         if (_have_control) {
1852
1853                 if (started_at_least_once) {
1854
1855                         /* we can control the backend */
1856
1857                         if (backend->requires_driver_selection()) {
1858                                 if (get_driver() != backend->driver_name()) {
1859                                         change_driver = true;
1860                                 }
1861                         }
1862
1863                         if (backend->use_separate_input_and_output_devices()) {
1864                                 if (get_input_device_name() != backend->input_device_name()) {
1865                                         change_device = true;
1866                                 }
1867                                 if (get_output_device_name() != backend->output_device_name()) {
1868                                         change_device = true;
1869                                 }
1870                         } else {
1871                                 if (get_device_name() != backend->device_name()) {
1872                                         change_device = true;
1873                                 }
1874                         }
1875
1876                         if (queue_device_changed) {
1877                                 change_device = true;
1878                         }
1879
1880                         if (get_rate() != backend->sample_rate()) {
1881                                 change_rate = true;
1882                         }
1883
1884                         if (get_buffer_size() != backend->buffer_size()) {
1885                                 change_bufsize = true;
1886                         }
1887
1888                         if (get_midi_option() != backend->midi_option()) {
1889                                 change_midi = true;
1890                         }
1891
1892                         /* zero-requested channels means "all available" */
1893
1894                         if (ichan == 0) {
1895                                 ichan = backend->input_channels();
1896                         }
1897
1898                         if (ochan == 0) {
1899                                 ochan = backend->output_channels();
1900                         }
1901
1902                         if (ichan != backend->input_channels()) {
1903                                 change_channels = true;
1904                         }
1905
1906                         if (ochan != backend->output_channels()) {
1907                                 change_channels = true;
1908                         }
1909
1910                         if (get_input_latency() != backend->systemic_input_latency() ||
1911                                         get_output_latency() != backend->systemic_output_latency()) {
1912                                 change_latency = true;
1913                         }
1914                 } else {
1915                         /* backend never started, so we have to force a group
1916                            of settings.
1917                          */
1918                         change_device = true;
1919                         if (backend->requires_driver_selection()) {
1920                                 change_driver = true;
1921                         }
1922                         change_rate = true;
1923                         change_bufsize = true;
1924                         change_channels = true;
1925                         change_latency = true;
1926                         change_midi = true;
1927                 }
1928
1929         } else {
1930
1931                 /* we have no control over the backend, meaning that we can
1932                  * only possibly change sample rate and buffer size.
1933                  */
1934
1935
1936                 if (get_rate() != backend->sample_rate()) {
1937                         change_bufsize = true;
1938                 }
1939
1940                 if (get_buffer_size() != backend->buffer_size()) {
1941                         change_bufsize = true;
1942                 }
1943         }
1944
1945         queue_device_changed = false;
1946
1947         if (!_have_control) {
1948
1949                 /* We do not have control over the backend, so the best we can
1950                  * do is try to change the sample rate and/or bufsize and get
1951                  * out of here.
1952                  */
1953
1954                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1955                         return 1;
1956                 }
1957
1958                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1959                         return 1;
1960                 }
1961
1962                 if (change_rate) {
1963                         backend->set_sample_rate (get_rate());
1964                 }
1965
1966                 if (change_bufsize) {
1967                         backend->set_buffer_size (get_buffer_size());
1968                 }
1969
1970                 if (start) {
1971                         if (ARDOUR::AudioEngine::instance()->start ()) {
1972                                 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1973                                 return -1;
1974                         }
1975                 }
1976
1977                 post_push ();
1978
1979                 return 0;
1980         }
1981
1982         /* determine if we need to stop the backend before changing parameters */
1983
1984         if (change_driver || change_device || change_channels || change_latency ||
1985                         (change_rate && !backend->can_change_sample_rate_when_running()) ||
1986                         change_midi ||
1987                         (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1988                 restart_required = true;
1989         } else {
1990                 restart_required = false;
1991         }
1992
1993         if (was_running) {
1994
1995                 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1996                         /* no changes in any parameters that absolutely require a
1997                          * restart, so check those that might be changeable without a
1998                          * restart
1999                          */
2000
2001                         if (change_rate && !backend->can_change_sample_rate_when_running()) {
2002                                 /* can't do this while running ... */
2003                                 restart_required = true;
2004                         }
2005
2006                         if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2007                                 /* can't do this while running ... */
2008                                 restart_required = true;
2009                         }
2010                 }
2011         }
2012
2013         if (was_running) {
2014                 if (restart_required) {
2015                         if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2016                                 return -1;
2017                         }
2018                 }
2019         }
2020
2021
2022         if (change_driver && backend->set_driver (get_driver())) {
2023                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2024                 return -1;
2025         }
2026         if (backend->use_separate_input_and_output_devices()) {
2027                 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2028                         error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2029                         return -1;
2030                 }
2031                 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2032                         error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2033                         return -1;
2034                 }
2035         } else {
2036                 if (change_device && backend->set_device_name (get_device_name())) {
2037                         error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2038                         return -1;
2039                 }
2040         }
2041         if (change_rate && backend->set_sample_rate (get_rate())) {
2042                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2043                 return -1;
2044         }
2045         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2046                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2047                 return -1;
2048         }
2049
2050         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2051                 if (backend->set_input_channels (get_input_channels())) {
2052                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2053                         return -1;
2054                 }
2055                 if (backend->set_output_channels (get_output_channels())) {
2056                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2057                         return -1;
2058                 }
2059         }
2060         if (change_latency) {
2061                 if (backend->set_systemic_input_latency (get_input_latency())) {
2062                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2063                         return -1;
2064                 }
2065                 if (backend->set_systemic_output_latency (get_output_latency())) {
2066                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2067                         return -1;
2068                 }
2069         }
2070
2071         if (change_midi) {
2072                 backend->set_midi_option (get_midi_option());
2073         }
2074
2075         if (1 /* TODO */) {
2076                 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2077                         if (_measure_midi) {
2078                                 if (*p == _measure_midi) {
2079                                         backend->set_midi_device_enabled ((*p)->name, true);
2080                                 } else {
2081                                         backend->set_midi_device_enabled ((*p)->name, false);
2082                                 }
2083                                 continue;
2084                         }
2085                         backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2086                         if (backend->can_set_systemic_midi_latencies()) {
2087                                 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2088                                 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2089                         }
2090                 }
2091         }
2092
2093         if (start || (was_running && restart_required)) {
2094                 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2095                         return -1;
2096                 }
2097         }
2098
2099         post_push ();
2100
2101         return 0;
2102 }
2103
2104 void
2105 EngineControl::post_push ()
2106 {
2107         /* get a pointer to the current state object, creating one if
2108          * necessary
2109          */
2110
2111         State state = get_saved_state_for_currently_displayed_backend_and_device ();
2112
2113         if (!state) {
2114                 state = save_state ();
2115                 assert (state);
2116         } else {
2117                 store_state(state);
2118         }
2119
2120         /* all off */
2121
2122         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2123                 (*i)->active = false;
2124         }
2125
2126         /* mark this one active (to be used next time the dialog is
2127          * shown)
2128          */
2129
2130         state->active = true;
2131
2132         if (_have_control) { // XXX
2133                 manage_control_app_sensitivity ();
2134         }
2135
2136         /* schedule a redisplay of MIDI ports */
2137         //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2138 }
2139
2140
2141 float
2142 EngineControl::get_rate () const
2143 {
2144         float r = atof (sample_rate_combo.get_active_text ());
2145         /* the string may have been translated with an abbreviation for
2146          * thousands, so use a crude heuristic to fix this.
2147          */
2148         if (r < 1000.0) {
2149                 r *= 1000.0;
2150         }
2151         return r;
2152 }
2153
2154
2155 uint32_t
2156 EngineControl::get_buffer_size () const
2157 {
2158         string txt = buffer_size_combo.get_active_text ();
2159         uint32_t samples;
2160
2161         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2162                 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2163                 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2164                 throw exception ();
2165         }
2166
2167         return samples;
2168 }
2169
2170 string
2171 EngineControl::get_midi_option () const
2172 {
2173         return midi_option_combo.get_active_text();
2174 }
2175
2176 uint32_t
2177 EngineControl::get_input_channels() const
2178 {
2179         if (ARDOUR::Profile->get_mixbus()) {
2180                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2181                 if (!backend) return 0;
2182                 return backend->input_channels();
2183         }
2184         return (uint32_t) input_channels_adjustment.get_value();
2185 }
2186
2187 uint32_t
2188 EngineControl::get_output_channels() const
2189 {
2190         if (ARDOUR::Profile->get_mixbus()) {
2191                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2192                 if (!backend) return 0;
2193                 return backend->input_channels();
2194         }
2195         return (uint32_t) output_channels_adjustment.get_value();
2196 }
2197
2198 uint32_t
2199 EngineControl::get_input_latency() const
2200 {
2201         return (uint32_t) input_latency_adjustment.get_value();
2202 }
2203
2204 uint32_t
2205 EngineControl::get_output_latency() const
2206 {
2207         return (uint32_t) output_latency_adjustment.get_value();
2208 }
2209
2210 string
2211 EngineControl::get_backend () const
2212 {
2213         return backend_combo.get_active_text ();
2214 }
2215
2216 string
2217 EngineControl::get_driver () const
2218 {
2219         if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2220                 return driver_combo.get_active_text ();
2221         } else {
2222                 return "";
2223         }
2224 }
2225
2226 string
2227 EngineControl::get_device_name () const
2228 {
2229         return device_combo.get_active_text ();
2230 }
2231
2232 string
2233 EngineControl::get_input_device_name () const
2234 {
2235         return input_device_combo.get_active_text ();
2236 }
2237
2238 string
2239 EngineControl::get_output_device_name () const
2240 {
2241         return output_device_combo.get_active_text ();
2242 }
2243
2244 void
2245 EngineControl::control_app_button_clicked ()
2246 {
2247         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2248
2249         if (!backend) {
2250                 return;
2251         }
2252
2253         backend->launch_control_app ();
2254 }
2255
2256 void
2257 EngineControl::manage_control_app_sensitivity ()
2258 {
2259         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2260
2261         if (!backend) {
2262                 return;
2263         }
2264
2265         string appname = backend->control_app_name();
2266
2267         if (appname.empty()) {
2268                 control_app_button.set_sensitive (false);
2269         } else {
2270                 control_app_button.set_sensitive (true);
2271         }
2272 }
2273
2274 void
2275 EngineControl::set_desired_sample_rate (uint32_t sr)
2276 {
2277         _desired_sample_rate = sr;
2278         device_changed ();
2279 }
2280
2281 void
2282 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2283 {
2284         if (page_num == 0) {
2285                 cancel_button->set_sensitive (true);
2286                 ok_button->set_sensitive (true);
2287                 apply_button->set_sensitive (true);
2288                 _measure_midi.reset();
2289         } else {
2290                 cancel_button->set_sensitive (false);
2291                 ok_button->set_sensitive (false);
2292                 apply_button->set_sensitive (false);
2293         }
2294
2295         if (page_num == midi_tab) {
2296                 /* MIDI tab */
2297                 refresh_midi_display ();
2298         }
2299
2300         if (page_num == latency_tab) {
2301                 /* latency tab */
2302
2303                 if (ARDOUR::AudioEngine::instance()->running()) {
2304                         // TODO - mark as 'stopped for latency
2305                         ARDOUR_UI::instance()->disconnect_from_engine ();
2306                 }
2307
2308                 {
2309                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2310
2311                         /* save any existing latency values */
2312
2313                         uint32_t il = (uint32_t) input_latency.get_value ();
2314                         uint32_t ol = (uint32_t) input_latency.get_value ();
2315
2316                         /* reset to zero so that our new test instance
2317                            will be clean of any existing latency measures.
2318
2319                            NB. this should really be done by the backend
2320                            when stated for latency measurement.
2321                         */
2322
2323                         input_latency.set_value (0);
2324                         output_latency.set_value (0);
2325
2326                         push_state_to_backend (false);
2327
2328                         /* reset control */
2329
2330                         input_latency.set_value (il);
2331                         output_latency.set_value (ol);
2332
2333                 }
2334                 // This should be done in push_state_to_backend()
2335                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2336                         disable_latency_tab ();
2337                 }
2338
2339                 enable_latency_tab ();
2340
2341         } else {
2342                 if (lm_running) {
2343                         end_latency_detection ();
2344                         ARDOUR::AudioEngine::instance()->stop_latency_detection();
2345                 }
2346         }
2347 }
2348
2349 /* latency measurement */
2350
2351 bool
2352 EngineControl::check_audio_latency_measurement ()
2353 {
2354         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2355
2356         if (mtdm->resolve () < 0) {
2357                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2358                 return true;
2359         }
2360
2361         if (mtdm->err () > 0.3) {
2362                 mtdm->invert ();
2363                 mtdm->resolve ();
2364         }
2365
2366         char buf[256];
2367         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2368
2369         if (sample_rate == 0) {
2370                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2371                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2372                 return false;
2373         }
2374
2375         int frames_total = mtdm->del();
2376         int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2377
2378         snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2379                         _("Detected roundtrip latency: "),
2380                         frames_total, frames_total * 1000.0f/sample_rate,
2381                         _("Systemic latency: "),
2382                         extra, extra * 1000.0f/sample_rate);
2383
2384         bool solid = true;
2385
2386         if (mtdm->err () > 0.2) {
2387                 strcat (buf, " ");
2388                 strcat (buf, _("(signal detection error)"));
2389                 solid = false;
2390         }
2391
2392         if (mtdm->inv ()) {
2393                 strcat (buf, " ");
2394                 strcat (buf, _("(inverted - bad wiring)"));
2395                 solid = false;
2396         }
2397
2398         lm_results.set_markup (string_compose (results_markup, buf));
2399
2400         if (solid) {
2401                 have_lm_results = true;
2402                 end_latency_detection ();
2403                 lm_use_button.set_sensitive (true);
2404                 return false;
2405         }
2406
2407         return true;
2408 }
2409
2410 bool
2411 EngineControl::check_midi_latency_measurement ()
2412 {
2413         ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2414
2415         if (!mididm->have_signal () || mididm->latency () == 0) {
2416                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2417                 return true;
2418         }
2419
2420         char buf[256];
2421         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2422
2423         if (sample_rate == 0) {
2424                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2425                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2426                 return false;
2427         }
2428
2429         ARDOUR::framecnt_t frames_total = mididm->latency();
2430         ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2431         snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2432                         _("Detected roundtrip latency: "),
2433                         frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2434                         _("Systemic latency: "),
2435                         extra, extra * 1000.0f / sample_rate);
2436
2437         bool solid = true;
2438
2439         if (!mididm->ok ()) {
2440                 strcat (buf, " ");
2441                 strcat (buf, _("(averaging)"));
2442                 solid = false;
2443         }
2444
2445         if (mididm->deviation () > 50.0) {
2446                 strcat (buf, " ");
2447                 strcat (buf, _("(too large jitter)"));
2448                 solid = false;
2449         } else if (mididm->deviation () > 10.0) {
2450                 strcat (buf, " ");
2451                 strcat (buf, _("(large jitter)"));
2452         }
2453
2454         if (solid) {
2455                 have_lm_results = true;
2456                 end_latency_detection ();
2457                 lm_use_button.set_sensitive (true);
2458                 lm_results.set_markup (string_compose (results_markup, buf));
2459                 return false;
2460         } else if (mididm->processed () > 400) {
2461                 have_lm_results = false;
2462                 end_latency_detection ();
2463                 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2464                 return false;
2465         }
2466
2467         lm_results.set_markup (string_compose (results_markup, buf));
2468
2469         return true;
2470 }
2471
2472 void
2473 EngineControl::start_latency_detection ()
2474 {
2475         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2476         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2477
2478         if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2479                 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2480                 if (_measure_midi) {
2481                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2482                 } else {
2483                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2484                 }
2485                 lm_measure_label.set_text (_("Cancel"));
2486                 have_lm_results = false;
2487                 lm_use_button.set_sensitive (false);
2488                 lm_input_channel_combo.set_sensitive (false);
2489                 lm_output_channel_combo.set_sensitive (false);
2490                 lm_running = true;
2491         }
2492 }
2493
2494 void
2495 EngineControl::end_latency_detection ()
2496 {
2497         latency_timeout.disconnect ();
2498         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2499         lm_measure_label.set_text (_("Measure"));
2500         if (!have_lm_results) {
2501                 lm_use_button.set_sensitive (false);
2502         }
2503         lm_input_channel_combo.set_sensitive (true);
2504         lm_output_channel_combo.set_sensitive (true);
2505         lm_running = false;
2506 }
2507
2508 void
2509 EngineControl::latency_button_clicked ()
2510 {
2511         if (!lm_running) {
2512                 start_latency_detection ();
2513         } else {
2514                 end_latency_detection ();
2515         }
2516 }
2517
2518 void
2519 EngineControl::use_latency_button_clicked ()
2520 {
2521         if (_measure_midi) {
2522                 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2523                 if (!mididm) {
2524                         return;
2525                 }
2526                 ARDOUR::framecnt_t frames_total = mididm->latency();
2527                 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2528                 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2529                 _measure_midi->input_latency = one_way;
2530                 _measure_midi->output_latency = one_way;
2531                 notebook.set_current_page (midi_tab);
2532         } else {
2533                 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2534
2535                 if (!mtdm) {
2536                         return;
2537                 }
2538
2539                 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2540                 one_way = std::max (0., one_way);
2541
2542                 input_latency_adjustment.set_value (one_way);
2543                 output_latency_adjustment.set_value (one_way);
2544
2545                 /* back to settings page */
2546                 notebook.set_current_page (0);
2547 }
2548         }
2549
2550
2551 bool
2552 EngineControl::on_delete_event (GdkEventAny* ev)
2553 {
2554         if (notebook.get_current_page() == 2) {
2555                 /* currently on latency tab - be sure to clean up */
2556                 end_latency_detection ();
2557         }
2558         return ArdourDialog::on_delete_event (ev);
2559 }
2560
2561 void
2562 EngineControl::engine_running ()
2563 {
2564         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2565         assert (backend);
2566
2567         set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2568         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2569
2570         buffer_size_combo.set_sensitive (true);
2571         sample_rate_combo.set_sensitive (true);
2572
2573         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2574         connect_disconnect_button.show();
2575
2576         started_at_least_once = true;
2577         engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2578 }
2579
2580 void
2581 EngineControl::engine_stopped ()
2582 {
2583         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2584         assert (backend);
2585
2586         buffer_size_combo.set_sensitive (false);
2587         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2588         connect_disconnect_button.show();
2589
2590         sample_rate_combo.set_sensitive (true);
2591         buffer_size_combo.set_sensitive (true);
2592         engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2593 }
2594
2595 void
2596 EngineControl::device_list_changed ()
2597 {
2598         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2599         list_devices ();
2600         midi_option_changed();
2601 }
2602
2603 void
2604 EngineControl::connect_disconnect_click()
2605 {
2606         if (ARDOUR::AudioEngine::instance()->running()) {
2607                 ARDOUR_UI::instance()->disconnect_from_engine ();
2608         } else {
2609                 ARDOUR_UI::instance()->reconnect_to_engine ();
2610         }
2611 }
2612
2613 void
2614 EngineControl::calibrate_audio_latency ()
2615 {
2616         _measure_midi.reset ();
2617         have_lm_results = false;
2618         lm_use_button.set_sensitive (false);
2619         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2620         notebook.set_current_page (latency_tab);
2621 }
2622
2623 void
2624 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2625 {
2626         _measure_midi = s;
2627         have_lm_results = false;
2628         lm_use_button.set_sensitive (false);
2629         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2630         notebook.set_current_page (latency_tab);
2631 }
2632
2633 void
2634 EngineControl::configure_midi_devices ()
2635 {
2636         notebook.set_current_page (midi_tab);
2637 }