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