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