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