Add utility method for choosing which device/s to display in Audio Setup dialog
[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 std::string
1066 EngineControl::get_default_device(const string& current_device_name,
1067                                   const vector<string>& available_devices)
1068 {
1069         // If the current device is available, use it as default
1070         if (std::find (available_devices.begin (),
1071                        available_devices.end (),
1072                        current_device_name) != available_devices.end ()) {
1073
1074                 return current_device_name;
1075         }
1076
1077         using namespace ARDOUR;
1078
1079         string default_device_name =
1080             AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1081
1082         vector<string>::const_iterator i;
1083
1084         // If there is a "Default" device available, use it
1085         for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1086                 if (*i == default_device_name) {
1087                         return *i;
1088                 }
1089         }
1090
1091         string none_device_name =
1092             AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1093
1094         // Use the first device that isn't "None"
1095         for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1096                 if (*i != none_device_name) {
1097                         return *i;
1098                 }
1099         }
1100
1101         // Use "None" if there are no other available
1102         return available_devices.front();
1103 }
1104
1105 // @return true if there are devices available
1106 bool
1107 EngineControl::set_device_popdown_strings ()
1108 {
1109         DEBUG_ECONTROL ("set_device_popdown_strings");
1110         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1111         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1112
1113         /* NOTE: Ardour currently does not display the "available" field of the
1114          * returned devices.
1115          *
1116          * Doing so would require a different GUI widget than the combo
1117          * box/popdown that we currently use, since it has no way to list
1118          * items that are not selectable. Something more like a popup menu,
1119          * which could have unselectable items, would be appropriate.
1120          */
1121
1122         vector<string> available_devices;
1123
1124         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1125                 available_devices.push_back (i->name);
1126         }
1127
1128         if (available_devices.empty ()) {
1129                 return false;
1130         }
1131
1132         set_popdown_strings (device_combo, available_devices);
1133
1134         std::string default_device =
1135             get_default_device(backend->device_name(), available_devices);
1136
1137         DEBUG_ECONTROL (
1138             string_compose ("set device_combo active text: %1", default_device));
1139
1140         device_combo.set_active_text(default_device);
1141         return true;
1142 }
1143
1144 // @return true if there are input devices available
1145 bool
1146 EngineControl::set_input_device_popdown_strings ()
1147 {
1148         DEBUG_ECONTROL ("set_input_device_popdown_strings");
1149         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1150         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1151
1152         vector<string> available_devices;
1153
1154         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1155                 available_devices.push_back (i->name);
1156         }
1157
1158         if (available_devices.empty()) {
1159                 return false;
1160         }
1161
1162         set_popdown_strings (input_device_combo, available_devices);
1163
1164         std::string default_device =
1165             get_default_device(backend->input_device_name(), available_devices);
1166
1167         DEBUG_ECONTROL (
1168             string_compose ("set input_device_combo active text: %1", default_device));
1169         input_device_combo.set_active_text(default_device);
1170         return true;
1171 }
1172
1173 // @return true if there are output devices available
1174 bool
1175 EngineControl::set_output_device_popdown_strings ()
1176 {
1177         DEBUG_ECONTROL ("set_output_device_popdown_strings");
1178         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1179         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1180
1181         vector<string> available_devices;
1182
1183         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1184                 available_devices.push_back (i->name);
1185         }
1186
1187         if (available_devices.empty()) {
1188                 return false;
1189         }
1190
1191         set_popdown_strings (output_device_combo, available_devices);
1192
1193         std::string default_device =
1194             get_default_device(backend->output_device_name(), available_devices);
1195
1196         DEBUG_ECONTROL (
1197             string_compose ("set output_device_combo active text: %1", default_device));
1198         output_device_combo.set_active_text(default_device);
1199         return true;
1200 }
1201
1202 void
1203 EngineControl::list_devices ()
1204 {
1205         DEBUG_ECONTROL ("list_devices");
1206         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1207         assert (backend);
1208
1209         /* now fill out devices, mark sample rates, buffer sizes insensitive */
1210
1211         bool devices_available = false;
1212
1213         if (backend->use_separate_input_and_output_devices ()) {
1214                 bool input_devices_available = set_input_device_popdown_strings ();
1215                 bool output_devices_available = set_output_device_popdown_strings ();
1216                 devices_available = input_devices_available || output_devices_available;
1217         } else {
1218                 devices_available = set_device_popdown_strings ();
1219         }
1220
1221         if (devices_available) {
1222                 device_changed ();
1223         } else {
1224                 device_combo.clear();
1225                 input_device_combo.clear();
1226                 output_device_combo.clear();
1227         }
1228         update_sensitivity ();
1229 }
1230
1231 void
1232 EngineControl::driver_changed ()
1233 {
1234         SignalBlocker blocker (*this, "driver_changed");
1235         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1236         assert (backend);
1237
1238         backend->set_driver (driver_combo.get_active_text());
1239         list_devices ();
1240
1241         if (!ignore_changes) {
1242                 maybe_display_saved_state ();
1243         }
1244 }
1245
1246 vector<float>
1247 EngineControl::get_sample_rates_for_all_devices ()
1248 {
1249         boost::shared_ptr<ARDOUR::AudioBackend> backend =
1250             ARDOUR::AudioEngine::instance ()->current_backend ();
1251         vector<float> all_rates;
1252
1253         if (backend->use_separate_input_and_output_devices ()) {
1254                 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1255         } else {
1256                 all_rates = backend->available_sample_rates (get_device_name ());
1257         }
1258         return all_rates;
1259 }
1260
1261 vector<float>
1262 EngineControl::get_default_sample_rates ()
1263 {
1264         vector<float> rates;
1265         rates.push_back (8000.0f);
1266         rates.push_back (16000.0f);
1267         rates.push_back (32000.0f);
1268         rates.push_back (44100.0f);
1269         rates.push_back (48000.0f);
1270         rates.push_back (88200.0f);
1271         rates.push_back (96000.0f);
1272         rates.push_back (192000.0f);
1273         rates.push_back (384000.0f);
1274         return rates;
1275 }
1276
1277 void
1278 EngineControl::set_samplerate_popdown_strings ()
1279 {
1280         DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1281         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1282         string desired;
1283         vector<float> sr;
1284         vector<string> s;
1285
1286         if (_have_control) {
1287                 sr = get_sample_rates_for_all_devices ();
1288         } else {
1289                 sr = get_default_sample_rates ();
1290         }
1291
1292         for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1293                 s.push_back (rate_as_string (*x));
1294                 if (*x == _desired_sample_rate) {
1295                         desired = s.back();
1296                 }
1297         }
1298
1299         set_popdown_strings (sample_rate_combo, s);
1300
1301         if (!s.empty()) {
1302                 if (desired.empty ()) {
1303                         float new_active_sr = backend->default_sample_rate ();
1304
1305                         if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1306                                 new_active_sr = sr.front ();
1307                         }
1308
1309                         sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1310                 } else {
1311                         sample_rate_combo.set_active_text (desired);
1312                 }
1313
1314         }
1315         update_sensitivity ();
1316 }
1317
1318 vector<uint32_t>
1319 EngineControl::get_buffer_sizes_for_all_devices ()
1320 {
1321         boost::shared_ptr<ARDOUR::AudioBackend> backend =
1322             ARDOUR::AudioEngine::instance ()->current_backend ();
1323         vector<uint32_t> all_sizes;
1324
1325         if (backend->use_separate_input_and_output_devices ()) {
1326                 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1327         } else {
1328                 all_sizes = backend->available_buffer_sizes (get_device_name ());
1329         }
1330         return all_sizes;
1331 }
1332
1333 vector<uint32_t>
1334 EngineControl::get_default_buffer_sizes ()
1335 {
1336         vector<uint32_t> sizes;
1337         sizes.push_back (8);
1338         sizes.push_back (16);
1339         sizes.push_back (32);
1340         sizes.push_back (64);
1341         sizes.push_back (128);
1342         sizes.push_back (256);
1343         sizes.push_back (512);
1344         sizes.push_back (1024);
1345         sizes.push_back (2048);
1346         sizes.push_back (4096);
1347         sizes.push_back (8192);
1348         return sizes;
1349 }
1350
1351 void
1352 EngineControl::set_buffersize_popdown_strings ()
1353 {
1354         DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1355         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1356         vector<uint32_t> bs;
1357         vector<string> s;
1358
1359         if (_have_control) {
1360                 bs = get_buffer_sizes_for_all_devices ();
1361         } else if (backend->can_change_buffer_size_when_running()) {
1362                 bs = get_default_buffer_sizes ();
1363         }
1364
1365         for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1366                 s.push_back (bufsize_as_string (*x));
1367         }
1368
1369         uint32_t previous_size = 0;
1370         if (!buffer_size_combo.get_active_text().empty()) {
1371                 previous_size = get_buffer_size ();
1372         }
1373
1374         set_popdown_strings (buffer_size_combo, s);
1375
1376         if (!s.empty()) {
1377
1378                 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1379                         buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1380                 } else {
1381
1382                         buffer_size_combo.set_active_text(s.front());
1383
1384                         uint32_t period = backend->buffer_size();
1385                         if (0 == period && backend->use_separate_input_and_output_devices()) {
1386                                 period = backend->default_buffer_size(get_input_device_name());
1387                         }
1388                         if (0 == period && backend->use_separate_input_and_output_devices()) {
1389                                 period = backend->default_buffer_size(get_output_device_name());
1390                         }
1391                         if (0 == period && !backend->use_separate_input_and_output_devices()) {
1392                                 period = backend->default_buffer_size(get_device_name());
1393                         }
1394
1395                         set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1396                 }
1397                 show_buffer_duration ();
1398         }
1399         update_sensitivity ();
1400 }
1401
1402 void
1403 EngineControl::device_changed ()
1404 {
1405         SignalBlocker blocker (*this, "device_changed");
1406         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1407         assert (backend);
1408
1409         string device_name_in;
1410         string device_name_out; // only used if backend support separate I/O devices
1411
1412         if (backend->use_separate_input_and_output_devices()) {
1413                 device_name_in  = get_input_device_name ();
1414                 device_name_out = get_output_device_name ();
1415         } else {
1416                 device_name_in = get_device_name ();
1417         }
1418
1419         /* we set the backend-device to query various device related intormation.
1420          * This has the side effect that backend->device_name() will match
1421          * the device_name and  'change_device' will never be true.
1422          * so work around this by setting...
1423          */
1424         if (backend->use_separate_input_and_output_devices()) {
1425                 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1426                         queue_device_changed = true;
1427                 }
1428         } else {
1429                 if (device_name_in != backend->device_name()) {
1430                         queue_device_changed = true;
1431                 }
1432         }
1433         
1434         //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1435         if (backend->use_separate_input_and_output_devices()) {
1436                 backend->set_input_device_name (device_name_in);
1437                 backend->set_output_device_name (device_name_out);
1438         } else {
1439                 backend->set_device_name(device_name_in);
1440         }
1441
1442         {
1443                 /* don't allow programmatic change to combos to cause a
1444                    recursive call to this method.
1445                  */
1446                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1447
1448                 set_samplerate_popdown_strings ();
1449                 set_buffersize_popdown_strings ();
1450
1451                 /* TODO set min + max channel counts here */
1452
1453                 manage_control_app_sensitivity ();
1454         }
1455
1456         /* pick up any saved state for this device */
1457
1458         if (!ignore_changes) {
1459                 maybe_display_saved_state ();
1460         }
1461 }
1462
1463 void
1464 EngineControl::input_device_changed ()
1465 {
1466         DEBUG_ECONTROL ("input_device_changed");
1467         device_changed ();
1468 }
1469
1470 void
1471 EngineControl::output_device_changed ()
1472 {
1473         DEBUG_ECONTROL ("output_device_changed");
1474         device_changed ();
1475 }
1476
1477 string
1478 EngineControl::bufsize_as_string (uint32_t sz)
1479 {
1480         /* Translators: "samples" is always plural here, so no
1481            need for plural+singular forms.
1482          */
1483         char buf[64];
1484         snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1485         return buf;
1486 }
1487
1488 void
1489 EngineControl::sample_rate_changed ()
1490 {
1491         DEBUG_ECONTROL ("sample_rate_changed");
1492         /* reset the strings for buffer size to show the correct msec value
1493            (reflecting the new sample rate).
1494          */
1495
1496         show_buffer_duration ();
1497
1498 }
1499
1500 void
1501 EngineControl::buffer_size_changed ()
1502 {
1503         DEBUG_ECONTROL ("buffer_size_changed");
1504         show_buffer_duration ();
1505 }
1506
1507 void
1508 EngineControl::show_buffer_duration ()
1509 {
1510         DEBUG_ECONTROL ("show_buffer_duration");
1511         /* buffer sizes  - convert from just samples to samples + msecs for
1512          * the displayed string
1513          */
1514
1515         string bs_text = buffer_size_combo.get_active_text ();
1516         uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1517         uint32_t rate = get_rate();
1518
1519         /* Developers: note the hard-coding of a double buffered model
1520            in the (2 * samples) computation of latency. we always start
1521            the audiobackend in this configuration.
1522          */
1523         /* note to jack1 developers: ardour also always starts the engine
1524          * in async mode (no jack2 --sync option) which adds an extra cycle
1525          * of latency with jack2 (and *3 would be correct)
1526          * The value can also be wrong if jackd is started externally..
1527          *
1528          * At the time of writing the ALSA backend always uses double-buffering *2,
1529          * The Dummy backend *1, and who knows what ASIO really does :)
1530          *
1531          * So just display the period size, that's also what
1532          * ARDOUR_UI::update_sample_rate() does for the status bar.
1533          * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1534          * but still, that's the buffer period, not [round-trip] latency)
1535          */
1536         char buf[32];
1537         snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1538         buffer_size_duration_label.set_text (buf);
1539 }
1540
1541 void
1542 EngineControl::midi_option_changed ()
1543 {
1544         DEBUG_ECONTROL ("midi_option_changed");
1545         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1546         assert (backend);
1547
1548         backend->set_midi_option (get_midi_option());
1549
1550         vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1551
1552         //_midi_devices.clear(); // TODO merge with state-saved settings..
1553         _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1554         std::vector<MidiDeviceSettings> new_devices;
1555
1556         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1557                 MidiDeviceSettings mds = find_midi_device (i->name);
1558                 if (i->available && !mds) {
1559                         uint32_t input_latency = 0;
1560                         uint32_t output_latency = 0;
1561                         if (_can_set_midi_latencies) {
1562                                 input_latency = backend->systemic_midi_input_latency (i->name);
1563                                 output_latency = backend->systemic_midi_output_latency (i->name);
1564                         }
1565                         bool enabled = backend->midi_device_enabled (i->name);
1566                         MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1567                         new_devices.push_back (ptr);
1568                 } else if (i->available) {
1569                         new_devices.push_back (mds);
1570                 }
1571         }
1572         _midi_devices = new_devices;
1573
1574         if (_midi_devices.empty()) {
1575                 midi_devices_button.set_sensitive (false);
1576         } else {
1577                 midi_devices_button.set_sensitive (true);
1578         }
1579 }
1580
1581 void
1582 EngineControl::parameter_changed ()
1583 {
1584 }
1585
1586 EngineControl::State
1587 EngineControl::get_matching_state (
1588                 const string& backend,
1589                 const string& driver,
1590                 const string& device)
1591 {
1592         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1593                 if ((*i)->backend == backend &&
1594                                 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1595                 {
1596                         return (*i);
1597                 }
1598         }
1599         return State();
1600 }
1601
1602 EngineControl::State
1603 EngineControl::get_matching_state (
1604                 const string& backend,
1605                 const string& driver,
1606                 const string& input_device,
1607                 const string& output_device)
1608 {
1609         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1610                 if ((*i)->backend == backend &&
1611                                 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1612                 {
1613                         return (*i);
1614                 }
1615         }
1616         return State();
1617 }
1618
1619 EngineControl::State
1620 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1621 {
1622         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1623
1624         if (backend) {
1625                 if (backend->use_separate_input_and_output_devices ()) {
1626                         return get_matching_state (backend_combo.get_active_text(),
1627                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1628                                         input_device_combo.get_active_text(),
1629                                         output_device_combo.get_active_text());
1630                 } else {
1631                         return get_matching_state (backend_combo.get_active_text(),
1632                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1633                                         device_combo.get_active_text());
1634                 }
1635         }
1636
1637         return get_matching_state (backend_combo.get_active_text(),
1638                         string(),
1639                         device_combo.get_active_text());
1640 }
1641
1642 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1643                                        const EngineControl::State& state2)
1644 {
1645         if (state1->backend == state2->backend &&
1646                         state1->driver == state2->driver &&
1647                         state1->device == state2->device &&
1648                         state1->input_device == state2->input_device &&
1649                         state1->output_device == state2->output_device) {
1650                 return true;
1651         }
1652         return false;
1653 }
1654
1655 EngineControl::State
1656 EngineControl::save_state ()
1657 {
1658         State state;
1659
1660         if (!_have_control) {
1661                 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1662                 if (state) {
1663                         return state;
1664                 }
1665                 state.reset(new StateStruct);
1666                 state->backend = get_backend ();
1667         } else {
1668                 state.reset(new StateStruct);
1669                 store_state (state);
1670         }
1671
1672         for (StateList::iterator i = states.begin(); i != states.end();) {
1673                 if (equivalent_states (*i, state)) {
1674                         i =  states.erase(i);
1675                 } else {
1676                         ++i;
1677                 }
1678         }
1679
1680         states.push_back (state);
1681
1682         return state;
1683 }
1684
1685 void
1686 EngineControl::store_state (State state)
1687 {
1688         state->backend = get_backend ();
1689         state->driver = get_driver ();
1690         state->device = get_device_name ();
1691         state->input_device = get_input_device_name ();
1692         state->output_device = get_output_device_name ();
1693         state->sample_rate = get_rate ();
1694         state->buffer_size = get_buffer_size ();
1695         state->input_latency = get_input_latency ();
1696         state->output_latency = get_output_latency ();
1697         state->input_channels = get_input_channels ();
1698         state->output_channels = get_output_channels ();
1699         state->midi_option = get_midi_option ();
1700         state->midi_devices = _midi_devices;
1701 }
1702
1703 void
1704 EngineControl::maybe_display_saved_state ()
1705 {
1706         if (!_have_control) {
1707                 return;
1708         }
1709
1710         State state = get_saved_state_for_currently_displayed_backend_and_device ();
1711
1712         if (state) {
1713                 DEBUG_ECONTROL ("Restoring saved state");
1714                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1715
1716                 if (!_desired_sample_rate) {
1717                         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1718                 }
1719                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1720                 /* call this explicitly because we're ignoring changes to
1721                    the controls at this point.
1722                  */
1723                 show_buffer_duration ();
1724                 input_latency.set_value (state->input_latency);
1725                 output_latency.set_value (state->output_latency);
1726
1727                 if (!state->midi_option.empty()) {
1728                         midi_option_combo.set_active_text (state->midi_option);
1729                         _midi_devices = state->midi_devices;
1730                 }
1731         } else {
1732                 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1733         }
1734 }
1735
1736 XMLNode&
1737 EngineControl::get_state ()
1738 {
1739         LocaleGuard lg (X_("C"));
1740
1741         XMLNode* root = new XMLNode ("AudioMIDISetup");
1742         std::string path;
1743
1744         if (!states.empty()) {
1745                 XMLNode* state_nodes = new XMLNode ("EngineStates");
1746
1747                 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1748
1749                         XMLNode* node = new XMLNode ("State");
1750
1751                         node->add_property ("backend", (*i)->backend);
1752                         node->add_property ("driver", (*i)->driver);
1753                         node->add_property ("device", (*i)->device);
1754                         node->add_property ("input-device", (*i)->input_device);
1755                         node->add_property ("output-device", (*i)->output_device);
1756                         node->add_property ("sample-rate", (*i)->sample_rate);
1757                         node->add_property ("buffer-size", (*i)->buffer_size);
1758                         node->add_property ("input-latency", (*i)->input_latency);
1759                         node->add_property ("output-latency", (*i)->output_latency);
1760                         node->add_property ("input-channels", (*i)->input_channels);
1761                         node->add_property ("output-channels", (*i)->output_channels);
1762                         node->add_property ("active", (*i)->active ? "yes" : "no");
1763                         node->add_property ("midi-option", (*i)->midi_option);
1764
1765                         XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1766                         for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1767                                 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1768                                 midi_device_stuff->add_property (X_("name"), (*p)->name);
1769                                 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1770                                 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1771                                 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1772                                 midi_devices->add_child_nocopy (*midi_device_stuff);
1773                         }
1774                         node->add_child_nocopy (*midi_devices);
1775
1776                         state_nodes->add_child_nocopy (*node);
1777                 }
1778
1779                 root->add_child_nocopy (*state_nodes);
1780         }
1781
1782         return *root;
1783 }
1784
1785 void
1786 EngineControl::set_default_state ()
1787 {
1788         vector<string> backend_names;
1789         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1790
1791         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1792                 backend_names.push_back ((*b)->name);
1793         }
1794         backend_combo.set_active_text (backend_names.front());
1795
1796         // We could set default backends per platform etc here
1797
1798         backend_changed ();
1799 }
1800
1801 bool
1802 EngineControl::set_state (const XMLNode& root)
1803 {
1804         XMLNodeList          clist, cclist;
1805         XMLNodeConstIterator citer, cciter;
1806         XMLNode* child;
1807         XMLNode* grandchild;
1808         XMLProperty* prop = NULL;
1809
1810         fprintf (stderr, "EngineControl::set_state\n");
1811
1812         if (root.name() != "AudioMIDISetup") {
1813                 return false;
1814         }
1815
1816         clist = root.children();
1817
1818         states.clear ();
1819
1820         for (citer = clist.begin(); citer != clist.end(); ++citer) {
1821
1822                 child = *citer;
1823
1824                 if (child->name() != "EngineStates") {
1825                         continue;
1826                 }
1827
1828                 cclist = child->children();
1829
1830                 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1831                         State state (new StateStruct);
1832
1833                         grandchild = *cciter;
1834
1835                         if (grandchild->name() != "State") {
1836                                 continue;
1837                         }
1838
1839                         if ((prop = grandchild->property ("backend")) == 0) {
1840                                 continue;
1841                         }
1842                         state->backend = prop->value ();
1843
1844                         if ((prop = grandchild->property ("driver")) == 0) {
1845                                 continue;
1846                         }
1847                         state->driver = prop->value ();
1848
1849                         if ((prop = grandchild->property ("device")) == 0) {
1850                                 continue;
1851                         }
1852                         state->device = prop->value ();
1853
1854                         if ((prop = grandchild->property ("input-device")) == 0) {
1855                                 continue;
1856                         }
1857                         state->input_device = prop->value ();
1858
1859                         if ((prop = grandchild->property ("output-device")) == 0) {
1860                                 continue;
1861                         }
1862                         state->output_device = prop->value ();
1863
1864                         if ((prop = grandchild->property ("sample-rate")) == 0) {
1865                                 continue;
1866                         }
1867                         state->sample_rate = atof (prop->value ());
1868
1869                         if ((prop = grandchild->property ("buffer-size")) == 0) {
1870                                 continue;
1871                         }
1872                         state->buffer_size = atoi (prop->value ());
1873
1874                         if ((prop = grandchild->property ("input-latency")) == 0) {
1875                                 continue;
1876                         }
1877                         state->input_latency = atoi (prop->value ());
1878
1879                         if ((prop = grandchild->property ("output-latency")) == 0) {
1880                                 continue;
1881                         }
1882                         state->output_latency = atoi (prop->value ());
1883
1884                         if ((prop = grandchild->property ("input-channels")) == 0) {
1885                                 continue;
1886                         }
1887                         state->input_channels = atoi (prop->value ());
1888
1889                         if ((prop = grandchild->property ("output-channels")) == 0) {
1890                                 continue;
1891                         }
1892                         state->output_channels = atoi (prop->value ());
1893
1894                         if ((prop = grandchild->property ("active")) == 0) {
1895                                 continue;
1896                         }
1897                         state->active = string_is_affirmative (prop->value ());
1898
1899                         if ((prop = grandchild->property ("midi-option")) == 0) {
1900                                 continue;
1901                         }
1902                         state->midi_option = prop->value ();
1903
1904                         state->midi_devices.clear();
1905                         XMLNode* midinode;
1906                         if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1907                                 const XMLNodeList mnc = midinode->children();
1908                                 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1909                                         if ((*n)->property (X_("name")) == 0
1910                                                         || (*n)->property (X_("enabled")) == 0
1911                                                         || (*n)->property (X_("input-latency")) == 0
1912                                                         || (*n)->property (X_("output-latency")) == 0
1913                                                  ) {
1914                                                 continue;
1915                                         }
1916
1917                                         MidiDeviceSettings ptr (new MidiDeviceSetting(
1918                                                                 (*n)->property (X_("name"))->value (),
1919                                                                 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1920                                                                 atoi ((*n)->property (X_("input-latency"))->value ()),
1921                                                                 atoi ((*n)->property (X_("output-latency"))->value ())
1922                                                                 ));
1923                                         state->midi_devices.push_back (ptr);
1924                                 }
1925                         }
1926
1927 #if 1
1928                         /* remove accumulated duplicates (due to bug in ealier version)
1929                          * this can be removed again before release
1930                          */
1931                         for (StateList::iterator i = states.begin(); i != states.end();) {
1932                                 if ((*i)->backend == state->backend &&
1933                                                 (*i)->driver == state->driver &&
1934                                                 (*i)->device == state->device) {
1935                                         i =  states.erase(i);
1936                                 } else {
1937                                         ++i;
1938                                 }
1939                         }
1940 #endif
1941
1942                         states.push_back (state);
1943                 }
1944         }
1945
1946         /* now see if there was an active state and switch the setup to it */
1947
1948         // purge states of backend that are not available in this built
1949         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1950         vector<std::string> backend_names;
1951
1952         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1953                 backend_names.push_back((*i)->name);
1954         }
1955         for (StateList::iterator i = states.begin(); i != states.end();) {
1956                 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1957                         i = states.erase(i);
1958                 } else {
1959                         ++i;
1960                 }
1961         }
1962
1963         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1964
1965                 if ((*i)->active) {
1966                         return set_current_state (*i);
1967                 }
1968         }
1969         return false;
1970 }
1971
1972 bool
1973 EngineControl::set_current_state (const State& state)
1974 {
1975         DEBUG_ECONTROL ("set_current_state");
1976
1977         boost::shared_ptr<ARDOUR::AudioBackend> backend;
1978
1979         if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1980                   state->backend, downcase (PROGRAM_NAME), ""))) {
1981                 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1982                 // this shouldn't happen as the invalid backend names should have been
1983                 // removed from the list of states.
1984                 return false;
1985         }
1986
1987         // now reflect the change in the backend in the GUI so backend_changed will
1988         // do the right thing
1989         backend_combo.set_active_text (state->backend);
1990
1991         if (!state->driver.empty ()) {
1992                 if (!backend->requires_driver_selection ()) {
1993                         DEBUG_ECONTROL ("Backend should require driver selection");
1994                         // A backend has changed from having driver selection to not having
1995                         // it or someone has been manually editing a config file and messed
1996                         // it up
1997                         return false;
1998                 }
1999
2000                 if (backend->set_driver (state->driver) != 0) {
2001                         DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2002                         // Driver names for a backend have changed and the name in the
2003                         // config file is now invalid or support for driver is no longer
2004                         // included in the backend
2005                         return false;
2006                 }
2007                 // no need to set the driver_combo as backend_changed will use
2008                 // backend->driver_name to set the active driver
2009         }
2010
2011         if (!state->device.empty ()) {
2012                 if (backend->set_device_name (state->device) != 0) {
2013                         DEBUG_ECONTROL (
2014                             string_compose ("Unable to set device name %1", state->device));
2015                         // device is no longer available on the system
2016                         return false;
2017                 }
2018                 // no need to set active device as it will be picked up in
2019                 // via backend_changed ()/set_device_popdown_strings
2020
2021         } else {
2022                 // backend supports separate input/output devices
2023                 if (backend->set_input_device_name (state->input_device) != 0) {
2024                         DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2025                                                         state->input_device));
2026                         // input device is no longer available on the system
2027                         return false;
2028                 }
2029
2030                 if (backend->set_output_device_name (state->output_device) != 0) {
2031                         DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2032                                                         state->input_device));
2033                         // output device is no longer available on the system
2034                         return false;
2035                 }
2036                 // no need to set active devices as it will be picked up in via
2037                 // backend_changed ()/set_*_device_popdown_strings
2038         }
2039
2040         backend_changed ();
2041
2042         // Now restore the state of the rest of the controls
2043
2044         // We don't use a SignalBlocker as set_current_state is currently only
2045         // called from set_state before any signals are connected. If at some point
2046         // a more general named state mechanism is implemented and
2047         // set_current_state is called while signals are connected then a
2048         // SignalBlocker will need to be instantiated before setting these.
2049
2050         device_combo.set_active_text (state->device);
2051         input_device_combo.set_active_text (state->input_device);
2052         output_device_combo.set_active_text (state->output_device);
2053         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2054         set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2055         input_latency.set_value (state->input_latency);
2056         output_latency.set_value (state->output_latency);
2057         midi_option_combo.set_active_text (state->midi_option);
2058         return true;
2059 }
2060
2061 int
2062 EngineControl::push_state_to_backend (bool start)
2063 {
2064         DEBUG_ECONTROL ("push_state_to_backend");
2065         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2066
2067         if (!backend) {
2068                 return 0;
2069         }
2070
2071         /* figure out what is going to change */
2072
2073         bool restart_required = false;
2074         bool was_running = ARDOUR::AudioEngine::instance()->running();
2075         bool change_driver = false;
2076         bool change_device = false;
2077         bool change_rate = false;
2078         bool change_bufsize = false;
2079         bool change_latency = false;
2080         bool change_channels = false;
2081         bool change_midi = false;
2082
2083         uint32_t ochan = get_output_channels ();
2084         uint32_t ichan = get_input_channels ();
2085
2086         if (_have_control) {
2087
2088                 if (started_at_least_once) {
2089
2090                         /* we can control the backend */
2091
2092                         if (backend->requires_driver_selection()) {
2093                                 if (get_driver() != backend->driver_name()) {
2094                                         change_driver = true;
2095                                 }
2096                         }
2097
2098                         if (backend->use_separate_input_and_output_devices()) {
2099                                 if (get_input_device_name() != backend->input_device_name()) {
2100                                         change_device = true;
2101                                 }
2102                                 if (get_output_device_name() != backend->output_device_name()) {
2103                                         change_device = true;
2104                                 }
2105                         } else {
2106                                 if (get_device_name() != backend->device_name()) {
2107                                         change_device = true;
2108                                 }
2109                         }
2110
2111                         if (queue_device_changed) {
2112                                 change_device = true;
2113                         }
2114
2115                         if (get_rate() != backend->sample_rate()) {
2116                                 change_rate = true;
2117                         }
2118
2119                         if (get_buffer_size() != backend->buffer_size()) {
2120                                 change_bufsize = true;
2121                         }
2122
2123                         if (get_midi_option() != backend->midi_option()) {
2124                                 change_midi = true;
2125                         }
2126
2127                         /* zero-requested channels means "all available" */
2128
2129                         if (ichan == 0) {
2130                                 ichan = backend->input_channels();
2131                         }
2132
2133                         if (ochan == 0) {
2134                                 ochan = backend->output_channels();
2135                         }
2136
2137                         if (ichan != backend->input_channels()) {
2138                                 change_channels = true;
2139                         }
2140
2141                         if (ochan != backend->output_channels()) {
2142                                 change_channels = true;
2143                         }
2144
2145                         if (get_input_latency() != backend->systemic_input_latency() ||
2146                                         get_output_latency() != backend->systemic_output_latency()) {
2147                                 change_latency = true;
2148                         }
2149                 } else {
2150                         /* backend never started, so we have to force a group
2151                            of settings.
2152                          */
2153                         change_device = true;
2154                         if (backend->requires_driver_selection()) {
2155                                 change_driver = true;
2156                         }
2157                         change_rate = true;
2158                         change_bufsize = true;
2159                         change_channels = true;
2160                         change_latency = true;
2161                         change_midi = true;
2162                 }
2163
2164         } else {
2165
2166                 /* we have no control over the backend, meaning that we can
2167                  * only possibly change sample rate and buffer size.
2168                  */
2169
2170
2171                 if (get_rate() != backend->sample_rate()) {
2172                         change_bufsize = true;
2173                 }
2174
2175                 if (get_buffer_size() != backend->buffer_size()) {
2176                         change_bufsize = true;
2177                 }
2178         }
2179
2180         queue_device_changed = false;
2181
2182         if (!_have_control) {
2183
2184                 /* We do not have control over the backend, so the best we can
2185                  * do is try to change the sample rate and/or bufsize and get
2186                  * out of here.
2187                  */
2188
2189                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2190                         return 1;
2191                 }
2192
2193                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2194                         return 1;
2195                 }
2196
2197                 if (change_rate) {
2198                         backend->set_sample_rate (get_rate());
2199                 }
2200
2201                 if (change_bufsize) {
2202                         backend->set_buffer_size (get_buffer_size());
2203                 }
2204
2205                 if (start) {
2206                         if (ARDOUR::AudioEngine::instance()->start ()) {
2207                                 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2208                                 return -1;
2209                         }
2210                 }
2211
2212                 post_push ();
2213
2214                 return 0;
2215         }
2216
2217         /* determine if we need to stop the backend before changing parameters */
2218
2219         if (change_driver || change_device || change_channels || change_latency ||
2220                         (change_rate && !backend->can_change_sample_rate_when_running()) ||
2221                         change_midi ||
2222                         (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2223                 restart_required = true;
2224         } else {
2225                 restart_required = false;
2226         }
2227
2228         if (was_running) {
2229
2230                 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2231                         /* no changes in any parameters that absolutely require a
2232                          * restart, so check those that might be changeable without a
2233                          * restart
2234                          */
2235
2236                         if (change_rate && !backend->can_change_sample_rate_when_running()) {
2237                                 /* can't do this while running ... */
2238                                 restart_required = true;
2239                         }
2240
2241                         if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2242                                 /* can't do this while running ... */
2243                                 restart_required = true;
2244                         }
2245                 }
2246         }
2247
2248         if (was_running) {
2249                 if (restart_required) {
2250                         if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2251                                 return -1;
2252                         }
2253                 }
2254         }
2255
2256
2257         if (change_driver && backend->set_driver (get_driver())) {
2258                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2259                 return -1;
2260         }
2261         if (backend->use_separate_input_and_output_devices()) {
2262                 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2263                         error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2264                         return -1;
2265                 }
2266                 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2267                         error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2268                         return -1;
2269                 }
2270         } else {
2271                 if (change_device && backend->set_device_name (get_device_name())) {
2272                         error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2273                         return -1;
2274                 }
2275         }
2276         if (change_rate && backend->set_sample_rate (get_rate())) {
2277                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2278                 return -1;
2279         }
2280         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2281                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2282                 return -1;
2283         }
2284
2285         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2286                 if (backend->set_input_channels (get_input_channels())) {
2287                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2288                         return -1;
2289                 }
2290                 if (backend->set_output_channels (get_output_channels())) {
2291                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2292                         return -1;
2293                 }
2294         }
2295         if (change_latency) {
2296                 if (backend->set_systemic_input_latency (get_input_latency())) {
2297                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2298                         return -1;
2299                 }
2300                 if (backend->set_systemic_output_latency (get_output_latency())) {
2301                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2302                         return -1;
2303                 }
2304         }
2305
2306         if (change_midi) {
2307                 backend->set_midi_option (get_midi_option());
2308         }
2309
2310         if (1 /* TODO */) {
2311                 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2312                         if (_measure_midi) {
2313                                 if (*p == _measure_midi) {
2314                                         backend->set_midi_device_enabled ((*p)->name, true);
2315                                 } else {
2316                                         backend->set_midi_device_enabled ((*p)->name, false);
2317                                 }
2318                                 continue;
2319                         }
2320                         backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2321                         if (backend->can_set_systemic_midi_latencies()) {
2322                                 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2323                                 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2324                         }
2325                 }
2326         }
2327
2328         if (start || (was_running && restart_required)) {
2329                 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2330                         return -1;
2331                 }
2332         }
2333
2334         post_push ();
2335
2336         return 0;
2337 }
2338
2339 void
2340 EngineControl::post_push ()
2341 {
2342         /* get a pointer to the current state object, creating one if
2343          * necessary
2344          */
2345
2346         State state = get_saved_state_for_currently_displayed_backend_and_device ();
2347
2348         if (!state) {
2349                 state = save_state ();
2350                 assert (state);
2351         } else {
2352                 store_state(state);
2353         }
2354
2355         /* all off */
2356
2357         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2358                 (*i)->active = false;
2359         }
2360
2361         /* mark this one active (to be used next time the dialog is
2362          * shown)
2363          */
2364
2365         state->active = true;
2366
2367         if (_have_control) { // XXX
2368                 manage_control_app_sensitivity ();
2369         }
2370
2371         /* schedule a redisplay of MIDI ports */
2372         //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2373 }
2374
2375
2376 float
2377 EngineControl::get_rate () const
2378 {
2379         float r = atof (sample_rate_combo.get_active_text ());
2380         /* the string may have been translated with an abbreviation for
2381          * thousands, so use a crude heuristic to fix this.
2382          */
2383         if (r < 1000.0) {
2384                 r *= 1000.0;
2385         }
2386         return r;
2387 }
2388
2389
2390 uint32_t
2391 EngineControl::get_buffer_size () const
2392 {
2393         string txt = buffer_size_combo.get_active_text ();
2394         uint32_t samples;
2395
2396         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2397                 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2398                 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2399                 throw exception ();
2400         }
2401
2402         return samples;
2403 }
2404
2405 string
2406 EngineControl::get_midi_option () const
2407 {
2408         return midi_option_combo.get_active_text();
2409 }
2410
2411 uint32_t
2412 EngineControl::get_input_channels() const
2413 {
2414         if (ARDOUR::Profile->get_mixbus()) {
2415                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2416                 if (!backend) return 0;
2417                 return backend->input_channels();
2418         }
2419         return (uint32_t) input_channels_adjustment.get_value();
2420 }
2421
2422 uint32_t
2423 EngineControl::get_output_channels() const
2424 {
2425         if (ARDOUR::Profile->get_mixbus()) {
2426                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2427                 if (!backend) return 0;
2428                 return backend->input_channels();
2429         }
2430         return (uint32_t) output_channels_adjustment.get_value();
2431 }
2432
2433 uint32_t
2434 EngineControl::get_input_latency() const
2435 {
2436         return (uint32_t) input_latency_adjustment.get_value();
2437 }
2438
2439 uint32_t
2440 EngineControl::get_output_latency() const
2441 {
2442         return (uint32_t) output_latency_adjustment.get_value();
2443 }
2444
2445 string
2446 EngineControl::get_backend () const
2447 {
2448         return backend_combo.get_active_text ();
2449 }
2450
2451 string
2452 EngineControl::get_driver () const
2453 {
2454         if (driver_combo.get_parent()) {
2455                 return driver_combo.get_active_text ();
2456         } else {
2457                 return "";
2458         }
2459 }
2460
2461 string
2462 EngineControl::get_device_name () const
2463 {
2464         return device_combo.get_active_text ();
2465 }
2466
2467 string
2468 EngineControl::get_input_device_name () const
2469 {
2470         return input_device_combo.get_active_text ();
2471 }
2472
2473 string
2474 EngineControl::get_output_device_name () const
2475 {
2476         return output_device_combo.get_active_text ();
2477 }
2478
2479 void
2480 EngineControl::control_app_button_clicked ()
2481 {
2482         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2483
2484         if (!backend) {
2485                 return;
2486         }
2487
2488         backend->launch_control_app ();
2489 }
2490
2491 void
2492 EngineControl::start_stop_button_clicked ()
2493 {
2494         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2495
2496         if (!backend) {
2497                 return;
2498         }
2499
2500         if (ARDOUR::AudioEngine::instance()->running()) {
2501                 ARDOUR::AudioEngine::instance()->stop ();
2502         } else {
2503                 push_state_to_backend (true);
2504         }
2505 }
2506
2507 void
2508 EngineControl::update_devices_button_clicked ()
2509 {
2510         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2511
2512         if (!backend) {
2513                 return;
2514         }
2515
2516         if (backend->update_devices()) {
2517                 device_list_changed ();
2518         }
2519 }
2520
2521 void
2522 EngineControl::manage_control_app_sensitivity ()
2523 {
2524         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2525
2526         if (!backend) {
2527                 return;
2528         }
2529
2530         string appname = backend->control_app_name();
2531
2532         if (appname.empty()) {
2533                 control_app_button.set_sensitive (false);
2534         } else {
2535                 control_app_button.set_sensitive (true);
2536         }
2537 }
2538
2539 void
2540 EngineControl::set_desired_sample_rate (uint32_t sr)
2541 {
2542         _desired_sample_rate = sr;
2543         device_changed ();
2544 }
2545
2546 void
2547 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2548 {
2549         if (page_num == 0) {
2550                 cancel_button->set_sensitive (true);
2551                 _measure_midi.reset();
2552                 update_sensitivity ();
2553         } else {
2554                 cancel_button->set_sensitive (false);
2555                 ok_button->set_sensitive (false);
2556         }
2557
2558         if (page_num == midi_tab) {
2559                 /* MIDI tab */
2560                 refresh_midi_display ();
2561         }
2562
2563         if (page_num == latency_tab) {
2564                 /* latency tab */
2565
2566                 if (ARDOUR::AudioEngine::instance()->running()) {
2567                         // TODO - mark as 'stopped for latency
2568                         ARDOUR_UI::instance()->disconnect_from_engine ();
2569                 }
2570
2571                 {
2572                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2573
2574                         /* save any existing latency values */
2575
2576                         uint32_t il = (uint32_t) input_latency.get_value ();
2577                         uint32_t ol = (uint32_t) input_latency.get_value ();
2578
2579                         /* reset to zero so that our new test instance
2580                            will be clean of any existing latency measures.
2581
2582                            NB. this should really be done by the backend
2583                            when stated for latency measurement.
2584                         */
2585
2586                         input_latency.set_value (0);
2587                         output_latency.set_value (0);
2588
2589                         push_state_to_backend (false);
2590
2591                         /* reset control */
2592
2593                         input_latency.set_value (il);
2594                         output_latency.set_value (ol);
2595
2596                 }
2597                 // This should be done in push_state_to_backend()
2598                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2599                         disable_latency_tab ();
2600                 }
2601
2602                 enable_latency_tab ();
2603
2604         } else {
2605                 if (lm_running) {
2606                         end_latency_detection ();
2607                         ARDOUR::AudioEngine::instance()->stop_latency_detection();
2608                 }
2609         }
2610 }
2611
2612 /* latency measurement */
2613
2614 bool
2615 EngineControl::check_audio_latency_measurement ()
2616 {
2617         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2618
2619         if (mtdm->resolve () < 0) {
2620                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2621                 return true;
2622         }
2623
2624         if (mtdm->err () > 0.3) {
2625                 mtdm->invert ();
2626                 mtdm->resolve ();
2627         }
2628
2629         char buf[256];
2630         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2631
2632         if (sample_rate == 0) {
2633                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2634                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2635                 return false;
2636         }
2637
2638         int frames_total = mtdm->del();
2639         int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2640
2641         snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2642                         _("Detected roundtrip latency: "),
2643                         frames_total, frames_total * 1000.0f/sample_rate,
2644                         _("Systemic latency: "),
2645                         extra, extra * 1000.0f/sample_rate);
2646
2647         bool solid = true;
2648
2649         if (mtdm->err () > 0.2) {
2650                 strcat (buf, " ");
2651                 strcat (buf, _("(signal detection error)"));
2652                 solid = false;
2653         }
2654
2655         if (mtdm->inv ()) {
2656                 strcat (buf, " ");
2657                 strcat (buf, _("(inverted - bad wiring)"));
2658                 solid = false;
2659         }
2660
2661         lm_results.set_markup (string_compose (results_markup, buf));
2662
2663         if (solid) {
2664                 have_lm_results = true;
2665                 end_latency_detection ();
2666                 lm_use_button.set_sensitive (true);
2667                 return false;
2668         }
2669
2670         return true;
2671 }
2672
2673 bool
2674 EngineControl::check_midi_latency_measurement ()
2675 {
2676         ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2677
2678         if (!mididm->have_signal () || mididm->latency () == 0) {
2679                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2680                 return true;
2681         }
2682
2683         char buf[256];
2684         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2685
2686         if (sample_rate == 0) {
2687                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2688                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2689                 return false;
2690         }
2691
2692         ARDOUR::framecnt_t frames_total = mididm->latency();
2693         ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2694         snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2695                         _("Detected roundtrip latency: "),
2696                         frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2697                         _("Systemic latency: "),
2698                         extra, extra * 1000.0f / sample_rate);
2699
2700         bool solid = true;
2701
2702         if (!mididm->ok ()) {
2703                 strcat (buf, " ");
2704                 strcat (buf, _("(averaging)"));
2705                 solid = false;
2706         }
2707
2708         if (mididm->deviation () > 50.0) {
2709                 strcat (buf, " ");
2710                 strcat (buf, _("(too large jitter)"));
2711                 solid = false;
2712         } else if (mididm->deviation () > 10.0) {
2713                 strcat (buf, " ");
2714                 strcat (buf, _("(large jitter)"));
2715         }
2716
2717         if (solid) {
2718                 have_lm_results = true;
2719                 end_latency_detection ();
2720                 lm_use_button.set_sensitive (true);
2721                 lm_results.set_markup (string_compose (results_markup, buf));
2722                 return false;
2723         } else if (mididm->processed () > 400) {
2724                 have_lm_results = false;
2725                 end_latency_detection ();
2726                 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2727                 return false;
2728         }
2729
2730         lm_results.set_markup (string_compose (results_markup, buf));
2731
2732         return true;
2733 }
2734
2735 void
2736 EngineControl::start_latency_detection ()
2737 {
2738         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2739         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2740
2741         if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2742                 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2743                 if (_measure_midi) {
2744                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2745                 } else {
2746                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2747                 }
2748                 lm_measure_label.set_text (_("Cancel"));
2749                 have_lm_results = false;
2750                 lm_use_button.set_sensitive (false);
2751                 lm_input_channel_combo.set_sensitive (false);
2752                 lm_output_channel_combo.set_sensitive (false);
2753                 lm_running = true;
2754         }
2755 }
2756
2757 void
2758 EngineControl::end_latency_detection ()
2759 {
2760         latency_timeout.disconnect ();
2761         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2762         lm_measure_label.set_text (_("Measure"));
2763         if (!have_lm_results) {
2764                 lm_use_button.set_sensitive (false);
2765         }
2766         lm_input_channel_combo.set_sensitive (true);
2767         lm_output_channel_combo.set_sensitive (true);
2768         lm_running = false;
2769 }
2770
2771 void
2772 EngineControl::latency_button_clicked ()
2773 {
2774         if (!lm_running) {
2775                 start_latency_detection ();
2776         } else {
2777                 end_latency_detection ();
2778         }
2779 }
2780
2781 void
2782 EngineControl::use_latency_button_clicked ()
2783 {
2784         if (_measure_midi) {
2785                 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2786                 if (!mididm) {
2787                         return;
2788                 }
2789                 ARDOUR::framecnt_t frames_total = mididm->latency();
2790                 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2791                 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2792                 _measure_midi->input_latency = one_way;
2793                 _measure_midi->output_latency = one_way;
2794                 notebook.set_current_page (midi_tab);
2795         } else {
2796                 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2797
2798                 if (!mtdm) {
2799                         return;
2800                 }
2801
2802                 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2803                 one_way = std::max (0., one_way);
2804
2805                 input_latency_adjustment.set_value (one_way);
2806                 output_latency_adjustment.set_value (one_way);
2807
2808                 /* back to settings page */
2809                 notebook.set_current_page (0);
2810 }
2811         }
2812
2813
2814 bool
2815 EngineControl::on_delete_event (GdkEventAny* ev)
2816 {
2817         if (notebook.get_current_page() == 2) {
2818                 /* currently on latency tab - be sure to clean up */
2819                 end_latency_detection ();
2820         }
2821         return ArdourDialog::on_delete_event (ev);
2822 }
2823
2824 void
2825 EngineControl::engine_running ()
2826 {
2827         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2828         assert (backend);
2829
2830         set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2831         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2832
2833         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2834         connect_disconnect_button.show();
2835
2836         started_at_least_once = true;
2837         if (_have_control) {
2838                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2839         } else {
2840                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2841         }
2842         update_sensitivity();
2843 }
2844
2845 void
2846 EngineControl::engine_stopped ()
2847 {
2848         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2849         assert (backend);
2850
2851         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2852         connect_disconnect_button.show();
2853
2854         if (_have_control) {
2855                 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
2856         } else {
2857                 engine_status.set_markup(X_(""));
2858         }
2859
2860         update_sensitivity();
2861 }
2862
2863 void
2864 EngineControl::device_list_changed ()
2865 {
2866         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2867         list_devices ();
2868         midi_option_changed();
2869 }
2870
2871 void
2872 EngineControl::connect_disconnect_click()
2873 {
2874         if (ARDOUR::AudioEngine::instance()->running()) {
2875                 ARDOUR_UI::instance()->disconnect_from_engine ();
2876         } else {
2877                 ARDOUR_UI::instance()->reconnect_to_engine ();
2878         }
2879 }
2880
2881 void
2882 EngineControl::calibrate_audio_latency ()
2883 {
2884         _measure_midi.reset ();
2885         have_lm_results = false;
2886         lm_use_button.set_sensitive (false);
2887         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2888         notebook.set_current_page (latency_tab);
2889 }
2890
2891 void
2892 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2893 {
2894         _measure_midi = s;
2895         have_lm_results = false;
2896         lm_use_button.set_sensitive (false);
2897         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2898         notebook.set_current_page (latency_tab);
2899 }
2900
2901 void
2902 EngineControl::configure_midi_devices ()
2903 {
2904         notebook.set_current_page (midi_tab);
2905 }