a5accc6e9bb64958cc2c0fc2baa7114eec8eeffb
[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
1072         bool existing = true;
1073         State* state = get_saved_state_for_currently_displayed_backend_and_device ();
1074
1075         if (!state) {
1076                 existing = false;
1077                 state = new State;
1078         }
1079
1080         store_state (*state);
1081
1082         if (!existing) {
1083                 states.push_back (*state);
1084         }
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                         states.push_back (state);
1295                 }
1296         }
1297
1298         /* now see if there was an active state and switch the setup to it */
1299
1300         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1301
1302                 if ((*i).active) {
1303                         ignore_changes++;
1304                         backend_combo.set_active_text ((*i).backend);
1305                         driver_combo.set_active_text ((*i).driver);
1306                         device_combo.set_active_text ((*i).device);
1307                         sample_rate_combo.set_active_text (rate_as_string ((*i).sample_rate));
1308                         buffer_size_combo.set_active_text (bufsize_as_string ((*i).buffer_size));
1309                         input_latency.set_value ((*i).input_latency);
1310                         output_latency.set_value ((*i).output_latency);
1311                         midi_option_combo.set_active_text ((*i).midi_option);
1312                         ignore_changes--;
1313                         break;
1314                 }
1315         }
1316 }
1317
1318 int
1319 EngineControl::push_state_to_backend (bool start)
1320 {
1321         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1322
1323         if (!backend) {
1324                 return 0;
1325         }
1326
1327         /* figure out what is going to change */
1328
1329         bool restart_required = false;
1330         bool was_running = ARDOUR::AudioEngine::instance()->running();
1331         bool change_driver = false;
1332         bool change_device = false;
1333         bool change_rate = false;
1334         bool change_bufsize = false;
1335         bool change_latency = false;
1336         bool change_channels = false;
1337         bool change_midi = false;
1338
1339         uint32_t ochan = get_output_channels ();
1340         uint32_t ichan = get_input_channels ();
1341
1342         if (_have_control) {
1343
1344                 if (started_at_least_once) {
1345
1346                         /* we can control the backend */
1347
1348                         if (backend->requires_driver_selection()) {
1349                                 if (get_driver() != backend->driver_name()) {
1350                                         change_driver = true;
1351                                 }
1352                         }
1353
1354                         if (get_device_name() != backend->device_name()) {
1355                                 change_device = true;
1356                         }
1357
1358                         if (get_rate() != backend->sample_rate()) {
1359                                 change_rate = true;
1360                         }
1361
1362                         if (get_buffer_size() != backend->buffer_size()) {
1363                                 change_bufsize = true;
1364                         }
1365
1366                         if (get_midi_option() != backend->midi_option()) {
1367                                 change_midi = true;
1368                         }
1369
1370                         /* zero-requested channels means "all available" */
1371
1372                         if (ichan == 0) {
1373                                 ichan = backend->input_channels();
1374                         }
1375
1376                         if (ochan == 0) {
1377                                 ochan = backend->output_channels();
1378                         }
1379
1380                         if (ichan != backend->input_channels()) {
1381                                 change_channels = true;
1382                         }
1383
1384                         if (ochan != backend->output_channels()) {
1385                                 change_channels = true;
1386                         }
1387
1388                         if (get_input_latency() != backend->systemic_input_latency() ||
1389                                         get_output_latency() != backend->systemic_output_latency()) {
1390                                 change_latency = true;
1391                         }
1392                 } else {
1393                         /* backend never started, so we have to force a group
1394                            of settings.
1395                          */
1396                         change_device = true;
1397                         if (backend->requires_driver_selection()) {
1398                                 change_driver = true;
1399                         }
1400                         change_rate = true;
1401                         change_bufsize = true;
1402                         change_channels = true;
1403                         change_latency = true;
1404                         change_midi = true;
1405                 }
1406
1407         } else {
1408
1409                 /* we have no control over the backend, meaning that we can
1410                  * only possibly change sample rate and buffer size.
1411                  */
1412
1413
1414                 if (get_rate() != backend->sample_rate()) {
1415                         change_bufsize = true;
1416                 }
1417
1418                 if (get_buffer_size() != backend->buffer_size()) {
1419                         change_bufsize = true;
1420                 }
1421         }
1422
1423         if (!_have_control) {
1424
1425                 /* We do not have control over the backend, so the best we can
1426                  * do is try to change the sample rate and/or bufsize and get
1427                  * out of here.
1428                  */
1429
1430                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1431                         return 1;
1432                 }
1433
1434                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1435                         return 1;
1436                 }
1437
1438                 if (change_rate) {
1439                         backend->set_sample_rate (get_rate());
1440                 }
1441
1442                 if (change_bufsize) {
1443                         backend->set_buffer_size (get_buffer_size());
1444                 }
1445
1446                 if (start) {
1447                         if (ARDOUR::AudioEngine::instance()->start ()) {
1448                                 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1449                                 return -1;
1450                         }
1451                 }
1452
1453                 post_push ();
1454
1455                 return 0;
1456         }
1457
1458         /* determine if we need to stop the backend before changing parameters */
1459
1460         if (change_driver || change_device || change_channels || change_latency ||
1461                         (change_rate && !backend->can_change_sample_rate_when_running()) ||
1462                         change_midi ||
1463                         (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1464                 restart_required = true;
1465         } else {
1466                 restart_required = false;
1467         }
1468
1469         if (was_running) {
1470
1471                 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1472                         /* no changes in any parameters that absolutely require a
1473                          * restart, so check those that might be changeable without a
1474                          * restart
1475                          */
1476
1477                         if (change_rate && !backend->can_change_sample_rate_when_running()) {
1478                                 /* can't do this while running ... */
1479                                 restart_required = true;
1480                         }
1481
1482                         if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1483                                 /* can't do this while running ... */
1484                                 restart_required = true;
1485                         }
1486                 }
1487         }
1488
1489         if (was_running) {
1490                 if (restart_required) {
1491                         if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1492                                 return -1;
1493                         }
1494                 }
1495         }
1496
1497
1498         if (change_driver && backend->set_driver (get_driver())) {
1499                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1500                 return -1;
1501         }
1502         if (change_device && backend->set_device_name (get_device_name())) {
1503                 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1504                 return -1;
1505         }
1506         if (change_rate && backend->set_sample_rate (get_rate())) {
1507                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1508                 return -1;
1509         }
1510         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1511                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1512                 return -1;
1513         }
1514
1515         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1516                 if (backend->set_input_channels (get_input_channels())) {
1517                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1518                         return -1;
1519                 }
1520                 if (backend->set_output_channels (get_output_channels())) {
1521                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1522                         return -1;
1523                 }
1524         }
1525         if (change_latency) {
1526                 if (backend->set_systemic_input_latency (get_input_latency())) {
1527                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1528                         return -1;
1529                 }
1530                 if (backend->set_systemic_output_latency (get_output_latency())) {
1531                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1532                         return -1;
1533                 }
1534         }
1535
1536         if (change_midi) {
1537                 backend->set_midi_option (get_midi_option());
1538         }
1539
1540         if (1 /* TODO */) {
1541                 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1542                         if (_measure_midi) {
1543                                 if (*p == _measure_midi) {
1544                                         backend->set_midi_device_enabled ((*p)->name, true);
1545                                 } else {
1546                                         backend->set_midi_device_enabled ((*p)->name, false);
1547                                 }
1548                                 continue;
1549                         }
1550                         backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
1551                         if (backend->can_set_systemic_midi_latencies()) {
1552                                 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
1553                                 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
1554                         }
1555                 }
1556         }
1557
1558         if (start || (was_running && restart_required)) {
1559                 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
1560                         return -1;
1561                 }
1562         }
1563
1564         post_push ();
1565
1566         return 0;
1567 }
1568
1569 void
1570 EngineControl::post_push ()
1571 {
1572         /* get a pointer to the current state object, creating one if
1573          * necessary
1574          */
1575
1576         if (_have_control) {
1577                 State* state = get_saved_state_for_currently_displayed_backend_and_device ();
1578
1579                 if (!state) {
1580                         state = save_state ();
1581                         assert (state);
1582                 }
1583
1584                 /* all off */
1585
1586                 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1587                         (*i).active = false;
1588                 }
1589
1590                 /* mark this one active (to be used next time the dialog is
1591                  * shown)
1592                  */
1593
1594                 state->active = true;
1595
1596                 manage_control_app_sensitivity ();
1597         }
1598
1599         /* schedule a redisplay of MIDI ports */
1600         //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
1601 }
1602
1603
1604 float
1605 EngineControl::get_rate () const
1606 {
1607         float r = atof (sample_rate_combo.get_active_text ());
1608         /* the string may have been translated with an abbreviation for
1609          * thousands, so use a crude heuristic to fix this.
1610          */
1611         if (r < 1000.0) {
1612                 r *= 1000.0;
1613         }
1614         return r;
1615 }
1616
1617
1618 uint32_t
1619 EngineControl::get_buffer_size () const
1620 {
1621         string txt = buffer_size_combo.get_active_text ();
1622         uint32_t samples;
1623
1624         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
1625                 throw exception ();
1626         }
1627
1628         return samples;
1629 }
1630
1631 string
1632 EngineControl::get_midi_option () const
1633 {
1634         return midi_option_combo.get_active_text();
1635 }
1636
1637 uint32_t
1638 EngineControl::get_input_channels() const
1639 {
1640         return (uint32_t) input_channels_adjustment.get_value();
1641 }
1642
1643 uint32_t
1644 EngineControl::get_output_channels() const
1645 {
1646         return (uint32_t) output_channels_adjustment.get_value();
1647 }
1648
1649 uint32_t
1650 EngineControl::get_input_latency() const
1651 {
1652         return (uint32_t) input_latency_adjustment.get_value();
1653 }
1654
1655 uint32_t
1656 EngineControl::get_output_latency() const
1657 {
1658         return (uint32_t) output_latency_adjustment.get_value();
1659 }
1660
1661 string
1662 EngineControl::get_backend () const
1663 {
1664         return backend_combo.get_active_text ();
1665 }
1666
1667 string
1668 EngineControl::get_driver () const
1669 {
1670         return driver_combo.get_active_text ();
1671 }
1672
1673 string
1674 EngineControl::get_device_name () const
1675 {
1676         return device_combo.get_active_text ();
1677 }
1678
1679 void
1680 EngineControl::control_app_button_clicked ()
1681 {
1682         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1683
1684         if (!backend) {
1685                 return;
1686         }
1687
1688         backend->launch_control_app ();
1689 }
1690
1691 void
1692 EngineControl::manage_control_app_sensitivity ()
1693 {
1694         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1695
1696         if (!backend) {
1697                 return;
1698         }
1699
1700         string appname = backend->control_app_name();
1701
1702         if (appname.empty()) {
1703                 control_app_button.set_sensitive (false);
1704         } else {
1705                 control_app_button.set_sensitive (true);
1706         }
1707 }
1708
1709 void
1710 EngineControl::set_desired_sample_rate (uint32_t sr)
1711 {
1712         _desired_sample_rate = sr;
1713         device_changed ();
1714 }
1715
1716 void
1717 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
1718 {
1719         if (page_num == 0) {
1720                 cancel_button->set_sensitive (true);
1721                 ok_button->set_sensitive (true);
1722                 apply_button->set_sensitive (true);
1723                 _measure_midi.reset();
1724         } else {
1725                 cancel_button->set_sensitive (false);
1726                 ok_button->set_sensitive (false);
1727                 apply_button->set_sensitive (false);
1728         }
1729
1730         if (page_num == midi_tab) {
1731                 /* MIDI tab */
1732                 refresh_midi_display ();
1733         }
1734
1735         if (page_num == latency_tab) {
1736                 /* latency tab */
1737
1738                 if (ARDOUR::AudioEngine::instance()->running()) {
1739                         // TODO - mark as 'stopped for latency
1740                         ARDOUR_UI::instance()->disconnect_from_engine ();
1741                 }
1742
1743                 {
1744                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1745
1746                         /* save any existing latency values */
1747
1748                         uint32_t il = (uint32_t) input_latency.get_value ();
1749                         uint32_t ol = (uint32_t) input_latency.get_value ();
1750
1751                         /* reset to zero so that our new test instance
1752                            will be clean of any existing latency measures.
1753
1754                            NB. this should really be done by the backend
1755                            when stated for latency measurement.
1756                         */
1757
1758                         input_latency.set_value (0);
1759                         output_latency.set_value (0);
1760
1761                         push_state_to_backend (false);
1762
1763                         /* reset control */
1764
1765                         input_latency.set_value (il);
1766                         output_latency.set_value (ol);
1767
1768                 }
1769                 // This should be done in push_state_to_backend()
1770                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
1771                         disable_latency_tab ();
1772                 }
1773
1774                 enable_latency_tab ();
1775
1776         } else {
1777                 if (lm_running) {
1778                         ARDOUR::AudioEngine::instance()->stop_latency_detection();
1779                 }
1780         }
1781 }
1782
1783 /* latency measurement */
1784
1785 bool
1786 EngineControl::check_audio_latency_measurement ()
1787 {
1788         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1789
1790         if (mtdm->resolve () < 0) {
1791                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1792                 return true;
1793         }
1794
1795         if (mtdm->err () > 0.3) {
1796                 mtdm->invert ();
1797                 mtdm->resolve ();
1798         }
1799
1800         char buf[256];
1801         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1802
1803         if (sample_rate == 0) {
1804                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1805                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1806                 return false;
1807         }
1808
1809         int frames_total = mtdm->del();
1810         int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1811
1812         snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
1813                         _("Detected roundtrip latency: "),
1814                         frames_total, frames_total * 1000.0f/sample_rate,
1815                         _("Systemic latency: "),
1816                         extra, extra * 1000.0f/sample_rate);
1817
1818         bool solid = true;
1819
1820         if (mtdm->err () > 0.2) {
1821                 strcat (buf, " ");
1822                 strcat (buf, _("(signal detection error)"));
1823                 solid = false;
1824         }
1825
1826         if (mtdm->inv ()) {
1827                 strcat (buf, " ");
1828                 strcat (buf, _("(inverted - bad wiring)"));
1829                 solid = false;
1830         }
1831
1832         if (solid) {
1833                 end_latency_detection ();
1834                 lm_use_button.set_sensitive (true);
1835                 have_lm_results = true;
1836         }
1837
1838         lm_results.set_markup (string_compose (results_markup, buf));
1839
1840         return true;
1841 }
1842
1843 bool
1844 EngineControl::check_midi_latency_measurement ()
1845 {
1846         ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1847
1848         if (!mididm->have_signal () || mididm->latency () == 0) {
1849                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1850                 return true;
1851         }
1852
1853         char buf[256];
1854         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1855
1856         if (sample_rate == 0) {
1857                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1858                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1859                 return false;
1860         }
1861
1862         ARDOUR::framecnt_t frames_total = mididm->latency();
1863         ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1864         snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
1865                         _("Detected roundtrip latency: "),
1866                         frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
1867                         _("Systemic latency: "),
1868                         extra, extra * 1000.0f / sample_rate);
1869
1870         bool solid = true;
1871
1872         if (!mididm->ok ()) {
1873                 strcat (buf, " ");
1874                 strcat (buf, _("(averaging)"));
1875                 solid = false;
1876         }
1877
1878         if (mididm->deviation () > 50.0) {
1879                 strcat (buf, " ");
1880                 strcat (buf, _("(too large jitter)"));
1881                 solid = false;
1882         } else if (mididm->deviation () > 10.0) {
1883                 strcat (buf, " ");
1884                 strcat (buf, _("(large jitter)"));
1885         }
1886
1887         if (solid) {
1888                 end_latency_detection ();
1889                 lm_use_button.set_sensitive (true);
1890                 have_lm_results = true;
1891         }
1892
1893         lm_results.set_markup (string_compose (results_markup, buf));
1894
1895         return true;
1896 }
1897
1898 void
1899 EngineControl::start_latency_detection ()
1900 {
1901         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
1902         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
1903
1904         if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
1905                 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
1906                 if (_measure_midi) {
1907                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
1908                 } else {
1909                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
1910                 }
1911                 lm_measure_label.set_text (_("Cancel"));
1912                 have_lm_results = false;
1913                 lm_use_button.set_sensitive (false);
1914                 lm_input_channel_combo.set_sensitive (false);
1915                 lm_output_channel_combo.set_sensitive (false);
1916                 lm_running = true;
1917         }
1918
1919         lm_back_button_signal.disconnect();
1920         if (_measure_midi) {
1921                 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
1922         } else {
1923                 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
1924         }
1925 }
1926
1927 void
1928 EngineControl::end_latency_detection ()
1929 {
1930         latency_timeout.disconnect ();
1931         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1932         lm_measure_label.set_text (_("Measure"));
1933         if (!have_lm_results) {
1934                 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
1935         } else {
1936                 lm_use_button.set_sensitive (false);
1937         }
1938         lm_input_channel_combo.set_sensitive (true);
1939         lm_output_channel_combo.set_sensitive (true);
1940         lm_running = false;
1941 }
1942
1943 void
1944 EngineControl::latency_button_clicked ()
1945 {
1946         if (!lm_running) {
1947                 start_latency_detection ();
1948         } else {
1949                 end_latency_detection ();
1950         }
1951 }
1952
1953 void
1954 EngineControl::use_latency_button_clicked ()
1955 {
1956         if (_measure_midi) {
1957                 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1958                 if (!mididm) {
1959                         return;
1960                 }
1961                 ARDOUR::framecnt_t frames_total = mididm->latency();
1962                 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1963                 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
1964                 _measure_midi->input_latency = one_way;
1965                 _measure_midi->output_latency = one_way;
1966                 notebook.set_current_page (midi_tab);
1967         } else {
1968                 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1969
1970                 if (!mtdm) {
1971                         return;
1972                 }
1973
1974                 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
1975                 one_way = std::max (0., one_way);
1976
1977                 input_latency_adjustment.set_value (one_way);
1978                 output_latency_adjustment.set_value (one_way);
1979
1980                 /* back to settings page */
1981                 notebook.set_current_page (0);
1982 }
1983         }
1984
1985
1986 bool
1987 EngineControl::on_delete_event (GdkEventAny* ev)
1988 {
1989         if (notebook.get_current_page() == 2) {
1990                 /* currently on latency tab - be sure to clean up */
1991                 end_latency_detection ();
1992         }
1993         return ArdourDialog::on_delete_event (ev);
1994 }
1995
1996 void
1997 EngineControl::engine_running ()
1998 {
1999         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2000         assert (backend);
2001
2002         buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size()));
2003         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2004
2005         buffer_size_combo.set_sensitive (true);
2006         sample_rate_combo.set_sensitive (true);
2007
2008         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2009
2010         started_at_least_once = true;
2011 }
2012
2013 void
2014 EngineControl::engine_stopped ()
2015 {
2016         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2017         assert (backend);
2018
2019         buffer_size_combo.set_sensitive (false);
2020         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2021
2022         sample_rate_combo.set_sensitive (true);
2023         buffer_size_combo.set_sensitive (true);
2024 }
2025
2026 void
2027 EngineControl::connect_disconnect_click()
2028 {
2029         if (ARDOUR::AudioEngine::instance()->running()) {
2030                 ARDOUR_UI::instance()->disconnect_from_engine ();
2031         } else {
2032                 ARDOUR_UI::instance()->reconnect_to_engine ();
2033         }
2034 }
2035
2036 void
2037 EngineControl::calibrate_audio_latency ()
2038 {
2039         _measure_midi.reset();
2040         notebook.set_current_page (latency_tab);
2041 }
2042
2043 void
2044 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2045 {
2046         _measure_midi = s;
2047         notebook.set_current_page (latency_tab);
2048 }
2049
2050 void
2051 EngineControl::configure_midi_devices ()
2052 {
2053         notebook.set_current_page (midi_tab);
2054 }