purge states of Audio-backends that are N/A
[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         // purge states of backend that are not available in this built
1341         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1342         vector<std::string> backend_names;
1343
1344         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1345                 backend_names.push_back((*i)->name);
1346         }
1347         for (StateList::iterator i = states.begin(); i != states.end();) {
1348                 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1349                         i = states.erase(i);
1350                 } else {
1351                         ++i;
1352                 }
1353         }
1354
1355         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1356
1357                 if ((*i)->active) {
1358                         ignore_changes++;
1359                         backend_combo.set_active_text ((*i)->backend);
1360                         driver_combo.set_active_text ((*i)->driver);
1361                         device_combo.set_active_text ((*i)->device);
1362                         sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1363                         buffer_size_combo.set_active_text (bufsize_as_string ((*i)->buffer_size));
1364                         input_latency.set_value ((*i)->input_latency);
1365                         output_latency.set_value ((*i)->output_latency);
1366                         midi_option_combo.set_active_text ((*i)->midi_option);
1367                         ignore_changes--;
1368                         break;
1369                 }
1370         }
1371 }
1372
1373 int
1374 EngineControl::push_state_to_backend (bool start)
1375 {
1376         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1377
1378         if (!backend) {
1379                 return 0;
1380         }
1381
1382         /* figure out what is going to change */
1383
1384         bool restart_required = false;
1385         bool was_running = ARDOUR::AudioEngine::instance()->running();
1386         bool change_driver = false;
1387         bool change_device = false;
1388         bool change_rate = false;
1389         bool change_bufsize = false;
1390         bool change_latency = false;
1391         bool change_channels = false;
1392         bool change_midi = false;
1393
1394         uint32_t ochan = get_output_channels ();
1395         uint32_t ichan = get_input_channels ();
1396
1397         if (_have_control) {
1398
1399                 if (started_at_least_once) {
1400
1401                         /* we can control the backend */
1402
1403                         if (backend->requires_driver_selection()) {
1404                                 if (get_driver() != backend->driver_name()) {
1405                                         change_driver = true;
1406                                 }
1407                         }
1408
1409                         if (get_device_name() != backend->device_name()) {
1410                                 change_device = true;
1411                         }
1412
1413                         if (get_rate() != backend->sample_rate()) {
1414                                 change_rate = true;
1415                         }
1416
1417                         if (get_buffer_size() != backend->buffer_size()) {
1418                                 change_bufsize = true;
1419                         }
1420
1421                         if (get_midi_option() != backend->midi_option()) {
1422                                 change_midi = true;
1423                         }
1424
1425                         /* zero-requested channels means "all available" */
1426
1427                         if (ichan == 0) {
1428                                 ichan = backend->input_channels();
1429                         }
1430
1431                         if (ochan == 0) {
1432                                 ochan = backend->output_channels();
1433                         }
1434
1435                         if (ichan != backend->input_channels()) {
1436                                 change_channels = true;
1437                         }
1438
1439                         if (ochan != backend->output_channels()) {
1440                                 change_channels = true;
1441                         }
1442
1443                         if (get_input_latency() != backend->systemic_input_latency() ||
1444                                         get_output_latency() != backend->systemic_output_latency()) {
1445                                 change_latency = true;
1446                         }
1447                 } else {
1448                         /* backend never started, so we have to force a group
1449                            of settings.
1450                          */
1451                         change_device = true;
1452                         if (backend->requires_driver_selection()) {
1453                                 change_driver = true;
1454                         }
1455                         change_rate = true;
1456                         change_bufsize = true;
1457                         change_channels = true;
1458                         change_latency = true;
1459                         change_midi = true;
1460                 }
1461
1462         } else {
1463
1464                 /* we have no control over the backend, meaning that we can
1465                  * only possibly change sample rate and buffer size.
1466                  */
1467
1468
1469                 if (get_rate() != backend->sample_rate()) {
1470                         change_bufsize = true;
1471                 }
1472
1473                 if (get_buffer_size() != backend->buffer_size()) {
1474                         change_bufsize = true;
1475                 }
1476         }
1477
1478         if (!_have_control) {
1479
1480                 /* We do not have control over the backend, so the best we can
1481                  * do is try to change the sample rate and/or bufsize and get
1482                  * out of here.
1483                  */
1484
1485                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1486                         return 1;
1487                 }
1488
1489                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1490                         return 1;
1491                 }
1492
1493                 if (change_rate) {
1494                         backend->set_sample_rate (get_rate());
1495                 }
1496
1497                 if (change_bufsize) {
1498                         backend->set_buffer_size (get_buffer_size());
1499                 }
1500
1501                 if (start) {
1502                         if (ARDOUR::AudioEngine::instance()->start ()) {
1503                                 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1504                                 return -1;
1505                         }
1506                 }
1507
1508                 post_push ();
1509
1510                 return 0;
1511         }
1512
1513         /* determine if we need to stop the backend before changing parameters */
1514
1515         if (change_driver || change_device || change_channels || change_latency ||
1516                         (change_rate && !backend->can_change_sample_rate_when_running()) ||
1517                         change_midi ||
1518                         (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1519                 restart_required = true;
1520         } else {
1521                 restart_required = false;
1522         }
1523
1524         if (was_running) {
1525
1526                 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1527                         /* no changes in any parameters that absolutely require a
1528                          * restart, so check those that might be changeable without a
1529                          * restart
1530                          */
1531
1532                         if (change_rate && !backend->can_change_sample_rate_when_running()) {
1533                                 /* can't do this while running ... */
1534                                 restart_required = true;
1535                         }
1536
1537                         if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1538                                 /* can't do this while running ... */
1539                                 restart_required = true;
1540                         }
1541                 }
1542         }
1543
1544         if (was_running) {
1545                 if (restart_required) {
1546                         if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1547                                 return -1;
1548                         }
1549                 }
1550         }
1551
1552
1553         if (change_driver && backend->set_driver (get_driver())) {
1554                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1555                 return -1;
1556         }
1557         if (change_device && backend->set_device_name (get_device_name())) {
1558                 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1559                 return -1;
1560         }
1561         if (change_rate && backend->set_sample_rate (get_rate())) {
1562                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1563                 return -1;
1564         }
1565         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1566                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1567                 return -1;
1568         }
1569
1570         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1571                 if (backend->set_input_channels (get_input_channels())) {
1572                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1573                         return -1;
1574                 }
1575                 if (backend->set_output_channels (get_output_channels())) {
1576                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1577                         return -1;
1578                 }
1579         }
1580         if (change_latency) {
1581                 if (backend->set_systemic_input_latency (get_input_latency())) {
1582                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1583                         return -1;
1584                 }
1585                 if (backend->set_systemic_output_latency (get_output_latency())) {
1586                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1587                         return -1;
1588                 }
1589         }
1590
1591         if (change_midi) {
1592                 backend->set_midi_option (get_midi_option());
1593         }
1594
1595         if (1 /* TODO */) {
1596                 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1597                         if (_measure_midi) {
1598                                 if (*p == _measure_midi) {
1599                                         backend->set_midi_device_enabled ((*p)->name, true);
1600                                 } else {
1601                                         backend->set_midi_device_enabled ((*p)->name, false);
1602                                 }
1603                                 continue;
1604                         }
1605                         backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
1606                         if (backend->can_set_systemic_midi_latencies()) {
1607                                 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
1608                                 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
1609                         }
1610                 }
1611         }
1612
1613         if (start || (was_running && restart_required)) {
1614                 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
1615                         return -1;
1616                 }
1617         }
1618
1619         post_push ();
1620
1621         return 0;
1622 }
1623
1624 void
1625 EngineControl::post_push ()
1626 {
1627         /* get a pointer to the current state object, creating one if
1628          * necessary
1629          */
1630
1631         State state = get_saved_state_for_currently_displayed_backend_and_device ();
1632
1633         if (!state) {
1634                 state = save_state ();
1635                 assert (state);
1636         }
1637
1638         /* all off */
1639
1640         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1641                 (*i)->active = false;
1642         }
1643
1644         /* mark this one active (to be used next time the dialog is
1645          * shown)
1646          */
1647
1648         state->active = true;
1649
1650         if (_have_control) { // XXX
1651                 manage_control_app_sensitivity ();
1652         }
1653
1654         /* schedule a redisplay of MIDI ports */
1655         //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
1656 }
1657
1658
1659 float
1660 EngineControl::get_rate () const
1661 {
1662         float r = atof (sample_rate_combo.get_active_text ());
1663         /* the string may have been translated with an abbreviation for
1664          * thousands, so use a crude heuristic to fix this.
1665          */
1666         if (r < 1000.0) {
1667                 r *= 1000.0;
1668         }
1669         return r;
1670 }
1671
1672
1673 uint32_t
1674 EngineControl::get_buffer_size () const
1675 {
1676         string txt = buffer_size_combo.get_active_text ();
1677         uint32_t samples;
1678
1679         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
1680                 throw exception ();
1681         }
1682
1683         return samples;
1684 }
1685
1686 string
1687 EngineControl::get_midi_option () const
1688 {
1689         return midi_option_combo.get_active_text();
1690 }
1691
1692 uint32_t
1693 EngineControl::get_input_channels() const
1694 {
1695         return (uint32_t) input_channels_adjustment.get_value();
1696 }
1697
1698 uint32_t
1699 EngineControl::get_output_channels() const
1700 {
1701         return (uint32_t) output_channels_adjustment.get_value();
1702 }
1703
1704 uint32_t
1705 EngineControl::get_input_latency() const
1706 {
1707         return (uint32_t) input_latency_adjustment.get_value();
1708 }
1709
1710 uint32_t
1711 EngineControl::get_output_latency() const
1712 {
1713         return (uint32_t) output_latency_adjustment.get_value();
1714 }
1715
1716 string
1717 EngineControl::get_backend () const
1718 {
1719         return backend_combo.get_active_text ();
1720 }
1721
1722 string
1723 EngineControl::get_driver () const
1724 {
1725         if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
1726                 return driver_combo.get_active_text ();
1727         } else {
1728                 return "";
1729         }
1730 }
1731
1732 string
1733 EngineControl::get_device_name () const
1734 {
1735         return device_combo.get_active_text ();
1736 }
1737
1738 void
1739 EngineControl::control_app_button_clicked ()
1740 {
1741         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1742
1743         if (!backend) {
1744                 return;
1745         }
1746
1747         backend->launch_control_app ();
1748 }
1749
1750 void
1751 EngineControl::manage_control_app_sensitivity ()
1752 {
1753         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1754
1755         if (!backend) {
1756                 return;
1757         }
1758
1759         string appname = backend->control_app_name();
1760
1761         if (appname.empty()) {
1762                 control_app_button.set_sensitive (false);
1763         } else {
1764                 control_app_button.set_sensitive (true);
1765         }
1766 }
1767
1768 void
1769 EngineControl::set_desired_sample_rate (uint32_t sr)
1770 {
1771         _desired_sample_rate = sr;
1772         device_changed ();
1773 }
1774
1775 void
1776 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
1777 {
1778         if (page_num == 0) {
1779                 cancel_button->set_sensitive (true);
1780                 ok_button->set_sensitive (true);
1781                 apply_button->set_sensitive (true);
1782                 _measure_midi.reset();
1783         } else {
1784                 cancel_button->set_sensitive (false);
1785                 ok_button->set_sensitive (false);
1786                 apply_button->set_sensitive (false);
1787         }
1788
1789         if (page_num == midi_tab) {
1790                 /* MIDI tab */
1791                 refresh_midi_display ();
1792         }
1793
1794         if (page_num == latency_tab) {
1795                 /* latency tab */
1796
1797                 if (ARDOUR::AudioEngine::instance()->running()) {
1798                         // TODO - mark as 'stopped for latency
1799                         ARDOUR_UI::instance()->disconnect_from_engine ();
1800                 }
1801
1802                 {
1803                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1804
1805                         /* save any existing latency values */
1806
1807                         uint32_t il = (uint32_t) input_latency.get_value ();
1808                         uint32_t ol = (uint32_t) input_latency.get_value ();
1809
1810                         /* reset to zero so that our new test instance
1811                            will be clean of any existing latency measures.
1812
1813                            NB. this should really be done by the backend
1814                            when stated for latency measurement.
1815                         */
1816
1817                         input_latency.set_value (0);
1818                         output_latency.set_value (0);
1819
1820                         push_state_to_backend (false);
1821
1822                         /* reset control */
1823
1824                         input_latency.set_value (il);
1825                         output_latency.set_value (ol);
1826
1827                 }
1828                 // This should be done in push_state_to_backend()
1829                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
1830                         disable_latency_tab ();
1831                 }
1832
1833                 enable_latency_tab ();
1834
1835         } else {
1836                 if (lm_running) {
1837                         end_latency_detection ();
1838                         ARDOUR::AudioEngine::instance()->stop_latency_detection();
1839                 }
1840         }
1841 }
1842
1843 /* latency measurement */
1844
1845 bool
1846 EngineControl::check_audio_latency_measurement ()
1847 {
1848         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1849
1850         if (mtdm->resolve () < 0) {
1851                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1852                 return true;
1853         }
1854
1855         if (mtdm->err () > 0.3) {
1856                 mtdm->invert ();
1857                 mtdm->resolve ();
1858         }
1859
1860         char buf[256];
1861         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1862
1863         if (sample_rate == 0) {
1864                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1865                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1866                 return false;
1867         }
1868
1869         int frames_total = mtdm->del();
1870         int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1871
1872         snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
1873                         _("Detected roundtrip latency: "),
1874                         frames_total, frames_total * 1000.0f/sample_rate,
1875                         _("Systemic latency: "),
1876                         extra, extra * 1000.0f/sample_rate);
1877
1878         bool solid = true;
1879
1880         if (mtdm->err () > 0.2) {
1881                 strcat (buf, " ");
1882                 strcat (buf, _("(signal detection error)"));
1883                 solid = false;
1884         }
1885
1886         if (mtdm->inv ()) {
1887                 strcat (buf, " ");
1888                 strcat (buf, _("(inverted - bad wiring)"));
1889                 solid = false;
1890         }
1891
1892         if (solid) {
1893                 have_lm_results = true;
1894                 end_latency_detection ();
1895                 lm_use_button.set_sensitive (true);
1896                 return false;
1897         }
1898
1899         lm_results.set_markup (string_compose (results_markup, buf));
1900
1901         return true;
1902 }
1903
1904 bool
1905 EngineControl::check_midi_latency_measurement ()
1906 {
1907         ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1908
1909         if (!mididm->have_signal () || mididm->latency () == 0) {
1910                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1911                 return true;
1912         }
1913
1914         char buf[256];
1915         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1916
1917         if (sample_rate == 0) {
1918                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1919                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1920                 return false;
1921         }
1922
1923         ARDOUR::framecnt_t frames_total = mididm->latency();
1924         ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1925         snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
1926                         _("Detected roundtrip latency: "),
1927                         frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
1928                         _("Systemic latency: "),
1929                         extra, extra * 1000.0f / sample_rate);
1930
1931         bool solid = true;
1932
1933         if (!mididm->ok ()) {
1934                 strcat (buf, " ");
1935                 strcat (buf, _("(averaging)"));
1936                 solid = false;
1937         }
1938
1939         if (mididm->deviation () > 50.0) {
1940                 strcat (buf, " ");
1941                 strcat (buf, _("(too large jitter)"));
1942                 solid = false;
1943         } else if (mididm->deviation () > 10.0) {
1944                 strcat (buf, " ");
1945                 strcat (buf, _("(large jitter)"));
1946         }
1947
1948         if (solid) {
1949                 have_lm_results = true;
1950                 end_latency_detection ();
1951                 lm_use_button.set_sensitive (true);
1952                 return false;
1953         } else if (mididm->processed () > 400) {
1954                 have_lm_results = false;
1955                 end_latency_detection ();
1956                 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
1957                 return false;
1958         }
1959
1960         lm_results.set_markup (string_compose (results_markup, buf));
1961
1962         return true;
1963 }
1964
1965 void
1966 EngineControl::start_latency_detection ()
1967 {
1968         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
1969         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
1970
1971         if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
1972                 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
1973                 if (_measure_midi) {
1974                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
1975                 } else {
1976                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
1977                 }
1978                 lm_measure_label.set_text (_("Cancel"));
1979                 have_lm_results = false;
1980                 lm_use_button.set_sensitive (false);
1981                 lm_input_channel_combo.set_sensitive (false);
1982                 lm_output_channel_combo.set_sensitive (false);
1983                 lm_running = true;
1984         }
1985 }
1986
1987 void
1988 EngineControl::end_latency_detection ()
1989 {
1990         latency_timeout.disconnect ();
1991         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1992         lm_measure_label.set_text (_("Measure"));
1993         if (!have_lm_results) {
1994                 lm_use_button.set_sensitive (false);
1995         }
1996         lm_input_channel_combo.set_sensitive (true);
1997         lm_output_channel_combo.set_sensitive (true);
1998         lm_running = false;
1999 }
2000
2001 void
2002 EngineControl::latency_button_clicked ()
2003 {
2004         if (!lm_running) {
2005                 start_latency_detection ();
2006         } else {
2007                 end_latency_detection ();
2008         }
2009 }
2010
2011 void
2012 EngineControl::use_latency_button_clicked ()
2013 {
2014         if (_measure_midi) {
2015                 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2016                 if (!mididm) {
2017                         return;
2018                 }
2019                 ARDOUR::framecnt_t frames_total = mididm->latency();
2020                 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2021                 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2022                 _measure_midi->input_latency = one_way;
2023                 _measure_midi->output_latency = one_way;
2024                 notebook.set_current_page (midi_tab);
2025         } else {
2026                 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2027
2028                 if (!mtdm) {
2029                         return;
2030                 }
2031
2032                 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2033                 one_way = std::max (0., one_way);
2034
2035                 input_latency_adjustment.set_value (one_way);
2036                 output_latency_adjustment.set_value (one_way);
2037
2038                 /* back to settings page */
2039                 notebook.set_current_page (0);
2040 }
2041         }
2042
2043
2044 bool
2045 EngineControl::on_delete_event (GdkEventAny* ev)
2046 {
2047         if (notebook.get_current_page() == 2) {
2048                 /* currently on latency tab - be sure to clean up */
2049                 end_latency_detection ();
2050         }
2051         return ArdourDialog::on_delete_event (ev);
2052 }
2053
2054 void
2055 EngineControl::engine_running ()
2056 {
2057         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2058         assert (backend);
2059
2060         buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size()));
2061         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2062
2063         buffer_size_combo.set_sensitive (true);
2064         sample_rate_combo.set_sensitive (true);
2065
2066         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2067
2068         started_at_least_once = true;
2069 }
2070
2071 void
2072 EngineControl::engine_stopped ()
2073 {
2074         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2075         assert (backend);
2076
2077         buffer_size_combo.set_sensitive (false);
2078         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2079
2080         sample_rate_combo.set_sensitive (true);
2081         buffer_size_combo.set_sensitive (true);
2082 }
2083
2084 void
2085 EngineControl::connect_disconnect_click()
2086 {
2087         if (ARDOUR::AudioEngine::instance()->running()) {
2088                 ARDOUR_UI::instance()->disconnect_from_engine ();
2089         } else {
2090                 ARDOUR_UI::instance()->reconnect_to_engine ();
2091         }
2092 }
2093
2094 void
2095 EngineControl::calibrate_audio_latency ()
2096 {
2097         _measure_midi.reset ();
2098         have_lm_results = false;
2099         lm_use_button.set_sensitive (false);
2100         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2101         notebook.set_current_page (latency_tab);
2102 }
2103
2104 void
2105 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2106 {
2107         _measure_midi = s;
2108         have_lm_results = false;
2109         lm_use_button.set_sensitive (false);
2110         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2111         notebook.set_current_page (latency_tab);
2112 }
2113
2114 void
2115 EngineControl::configure_midi_devices ()
2116 {
2117         notebook.set_current_page (midi_tab);
2118 }