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