Add "Refresh Devices" button in Audio Setup dialog for backends that support it
[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 "debug.h"
53 #include "ardour_ui.h"
54 #include "engine_dialog.h"
55 #include "gui_thread.h"
56 #include "utils.h"
57 #include "i18n.h"
58
59 using namespace std;
60 using namespace Gtk;
61 using namespace Gtkmm2ext;
62 using namespace PBD;
63 using namespace Glib;
64 using namespace ARDOUR_UI_UTILS;
65
66 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
67
68 static const unsigned int midi_tab = 2;
69 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
70
71 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
72
73 EngineControl::EngineControl ()
74         : ArdourDialog (_("Audio/MIDI Setup"))
75         , engine_status ("")
76         , basic_packer (9, 4)
77         , input_latency_adjustment (0, 0, 99999, 1)
78         , input_latency (input_latency_adjustment)
79         , output_latency_adjustment (0, 0, 99999, 1)
80         , output_latency (output_latency_adjustment)
81         , input_channels_adjustment (0, 0, 256, 1)
82         , input_channels (input_channels_adjustment)
83         , output_channels_adjustment (0, 0, 256, 1)
84         , output_channels (output_channels_adjustment)
85         , ports_adjustment (128, 8, 1024, 1, 16)
86         , ports_spinner (ports_adjustment)
87         , control_app_button (_("Device Control Panel"))
88         , midi_devices_button (_("Midi Device Setup"))
89         , start_stop_button (_("Stop"))
90         , update_devices_button (_("Refresh Devices"))
91         , lm_measure_label (_("Measure"))
92         , lm_use_button (_("Use results"))
93         , lm_back_button (_("Back to settings ... (ignore results)"))
94         , lm_button_audio (_("Calibrate Audio"))
95         , lm_table (12, 3)
96         , have_lm_results (false)
97         , lm_running (false)
98         , midi_back_button (_("Back to settings"))
99         , ignore_changes (0)
100         , _desired_sample_rate (0)
101         , started_at_least_once (false)
102         , queue_device_changed (false)
103         , block_signals(0)
104 {
105         using namespace Notebook_Helpers;
106         vector<string> backend_names;
107         Label* label;
108         AttachOptions xopt = AttachOptions (FILL|EXPAND);
109         int row;
110
111         set_name (X_("AudioMIDISetup"));
112
113         /* the backend combo is the one thing that is ALWAYS visible */
114
115         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
116
117         if (backends.empty()) {
118                 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));
119                 msg.run ();
120                 throw failed_constructor ();
121         }
122
123         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
124                 backend_names.push_back ((*b)->name);
125         }
126
127         set_popdown_strings (backend_combo, backend_names);
128
129         /* setup basic packing characteristics for the table used on the main
130          * tab of the notebook
131          */
132
133         basic_packer.set_spacings (6);
134         basic_packer.set_border_width (12);
135         basic_packer.set_homogeneous (false);
136
137         /* pack it in */
138
139         basic_hbox.pack_start (basic_packer, false, false);
140
141         /* latency measurement tab */
142
143         lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
144
145         row = 0;
146         lm_table.set_row_spacings (12);
147         lm_table.set_col_spacings (6);
148         lm_table.set_homogeneous (false);
149
150         lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
151         row++;
152
153         lm_preamble.set_width_chars (60);
154         lm_preamble.set_line_wrap (true);
155         lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
156
157         lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
158         row++;
159
160         Gtk::Label* preamble;
161         preamble = manage (new Label);
162         preamble->set_width_chars (60);
163         preamble->set_line_wrap (true);
164         preamble->set_markup (_("Select two channels below and connect them using a cable."));
165
166         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
167         row++;
168
169         label = manage (new Label (_("Output channel")));
170         lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
171
172         Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
173         misc_align->add (lm_output_channel_combo);
174         lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
175         ++row;
176
177         label = manage (new Label (_("Input channel")));
178         lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
179
180         misc_align = manage (new Alignment (0.0, 0.5));
181         misc_align->add (lm_input_channel_combo);
182         lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
183         ++row;
184
185         lm_measure_label.set_padding (10, 10);
186         lm_measure_button.add (lm_measure_label);
187         lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
188         lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
189         lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
190
191         lm_use_button.set_sensitive (false);
192
193         /* Increase the default spacing around the labels of these three
194          * buttons
195          */
196
197         Gtk::Misc* l;
198
199         if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
200                 l->set_padding (10, 10);
201         }
202
203         if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
204                 l->set_padding (10, 10);
205         }
206
207         preamble = manage (new Label);
208         preamble->set_width_chars (60);
209         preamble->set_line_wrap (true);
210         preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
211         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
212         row++;
213
214         preamble = manage (new Label);
215         preamble->set_width_chars (60);
216         preamble->set_line_wrap (true);
217         preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
218         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
219
220         ++row; // skip a row in the table
221         ++row; // skip a row in the table
222
223         lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
224
225         ++row; // skip a row in the table
226         ++row; // skip a row in the table
227
228         lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
229         lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
230         lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
231
232         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
233
234         lm_vbox.set_border_width (12);
235         lm_vbox.pack_start (lm_table, false, false);
236
237         midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
238
239         /* pack it all up */
240
241         notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
242         notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
243         notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
244         notebook.set_border_width (12);
245
246         notebook.set_show_tabs (false);
247         notebook.show_all ();
248
249         notebook.set_name ("SettingsNotebook");
250
251         /* packup the notebook */
252
253         get_vbox()->set_border_width (12);
254         get_vbox()->pack_start (notebook);
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         control_app_button.set_name ("generic button");
270         control_app_button.set_can_focus(true);
271         manage_control_app_sensitivity ();
272
273         start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
274         start_stop_button.set_sensitive (false);
275         start_stop_button.set_name ("generic button");
276         start_stop_button.set_can_focus(true);
277
278         update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
279         update_devices_button.set_sensitive (false);
280         update_devices_button.set_name ("generic button");
281         update_devices_button.set_can_focus(true);
282
283         cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
284         ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
285
286         /* Pick up any existing audio setup configuration, if appropriate */
287
288         XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
289
290         ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
291         ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
292         ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
293         ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
294
295         if (audio_setup) {
296                 if (!set_state (*audio_setup)) {
297                         set_default_state ();
298                 }
299         } else {
300                 set_default_state ();
301         }
302
303         connect_changed_signals ();
304
305         notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
306
307         connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
308         connect_disconnect_button.set_no_show_all();
309
310 }
311
312 void
313 EngineControl::connect_changed_signals ()
314 {
315         backend_combo_connection = backend_combo.signal_changed ().connect (
316             sigc::mem_fun (*this, &EngineControl::backend_changed));
317         driver_combo_connection = driver_combo.signal_changed ().connect (
318             sigc::mem_fun (*this, &EngineControl::driver_changed));
319         sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
320             sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
321         buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
322             sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
323         device_combo_connection = device_combo.signal_changed ().connect (
324             sigc::mem_fun (*this, &EngineControl::device_changed));
325         midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
326             sigc::mem_fun (*this, &EngineControl::midi_option_changed));
327
328         input_device_combo_connection = input_device_combo.signal_changed ().connect (
329             sigc::mem_fun (*this, &EngineControl::input_device_changed));
330         output_device_combo_connection = output_device_combo.signal_changed ().connect (
331             sigc::mem_fun (*this, &EngineControl::output_device_changed));
332
333         input_latency_connection = input_latency.signal_changed ().connect (
334             sigc::mem_fun (*this, &EngineControl::parameter_changed));
335         output_latency_connection = output_latency.signal_changed ().connect (
336             sigc::mem_fun (*this, &EngineControl::parameter_changed));
337         input_channels_connection = input_channels.signal_changed ().connect (
338             sigc::mem_fun (*this, &EngineControl::parameter_changed));
339         output_channels_connection = output_channels.signal_changed ().connect (
340             sigc::mem_fun (*this, &EngineControl::parameter_changed));
341 }
342
343 void
344 EngineControl::block_changed_signals ()
345 {
346         if (block_signals++ == 0) {
347                 DEBUG_ECONTROL ("Blocking changed signals");
348                 backend_combo_connection.block ();
349                 driver_combo_connection.block ();
350                 sample_rate_combo_connection.block ();
351                 buffer_size_combo_connection.block ();
352                 device_combo_connection.block ();
353                 input_device_combo_connection.block ();
354                 output_device_combo_connection.block ();
355                 midi_option_combo_connection.block ();
356                 input_latency_connection.block ();
357                 output_latency_connection.block ();
358                 input_channels_connection.block ();
359                 output_channels_connection.block ();
360         }
361 }
362
363 void
364 EngineControl::unblock_changed_signals ()
365 {
366         if (--block_signals == 0) {
367                 DEBUG_ECONTROL ("Unblocking changed signals");
368                 backend_combo_connection.unblock ();
369                 driver_combo_connection.unblock ();
370                 sample_rate_combo_connection.unblock ();
371                 buffer_size_combo_connection.unblock ();
372                 device_combo_connection.unblock ();
373                 input_device_combo_connection.unblock ();
374                 output_device_combo_connection.unblock ();
375                 midi_option_combo_connection.unblock ();
376                 input_latency_connection.unblock ();
377                 output_latency_connection.unblock ();
378                 input_channels_connection.unblock ();
379                 output_channels_connection.unblock ();
380         }
381 }
382
383 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
384                                              const std::string& reason)
385     : ec (engine_control)
386     , m_reason (reason)
387 {
388         DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
389         ec.block_changed_signals ();
390 }
391
392 EngineControl::SignalBlocker::~SignalBlocker ()
393 {
394         DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
395         ec.unblock_changed_signals ();
396 }
397
398 void
399 EngineControl::on_show ()
400 {
401         ArdourDialog::on_show ();
402         if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
403                 // re-check _have_control (jackd running) see #6041
404                 backend_changed ();
405         }
406         device_changed ();
407         ok_button->grab_focus();
408 }
409
410 void
411 EngineControl::on_response (int response_id)
412 {
413         ArdourDialog::on_response (response_id);
414
415         switch (response_id) {
416                 case RESPONSE_OK:
417 #ifdef PLATFORM_WINDOWS
418                         // For some reason we don't understand, 'hide()'
419                         // needs to get called first in Windows
420                         hide ();
421
422                         // But if there's no session open, this can produce
423                         // a long gap when nothing appears to be happening.
424                         // Let's show the splash image while we're waiting.
425                         if ( !ARDOUR_COMMAND_LINE::no_splash ) {
426                                 if ( ARDOUR_UI::instance() ) {
427                                         if ( !ARDOUR_UI::instance()->session_loaded ) {
428                                                 ARDOUR_UI::instance()->show_splash();
429                                         }
430                                 }
431                         }
432                         push_state_to_backend (true);
433                         break;
434 #else
435                         push_state_to_backend (true);
436                         hide ();
437                         break;
438 #endif
439                 case RESPONSE_DELETE_EVENT:
440                         {
441                                 GdkEventButton ev;
442                                 ev.type = GDK_BUTTON_PRESS;
443                                 ev.button = 1;
444                                 on_delete_event ((GdkEventAny*) &ev);
445                                 break;
446                         }
447                 default:
448                         hide ();
449         }
450 }
451
452 void
453 EngineControl::build_notebook ()
454 {
455         Label* label;
456         AttachOptions xopt = AttachOptions (FILL|EXPAND);
457
458         /* clear the table */
459
460         Gtkmm2ext::container_clear (basic_vbox);
461         Gtkmm2ext::container_clear (basic_packer);
462
463         if (control_app_button.get_parent()) {
464                 control_app_button.get_parent()->remove (control_app_button);
465         }
466
467         label = manage (left_aligned_label (_("Audio System:")));
468         basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
469         basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
470
471         basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
472         engine_status.show();
473
474         basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
475         basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
476
477         lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
478         lm_button_audio.set_name ("generic button");
479         lm_button_audio.set_can_focus(true);
480
481         if (_have_control) {
482                 build_full_control_notebook ();
483         } else {
484                 build_no_control_notebook ();
485         }
486
487         basic_vbox.pack_start (basic_hbox, false, false);
488
489         {
490                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
491                 basic_vbox.show_all ();
492         }
493 }
494
495 void
496 EngineControl::build_full_control_notebook ()
497 {
498         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
499         assert (backend);
500
501         using namespace Notebook_Helpers;
502         Label* label;
503         vector<string> strings;
504         AttachOptions xopt = AttachOptions (FILL|EXPAND);
505         int row = 1; // row zero == backend combo
506
507         /* start packing it up */
508
509         if (backend->requires_driver_selection()) {
510                 label = manage (left_aligned_label (_("Driver:")));
511                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
512                 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
513                 row++;
514         }
515
516         if (backend->use_separate_input_and_output_devices()) {
517                 label = manage (left_aligned_label (_("Input Device:")));
518                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
519                 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
520                 row++;
521                 label = manage (left_aligned_label (_("Output Device:")));
522                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
523                 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
524                 row++;
525                 // reset so it isn't used in state comparisons
526                 device_combo.set_active_text ("");
527         } else {
528                 label = manage (left_aligned_label (_("Device:")));
529                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
530                 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
531                 row++;
532                 // reset these so they don't get used in state comparisons
533                 input_device_combo.set_active_text ("");
534                 output_device_combo.set_active_text ("");
535         }
536
537         label = manage (left_aligned_label (_("Sample rate:")));
538         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
539         basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
540         row++;
541
542
543         label = manage (left_aligned_label (_("Buffer size:")));
544         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
545         basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
546         buffer_size_duration_label.set_alignment (0.0); /* left-align */
547         basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
548
549         /* button spans 2 rows */
550
551         basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
552         row++;
553
554         input_channels.set_name ("InputChannels");
555         input_channels.set_flags (Gtk::CAN_FOCUS);
556         input_channels.set_digits (0);
557         input_channels.set_wrap (false);
558         output_channels.set_editable (true);
559
560         if (!ARDOUR::Profile->get_mixbus()) {
561                 label = manage (left_aligned_label (_("Input Channels:")));
562                 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
563                 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
564                 ++row;
565         }
566         
567         output_channels.set_name ("OutputChannels");
568         output_channels.set_flags (Gtk::CAN_FOCUS);
569         output_channels.set_digits (0);
570         output_channels.set_wrap (false);
571         output_channels.set_editable (true);
572
573         if (!ARDOUR::Profile->get_mixbus()) {
574                 label = manage (left_aligned_label (_("Output Channels:")));
575                 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
576                 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
577                 ++row;
578         }
579         
580         input_latency.set_name ("InputLatency");
581         input_latency.set_flags (Gtk::CAN_FOCUS);
582         input_latency.set_digits (0);
583         input_latency.set_wrap (false);
584         input_latency.set_editable (true);
585
586         label = manage (left_aligned_label (_("Hardware input latency:")));
587         basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
588         basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
589         label = manage (left_aligned_label (_("samples")));
590         basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
591         ++row;
592
593         output_latency.set_name ("OutputLatency");
594         output_latency.set_flags (Gtk::CAN_FOCUS);
595         output_latency.set_digits (0);
596         output_latency.set_wrap (false);
597         output_latency.set_editable (true);
598
599         label = manage (left_aligned_label (_("Hardware output latency:")));
600         basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
601         basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
602         label = manage (left_aligned_label (_("samples")));
603         basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
604
605         /* button spans 2 rows */
606
607         basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
608         ++row;
609
610         label = manage (left_aligned_label (_("MIDI System:")));
611         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
612         basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
613 #if ! defined __APPLE__  && ! defined PLATFORM_WINDOWS // => linux, YAY
614         /* Currently the only backend with dedicated Midi setup is ALSA.
615          * lot of people complain that this is greyed out
616          * "I can't use MIDI, the setup is greyed out"
617          */
618         basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
619 #endif
620         row++;
621 }
622
623 void
624 EngineControl::build_no_control_notebook ()
625 {
626         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
627         assert (backend);
628
629         using namespace Notebook_Helpers;
630         Label* label;
631         vector<string> strings;
632         AttachOptions xopt = AttachOptions (FILL|EXPAND);
633         int row = 1; // row zero == backend combo
634         const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
635
636         label = manage (new Label);
637         label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
638         basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
639         row++;
640
641         if (backend->can_change_sample_rate_when_running()) {
642                 label = manage (left_aligned_label (_("Sample rate:")));
643                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
644                 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
645                 row++;
646         }
647
648         if (backend->can_change_buffer_size_when_running()) {
649                 label = manage (left_aligned_label (_("Buffer size:")));
650                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
651                 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
652                 buffer_size_duration_label.set_alignment (0.0); /* left-align */
653                 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
654                 row++;
655         }
656
657         basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
658         row++;
659 }
660
661 EngineControl::~EngineControl ()
662 {
663         ignore_changes = true;
664 }
665
666 void
667 EngineControl::disable_latency_tab ()
668 {
669         vector<string> empty;
670         set_popdown_strings (lm_output_channel_combo, empty);
671         set_popdown_strings (lm_input_channel_combo, empty);
672         lm_measure_button.set_sensitive (false);
673         lm_use_button.set_sensitive (false);
674 }
675
676 void
677 EngineControl::enable_latency_tab ()
678 {
679         vector<string> outputs;
680         vector<string> inputs;
681
682         ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
683         ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
684         ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
685
686         if (!ARDOUR::AudioEngine::instance()->running()) {
687                 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
688                 notebook.set_current_page (0);
689                 msg.run ();
690                 return;
691         }
692         else if (inputs.empty() || outputs.empty()) {
693                 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
694                 notebook.set_current_page (0);
695                 msg.run ();
696                 return;
697         }
698
699         lm_back_button_signal.disconnect();
700         if (_measure_midi) {
701                 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
702                 lm_preamble.hide ();
703         } else {
704                 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
705                 lm_preamble.show ();
706         }
707
708         set_popdown_strings (lm_output_channel_combo, outputs);
709         lm_output_channel_combo.set_active_text (outputs.front());
710         lm_output_channel_combo.set_sensitive (true);
711
712         set_popdown_strings (lm_input_channel_combo, inputs);
713         lm_input_channel_combo.set_active_text (inputs.front());
714         lm_input_channel_combo.set_sensitive (true);
715
716         lm_measure_button.set_sensitive (true);
717 }
718
719 void
720 EngineControl::setup_midi_tab_for_backend ()
721 {
722         string backend = backend_combo.get_active_text ();
723
724         Gtkmm2ext::container_clear (midi_vbox);
725
726         midi_vbox.set_border_width (12);
727         midi_device_table.set_border_width (12);
728
729         if (backend == "JACK") {
730                 setup_midi_tab_for_jack ();
731         }
732
733         midi_vbox.pack_start (midi_device_table, true, true);
734         midi_vbox.pack_start (midi_back_button, false, false);
735         midi_vbox.show_all ();
736 }
737
738 void
739 EngineControl::update_sensitivity ()
740 {
741         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
742         if (!backend) {
743                 ok_button->set_sensitive (false);
744                 start_stop_button.set_sensitive (false);
745                 return;
746         }
747
748         bool valid = true;
749         size_t devices_available = 0;
750
751         if (backend->use_separate_input_and_output_devices ()) {
752                 devices_available += get_popdown_string_count (input_device_combo);
753                 devices_available += get_popdown_string_count (output_device_combo);
754         } else {
755                 devices_available += get_popdown_string_count (device_combo);
756         }
757
758         if (devices_available == 0) {
759                 valid = false;
760                 input_latency.set_sensitive (false);
761                 output_latency.set_sensitive (false);
762                 input_channels.set_sensitive (false);
763                 output_channels.set_sensitive (false);
764         } else {
765                 input_latency.set_sensitive (true);
766                 output_latency.set_sensitive (true);
767                 input_channels.set_sensitive (true);
768                 output_channels.set_sensitive (true);
769         }
770
771         if (get_popdown_string_count (buffer_size_combo) > 0) {
772                 if (!ARDOUR::AudioEngine::instance()->running()) {
773                         buffer_size_combo.set_sensitive (valid);
774                 } else if (backend->can_change_sample_rate_when_running()) {
775                         buffer_size_combo.set_sensitive (valid || !_have_control);
776                 } else {
777 #if 1
778                         /* TODO
779                          * Currently there is no way to manually stop the
780                          * engine in order to re-configure it.
781                          * This needs to remain sensitive for now.
782                          *
783                          * (it's also handy to implicily
784                          * re-start the engine)
785                          */
786                         buffer_size_combo.set_sensitive (true);
787 #else
788                         buffer_size_combo.set_sensitive (false);
789 #endif
790                 }
791         } else {
792                 buffer_size_combo.set_sensitive (false);
793                 valid = false;
794         }
795
796         if (get_popdown_string_count (sample_rate_combo) > 0) {
797                 if (!ARDOUR::AudioEngine::instance()->running()) {
798                         sample_rate_combo.set_sensitive (true);
799                 } else {
800                         sample_rate_combo.set_sensitive (false);
801                 }
802         } else {
803                 sample_rate_combo.set_sensitive (false);
804                 valid = false;
805         }
806
807         if (_have_control) {
808                 start_stop_button.set_sensitive(true);
809                 start_stop_button.show();
810                 if (ARDOUR::AudioEngine::instance()->running()) {
811                         start_stop_button.set_text("Stop");
812                         update_devices_button.set_sensitive(false);
813                 } else {
814                         if (backend->can_request_update_devices()) {
815                                 update_devices_button.show();
816                         } else {
817                                 update_devices_button.hide();
818                         }
819                         start_stop_button.set_text("Start");
820                         update_devices_button.set_sensitive(true);
821                 }
822         } else {
823                 update_devices_button.set_sensitive(false);
824                 update_devices_button.hide();
825                 start_stop_button.set_sensitive(false);
826                 start_stop_button.hide();
827         }
828
829         if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
830                 input_device_combo.set_sensitive (false);
831                 output_device_combo.set_sensitive (false);
832                 device_combo.set_sensitive (false);
833                 driver_combo.set_sensitive (false);
834         } else {
835                 input_device_combo.set_sensitive (true);
836                 output_device_combo.set_sensitive (true);
837                 device_combo.set_sensitive (true);
838                 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
839                         driver_combo.set_sensitive (true);
840                 } else {
841                         driver_combo.set_sensitive (false);
842                 }
843         }
844
845         if (valid || !_have_control) {
846                 ok_button->set_sensitive (true);
847         } else {
848                 ok_button->set_sensitive (false);
849         }
850 }
851
852 void
853 EngineControl::setup_midi_tab_for_jack ()
854 {
855 }
856
857 void
858 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
859         if (for_input) {
860                 device->input_latency = a->get_value();
861         } else {
862                 device->output_latency = a->get_value();
863         }
864 }
865
866 void
867 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
868         b->set_active (!b->get_active());
869         device->enabled = b->get_active();
870         refresh_midi_display(device->name);
871 }
872
873 void
874 EngineControl::refresh_midi_display (std::string focus)
875 {
876         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
877         assert (backend);
878
879         int row  = 0;
880         AttachOptions xopt = AttachOptions (FILL|EXPAND);
881         Gtk::Label* l;
882
883         Gtkmm2ext::container_clear (midi_device_table);
884
885         midi_device_table.set_spacings (6);
886
887         l = manage (new Label);
888         l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
889         midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
890         l->set_alignment (0.5, 0.5);
891         row++;
892         l->show ();
893
894         l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
895         midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
896         l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
897         midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
898         row++;
899         l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
900         midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
901         l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
902         midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
903         row++;
904
905         for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
906                 ArdourButton *m;
907                 Gtk::Button* b;
908                 Gtk::Adjustment *a;
909                 Gtk::SpinButton *s;
910                 bool enabled = (*p)->enabled;
911
912                 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
913                 m->set_name ("midi device");
914                 m->set_can_focus (Gtk::CAN_FOCUS);
915                 m->add_events (Gdk::BUTTON_RELEASE_MASK);
916                 m->set_active (enabled);
917                 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
918                 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
919                 if ((*p)->name == focus) {
920                         m->grab_focus();
921                 }
922
923                 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
924                 s = manage (new Gtk::SpinButton (*a));
925                 a->set_value ((*p)->input_latency);
926                 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
927                 s->set_sensitive (_can_set_midi_latencies && enabled);
928                 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
929
930                 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
931                 s = manage (new Gtk::SpinButton (*a));
932                 a->set_value ((*p)->output_latency);
933                 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
934                 s->set_sensitive (_can_set_midi_latencies && enabled);
935                 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
936
937                 b = manage (new Button (_("Calibrate")));
938                 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
939                 b->set_sensitive (_can_set_midi_latencies && enabled);
940                 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
941
942                 row++;
943         }
944 }
945
946 void
947 EngineControl::backend_changed ()
948 {
949         SignalBlocker blocker (*this, "backend_changed");
950         string backend_name = backend_combo.get_active_text();
951         boost::shared_ptr<ARDOUR::AudioBackend> backend;
952
953         if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (PROGRAM_NAME), ""))) {
954                 /* eh? setting the backend failed... how ? */
955                 /* A: stale config contains a backend that does not exist in current build */
956                 return;
957         }
958
959         DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
960
961         _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
962
963         build_notebook ();
964         setup_midi_tab_for_backend ();
965         _midi_devices.clear();
966
967         if (backend->requires_driver_selection()) {
968                 if (set_driver_popdown_strings ()) {
969                         driver_changed ();
970                 }
971         } else {
972                 /* this will change the device text which will cause a call to
973                  * device changed which will set up parameters
974                  */
975                 list_devices ();
976         }
977
978         update_midi_options ();
979
980         connect_disconnect_button.hide();
981
982         midi_option_changed();
983
984         started_at_least_once = false;
985
986         /* changing the backend implies stopping the engine
987          * ARDOUR::AudioEngine() may or may not emit this signal
988          * depending on previous engine state
989          */
990         engine_stopped (); // set "active/inactive"
991
992         if (!ignore_changes) {
993                 maybe_display_saved_state ();
994         }
995 }
996
997 void
998 EngineControl::update_midi_options ()
999 {
1000         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1001         vector<string> midi_options = backend->enumerate_midi_options();
1002
1003         if (midi_options.size() == 1) {
1004                 /* only contains the "none" option */
1005                 midi_option_combo.set_sensitive (false);
1006         } else {
1007                 if (_have_control) {
1008                         set_popdown_strings (midi_option_combo, midi_options);
1009                         midi_option_combo.set_active_text (midi_options.front());
1010                         midi_option_combo.set_sensitive (true);
1011                 } else {
1012                         midi_option_combo.set_sensitive (false);
1013                 }
1014         }
1015 }
1016
1017 bool
1018 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1019 {
1020         if (ARDOUR::Profile->get_mixbus()) {
1021                 return true;
1022         }
1023         
1024         uint32_t cnt = (uint32_t) sb->get_value();
1025         if (cnt == 0) {
1026                 sb->set_text (_("all available channels"));
1027         } else {
1028                 char buf[32];
1029                 snprintf (buf, sizeof (buf), "%d", cnt);
1030                 sb->set_text (buf);
1031         }
1032         return true;
1033 }
1034
1035 // @return true if there are drivers available
1036 bool
1037 EngineControl::set_driver_popdown_strings ()
1038 {
1039         DEBUG_ECONTROL ("set_driver_popdown_strings");
1040         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1041         vector<string> drivers = backend->enumerate_drivers();
1042
1043         if (drivers.empty ()) {
1044                 // This is an error...?
1045                 return false;
1046         }
1047
1048         string current_driver = backend->driver_name ();
1049
1050         DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1051
1052         if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1053             drivers.end ()) {
1054
1055                 current_driver = drivers.front ();
1056         }
1057
1058         set_popdown_strings (driver_combo, drivers);
1059         DEBUG_ECONTROL (
1060             string_compose ("driver_combo.set_active_text: %1", current_driver));
1061         driver_combo.set_active_text (current_driver);
1062         return true;
1063 }
1064
1065 // @return true if there are devices available
1066 bool
1067 EngineControl::set_device_popdown_strings ()
1068 {
1069         DEBUG_ECONTROL ("set_device_popdown_strings");
1070         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1071         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1072
1073         /* NOTE: Ardour currently does not display the "available" field of the
1074          * returned devices.
1075          *
1076          * Doing so would require a different GUI widget than the combo
1077          * box/popdown that we currently use, since it has no way to list
1078          * items that are not selectable. Something more like a popup menu,
1079          * which could have unselectable items, would be appropriate.
1080          */
1081
1082         vector<string> available_devices;
1083
1084         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1085                 available_devices.push_back (i->name);
1086         }
1087
1088         if (available_devices.empty ()) {
1089                 return false;
1090         }
1091
1092         string current_device = backend->device_name ();
1093
1094         // Make sure that backend->device_name () is a valid
1095         // device, the backend may not return a valid device if it hasn't
1096         // been set yet.
1097         if (std::find (available_devices.begin (),
1098                        available_devices.end (),
1099                        current_device) == available_devices.end ()) {
1100
1101                 current_device = available_devices.front ();
1102         }
1103
1104         set_popdown_strings (device_combo, available_devices);
1105         DEBUG_ECONTROL (
1106             string_compose ("set device_combo active text: %1", current_device));
1107
1108         device_combo.set_active_text (current_device);
1109         return true;
1110 }
1111
1112 // @return true if there are input devices available
1113 bool
1114 EngineControl::set_input_device_popdown_strings ()
1115 {
1116         DEBUG_ECONTROL ("set_input_device_popdown_strings");
1117         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1118         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1119
1120         vector<string> available_devices;
1121
1122         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1123                 available_devices.push_back (i->name);
1124         }
1125
1126         if (available_devices.empty()) {
1127                 return false;
1128         }
1129
1130         string current_device = backend->input_device_name ();
1131
1132         // Make sure that backend->input_device_name () is a valid
1133         // device, the backend may not return a valid device if it hasn't
1134         // been set yet.
1135         if (std::find (available_devices.begin (),
1136                        available_devices.end (),
1137                        current_device) == available_devices.end ()) {
1138
1139                 current_device = available_devices.front ();
1140         }
1141
1142         set_popdown_strings (input_device_combo, available_devices);
1143
1144         DEBUG_ECONTROL (
1145             string_compose ("set input_device_combo active text: %1", current_device));
1146         input_device_combo.set_active_text (current_device);
1147         return true;
1148 }
1149
1150 // @return true if there are output devices available
1151 bool
1152 EngineControl::set_output_device_popdown_strings ()
1153 {
1154         DEBUG_ECONTROL ("set_output_device_popdown_strings");
1155         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1156         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1157
1158         vector<string> available_devices;
1159
1160         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1161                 available_devices.push_back (i->name);
1162         }
1163
1164         if (available_devices.empty()) {
1165                 return false;
1166         }
1167
1168         string current_device = backend->output_device_name ();
1169
1170         // Make sure that backend->output_device_name () is a valid
1171         // device, the backend may not return a valid device if it hasn't
1172         // been set yet.
1173         if (std::find (available_devices.begin (),
1174                        available_devices.end (),
1175                        current_device) == available_devices.end ()) {
1176
1177                 current_device = available_devices.front ();
1178         }
1179
1180         set_popdown_strings (output_device_combo, available_devices);
1181
1182         DEBUG_ECONTROL (
1183             string_compose ("set output_device_combo active text: %1", current_device));
1184         output_device_combo.set_active_text (current_device);
1185         return true;
1186 }
1187
1188 void
1189 EngineControl::list_devices ()
1190 {
1191         DEBUG_ECONTROL ("list_devices");
1192         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1193         assert (backend);
1194
1195         /* now fill out devices, mark sample rates, buffer sizes insensitive */
1196
1197         bool devices_available = false;
1198
1199         if (backend->use_separate_input_and_output_devices ()) {
1200                 bool input_devices_available = set_input_device_popdown_strings ();
1201                 bool output_devices_available = set_output_device_popdown_strings ();
1202                 devices_available = input_devices_available || output_devices_available;
1203         } else {
1204                 devices_available = set_device_popdown_strings ();
1205         }
1206
1207         if (devices_available) {
1208                 device_changed ();
1209         } else {
1210                 device_combo.clear();
1211                 input_device_combo.clear();
1212                 output_device_combo.clear();
1213         }
1214         update_sensitivity ();
1215 }
1216
1217 void
1218 EngineControl::driver_changed ()
1219 {
1220         SignalBlocker blocker (*this, "driver_changed");
1221         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1222         assert (backend);
1223
1224         backend->set_driver (driver_combo.get_active_text());
1225         list_devices ();
1226
1227         if (!ignore_changes) {
1228                 maybe_display_saved_state ();
1229         }
1230 }
1231
1232 vector<float>
1233 EngineControl::get_sample_rates_for_all_devices ()
1234 {
1235         boost::shared_ptr<ARDOUR::AudioBackend> backend =
1236             ARDOUR::AudioEngine::instance ()->current_backend ();
1237         vector<float> all_rates;
1238
1239         if (backend->use_separate_input_and_output_devices ()) {
1240                 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1241         } else {
1242                 all_rates = backend->available_sample_rates (get_device_name ());
1243         }
1244         return all_rates;
1245 }
1246
1247 vector<float>
1248 EngineControl::get_default_sample_rates ()
1249 {
1250         vector<float> rates;
1251         rates.push_back (8000.0f);
1252         rates.push_back (16000.0f);
1253         rates.push_back (32000.0f);
1254         rates.push_back (44100.0f);
1255         rates.push_back (48000.0f);
1256         rates.push_back (88200.0f);
1257         rates.push_back (96000.0f);
1258         rates.push_back (192000.0f);
1259         rates.push_back (384000.0f);
1260         return rates;
1261 }
1262
1263 void
1264 EngineControl::set_samplerate_popdown_strings ()
1265 {
1266         DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1267         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1268         string desired;
1269         vector<float> sr;
1270         vector<string> s;
1271
1272         if (_have_control) {
1273                 sr = get_sample_rates_for_all_devices ();
1274         } else {
1275                 sr = get_default_sample_rates ();
1276         }
1277
1278         for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1279                 s.push_back (rate_as_string (*x));
1280                 if (*x == _desired_sample_rate) {
1281                         desired = s.back();
1282                 }
1283         }
1284
1285         set_popdown_strings (sample_rate_combo, s);
1286
1287         if (!s.empty()) {
1288                 if (desired.empty ()) {
1289                         float new_active_sr = backend->default_sample_rate ();
1290
1291                         if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1292                                 new_active_sr = sr.front ();
1293                         }
1294
1295                         sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1296                 } else {
1297                         sample_rate_combo.set_active_text (desired);
1298                 }
1299
1300         }
1301         update_sensitivity ();
1302 }
1303
1304 vector<uint32_t>
1305 EngineControl::get_buffer_sizes_for_all_devices ()
1306 {
1307         boost::shared_ptr<ARDOUR::AudioBackend> backend =
1308             ARDOUR::AudioEngine::instance ()->current_backend ();
1309         vector<uint32_t> all_sizes;
1310
1311         if (backend->use_separate_input_and_output_devices ()) {
1312                 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1313         } else {
1314                 all_sizes = backend->available_buffer_sizes (get_device_name ());
1315         }
1316         return all_sizes;
1317 }
1318
1319 vector<uint32_t>
1320 EngineControl::get_default_buffer_sizes ()
1321 {
1322         vector<uint32_t> sizes;
1323         sizes.push_back (8);
1324         sizes.push_back (16);
1325         sizes.push_back (32);
1326         sizes.push_back (64);
1327         sizes.push_back (128);
1328         sizes.push_back (256);
1329         sizes.push_back (512);
1330         sizes.push_back (1024);
1331         sizes.push_back (2048);
1332         sizes.push_back (4096);
1333         sizes.push_back (8192);
1334         return sizes;
1335 }
1336
1337 void
1338 EngineControl::set_buffersize_popdown_strings ()
1339 {
1340         DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1341         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1342         vector<uint32_t> bs;
1343         vector<string> s;
1344
1345         if (_have_control) {
1346                 bs = get_buffer_sizes_for_all_devices ();
1347         } else if (backend->can_change_buffer_size_when_running()) {
1348                 bs = get_default_buffer_sizes ();
1349         }
1350
1351         for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1352                 s.push_back (bufsize_as_string (*x));
1353         }
1354
1355         set_popdown_strings (buffer_size_combo, s);
1356
1357         if (!s.empty()) {
1358                 buffer_size_combo.set_active_text (s.front());
1359
1360                 uint32_t period = backend->buffer_size();
1361                 if (0 == period && backend->use_separate_input_and_output_devices ()) {
1362                         period = backend->default_buffer_size (get_input_device_name ());
1363                 }
1364                 if (0 == period && backend->use_separate_input_and_output_devices ()) {
1365                         period = backend->default_buffer_size (get_output_device_name ());
1366                 }
1367                 if (0 == period && !backend->use_separate_input_and_output_devices ()) {
1368                         period = backend->default_buffer_size (get_device_name ());
1369                 }
1370
1371                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1372                 show_buffer_duration ();
1373         }
1374         update_sensitivity ();
1375 }
1376
1377 void
1378 EngineControl::device_changed ()
1379 {
1380         SignalBlocker blocker (*this, "device_changed");
1381         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1382         assert (backend);
1383
1384         string device_name_in;
1385         string device_name_out; // only used if backend support separate I/O devices
1386
1387         if (backend->use_separate_input_and_output_devices()) {
1388                 device_name_in  = get_input_device_name ();
1389                 device_name_out = get_output_device_name ();
1390         } else {
1391                 device_name_in = get_device_name ();
1392         }
1393
1394         /* we set the backend-device to query various device related intormation.
1395          * This has the side effect that backend->device_name() will match
1396          * the device_name and  'change_device' will never be true.
1397          * so work around this by setting...
1398          */
1399         if (backend->use_separate_input_and_output_devices()) {
1400                 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1401                         queue_device_changed = true;
1402                 }
1403         } else {
1404                 if (device_name_in != backend->device_name()) {
1405                         queue_device_changed = true;
1406                 }
1407         }
1408         
1409         //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1410         if (backend->use_separate_input_and_output_devices()) {
1411                 backend->set_input_device_name (device_name_in);
1412                 backend->set_output_device_name (device_name_out);
1413         } else {
1414                 backend->set_device_name(device_name_in);
1415         }
1416
1417         {
1418                 /* don't allow programmatic change to combos to cause a
1419                    recursive call to this method.
1420                  */
1421                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1422
1423                 set_samplerate_popdown_strings ();
1424                 set_buffersize_popdown_strings ();
1425
1426                 /* TODO set min + max channel counts here */
1427
1428                 manage_control_app_sensitivity ();
1429         }
1430
1431         /* pick up any saved state for this device */
1432
1433         if (!ignore_changes) {
1434                 maybe_display_saved_state ();
1435         }
1436 }
1437
1438 void
1439 EngineControl::input_device_changed ()
1440 {
1441         DEBUG_ECONTROL ("input_device_changed");
1442         device_changed ();
1443 }
1444
1445 void
1446 EngineControl::output_device_changed ()
1447 {
1448         DEBUG_ECONTROL ("output_device_changed");
1449         device_changed ();
1450 }
1451
1452 string
1453 EngineControl::bufsize_as_string (uint32_t sz)
1454 {
1455         /* Translators: "samples" is always plural here, so no
1456            need for plural+singular forms.
1457          */
1458         char buf[64];
1459         snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1460         return buf;
1461 }
1462
1463 void
1464 EngineControl::sample_rate_changed ()
1465 {
1466         DEBUG_ECONTROL ("sample_rate_changed");
1467         /* reset the strings for buffer size to show the correct msec value
1468            (reflecting the new sample rate).
1469          */
1470
1471         show_buffer_duration ();
1472
1473 }
1474
1475 void
1476 EngineControl::buffer_size_changed ()
1477 {
1478         DEBUG_ECONTROL ("buffer_size_changed");
1479         show_buffer_duration ();
1480 }
1481
1482 void
1483 EngineControl::show_buffer_duration ()
1484 {
1485         DEBUG_ECONTROL ("show_buffer_duration");
1486         /* buffer sizes  - convert from just samples to samples + msecs for
1487          * the displayed string
1488          */
1489
1490         string bs_text = buffer_size_combo.get_active_text ();
1491         uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1492         uint32_t rate = get_rate();
1493
1494         /* Developers: note the hard-coding of a double buffered model
1495            in the (2 * samples) computation of latency. we always start
1496            the audiobackend in this configuration.
1497          */
1498         /* note to jack1 developers: ardour also always starts the engine
1499          * in async mode (no jack2 --sync option) which adds an extra cycle
1500          * of latency with jack2 (and *3 would be correct)
1501          * The value can also be wrong if jackd is started externally..
1502          *
1503          * At the time of writing the ALSA backend always uses double-buffering *2,
1504          * The Dummy backend *1, and who knows what ASIO really does :)
1505          *
1506          * So just display the period size, that's also what
1507          * ARDOUR_UI::update_sample_rate() does for the status bar.
1508          * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1509          * but still, that's the buffer period, not [round-trip] latency)
1510          */
1511         char buf[32];
1512         snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1513         buffer_size_duration_label.set_text (buf);
1514 }
1515
1516 void
1517 EngineControl::midi_option_changed ()
1518 {
1519         DEBUG_ECONTROL ("midi_option_changed");
1520         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1521         assert (backend);
1522
1523         backend->set_midi_option (get_midi_option());
1524
1525         vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1526
1527         //_midi_devices.clear(); // TODO merge with state-saved settings..
1528         _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1529         std::vector<MidiDeviceSettings> new_devices;
1530
1531         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1532                 MidiDeviceSettings mds = find_midi_device (i->name);
1533                 if (i->available && !mds) {
1534                         uint32_t input_latency = 0;
1535                         uint32_t output_latency = 0;
1536                         if (_can_set_midi_latencies) {
1537                                 input_latency = backend->systemic_midi_input_latency (i->name);
1538                                 output_latency = backend->systemic_midi_output_latency (i->name);
1539                         }
1540                         bool enabled = backend->midi_device_enabled (i->name);
1541                         MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1542                         new_devices.push_back (ptr);
1543                 } else if (i->available) {
1544                         new_devices.push_back (mds);
1545                 }
1546         }
1547         _midi_devices = new_devices;
1548
1549         if (_midi_devices.empty()) {
1550                 midi_devices_button.set_sensitive (false);
1551         } else {
1552                 midi_devices_button.set_sensitive (true);
1553         }
1554 }
1555
1556 void
1557 EngineControl::parameter_changed ()
1558 {
1559 }
1560
1561 EngineControl::State
1562 EngineControl::get_matching_state (
1563                 const string& backend,
1564                 const string& driver,
1565                 const string& device)
1566 {
1567         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1568                 if ((*i)->backend == backend &&
1569                                 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1570                 {
1571                         return (*i);
1572                 }
1573         }
1574         return State();
1575 }
1576
1577 EngineControl::State
1578 EngineControl::get_matching_state (
1579                 const string& backend,
1580                 const string& driver,
1581                 const string& input_device,
1582                 const string& output_device)
1583 {
1584         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1585                 if ((*i)->backend == backend &&
1586                                 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1587                 {
1588                         return (*i);
1589                 }
1590         }
1591         return State();
1592 }
1593
1594 EngineControl::State
1595 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1596 {
1597         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1598
1599         if (backend) {
1600                 if (backend->use_separate_input_and_output_devices ()) {
1601                         return get_matching_state (backend_combo.get_active_text(),
1602                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1603                                         input_device_combo.get_active_text(),
1604                                         output_device_combo.get_active_text());
1605                 } else {
1606                         return get_matching_state (backend_combo.get_active_text(),
1607                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1608                                         device_combo.get_active_text());
1609                 }
1610         }
1611
1612         return get_matching_state (backend_combo.get_active_text(),
1613                         string(),
1614                         device_combo.get_active_text());
1615 }
1616
1617 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1618                                        const EngineControl::State& state2)
1619 {
1620         if (state1->backend == state2->backend &&
1621                         state1->driver == state2->driver &&
1622                         state1->device == state2->device &&
1623                         state1->input_device == state2->input_device &&
1624                         state1->output_device == state2->output_device) {
1625                 return true;
1626         }
1627         return false;
1628 }
1629
1630 EngineControl::State
1631 EngineControl::save_state ()
1632 {
1633         State state;
1634
1635         if (!_have_control) {
1636                 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1637                 if (state) {
1638                         return state;
1639                 }
1640                 state.reset(new StateStruct);
1641                 state->backend = get_backend ();
1642         } else {
1643                 state.reset(new StateStruct);
1644                 store_state (state);
1645         }
1646
1647         for (StateList::iterator i = states.begin(); i != states.end();) {
1648                 if (equivalent_states (*i, state)) {
1649                         i =  states.erase(i);
1650                 } else {
1651                         ++i;
1652                 }
1653         }
1654
1655         states.push_back (state);
1656
1657         return state;
1658 }
1659
1660 void
1661 EngineControl::store_state (State state)
1662 {
1663         state->backend = get_backend ();
1664         state->driver = get_driver ();
1665         state->device = get_device_name ();
1666         state->input_device = get_input_device_name ();
1667         state->output_device = get_output_device_name ();
1668         state->sample_rate = get_rate ();
1669         state->buffer_size = get_buffer_size ();
1670         state->input_latency = get_input_latency ();
1671         state->output_latency = get_output_latency ();
1672         state->input_channels = get_input_channels ();
1673         state->output_channels = get_output_channels ();
1674         state->midi_option = get_midi_option ();
1675         state->midi_devices = _midi_devices;
1676 }
1677
1678 void
1679 EngineControl::maybe_display_saved_state ()
1680 {
1681         if (!_have_control) {
1682                 return;
1683         }
1684
1685         State state = get_saved_state_for_currently_displayed_backend_and_device ();
1686
1687         if (state) {
1688                 DEBUG_ECONTROL ("Restoring saved state");
1689                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1690
1691                 if (!_desired_sample_rate) {
1692                         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1693                 }
1694                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1695                 /* call this explicitly because we're ignoring changes to
1696                    the controls at this point.
1697                  */
1698                 show_buffer_duration ();
1699                 input_latency.set_value (state->input_latency);
1700                 output_latency.set_value (state->output_latency);
1701
1702                 if (!state->midi_option.empty()) {
1703                         midi_option_combo.set_active_text (state->midi_option);
1704                         _midi_devices = state->midi_devices;
1705                 }
1706         } else {
1707                 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1708         }
1709 }
1710
1711 XMLNode&
1712 EngineControl::get_state ()
1713 {
1714         LocaleGuard lg (X_("C"));
1715
1716         XMLNode* root = new XMLNode ("AudioMIDISetup");
1717         std::string path;
1718
1719         if (!states.empty()) {
1720                 XMLNode* state_nodes = new XMLNode ("EngineStates");
1721
1722                 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1723
1724                         XMLNode* node = new XMLNode ("State");
1725
1726                         node->add_property ("backend", (*i)->backend);
1727                         node->add_property ("driver", (*i)->driver);
1728                         node->add_property ("device", (*i)->device);
1729                         node->add_property ("input-device", (*i)->input_device);
1730                         node->add_property ("output-device", (*i)->output_device);
1731                         node->add_property ("sample-rate", (*i)->sample_rate);
1732                         node->add_property ("buffer-size", (*i)->buffer_size);
1733                         node->add_property ("input-latency", (*i)->input_latency);
1734                         node->add_property ("output-latency", (*i)->output_latency);
1735                         node->add_property ("input-channels", (*i)->input_channels);
1736                         node->add_property ("output-channels", (*i)->output_channels);
1737                         node->add_property ("active", (*i)->active ? "yes" : "no");
1738                         node->add_property ("midi-option", (*i)->midi_option);
1739
1740                         XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1741                         for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1742                                 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1743                                 midi_device_stuff->add_property (X_("name"), (*p)->name);
1744                                 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1745                                 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1746                                 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1747                                 midi_devices->add_child_nocopy (*midi_device_stuff);
1748                         }
1749                         node->add_child_nocopy (*midi_devices);
1750
1751                         state_nodes->add_child_nocopy (*node);
1752                 }
1753
1754                 root->add_child_nocopy (*state_nodes);
1755         }
1756
1757         return *root;
1758 }
1759
1760 void
1761 EngineControl::set_default_state ()
1762 {
1763         vector<string> backend_names;
1764         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1765
1766         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1767                 backend_names.push_back ((*b)->name);
1768         }
1769         backend_combo.set_active_text (backend_names.front());
1770
1771         // We could set default backends per platform etc here
1772
1773         backend_changed ();
1774 }
1775
1776 bool
1777 EngineControl::set_state (const XMLNode& root)
1778 {
1779         XMLNodeList          clist, cclist;
1780         XMLNodeConstIterator citer, cciter;
1781         XMLNode* child;
1782         XMLNode* grandchild;
1783         XMLProperty* prop = NULL;
1784
1785         fprintf (stderr, "EngineControl::set_state\n");
1786
1787         if (root.name() != "AudioMIDISetup") {
1788                 return false;
1789         }
1790
1791         clist = root.children();
1792
1793         states.clear ();
1794
1795         for (citer = clist.begin(); citer != clist.end(); ++citer) {
1796
1797                 child = *citer;
1798
1799                 if (child->name() != "EngineStates") {
1800                         continue;
1801                 }
1802
1803                 cclist = child->children();
1804
1805                 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1806                         State state (new StateStruct);
1807
1808                         grandchild = *cciter;
1809
1810                         if (grandchild->name() != "State") {
1811                                 continue;
1812                         }
1813
1814                         if ((prop = grandchild->property ("backend")) == 0) {
1815                                 continue;
1816                         }
1817                         state->backend = prop->value ();
1818
1819                         if ((prop = grandchild->property ("driver")) == 0) {
1820                                 continue;
1821                         }
1822                         state->driver = prop->value ();
1823
1824                         if ((prop = grandchild->property ("device")) == 0) {
1825                                 continue;
1826                         }
1827                         state->device = prop->value ();
1828
1829                         if ((prop = grandchild->property ("input-device")) == 0) {
1830                                 continue;
1831                         }
1832                         state->input_device = prop->value ();
1833
1834                         if ((prop = grandchild->property ("output-device")) == 0) {
1835                                 continue;
1836                         }
1837                         state->output_device = prop->value ();
1838
1839                         if ((prop = grandchild->property ("sample-rate")) == 0) {
1840                                 continue;
1841                         }
1842                         state->sample_rate = atof (prop->value ());
1843
1844                         if ((prop = grandchild->property ("buffer-size")) == 0) {
1845                                 continue;
1846                         }
1847                         state->buffer_size = atoi (prop->value ());
1848
1849                         if ((prop = grandchild->property ("input-latency")) == 0) {
1850                                 continue;
1851                         }
1852                         state->input_latency = atoi (prop->value ());
1853
1854                         if ((prop = grandchild->property ("output-latency")) == 0) {
1855                                 continue;
1856                         }
1857                         state->output_latency = atoi (prop->value ());
1858
1859                         if ((prop = grandchild->property ("input-channels")) == 0) {
1860                                 continue;
1861                         }
1862                         state->input_channels = atoi (prop->value ());
1863
1864                         if ((prop = grandchild->property ("output-channels")) == 0) {
1865                                 continue;
1866                         }
1867                         state->output_channels = atoi (prop->value ());
1868
1869                         if ((prop = grandchild->property ("active")) == 0) {
1870                                 continue;
1871                         }
1872                         state->active = string_is_affirmative (prop->value ());
1873
1874                         if ((prop = grandchild->property ("midi-option")) == 0) {
1875                                 continue;
1876                         }
1877                         state->midi_option = prop->value ();
1878
1879                         state->midi_devices.clear();
1880                         XMLNode* midinode;
1881                         if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1882                                 const XMLNodeList mnc = midinode->children();
1883                                 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1884                                         if ((*n)->property (X_("name")) == 0
1885                                                         || (*n)->property (X_("enabled")) == 0
1886                                                         || (*n)->property (X_("input-latency")) == 0
1887                                                         || (*n)->property (X_("output-latency")) == 0
1888                                                  ) {
1889                                                 continue;
1890                                         }
1891
1892                                         MidiDeviceSettings ptr (new MidiDeviceSetting(
1893                                                                 (*n)->property (X_("name"))->value (),
1894                                                                 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1895                                                                 atoi ((*n)->property (X_("input-latency"))->value ()),
1896                                                                 atoi ((*n)->property (X_("output-latency"))->value ())
1897                                                                 ));
1898                                         state->midi_devices.push_back (ptr);
1899                                 }
1900                         }
1901
1902 #if 1
1903                         /* remove accumulated duplicates (due to bug in ealier version)
1904                          * this can be removed again before release
1905                          */
1906                         for (StateList::iterator i = states.begin(); i != states.end();) {
1907                                 if ((*i)->backend == state->backend &&
1908                                                 (*i)->driver == state->driver &&
1909                                                 (*i)->device == state->device) {
1910                                         i =  states.erase(i);
1911                                 } else {
1912                                         ++i;
1913                                 }
1914                         }
1915 #endif
1916
1917                         states.push_back (state);
1918                 }
1919         }
1920
1921         /* now see if there was an active state and switch the setup to it */
1922
1923         // purge states of backend that are not available in this built
1924         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1925         vector<std::string> backend_names;
1926
1927         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1928                 backend_names.push_back((*i)->name);
1929         }
1930         for (StateList::iterator i = states.begin(); i != states.end();) {
1931                 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1932                         i = states.erase(i);
1933                 } else {
1934                         ++i;
1935                 }
1936         }
1937
1938         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1939
1940                 if ((*i)->active) {
1941                         return set_current_state (*i);
1942                 }
1943         }
1944         return false;
1945 }
1946
1947 bool
1948 EngineControl::set_current_state (const State& state)
1949 {
1950         DEBUG_ECONTROL ("set_current_state");
1951
1952         boost::shared_ptr<ARDOUR::AudioBackend> backend;
1953
1954         if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1955                   state->backend, downcase (PROGRAM_NAME), ""))) {
1956                 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1957                 // this shouldn't happen as the invalid backend names should have been
1958                 // removed from the list of states.
1959                 return false;
1960         }
1961
1962         // now reflect the change in the backend in the GUI so backend_changed will
1963         // do the right thing
1964         backend_combo.set_active_text (state->backend);
1965
1966         if (!state->driver.empty ()) {
1967                 if (!backend->requires_driver_selection ()) {
1968                         DEBUG_ECONTROL ("Backend should require driver selection");
1969                         // A backend has changed from having driver selection to not having
1970                         // it or someone has been manually editing a config file and messed
1971                         // it up
1972                         return false;
1973                 }
1974
1975                 if (backend->set_driver (state->driver) != 0) {
1976                         DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
1977                         // Driver names for a backend have changed and the name in the
1978                         // config file is now invalid or support for driver is no longer
1979                         // included in the backend
1980                         return false;
1981                 }
1982                 // no need to set the driver_combo as backend_changed will use
1983                 // backend->driver_name to set the active driver
1984         }
1985
1986         if (!state->device.empty ()) {
1987                 if (backend->set_device_name (state->device) != 0) {
1988                         DEBUG_ECONTROL (
1989                             string_compose ("Unable to set device name %1", state->device));
1990                         // device is no longer available on the system
1991                         return false;
1992                 }
1993                 // no need to set active device as it will be picked up in
1994                 // via backend_changed ()/set_device_popdown_strings
1995
1996         } else {
1997                 // backend supports separate input/output devices
1998                 if (backend->set_input_device_name (state->input_device) != 0) {
1999                         DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2000                                                         state->input_device));
2001                         // input device is no longer available on the system
2002                         return false;
2003                 }
2004
2005                 if (backend->set_output_device_name (state->output_device) != 0) {
2006                         DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2007                                                         state->input_device));
2008                         // output device is no longer available on the system
2009                         return false;
2010                 }
2011                 // no need to set active devices as it will be picked up in via
2012                 // backend_changed ()/set_*_device_popdown_strings
2013         }
2014
2015         backend_changed ();
2016
2017         // Now restore the state of the rest of the controls
2018
2019         // We don't use a SignalBlocker as set_current_state is currently only
2020         // called from set_state before any signals are connected. If at some point
2021         // a more general named state mechanism is implemented and
2022         // set_current_state is called while signals are connected then a
2023         // SignalBlocker will need to be instantiated before setting these.
2024
2025         device_combo.set_active_text (state->device);
2026         input_device_combo.set_active_text (state->input_device);
2027         output_device_combo.set_active_text (state->output_device);
2028         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2029         set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2030         input_latency.set_value (state->input_latency);
2031         output_latency.set_value (state->output_latency);
2032         midi_option_combo.set_active_text (state->midi_option);
2033         return true;
2034 }
2035
2036 int
2037 EngineControl::push_state_to_backend (bool start)
2038 {
2039         DEBUG_ECONTROL ("push_state_to_backend");
2040         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2041
2042         if (!backend) {
2043                 return 0;
2044         }
2045
2046         /* figure out what is going to change */
2047
2048         bool restart_required = false;
2049         bool was_running = ARDOUR::AudioEngine::instance()->running();
2050         bool change_driver = false;
2051         bool change_device = false;
2052         bool change_rate = false;
2053         bool change_bufsize = false;
2054         bool change_latency = false;
2055         bool change_channels = false;
2056         bool change_midi = false;
2057
2058         uint32_t ochan = get_output_channels ();
2059         uint32_t ichan = get_input_channels ();
2060
2061         if (_have_control) {
2062
2063                 if (started_at_least_once) {
2064
2065                         /* we can control the backend */
2066
2067                         if (backend->requires_driver_selection()) {
2068                                 if (get_driver() != backend->driver_name()) {
2069                                         change_driver = true;
2070                                 }
2071                         }
2072
2073                         if (backend->use_separate_input_and_output_devices()) {
2074                                 if (get_input_device_name() != backend->input_device_name()) {
2075                                         change_device = true;
2076                                 }
2077                                 if (get_output_device_name() != backend->output_device_name()) {
2078                                         change_device = true;
2079                                 }
2080                         } else {
2081                                 if (get_device_name() != backend->device_name()) {
2082                                         change_device = true;
2083                                 }
2084                         }
2085
2086                         if (queue_device_changed) {
2087                                 change_device = true;
2088                         }
2089
2090                         if (get_rate() != backend->sample_rate()) {
2091                                 change_rate = true;
2092                         }
2093
2094                         if (get_buffer_size() != backend->buffer_size()) {
2095                                 change_bufsize = true;
2096                         }
2097
2098                         if (get_midi_option() != backend->midi_option()) {
2099                                 change_midi = true;
2100                         }
2101
2102                         /* zero-requested channels means "all available" */
2103
2104                         if (ichan == 0) {
2105                                 ichan = backend->input_channels();
2106                         }
2107
2108                         if (ochan == 0) {
2109                                 ochan = backend->output_channels();
2110                         }
2111
2112                         if (ichan != backend->input_channels()) {
2113                                 change_channels = true;
2114                         }
2115
2116                         if (ochan != backend->output_channels()) {
2117                                 change_channels = true;
2118                         }
2119
2120                         if (get_input_latency() != backend->systemic_input_latency() ||
2121                                         get_output_latency() != backend->systemic_output_latency()) {
2122                                 change_latency = true;
2123                         }
2124                 } else {
2125                         /* backend never started, so we have to force a group
2126                            of settings.
2127                          */
2128                         change_device = true;
2129                         if (backend->requires_driver_selection()) {
2130                                 change_driver = true;
2131                         }
2132                         change_rate = true;
2133                         change_bufsize = true;
2134                         change_channels = true;
2135                         change_latency = true;
2136                         change_midi = true;
2137                 }
2138
2139         } else {
2140
2141                 /* we have no control over the backend, meaning that we can
2142                  * only possibly change sample rate and buffer size.
2143                  */
2144
2145
2146                 if (get_rate() != backend->sample_rate()) {
2147                         change_bufsize = true;
2148                 }
2149
2150                 if (get_buffer_size() != backend->buffer_size()) {
2151                         change_bufsize = true;
2152                 }
2153         }
2154
2155         queue_device_changed = false;
2156
2157         if (!_have_control) {
2158
2159                 /* We do not have control over the backend, so the best we can
2160                  * do is try to change the sample rate and/or bufsize and get
2161                  * out of here.
2162                  */
2163
2164                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2165                         return 1;
2166                 }
2167
2168                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2169                         return 1;
2170                 }
2171
2172                 if (change_rate) {
2173                         backend->set_sample_rate (get_rate());
2174                 }
2175
2176                 if (change_bufsize) {
2177                         backend->set_buffer_size (get_buffer_size());
2178                 }
2179
2180                 if (start) {
2181                         if (ARDOUR::AudioEngine::instance()->start ()) {
2182                                 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2183                                 return -1;
2184                         }
2185                 }
2186
2187                 post_push ();
2188
2189                 return 0;
2190         }
2191
2192         /* determine if we need to stop the backend before changing parameters */
2193
2194         if (change_driver || change_device || change_channels || change_latency ||
2195                         (change_rate && !backend->can_change_sample_rate_when_running()) ||
2196                         change_midi ||
2197                         (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2198                 restart_required = true;
2199         } else {
2200                 restart_required = false;
2201         }
2202
2203         if (was_running) {
2204
2205                 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2206                         /* no changes in any parameters that absolutely require a
2207                          * restart, so check those that might be changeable without a
2208                          * restart
2209                          */
2210
2211                         if (change_rate && !backend->can_change_sample_rate_when_running()) {
2212                                 /* can't do this while running ... */
2213                                 restart_required = true;
2214                         }
2215
2216                         if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2217                                 /* can't do this while running ... */
2218                                 restart_required = true;
2219                         }
2220                 }
2221         }
2222
2223         if (was_running) {
2224                 if (restart_required) {
2225                         if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2226                                 return -1;
2227                         }
2228                 }
2229         }
2230
2231
2232         if (change_driver && backend->set_driver (get_driver())) {
2233                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2234                 return -1;
2235         }
2236         if (backend->use_separate_input_and_output_devices()) {
2237                 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2238                         error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2239                         return -1;
2240                 }
2241                 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2242                         error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2243                         return -1;
2244                 }
2245         } else {
2246                 if (change_device && backend->set_device_name (get_device_name())) {
2247                         error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2248                         return -1;
2249                 }
2250         }
2251         if (change_rate && backend->set_sample_rate (get_rate())) {
2252                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2253                 return -1;
2254         }
2255         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2256                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2257                 return -1;
2258         }
2259
2260         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2261                 if (backend->set_input_channels (get_input_channels())) {
2262                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2263                         return -1;
2264                 }
2265                 if (backend->set_output_channels (get_output_channels())) {
2266                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2267                         return -1;
2268                 }
2269         }
2270         if (change_latency) {
2271                 if (backend->set_systemic_input_latency (get_input_latency())) {
2272                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2273                         return -1;
2274                 }
2275                 if (backend->set_systemic_output_latency (get_output_latency())) {
2276                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2277                         return -1;
2278                 }
2279         }
2280
2281         if (change_midi) {
2282                 backend->set_midi_option (get_midi_option());
2283         }
2284
2285         if (1 /* TODO */) {
2286                 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2287                         if (_measure_midi) {
2288                                 if (*p == _measure_midi) {
2289                                         backend->set_midi_device_enabled ((*p)->name, true);
2290                                 } else {
2291                                         backend->set_midi_device_enabled ((*p)->name, false);
2292                                 }
2293                                 continue;
2294                         }
2295                         backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2296                         if (backend->can_set_systemic_midi_latencies()) {
2297                                 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2298                                 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2299                         }
2300                 }
2301         }
2302
2303         if (start || (was_running && restart_required)) {
2304                 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2305                         return -1;
2306                 }
2307         }
2308
2309         post_push ();
2310
2311         return 0;
2312 }
2313
2314 void
2315 EngineControl::post_push ()
2316 {
2317         /* get a pointer to the current state object, creating one if
2318          * necessary
2319          */
2320
2321         State state = get_saved_state_for_currently_displayed_backend_and_device ();
2322
2323         if (!state) {
2324                 state = save_state ();
2325                 assert (state);
2326         } else {
2327                 store_state(state);
2328         }
2329
2330         /* all off */
2331
2332         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2333                 (*i)->active = false;
2334         }
2335
2336         /* mark this one active (to be used next time the dialog is
2337          * shown)
2338          */
2339
2340         state->active = true;
2341
2342         if (_have_control) { // XXX
2343                 manage_control_app_sensitivity ();
2344         }
2345
2346         /* schedule a redisplay of MIDI ports */
2347         //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2348 }
2349
2350
2351 float
2352 EngineControl::get_rate () const
2353 {
2354         float r = atof (sample_rate_combo.get_active_text ());
2355         /* the string may have been translated with an abbreviation for
2356          * thousands, so use a crude heuristic to fix this.
2357          */
2358         if (r < 1000.0) {
2359                 r *= 1000.0;
2360         }
2361         return r;
2362 }
2363
2364
2365 uint32_t
2366 EngineControl::get_buffer_size () const
2367 {
2368         string txt = buffer_size_combo.get_active_text ();
2369         uint32_t samples;
2370
2371         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2372                 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2373                 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2374                 throw exception ();
2375         }
2376
2377         return samples;
2378 }
2379
2380 string
2381 EngineControl::get_midi_option () const
2382 {
2383         return midi_option_combo.get_active_text();
2384 }
2385
2386 uint32_t
2387 EngineControl::get_input_channels() const
2388 {
2389         if (ARDOUR::Profile->get_mixbus()) {
2390                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2391                 if (!backend) return 0;
2392                 return backend->input_channels();
2393         }
2394         return (uint32_t) input_channels_adjustment.get_value();
2395 }
2396
2397 uint32_t
2398 EngineControl::get_output_channels() const
2399 {
2400         if (ARDOUR::Profile->get_mixbus()) {
2401                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2402                 if (!backend) return 0;
2403                 return backend->input_channels();
2404         }
2405         return (uint32_t) output_channels_adjustment.get_value();
2406 }
2407
2408 uint32_t
2409 EngineControl::get_input_latency() const
2410 {
2411         return (uint32_t) input_latency_adjustment.get_value();
2412 }
2413
2414 uint32_t
2415 EngineControl::get_output_latency() const
2416 {
2417         return (uint32_t) output_latency_adjustment.get_value();
2418 }
2419
2420 string
2421 EngineControl::get_backend () const
2422 {
2423         return backend_combo.get_active_text ();
2424 }
2425
2426 string
2427 EngineControl::get_driver () const
2428 {
2429         if (driver_combo.get_parent()) {
2430                 return driver_combo.get_active_text ();
2431         } else {
2432                 return "";
2433         }
2434 }
2435
2436 string
2437 EngineControl::get_device_name () const
2438 {
2439         return device_combo.get_active_text ();
2440 }
2441
2442 string
2443 EngineControl::get_input_device_name () const
2444 {
2445         return input_device_combo.get_active_text ();
2446 }
2447
2448 string
2449 EngineControl::get_output_device_name () const
2450 {
2451         return output_device_combo.get_active_text ();
2452 }
2453
2454 void
2455 EngineControl::control_app_button_clicked ()
2456 {
2457         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2458
2459         if (!backend) {
2460                 return;
2461         }
2462
2463         backend->launch_control_app ();
2464 }
2465
2466 void
2467 EngineControl::start_stop_button_clicked ()
2468 {
2469         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2470
2471         if (!backend) {
2472                 return;
2473         }
2474
2475         if (ARDOUR::AudioEngine::instance()->running()) {
2476                 ARDOUR::AudioEngine::instance()->stop ();
2477         } else {
2478                 push_state_to_backend (true);
2479         }
2480 }
2481
2482 void
2483 EngineControl::update_devices_button_clicked ()
2484 {
2485         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2486
2487         if (!backend) {
2488                 return;
2489         }
2490
2491         if (backend->update_devices()) {
2492                 device_list_changed ();
2493         }
2494 }
2495
2496 void
2497 EngineControl::manage_control_app_sensitivity ()
2498 {
2499         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2500
2501         if (!backend) {
2502                 return;
2503         }
2504
2505         string appname = backend->control_app_name();
2506
2507         if (appname.empty()) {
2508                 control_app_button.set_sensitive (false);
2509         } else {
2510                 control_app_button.set_sensitive (true);
2511         }
2512 }
2513
2514 void
2515 EngineControl::set_desired_sample_rate (uint32_t sr)
2516 {
2517         _desired_sample_rate = sr;
2518         device_changed ();
2519 }
2520
2521 void
2522 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2523 {
2524         if (page_num == 0) {
2525                 cancel_button->set_sensitive (true);
2526                 _measure_midi.reset();
2527                 update_sensitivity ();
2528         } else {
2529                 cancel_button->set_sensitive (false);
2530                 ok_button->set_sensitive (false);
2531         }
2532
2533         if (page_num == midi_tab) {
2534                 /* MIDI tab */
2535                 refresh_midi_display ();
2536         }
2537
2538         if (page_num == latency_tab) {
2539                 /* latency tab */
2540
2541                 if (ARDOUR::AudioEngine::instance()->running()) {
2542                         // TODO - mark as 'stopped for latency
2543                         ARDOUR_UI::instance()->disconnect_from_engine ();
2544                 }
2545
2546                 {
2547                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2548
2549                         /* save any existing latency values */
2550
2551                         uint32_t il = (uint32_t) input_latency.get_value ();
2552                         uint32_t ol = (uint32_t) input_latency.get_value ();
2553
2554                         /* reset to zero so that our new test instance
2555                            will be clean of any existing latency measures.
2556
2557                            NB. this should really be done by the backend
2558                            when stated for latency measurement.
2559                         */
2560
2561                         input_latency.set_value (0);
2562                         output_latency.set_value (0);
2563
2564                         push_state_to_backend (false);
2565
2566                         /* reset control */
2567
2568                         input_latency.set_value (il);
2569                         output_latency.set_value (ol);
2570
2571                 }
2572                 // This should be done in push_state_to_backend()
2573                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2574                         disable_latency_tab ();
2575                 }
2576
2577                 enable_latency_tab ();
2578
2579         } else {
2580                 if (lm_running) {
2581                         end_latency_detection ();
2582                         ARDOUR::AudioEngine::instance()->stop_latency_detection();
2583                 }
2584         }
2585 }
2586
2587 /* latency measurement */
2588
2589 bool
2590 EngineControl::check_audio_latency_measurement ()
2591 {
2592         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2593
2594         if (mtdm->resolve () < 0) {
2595                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2596                 return true;
2597         }
2598
2599         if (mtdm->err () > 0.3) {
2600                 mtdm->invert ();
2601                 mtdm->resolve ();
2602         }
2603
2604         char buf[256];
2605         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2606
2607         if (sample_rate == 0) {
2608                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2609                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2610                 return false;
2611         }
2612
2613         int frames_total = mtdm->del();
2614         int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2615
2616         snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2617                         _("Detected roundtrip latency: "),
2618                         frames_total, frames_total * 1000.0f/sample_rate,
2619                         _("Systemic latency: "),
2620                         extra, extra * 1000.0f/sample_rate);
2621
2622         bool solid = true;
2623
2624         if (mtdm->err () > 0.2) {
2625                 strcat (buf, " ");
2626                 strcat (buf, _("(signal detection error)"));
2627                 solid = false;
2628         }
2629
2630         if (mtdm->inv ()) {
2631                 strcat (buf, " ");
2632                 strcat (buf, _("(inverted - bad wiring)"));
2633                 solid = false;
2634         }
2635
2636         lm_results.set_markup (string_compose (results_markup, buf));
2637
2638         if (solid) {
2639                 have_lm_results = true;
2640                 end_latency_detection ();
2641                 lm_use_button.set_sensitive (true);
2642                 return false;
2643         }
2644
2645         return true;
2646 }
2647
2648 bool
2649 EngineControl::check_midi_latency_measurement ()
2650 {
2651         ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2652
2653         if (!mididm->have_signal () || mididm->latency () == 0) {
2654                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2655                 return true;
2656         }
2657
2658         char buf[256];
2659         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2660
2661         if (sample_rate == 0) {
2662                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2663                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2664                 return false;
2665         }
2666
2667         ARDOUR::framecnt_t frames_total = mididm->latency();
2668         ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2669         snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2670                         _("Detected roundtrip latency: "),
2671                         frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2672                         _("Systemic latency: "),
2673                         extra, extra * 1000.0f / sample_rate);
2674
2675         bool solid = true;
2676
2677         if (!mididm->ok ()) {
2678                 strcat (buf, " ");
2679                 strcat (buf, _("(averaging)"));
2680                 solid = false;
2681         }
2682
2683         if (mididm->deviation () > 50.0) {
2684                 strcat (buf, " ");
2685                 strcat (buf, _("(too large jitter)"));
2686                 solid = false;
2687         } else if (mididm->deviation () > 10.0) {
2688                 strcat (buf, " ");
2689                 strcat (buf, _("(large jitter)"));
2690         }
2691
2692         if (solid) {
2693                 have_lm_results = true;
2694                 end_latency_detection ();
2695                 lm_use_button.set_sensitive (true);
2696                 lm_results.set_markup (string_compose (results_markup, buf));
2697                 return false;
2698         } else if (mididm->processed () > 400) {
2699                 have_lm_results = false;
2700                 end_latency_detection ();
2701                 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2702                 return false;
2703         }
2704
2705         lm_results.set_markup (string_compose (results_markup, buf));
2706
2707         return true;
2708 }
2709
2710 void
2711 EngineControl::start_latency_detection ()
2712 {
2713         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2714         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2715
2716         if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2717                 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2718                 if (_measure_midi) {
2719                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2720                 } else {
2721                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2722                 }
2723                 lm_measure_label.set_text (_("Cancel"));
2724                 have_lm_results = false;
2725                 lm_use_button.set_sensitive (false);
2726                 lm_input_channel_combo.set_sensitive (false);
2727                 lm_output_channel_combo.set_sensitive (false);
2728                 lm_running = true;
2729         }
2730 }
2731
2732 void
2733 EngineControl::end_latency_detection ()
2734 {
2735         latency_timeout.disconnect ();
2736         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2737         lm_measure_label.set_text (_("Measure"));
2738         if (!have_lm_results) {
2739                 lm_use_button.set_sensitive (false);
2740         }
2741         lm_input_channel_combo.set_sensitive (true);
2742         lm_output_channel_combo.set_sensitive (true);
2743         lm_running = false;
2744 }
2745
2746 void
2747 EngineControl::latency_button_clicked ()
2748 {
2749         if (!lm_running) {
2750                 start_latency_detection ();
2751         } else {
2752                 end_latency_detection ();
2753         }
2754 }
2755
2756 void
2757 EngineControl::use_latency_button_clicked ()
2758 {
2759         if (_measure_midi) {
2760                 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2761                 if (!mididm) {
2762                         return;
2763                 }
2764                 ARDOUR::framecnt_t frames_total = mididm->latency();
2765                 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2766                 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2767                 _measure_midi->input_latency = one_way;
2768                 _measure_midi->output_latency = one_way;
2769                 notebook.set_current_page (midi_tab);
2770         } else {
2771                 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2772
2773                 if (!mtdm) {
2774                         return;
2775                 }
2776
2777                 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2778                 one_way = std::max (0., one_way);
2779
2780                 input_latency_adjustment.set_value (one_way);
2781                 output_latency_adjustment.set_value (one_way);
2782
2783                 /* back to settings page */
2784                 notebook.set_current_page (0);
2785 }
2786         }
2787
2788
2789 bool
2790 EngineControl::on_delete_event (GdkEventAny* ev)
2791 {
2792         if (notebook.get_current_page() == 2) {
2793                 /* currently on latency tab - be sure to clean up */
2794                 end_latency_detection ();
2795         }
2796         return ArdourDialog::on_delete_event (ev);
2797 }
2798
2799 void
2800 EngineControl::engine_running ()
2801 {
2802         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2803         assert (backend);
2804
2805         set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2806         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2807
2808         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2809         connect_disconnect_button.show();
2810
2811         started_at_least_once = true;
2812         if (_have_control) {
2813                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2814         } else {
2815                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2816         }
2817         update_sensitivity();
2818 }
2819
2820 void
2821 EngineControl::engine_stopped ()
2822 {
2823         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2824         assert (backend);
2825
2826         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2827         connect_disconnect_button.show();
2828
2829         if (_have_control) {
2830                 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
2831         } else {
2832                 engine_status.set_markup(X_(""));
2833         }
2834
2835         update_sensitivity();
2836 }
2837
2838 void
2839 EngineControl::device_list_changed ()
2840 {
2841         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2842         list_devices ();
2843         midi_option_changed();
2844 }
2845
2846 void
2847 EngineControl::connect_disconnect_click()
2848 {
2849         if (ARDOUR::AudioEngine::instance()->running()) {
2850                 ARDOUR_UI::instance()->disconnect_from_engine ();
2851         } else {
2852                 ARDOUR_UI::instance()->reconnect_to_engine ();
2853         }
2854 }
2855
2856 void
2857 EngineControl::calibrate_audio_latency ()
2858 {
2859         _measure_midi.reset ();
2860         have_lm_results = false;
2861         lm_use_button.set_sensitive (false);
2862         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2863         notebook.set_current_page (latency_tab);
2864 }
2865
2866 void
2867 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2868 {
2869         _measure_midi = s;
2870         have_lm_results = false;
2871         lm_use_button.set_sensitive (false);
2872         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2873         notebook.set_current_page (latency_tab);
2874 }
2875
2876 void
2877 EngineControl::configure_midi_devices ()
2878 {
2879         notebook.set_current_page (midi_tab);
2880 }