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