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