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