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