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