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