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