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