if we don't have control over the device/backend, allow to proceed.
[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
47 #include "pbd/convert.h"
48 #include "pbd/error.h"
49
50 #include "ardour_ui.h"
51 #include "engine_dialog.h"
52 #include "gui_thread.h"
53 #include "utils.h"
54 #include "i18n.h"
55
56 using namespace std;
57 using namespace Gtk;
58 using namespace Gtkmm2ext;
59 using namespace PBD;
60 using namespace Glib;
61
62 static const unsigned int midi_tab = 2;
63 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
64
65 static const char* results_markup = X_("<span foreground=\"red\" style=\"italic\" size=\"larger\">%1</span>");
66
67 EngineControl::EngineControl ()
68         : ArdourDialog (_("Audio/MIDI Setup"))
69         , basic_packer (9, 4)
70         , input_latency_adjustment (0, 0, 99999, 1)
71         , input_latency (input_latency_adjustment)
72         , output_latency_adjustment (0, 0, 99999, 1)
73         , output_latency (output_latency_adjustment)
74         , input_channels_adjustment (0, 0, 256, 1)
75         , input_channels (input_channels_adjustment)
76         , output_channels_adjustment (0, 0, 256, 1)
77         , output_channels (output_channels_adjustment)
78         , ports_adjustment (128, 8, 1024, 1, 16)
79         , ports_spinner (ports_adjustment)
80         , control_app_button (_("Device Control Panel"))
81         , midi_devices_button (_("Midi Device Setup"))
82         , lm_measure_label (_("Measure"))
83         , lm_use_button (_("Use results"))
84         , lm_back_button (_("Back to settings ... (ignore results)"))
85         , lm_button_audio (_("Calibrate Audio"))
86         , lm_table (12, 3)
87         , have_lm_results (false)
88         , lm_running (false)
89         , midi_back_button (_("Back to settings"))
90         , ignore_changes (0)
91         , _desired_sample_rate (0)
92         , started_at_least_once (false)
93 {
94         using namespace Notebook_Helpers;
95         vector<string> strings;
96         Label* label;
97         AttachOptions xopt = AttachOptions (FILL|EXPAND);
98         int row;
99
100         set_name (X_("AudioMIDISetup"));
101
102         /* the backend combo is the one thing that is ALWAYS visible */
103
104         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
105
106         if (backends.empty()) {
107                 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));
108                 msg.run ();
109                 throw failed_constructor ();
110         }
111
112         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
113                 strings.push_back ((*b)->name);
114         }
115
116         set_popdown_strings (backend_combo, strings);
117         backend_combo.set_active_text (strings.front());
118         backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
119
120         /* setup basic packing characteristics for the table used on the main
121          * tab of the notebook
122          */
123
124         basic_packer.set_spacings (6);
125         basic_packer.set_border_width (12);
126         basic_packer.set_homogeneous (false);
127
128         /* pack it in */
129
130         basic_hbox.pack_start (basic_packer, false, false);
131
132         /* latency measurement tab */
133
134         lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
135
136         row = 0;
137         lm_table.set_row_spacings (12);
138         lm_table.set_col_spacings (6);
139         lm_table.set_homogeneous (false);
140
141         lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
142         row++;
143
144         Gtk::Label* preamble;
145
146         preamble = manage (new Label);
147         preamble->set_width_chars (60);
148         preamble->set_line_wrap (true);
149         preamble->set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
150
151         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
152         row++;
153
154         preamble = manage (new Label);
155         preamble->set_width_chars (60);
156         preamble->set_line_wrap (true);
157         preamble->set_markup (_("Select two channels below and connect them using a cable."));
158
159         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
160         row++;
161
162         label = manage (new Label (_("Output channel")));
163         lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
164
165         Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
166         misc_align->add (lm_output_channel_combo);
167         lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
168         ++row;
169
170         label = manage (new Label (_("Input channel")));
171         lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
172
173         misc_align = manage (new Alignment (0.0, 0.5));
174         misc_align->add (lm_input_channel_combo);
175         lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
176         ++row;
177
178         xopt = AttachOptions(0);
179
180         lm_measure_label.set_padding (10, 10);
181         lm_measure_button.add (lm_measure_label);
182         lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
183         lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
184         lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
185
186         lm_use_button.set_sensitive (false);
187
188         /* Increase the default spacing around the labels of these three
189          * buttons
190          */
191
192         Gtk::Misc* l;
193
194         if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
195                 l->set_padding (10, 10);
196         }
197
198         if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
199                 l->set_padding (10, 10);
200         }
201
202         preamble = manage (new Label);
203         preamble->set_width_chars (60);
204         preamble->set_line_wrap (true);
205         preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
206         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
207         row++;
208
209         preamble = manage (new Label);
210         preamble->set_width_chars (60);
211         preamble->set_line_wrap (true);
212         preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
213         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
214
215         ++row; // skip a row in the table
216         ++row; // skip a row in the table
217
218         lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
219
220         ++row; // skip a row in the table
221         ++row; // skip a row in the table
222
223         lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
224         lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
225         lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
226
227         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
228
229         lm_vbox.set_border_width (12);
230         lm_vbox.pack_start (lm_table, false, false);
231
232         midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
233
234         /* pack it all up */
235
236         notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
237         notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
238         notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
239         notebook.set_border_width (12);
240
241         notebook.set_show_tabs (false);
242         notebook.show_all ();
243
244         notebook.set_name ("SettingsNotebook");
245
246         /* packup the notebook */
247
248         get_vbox()->set_border_width (12);
249         get_vbox()->pack_start (notebook);
250
251         /* need a special function to print "all available channels" when the
252          * channel counts hit zero.
253          */
254
255         input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
256         output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
257
258         midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
259         midi_devices_button.set_sensitive (false);
260         midi_devices_button.set_name ("generic button");
261         midi_devices_button.set_can_focus(true);
262
263         control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
264         manage_control_app_sensitivity ();
265
266         cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
267         ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
268         apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
269
270         /* Pick up any existing audio setup configuration, if appropriate */
271
272         XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
273
274         ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
275         ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
276         ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
277
278         {
279                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
280                 backend_changed ();
281         }
282         maybe_display_saved_state();
283
284         /* Connect to signals */
285
286         driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
287         sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
288         buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
289         device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed));
290         midi_option_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::midi_option_changed));
291
292         input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
293         output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
294         input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
295         output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
296
297         if (audio_setup) {
298                 set_state (*audio_setup);
299         }
300
301         notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
302 }
303
304 void
305 EngineControl::on_response (int response_id)
306 {
307         ArdourDialog::on_response (response_id);
308
309         switch (response_id) {
310                 case RESPONSE_APPLY:
311                         push_state_to_backend (true);
312                         break;
313                 case RESPONSE_OK:
314                         push_state_to_backend (true);
315                         hide ();
316                         break;
317                 case RESPONSE_DELETE_EVENT:
318                         {
319                                 GdkEventButton ev;
320                                 ev.type = GDK_BUTTON_PRESS;
321                                 ev.button = 1;
322                                 on_delete_event ((GdkEventAny*) &ev);
323                                 break;
324                         }
325                 default:
326                         hide ();
327         }
328 }
329
330 void
331 EngineControl::build_notebook ()
332 {
333         Label* label;
334         AttachOptions xopt = AttachOptions (FILL|EXPAND);
335
336         /* clear the table */
337
338         Gtkmm2ext::container_clear (basic_vbox);
339         Gtkmm2ext::container_clear (basic_packer);
340
341         if (control_app_button.get_parent()) {
342                 control_app_button.get_parent()->remove (control_app_button);
343         }
344
345         label = manage (left_aligned_label (_("Audio System:")));
346         basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
347         basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
348
349         lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
350         lm_button_audio.set_name ("generic button");
351         lm_button_audio.set_can_focus(true);
352
353         if (_have_control) {
354                 build_full_control_notebook ();
355         } else {
356                 build_no_control_notebook ();
357         }
358
359         basic_vbox.pack_start (basic_hbox, false, false);
360
361         if (_have_control) {
362                 Gtk::HBox* hpacker = manage (new HBox);
363                 hpacker->set_border_width (12);
364                 hpacker->pack_start (control_app_button, false, false);
365                 hpacker->show ();
366                 control_app_button.show();
367                 basic_vbox.pack_start (*hpacker);
368         }
369
370         basic_vbox.show_all ();
371 }
372
373 void
374 EngineControl::build_full_control_notebook ()
375 {
376         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
377         assert (backend);
378
379         using namespace Notebook_Helpers;
380         Label* label;
381         vector<string> strings;
382         AttachOptions xopt = AttachOptions (FILL|EXPAND);
383         int row = 1; // row zero == backend combo
384
385         /* start packing it up */
386
387         if (backend->requires_driver_selection()) {
388                 label = manage (left_aligned_label (_("Driver:")));
389                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
390                 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
391                 row++;
392         }
393
394         label = manage (left_aligned_label (_("Device:")));
395         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
396         basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
397         row++;
398
399         label = manage (left_aligned_label (_("Sample rate:")));
400         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
401         basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
402         row++;
403
404
405         label = manage (left_aligned_label (_("Buffer size:")));
406         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
407         basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
408         buffer_size_duration_label.set_alignment (0.0); /* left-align */
409         basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
410         row++;
411
412         input_channels.set_name ("InputChannels");
413         input_channels.set_flags (Gtk::CAN_FOCUS);
414         input_channels.set_digits (0);
415         input_channels.set_wrap (false);
416         output_channels.set_editable (true);
417
418         label = manage (left_aligned_label (_("Input Channels:")));
419         basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
420         basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
421         ++row;
422
423         output_channels.set_name ("OutputChannels");
424         output_channels.set_flags (Gtk::CAN_FOCUS);
425         output_channels.set_digits (0);
426         output_channels.set_wrap (false);
427         output_channels.set_editable (true);
428
429         label = manage (left_aligned_label (_("Output Channels:")));
430         basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
431         basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
432         ++row;
433
434         input_latency.set_name ("InputLatency");
435         input_latency.set_flags (Gtk::CAN_FOCUS);
436         input_latency.set_digits (0);
437         input_latency.set_wrap (false);
438         input_latency.set_editable (true);
439
440         label = manage (left_aligned_label (_("Hardware input latency:")));
441         basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
442         basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
443         label = manage (left_aligned_label (_("samples")));
444         basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
445         ++row;
446
447         output_latency.set_name ("OutputLatency");
448         output_latency.set_flags (Gtk::CAN_FOCUS);
449         output_latency.set_digits (0);
450         output_latency.set_wrap (false);
451         output_latency.set_editable (true);
452
453         label = manage (left_aligned_label (_("Hardware output latency:")));
454         basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
455         basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
456         label = manage (left_aligned_label (_("samples")));
457         basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
458
459         /* button spans 2 rows */
460
461         basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
462         ++row;
463
464         label = manage (left_aligned_label (_("MIDI System")));
465         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
466         basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
467         basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
468         row++;
469 }
470
471 void
472 EngineControl::build_no_control_notebook ()
473 {
474         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
475         assert (backend);
476
477         using namespace Notebook_Helpers;
478         Label* label;
479         vector<string> strings;
480         AttachOptions xopt = AttachOptions (FILL|EXPAND);
481         int row = 1; // row zero == backend combo
482         const string msg = string_compose (_("The %1 audio backend was configured and started externally.\nThis limits your control over it."), backend->name());
483
484         label = manage (new Label);
485         label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
486         basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
487         row++;
488
489         if (backend->can_change_sample_rate_when_running()) {
490                 label = manage (left_aligned_label (_("Sample rate:")));
491                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
492                 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
493                 row++;
494         }
495
496         if (backend->can_change_buffer_size_when_running()) {
497                 label = manage (left_aligned_label (_("Buffer size:")));
498                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
499                 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
500                 buffer_size_duration_label.set_alignment (0.0); /* left-align */
501                 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
502                 row++;
503         }
504
505         connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
506
507         basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
508         row++;
509 }
510
511 EngineControl::~EngineControl ()
512 {
513         ignore_changes = true;
514 }
515
516 void
517 EngineControl::disable_latency_tab ()
518 {
519         vector<string> empty;
520         set_popdown_strings (lm_output_channel_combo, empty);
521         set_popdown_strings (lm_input_channel_combo, empty);
522         lm_measure_button.set_sensitive (false);
523         lm_use_button.set_sensitive (false);
524 }
525
526 void
527 EngineControl::enable_latency_tab ()
528 {
529         vector<string> outputs;
530         vector<string> inputs;
531
532         ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
533         ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
534         ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
535
536         if (inputs.empty() || outputs.empty()) {
537                 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
538                 lm_measure_button.set_sensitive (false);
539                 notebook.set_current_page (0);
540                 msg.run ();
541                 return;
542         }
543
544         if (!outputs.empty()) {
545                 set_popdown_strings (lm_output_channel_combo, outputs);
546                 lm_output_channel_combo.set_active_text (outputs.front());
547                 lm_output_channel_combo.set_sensitive (true);
548         } else {
549                 lm_output_channel_combo.set_sensitive (false);
550         }
551
552         if (!inputs.empty()) {
553                 set_popdown_strings (lm_input_channel_combo, inputs);
554                 lm_input_channel_combo.set_active_text (inputs.front());
555                 lm_input_channel_combo.set_sensitive (true);
556         } else {
557                 lm_input_channel_combo.set_sensitive (false);
558         }
559
560         lm_measure_button.set_sensitive (true);
561 }
562
563 void
564 EngineControl::setup_midi_tab_for_backend ()
565 {
566         string backend = backend_combo.get_active_text ();
567
568         Gtkmm2ext::container_clear (midi_vbox);
569
570         midi_vbox.set_border_width (12);
571         midi_device_table.set_border_width (12);
572
573         if (backend == "JACK") {
574                 setup_midi_tab_for_jack ();
575         }
576
577         midi_vbox.pack_start (midi_device_table, true, true);
578         midi_vbox.pack_start (midi_back_button, false, false);
579         midi_vbox.show_all ();
580 }
581
582 void
583 EngineControl::setup_midi_tab_for_jack ()
584 {
585 }
586
587 void
588 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
589         if (for_input) {
590                 device->input_latency = a->get_value();
591         } else {
592                 device->output_latency = a->get_value();
593         }
594 }
595
596 void
597 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
598         b->set_active (!b->get_active());
599         device->enabled = b->get_active();
600         refresh_midi_display(device->name);
601 }
602
603 void
604 EngineControl::refresh_midi_display (std::string focus)
605 {
606         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
607         assert (backend);
608
609         int row  = 0;
610         AttachOptions xopt = AttachOptions (FILL|EXPAND);
611         Gtk::Label* l;
612
613         Gtkmm2ext::container_clear (midi_device_table);
614
615         midi_device_table.set_spacings (6);
616
617         l = manage (new Label);
618         l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
619         midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
620         l->set_alignment (0.5, 0.5);
621         row++;
622         l->show ();
623
624         l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
625         midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
626         l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
627         midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
628         row++;
629         l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
630         midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
631         l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
632         midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
633         row++;
634
635         for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
636                 ArdourButton *m;
637                 Gtk::Button* b;
638                 Gtk::Adjustment *a;
639                 Gtk::SpinButton *s;
640                 bool enabled = (*p)->enabled;
641
642                 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
643                 m->set_name ("midi device");
644                 m->set_can_focus (Gtk::CAN_FOCUS);
645                 m->add_events (Gdk::BUTTON_RELEASE_MASK);
646                 m->set_active (enabled);
647                 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
648                 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
649                 if ((*p)->name == focus) {
650                         m->grab_focus();
651                 }
652
653                 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
654                 s = manage (new Gtk::SpinButton (*a));
655                 a->set_value ((*p)->input_latency);
656                 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
657                 s->set_sensitive (_can_set_midi_latencies && enabled);
658                 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
659
660                 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
661                 s = manage (new Gtk::SpinButton (*a));
662                 a->set_value ((*p)->output_latency);
663                 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
664                 s->set_sensitive (_can_set_midi_latencies && enabled);
665                 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
666
667                 b = manage (new Button (_("Calibrate")));
668                 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
669                 b->set_sensitive (_can_set_midi_latencies && enabled);
670                 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
671
672                 row++;
673         }
674 }
675
676 void
677 EngineControl::update_sensitivity ()
678 {
679 }
680
681 void
682 EngineControl::backend_changed ()
683 {
684         string backend_name = backend_combo.get_active_text();
685         boost::shared_ptr<ARDOUR::AudioBackend> backend;
686
687         if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
688                 /* eh? setting the backend failed... how ? */
689                 return;
690         }
691
692         _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
693
694         build_notebook ();
695         setup_midi_tab_for_backend ();
696         _midi_devices.clear();
697
698         if (backend->requires_driver_selection()) {
699                 vector<string> drivers = backend->enumerate_drivers();
700                 driver_combo.set_sensitive (true);
701
702                 if (!drivers.empty()) {
703                         {
704                                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
705                                 set_popdown_strings (driver_combo, drivers);
706                                 driver_combo.set_active_text (drivers.front());
707                         }
708
709                         driver_changed ();
710                 }
711
712         } else {
713                 driver_combo.set_sensitive (false);
714                 /* this will change the device text which will cause a call to
715                  * device changed which will set up parameters
716                  */
717                 list_devices ();
718         }
719
720         vector<string> midi_options = backend->enumerate_midi_options();
721
722         if (midi_options.size() == 1) {
723                 /* only contains the "none" option */
724                 midi_option_combo.set_sensitive (false);
725         } else {
726                 if (_have_control) {
727                         set_popdown_strings (midi_option_combo, midi_options);
728                         midi_option_combo.set_active_text (midi_options.front());
729                         midi_option_combo.set_sensitive (true);
730                 } else {
731                         midi_option_combo.set_sensitive (false);
732                 }
733         }
734
735         midi_option_changed();
736
737         started_at_least_once = false;
738
739         if (!ignore_changes) {
740                 maybe_display_saved_state ();
741         }
742 }
743
744 bool
745 EngineControl::print_channel_count (Gtk::SpinButton* sb)
746 {
747         uint32_t cnt = (uint32_t) sb->get_value();
748         if (cnt == 0) {
749                 sb->set_text (_("all available channels"));
750         } else {
751                 char buf[32];
752                 snprintf (buf, sizeof (buf), "%d", cnt);
753                 sb->set_text (buf);
754         }
755         return true;
756 }
757
758 void
759 EngineControl::list_devices ()
760 {
761         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
762         assert (backend);
763
764         /* now fill out devices, mark sample rates, buffer sizes insensitive */
765
766         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
767
768         /* NOTE: Ardour currently does not display the "available" field of the
769          * returned devices.
770          *
771          * Doing so would require a different GUI widget than the combo
772          * box/popdown that we currently use, since it has no way to list
773          * items that are not selectable. Something more like a popup menu,
774          * which could have unselectable items, would be appropriate.
775          */
776
777         vector<string> available_devices;
778
779         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
780                 available_devices.push_back (i->name);
781         }
782
783         if (!available_devices.empty()) {
784
785                 update_sensitivity ();
786
787                 {
788                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
789                         set_popdown_strings (device_combo, available_devices);
790                         device_combo.set_active_text (available_devices.front());
791                 }
792
793                 device_changed ();
794
795                 ok_button->set_sensitive (true);
796                 apply_button->set_sensitive (true);
797
798         } else {
799                 sample_rate_combo.set_sensitive (false);
800                 buffer_size_combo.set_sensitive (false);
801                 input_latency.set_sensitive (false);
802                 output_latency.set_sensitive (false);
803                 input_channels.set_sensitive (false);
804                 output_channels.set_sensitive (false);
805                 if (_have_control) {
806                         ok_button->set_sensitive (false);
807                         apply_button->set_sensitive (false);
808                 } else {
809                         ok_button->set_sensitive (true);
810                         apply_button->set_sensitive (true);
811                 }
812         }
813 }
814
815 void
816 EngineControl::driver_changed ()
817 {
818         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
819         assert (backend);
820
821         backend->set_driver (driver_combo.get_active_text());
822         list_devices ();
823
824         if (!ignore_changes) {
825                 maybe_display_saved_state ();
826         }
827 }
828
829 void
830 EngineControl::device_changed ()
831 {
832
833         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
834         assert (backend);
835         string device_name = device_combo.get_active_text ();
836         vector<string> s;
837
838         {
839                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
840
841                 /* don't allow programmatic change to combos to cause a
842                    recursive call to this method.
843                  */
844
845                 /* sample rates */
846
847                 string desired;
848
849                 vector<float> sr;
850
851                 if (_have_control) {
852                         sr = backend->available_sample_rates (device_name);
853                 } else {
854
855                         sr.push_back (8000.0f);
856                         sr.push_back (16000.0f);
857                         sr.push_back (32000.0f);
858                         sr.push_back (44100.0f);
859                         sr.push_back (48000.0f);
860                         sr.push_back (88200.0f);
861                         sr.push_back (96000.0f);
862                         sr.push_back (192000.0f);
863                         sr.push_back (384000.0f);
864                 }
865
866                 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
867                         s.push_back (rate_as_string (*x));
868                         if (*x == _desired_sample_rate) {
869                                 desired = s.back();
870                         }
871                 }
872
873                 if (!s.empty()) {
874                         sample_rate_combo.set_sensitive (true);
875                         set_popdown_strings (sample_rate_combo, s);
876
877                         if (desired.empty()) {
878                                 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
879                         } else {
880                                 sample_rate_combo.set_active_text (desired);
881                         }
882
883                 } else {
884                         sample_rate_combo.set_sensitive (false);
885                 }
886
887                 /* buffer sizes */
888
889                 vector<uint32_t> bs;
890
891                 if (_have_control) {
892                         bs = backend->available_buffer_sizes (device_name);
893                 } else if (backend->can_change_buffer_size_when_running()) {
894                         bs.push_back (8);
895                         bs.push_back (16);
896                         bs.push_back (32);
897                         bs.push_back (64);
898                         bs.push_back (128);
899                         bs.push_back (256);
900                         bs.push_back (512);
901                         bs.push_back (1024);
902                         bs.push_back (2048);
903                         bs.push_back (4096);
904                         bs.push_back (8192);
905                 }
906                 s.clear ();
907                 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
908                         s.push_back (bufsize_as_string (*x));
909                 }
910
911                 if (!s.empty()) {
912                         buffer_size_combo.set_sensitive (true);
913                         set_popdown_strings (buffer_size_combo, s);
914
915                         buffer_size_combo.set_active_text (bufsize_as_string (backend->default_buffer_size()));
916                         show_buffer_duration ();
917                 } else {
918                         buffer_size_combo.set_sensitive (false);
919                 }
920
921                 /* XXX theoretically need to set min + max channel counts here
922                 */
923
924                 manage_control_app_sensitivity ();
925         }
926
927         /* pick up any saved state for this device */
928
929         if (!ignore_changes) {
930                 maybe_display_saved_state ();
931         }
932 }
933
934 string
935 EngineControl::bufsize_as_string (uint32_t sz)
936 {
937         /* Translators: "samples" is always plural here, so no
938            need for plural+singular forms.
939          */
940         char buf[32];
941         snprintf (buf, sizeof (buf), _("%u samples"), sz);
942         return buf;
943 }
944
945 void
946 EngineControl::sample_rate_changed ()
947 {
948         /* reset the strings for buffer size to show the correct msec value
949            (reflecting the new sample rate).
950          */
951
952         show_buffer_duration ();
953         if (!ignore_changes) {
954                 save_state ();
955         }
956
957 }
958
959 void
960 EngineControl::buffer_size_changed ()
961 {
962         show_buffer_duration ();
963         if (!ignore_changes) {
964                 save_state ();
965         }
966 }
967
968 void
969 EngineControl::show_buffer_duration ()
970 {
971
972         /* buffer sizes  - convert from just samples to samples + msecs for
973          * the displayed string
974          */
975
976         string bs_text = buffer_size_combo.get_active_text ();
977         uint32_t samples = atoi (bs_text); /* will ignore trailing text */
978         uint32_t rate = get_rate();
979
980         /* Translators: "msecs" is ALWAYS plural here, so we do not
981            need singular form as well.
982          */
983         /* Developers: note the hard-coding of a double buffered model
984            in the (2 * samples) computation of latency. we always start
985            the audiobackend in this configuration.
986          */
987         char buf[32];
988         snprintf (buf, sizeof (buf), _("(%.1f msecs)"), (2 * samples) / (rate/1000.0));
989         buffer_size_duration_label.set_text (buf);
990 }
991
992 void
993 EngineControl::midi_option_changed ()
994 {
995         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
996         assert (backend);
997
998         backend->set_midi_option (get_midi_option());
999
1000         vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1001
1002         //_midi_devices.clear(); // TODO merge with state-saved settings..
1003         _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1004         std::vector<MidiDeviceSettings> new_devices;
1005
1006         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1007                 MidiDeviceSettings mds = find_midi_device (i->name);
1008                 if (i->available && !mds) {
1009                         uint32_t input_latency = 0;
1010                         uint32_t output_latency = 0;
1011                         if (_can_set_midi_latencies) {
1012                                 input_latency = backend->systemic_midi_input_latency (i->name);
1013                                 output_latency = backend->systemic_midi_output_latency (i->name);
1014                         }
1015                         bool enabled = backend->midi_device_enabled (i->name);
1016                         MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1017                         new_devices.push_back (ptr);
1018                 } else if (i->available) {
1019                         new_devices.push_back (mds);
1020                 }
1021         }
1022         _midi_devices = new_devices;
1023
1024         if (_midi_devices.empty()) {
1025                 midi_devices_button.set_sensitive (false);
1026         } else {
1027                 midi_devices_button.set_sensitive (true);
1028         }
1029
1030         if (!ignore_changes) {
1031                 save_state ();
1032         }
1033 }
1034
1035 void
1036 EngineControl::parameter_changed ()
1037 {
1038         if (!ignore_changes) {
1039                 save_state ();
1040         }
1041 }
1042
1043 EngineControl::State*
1044 EngineControl::get_matching_state (
1045                 const string& backend,
1046                 const string& driver,
1047                 const string& device)
1048 {
1049         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1050                 if ((*i).backend == backend &&
1051                                 (*i).driver == driver &&
1052                                 (*i).device == device) {
1053                         return &(*i);
1054                 }
1055         }
1056         return 0;
1057 }
1058
1059 EngineControl::State*
1060 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1061 {
1062         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1063
1064         if (backend) {
1065                 return get_matching_state (backend_combo.get_active_text(),
1066                                 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1067                                 device_combo.get_active_text());
1068         }
1069
1070
1071         return get_matching_state (backend_combo.get_active_text(),
1072                         string(),
1073                         device_combo.get_active_text());
1074 }
1075
1076 EngineControl::State*
1077 EngineControl::save_state ()
1078 {
1079         if (!_have_control) {
1080                 return 0;
1081         }
1082         State* state = new State;
1083         store_state (*state);
1084
1085         for (StateList::iterator i = states.begin(); i != states.end();) {
1086                 if ((*i).backend == state->backend &&
1087                                 (*i).driver == state->driver &&
1088                                 (*i).device == state->device) {
1089                         i =  states.erase(i);
1090                 } else {
1091                         ++i;
1092                 }
1093         }
1094
1095         states.push_back (*state);
1096
1097         return state;
1098 }
1099
1100 void
1101 EngineControl::store_state (State& state)
1102 {
1103         state.backend = get_backend ();
1104         state.driver = get_driver ();
1105         state.device = get_device_name ();
1106         state.sample_rate = get_rate ();
1107         state.buffer_size = get_buffer_size ();
1108         state.input_latency = get_input_latency ();
1109         state.output_latency = get_output_latency ();
1110         state.input_channels = get_input_channels ();
1111         state.output_channels = get_output_channels ();
1112         state.midi_option = get_midi_option ();
1113         state.midi_devices = _midi_devices;
1114 }
1115
1116 void
1117 EngineControl::maybe_display_saved_state ()
1118 {
1119         if (!_have_control) {
1120                 return;
1121         }
1122
1123         State* state = get_saved_state_for_currently_displayed_backend_and_device ();
1124
1125         if (state) {
1126                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1127
1128                 if (!_desired_sample_rate) {
1129                         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1130                 }
1131                 buffer_size_combo.set_active_text (bufsize_as_string (state->buffer_size));
1132                 /* call this explicitly because we're ignoring changes to
1133                    the controls at this point.
1134                  */
1135                 show_buffer_duration ();
1136                 input_latency.set_value (state->input_latency);
1137                 output_latency.set_value (state->output_latency);
1138
1139                 if (!state->midi_option.empty()) {
1140                         midi_option_combo.set_active_text (state->midi_option);
1141                         _midi_devices = state->midi_devices;
1142                 }
1143         }
1144 }
1145
1146 XMLNode&
1147 EngineControl::get_state ()
1148 {
1149         XMLNode* root = new XMLNode ("AudioMIDISetup");
1150         std::string path;
1151
1152         if (!states.empty()) {
1153                 XMLNode* state_nodes = new XMLNode ("EngineStates");
1154
1155                 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1156
1157                         XMLNode* node = new XMLNode ("State");
1158
1159                         node->add_property ("backend", (*i).backend);
1160                         node->add_property ("driver", (*i).driver);
1161                         node->add_property ("device", (*i).device);
1162                         node->add_property ("sample-rate", (*i).sample_rate);
1163                         node->add_property ("buffer-size", (*i).buffer_size);
1164                         node->add_property ("input-latency", (*i).input_latency);
1165                         node->add_property ("output-latency", (*i).output_latency);
1166                         node->add_property ("input-channels", (*i).input_channels);
1167                         node->add_property ("output-channels", (*i).output_channels);
1168                         node->add_property ("active", (*i).active ? "yes" : "no");
1169                         node->add_property ("midi-option", (*i).midi_option);
1170
1171                         XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1172                         for (std::vector<MidiDeviceSettings>::const_iterator p = (*i).midi_devices.begin(); p != (*i).midi_devices.end(); ++p) {
1173                                 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1174                                 midi_device_stuff->add_property (X_("name"), (*p)->name);
1175                                 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1176                                 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1177                                 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1178                                 midi_devices->add_child_nocopy (*midi_device_stuff);
1179                         }
1180                         node->add_child_nocopy (*midi_devices);
1181
1182                         state_nodes->add_child_nocopy (*node);
1183                 }
1184
1185                 root->add_child_nocopy (*state_nodes);
1186         }
1187
1188         return *root;
1189 }
1190
1191 void
1192 EngineControl::set_state (const XMLNode& root)
1193 {
1194         XMLNodeList          clist, cclist;
1195         XMLNodeConstIterator citer, cciter;
1196         XMLNode* child;
1197         XMLNode* grandchild;
1198         XMLProperty* prop = NULL;
1199
1200         if (root.name() != "AudioMIDISetup") {
1201                 return;
1202         }
1203
1204         clist = root.children();
1205
1206         states.clear ();
1207
1208         for (citer = clist.begin(); citer != clist.end(); ++citer) {
1209
1210                 child = *citer;
1211
1212                 if (child->name() != "EngineStates") {
1213                         continue;
1214                 }
1215
1216                 cclist = child->children();
1217
1218                 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1219                         State state;
1220
1221                         grandchild = *cciter;
1222
1223                         if (grandchild->name() != "State") {
1224                                 continue;
1225                         }
1226
1227                         if ((prop = grandchild->property ("backend")) == 0) {
1228                                 continue;
1229                         }
1230                         state.backend = prop->value ();
1231
1232                         if ((prop = grandchild->property ("driver")) == 0) {
1233                                 continue;
1234                         }
1235                         state.driver = prop->value ();
1236
1237                         if ((prop = grandchild->property ("device")) == 0) {
1238                                 continue;
1239                         }
1240                         state.device = prop->value ();
1241
1242                         if ((prop = grandchild->property ("sample-rate")) == 0) {
1243                                 continue;
1244                         }
1245                         state.sample_rate = atof (prop->value ());
1246
1247                         if ((prop = grandchild->property ("buffer-size")) == 0) {
1248                                 continue;
1249                         }
1250                         state.buffer_size = atoi (prop->value ());
1251
1252                         if ((prop = grandchild->property ("input-latency")) == 0) {
1253                                 continue;
1254                         }
1255                         state.input_latency = atoi (prop->value ());
1256
1257                         if ((prop = grandchild->property ("output-latency")) == 0) {
1258                                 continue;
1259                         }
1260                         state.output_latency = atoi (prop->value ());
1261
1262                         if ((prop = grandchild->property ("input-channels")) == 0) {
1263                                 continue;
1264                         }
1265                         state.input_channels = atoi (prop->value ());
1266
1267                         if ((prop = grandchild->property ("output-channels")) == 0) {
1268                                 continue;
1269                         }
1270                         state.output_channels = atoi (prop->value ());
1271
1272                         if ((prop = grandchild->property ("active")) == 0) {
1273                                 continue;
1274                         }
1275                         state.active = string_is_affirmative (prop->value ());
1276
1277                         if ((prop = grandchild->property ("midi-option")) == 0) {
1278                                 continue;
1279                         }
1280                         state.midi_option = prop->value ();
1281
1282                         state.midi_devices.clear();
1283                         XMLNode* midinode;
1284                         if ((midinode = find_named_node (*grandchild, "MIDIDevices")) != 0) {
1285                                 const XMLNodeList mnc = midinode->children();
1286                                 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1287                                         if ((*n)->property (X_("name")) == 0
1288                                                         || (*n)->property (X_("enabled")) == 0
1289                                                         || (*n)->property (X_("input-latency")) == 0
1290                                                         || (*n)->property (X_("output-latency")) == 0
1291                                                  ) {
1292                                                 continue;
1293                                         }
1294
1295                                         MidiDeviceSettings ptr (new MidiDeviceSetting(
1296                                                                 (*n)->property (X_("name"))->value (),
1297                                                                 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1298                                                                 atoi ((*n)->property (X_("input-latency"))->value ()),
1299                                                                 atoi ((*n)->property (X_("output-latency"))->value ())
1300                                                                 ));
1301                                         state.midi_devices.push_back (ptr);
1302                                 }
1303                         }
1304
1305 #if 1
1306                         /* remove accumulated duplicates (due to bug in ealier version)
1307                          * this can be removed again before release
1308                          */
1309                         for (StateList::iterator i = states.begin(); i != states.end();) {
1310                                 if ((*i).backend == state.backend &&
1311                                                 (*i).driver == state.driver &&
1312                                                 (*i).device == state.device) {
1313                                         i =  states.erase(i);
1314                                 } else {
1315                                         ++i;
1316                                 }
1317                         }
1318 #endif
1319
1320                         states.push_back (state);
1321                 }
1322         }
1323
1324         /* now see if there was an active state and switch the setup to it */
1325
1326         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1327
1328                 if ((*i).active) {
1329                         ignore_changes++;
1330                         backend_combo.set_active_text ((*i).backend);
1331                         driver_combo.set_active_text ((*i).driver);
1332                         device_combo.set_active_text ((*i).device);
1333                         sample_rate_combo.set_active_text (rate_as_string ((*i).sample_rate));
1334                         buffer_size_combo.set_active_text (bufsize_as_string ((*i).buffer_size));
1335                         input_latency.set_value ((*i).input_latency);
1336                         output_latency.set_value ((*i).output_latency);
1337                         midi_option_combo.set_active_text ((*i).midi_option);
1338                         ignore_changes--;
1339                         break;
1340                 }
1341         }
1342 }
1343
1344 int
1345 EngineControl::push_state_to_backend (bool start)
1346 {
1347         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1348
1349         if (!backend) {
1350                 return 0;
1351         }
1352
1353         /* figure out what is going to change */
1354
1355         bool restart_required = false;
1356         bool was_running = ARDOUR::AudioEngine::instance()->running();
1357         bool change_driver = false;
1358         bool change_device = false;
1359         bool change_rate = false;
1360         bool change_bufsize = false;
1361         bool change_latency = false;
1362         bool change_channels = false;
1363         bool change_midi = false;
1364
1365         uint32_t ochan = get_output_channels ();
1366         uint32_t ichan = get_input_channels ();
1367
1368         if (_have_control) {
1369
1370                 if (started_at_least_once) {
1371
1372                         /* we can control the backend */
1373
1374                         if (backend->requires_driver_selection()) {
1375                                 if (get_driver() != backend->driver_name()) {
1376                                         change_driver = true;
1377                                 }
1378                         }
1379
1380                         if (get_device_name() != backend->device_name()) {
1381                                 change_device = true;
1382                         }
1383
1384                         if (get_rate() != backend->sample_rate()) {
1385                                 change_rate = true;
1386                         }
1387
1388                         if (get_buffer_size() != backend->buffer_size()) {
1389                                 change_bufsize = true;
1390                         }
1391
1392                         if (get_midi_option() != backend->midi_option()) {
1393                                 change_midi = true;
1394                         }
1395
1396                         /* zero-requested channels means "all available" */
1397
1398                         if (ichan == 0) {
1399                                 ichan = backend->input_channels();
1400                         }
1401
1402                         if (ochan == 0) {
1403                                 ochan = backend->output_channels();
1404                         }
1405
1406                         if (ichan != backend->input_channels()) {
1407                                 change_channels = true;
1408                         }
1409
1410                         if (ochan != backend->output_channels()) {
1411                                 change_channels = true;
1412                         }
1413
1414                         if (get_input_latency() != backend->systemic_input_latency() ||
1415                                         get_output_latency() != backend->systemic_output_latency()) {
1416                                 change_latency = true;
1417                         }
1418                 } else {
1419                         /* backend never started, so we have to force a group
1420                            of settings.
1421                          */
1422                         change_device = true;
1423                         if (backend->requires_driver_selection()) {
1424                                 change_driver = true;
1425                         }
1426                         change_rate = true;
1427                         change_bufsize = true;
1428                         change_channels = true;
1429                         change_latency = true;
1430                         change_midi = true;
1431                 }
1432
1433         } else {
1434
1435                 /* we have no control over the backend, meaning that we can
1436                  * only possibly change sample rate and buffer size.
1437                  */
1438
1439
1440                 if (get_rate() != backend->sample_rate()) {
1441                         change_bufsize = true;
1442                 }
1443
1444                 if (get_buffer_size() != backend->buffer_size()) {
1445                         change_bufsize = true;
1446                 }
1447         }
1448
1449         if (!_have_control) {
1450
1451                 /* We do not have control over the backend, so the best we can
1452                  * do is try to change the sample rate and/or bufsize and get
1453                  * out of here.
1454                  */
1455
1456                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1457                         return 1;
1458                 }
1459
1460                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1461                         return 1;
1462                 }
1463
1464                 if (change_rate) {
1465                         backend->set_sample_rate (get_rate());
1466                 }
1467
1468                 if (change_bufsize) {
1469                         backend->set_buffer_size (get_buffer_size());
1470                 }
1471
1472                 if (start) {
1473                         if (ARDOUR::AudioEngine::instance()->start ()) {
1474                                 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1475                                 return -1;
1476                         }
1477                 }
1478
1479                 post_push ();
1480
1481                 return 0;
1482         }
1483
1484         /* determine if we need to stop the backend before changing parameters */
1485
1486         if (change_driver || change_device || change_channels || change_latency ||
1487                         (change_rate && !backend->can_change_sample_rate_when_running()) ||
1488                         change_midi ||
1489                         (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1490                 restart_required = true;
1491         } else {
1492                 restart_required = false;
1493         }
1494
1495         if (was_running) {
1496
1497                 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1498                         /* no changes in any parameters that absolutely require a
1499                          * restart, so check those that might be changeable without a
1500                          * restart
1501                          */
1502
1503                         if (change_rate && !backend->can_change_sample_rate_when_running()) {
1504                                 /* can't do this while running ... */
1505                                 restart_required = true;
1506                         }
1507
1508                         if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1509                                 /* can't do this while running ... */
1510                                 restart_required = true;
1511                         }
1512                 }
1513         }
1514
1515         if (was_running) {
1516                 if (restart_required) {
1517                         if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1518                                 return -1;
1519                         }
1520                 }
1521         }
1522
1523
1524         if (change_driver && backend->set_driver (get_driver())) {
1525                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1526                 return -1;
1527         }
1528         if (change_device && backend->set_device_name (get_device_name())) {
1529                 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1530                 return -1;
1531         }
1532         if (change_rate && backend->set_sample_rate (get_rate())) {
1533                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1534                 return -1;
1535         }
1536         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1537                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1538                 return -1;
1539         }
1540
1541         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1542                 if (backend->set_input_channels (get_input_channels())) {
1543                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1544                         return -1;
1545                 }
1546                 if (backend->set_output_channels (get_output_channels())) {
1547                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1548                         return -1;
1549                 }
1550         }
1551         if (change_latency) {
1552                 if (backend->set_systemic_input_latency (get_input_latency())) {
1553                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1554                         return -1;
1555                 }
1556                 if (backend->set_systemic_output_latency (get_output_latency())) {
1557                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1558                         return -1;
1559                 }
1560         }
1561
1562         if (change_midi) {
1563                 backend->set_midi_option (get_midi_option());
1564         }
1565
1566         if (1 /* TODO */) {
1567                 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1568                         if (_measure_midi) {
1569                                 if (*p == _measure_midi) {
1570                                         backend->set_midi_device_enabled ((*p)->name, true);
1571                                 } else {
1572                                         backend->set_midi_device_enabled ((*p)->name, false);
1573                                 }
1574                                 continue;
1575                         }
1576                         backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
1577                         if (backend->can_set_systemic_midi_latencies()) {
1578                                 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
1579                                 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
1580                         }
1581                 }
1582         }
1583
1584         if (start || (was_running && restart_required)) {
1585                 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
1586                         return -1;
1587                 }
1588         }
1589
1590         post_push ();
1591
1592         return 0;
1593 }
1594
1595 void
1596 EngineControl::post_push ()
1597 {
1598         /* get a pointer to the current state object, creating one if
1599          * necessary
1600          */
1601
1602         if (_have_control) {
1603                 State* state = get_saved_state_for_currently_displayed_backend_and_device ();
1604
1605                 if (!state) {
1606                         state = save_state ();
1607                         assert (state);
1608                 }
1609
1610                 /* all off */
1611
1612                 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1613                         (*i).active = false;
1614                 }
1615
1616                 /* mark this one active (to be used next time the dialog is
1617                  * shown)
1618                  */
1619
1620                 state->active = true;
1621
1622                 manage_control_app_sensitivity ();
1623         }
1624
1625         /* schedule a redisplay of MIDI ports */
1626         //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
1627 }
1628
1629
1630 float
1631 EngineControl::get_rate () const
1632 {
1633         float r = atof (sample_rate_combo.get_active_text ());
1634         /* the string may have been translated with an abbreviation for
1635          * thousands, so use a crude heuristic to fix this.
1636          */
1637         if (r < 1000.0) {
1638                 r *= 1000.0;
1639         }
1640         return r;
1641 }
1642
1643
1644 uint32_t
1645 EngineControl::get_buffer_size () const
1646 {
1647         string txt = buffer_size_combo.get_active_text ();
1648         uint32_t samples;
1649
1650         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
1651                 throw exception ();
1652         }
1653
1654         return samples;
1655 }
1656
1657 string
1658 EngineControl::get_midi_option () const
1659 {
1660         return midi_option_combo.get_active_text();
1661 }
1662
1663 uint32_t
1664 EngineControl::get_input_channels() const
1665 {
1666         return (uint32_t) input_channels_adjustment.get_value();
1667 }
1668
1669 uint32_t
1670 EngineControl::get_output_channels() const
1671 {
1672         return (uint32_t) output_channels_adjustment.get_value();
1673 }
1674
1675 uint32_t
1676 EngineControl::get_input_latency() const
1677 {
1678         return (uint32_t) input_latency_adjustment.get_value();
1679 }
1680
1681 uint32_t
1682 EngineControl::get_output_latency() const
1683 {
1684         return (uint32_t) output_latency_adjustment.get_value();
1685 }
1686
1687 string
1688 EngineControl::get_backend () const
1689 {
1690         return backend_combo.get_active_text ();
1691 }
1692
1693 string
1694 EngineControl::get_driver () const
1695 {
1696         if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
1697                 return driver_combo.get_active_text ();
1698         } else {
1699                 return "";
1700         }
1701 }
1702
1703 string
1704 EngineControl::get_device_name () const
1705 {
1706         return device_combo.get_active_text ();
1707 }
1708
1709 void
1710 EngineControl::control_app_button_clicked ()
1711 {
1712         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1713
1714         if (!backend) {
1715                 return;
1716         }
1717
1718         backend->launch_control_app ();
1719 }
1720
1721 void
1722 EngineControl::manage_control_app_sensitivity ()
1723 {
1724         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1725
1726         if (!backend) {
1727                 return;
1728         }
1729
1730         string appname = backend->control_app_name();
1731
1732         if (appname.empty()) {
1733                 control_app_button.set_sensitive (false);
1734         } else {
1735                 control_app_button.set_sensitive (true);
1736         }
1737 }
1738
1739 void
1740 EngineControl::set_desired_sample_rate (uint32_t sr)
1741 {
1742         _desired_sample_rate = sr;
1743         device_changed ();
1744 }
1745
1746 void
1747 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
1748 {
1749         if (page_num == 0) {
1750                 cancel_button->set_sensitive (true);
1751                 ok_button->set_sensitive (true);
1752                 apply_button->set_sensitive (true);
1753                 _measure_midi.reset();
1754         } else {
1755                 cancel_button->set_sensitive (false);
1756                 ok_button->set_sensitive (false);
1757                 apply_button->set_sensitive (false);
1758         }
1759
1760         if (page_num == midi_tab) {
1761                 /* MIDI tab */
1762                 refresh_midi_display ();
1763         }
1764
1765         if (page_num == latency_tab) {
1766                 /* latency tab */
1767
1768                 if (ARDOUR::AudioEngine::instance()->running()) {
1769                         // TODO - mark as 'stopped for latency
1770                         ARDOUR_UI::instance()->disconnect_from_engine ();
1771                 }
1772
1773                 {
1774                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1775
1776                         /* save any existing latency values */
1777
1778                         uint32_t il = (uint32_t) input_latency.get_value ();
1779                         uint32_t ol = (uint32_t) input_latency.get_value ();
1780
1781                         /* reset to zero so that our new test instance
1782                            will be clean of any existing latency measures.
1783
1784                            NB. this should really be done by the backend
1785                            when stated for latency measurement.
1786                         */
1787
1788                         input_latency.set_value (0);
1789                         output_latency.set_value (0);
1790
1791                         push_state_to_backend (false);
1792
1793                         /* reset control */
1794
1795                         input_latency.set_value (il);
1796                         output_latency.set_value (ol);
1797
1798                 }
1799                 // This should be done in push_state_to_backend()
1800                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
1801                         disable_latency_tab ();
1802                 }
1803
1804                 enable_latency_tab ();
1805
1806         } else {
1807                 if (lm_running) {
1808                         ARDOUR::AudioEngine::instance()->stop_latency_detection();
1809                 }
1810         }
1811 }
1812
1813 /* latency measurement */
1814
1815 bool
1816 EngineControl::check_audio_latency_measurement ()
1817 {
1818         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1819
1820         if (mtdm->resolve () < 0) {
1821                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1822                 return true;
1823         }
1824
1825         if (mtdm->err () > 0.3) {
1826                 mtdm->invert ();
1827                 mtdm->resolve ();
1828         }
1829
1830         char buf[256];
1831         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1832
1833         if (sample_rate == 0) {
1834                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1835                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1836                 return false;
1837         }
1838
1839         int frames_total = mtdm->del();
1840         int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1841
1842         snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
1843                         _("Detected roundtrip latency: "),
1844                         frames_total, frames_total * 1000.0f/sample_rate,
1845                         _("Systemic latency: "),
1846                         extra, extra * 1000.0f/sample_rate);
1847
1848         bool solid = true;
1849
1850         if (mtdm->err () > 0.2) {
1851                 strcat (buf, " ");
1852                 strcat (buf, _("(signal detection error)"));
1853                 solid = false;
1854         }
1855
1856         if (mtdm->inv ()) {
1857                 strcat (buf, " ");
1858                 strcat (buf, _("(inverted - bad wiring)"));
1859                 solid = false;
1860         }
1861
1862         if (solid) {
1863                 end_latency_detection ();
1864                 lm_use_button.set_sensitive (true);
1865                 have_lm_results = true;
1866         }
1867
1868         lm_results.set_markup (string_compose (results_markup, buf));
1869
1870         return true;
1871 }
1872
1873 bool
1874 EngineControl::check_midi_latency_measurement ()
1875 {
1876         ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1877
1878         if (!mididm->have_signal () || mididm->latency () == 0) {
1879                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1880                 return true;
1881         }
1882
1883         char buf[256];
1884         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1885
1886         if (sample_rate == 0) {
1887                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1888                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1889                 return false;
1890         }
1891
1892         ARDOUR::framecnt_t frames_total = mididm->latency();
1893         ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1894         snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
1895                         _("Detected roundtrip latency: "),
1896                         frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
1897                         _("Systemic latency: "),
1898                         extra, extra * 1000.0f / sample_rate);
1899
1900         bool solid = true;
1901
1902         if (!mididm->ok ()) {
1903                 strcat (buf, " ");
1904                 strcat (buf, _("(averaging)"));
1905                 solid = false;
1906         }
1907
1908         if (mididm->deviation () > 50.0) {
1909                 strcat (buf, " ");
1910                 strcat (buf, _("(too large jitter)"));
1911                 solid = false;
1912         } else if (mididm->deviation () > 10.0) {
1913                 strcat (buf, " ");
1914                 strcat (buf, _("(large jitter)"));
1915         }
1916
1917         if (solid) {
1918                 end_latency_detection ();
1919                 lm_use_button.set_sensitive (true);
1920                 have_lm_results = true;
1921         }
1922
1923         lm_results.set_markup (string_compose (results_markup, buf));
1924
1925         return true;
1926 }
1927
1928 void
1929 EngineControl::start_latency_detection ()
1930 {
1931         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
1932         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
1933
1934         if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
1935                 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
1936                 if (_measure_midi) {
1937                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
1938                 } else {
1939                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
1940                 }
1941                 lm_measure_label.set_text (_("Cancel"));
1942                 have_lm_results = false;
1943                 lm_use_button.set_sensitive (false);
1944                 lm_input_channel_combo.set_sensitive (false);
1945                 lm_output_channel_combo.set_sensitive (false);
1946                 lm_running = true;
1947         }
1948
1949         lm_back_button_signal.disconnect();
1950         if (_measure_midi) {
1951                 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
1952         } else {
1953                 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
1954         }
1955 }
1956
1957 void
1958 EngineControl::end_latency_detection ()
1959 {
1960         latency_timeout.disconnect ();
1961         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1962         lm_measure_label.set_text (_("Measure"));
1963         if (!have_lm_results) {
1964                 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
1965         } else {
1966                 lm_use_button.set_sensitive (false);
1967         }
1968         lm_input_channel_combo.set_sensitive (true);
1969         lm_output_channel_combo.set_sensitive (true);
1970         lm_running = false;
1971 }
1972
1973 void
1974 EngineControl::latency_button_clicked ()
1975 {
1976         if (!lm_running) {
1977                 start_latency_detection ();
1978         } else {
1979                 end_latency_detection ();
1980         }
1981 }
1982
1983 void
1984 EngineControl::use_latency_button_clicked ()
1985 {
1986         if (_measure_midi) {
1987                 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1988                 if (!mididm) {
1989                         return;
1990                 }
1991                 ARDOUR::framecnt_t frames_total = mididm->latency();
1992                 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1993                 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
1994                 _measure_midi->input_latency = one_way;
1995                 _measure_midi->output_latency = one_way;
1996                 notebook.set_current_page (midi_tab);
1997         } else {
1998                 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1999
2000                 if (!mtdm) {
2001                         return;
2002                 }
2003
2004                 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2005                 one_way = std::max (0., one_way);
2006
2007                 input_latency_adjustment.set_value (one_way);
2008                 output_latency_adjustment.set_value (one_way);
2009
2010                 /* back to settings page */
2011                 notebook.set_current_page (0);
2012 }
2013         }
2014
2015
2016 bool
2017 EngineControl::on_delete_event (GdkEventAny* ev)
2018 {
2019         if (notebook.get_current_page() == 2) {
2020                 /* currently on latency tab - be sure to clean up */
2021                 end_latency_detection ();
2022         }
2023         return ArdourDialog::on_delete_event (ev);
2024 }
2025
2026 void
2027 EngineControl::engine_running ()
2028 {
2029         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2030         assert (backend);
2031
2032         buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size()));
2033         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2034
2035         buffer_size_combo.set_sensitive (true);
2036         sample_rate_combo.set_sensitive (true);
2037
2038         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2039
2040         started_at_least_once = true;
2041 }
2042
2043 void
2044 EngineControl::engine_stopped ()
2045 {
2046         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2047         assert (backend);
2048
2049         buffer_size_combo.set_sensitive (false);
2050         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2051
2052         sample_rate_combo.set_sensitive (true);
2053         buffer_size_combo.set_sensitive (true);
2054 }
2055
2056 void
2057 EngineControl::connect_disconnect_click()
2058 {
2059         if (ARDOUR::AudioEngine::instance()->running()) {
2060                 ARDOUR_UI::instance()->disconnect_from_engine ();
2061         } else {
2062                 ARDOUR_UI::instance()->reconnect_to_engine ();
2063         }
2064 }
2065
2066 void
2067 EngineControl::calibrate_audio_latency ()
2068 {
2069         _measure_midi.reset();
2070         notebook.set_current_page (latency_tab);
2071 }
2072
2073 void
2074 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2075 {
2076         _measure_midi = s;
2077         notebook.set_current_page (latency_tab);
2078 }
2079
2080 void
2081 EngineControl::configure_midi_devices ()
2082 {
2083         notebook.set_current_page (midi_tab);
2084 }