Run gtk-main iteration after hiding dialogs
[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 (to_string (*x));
1486         }
1487
1488         set_popdown_strings (nperiods_combo, s);
1489
1490         if (!s.empty()) {
1491                 set_active_text_if_present (nperiods_combo, to_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), to_string(sz));
1612 }
1613
1614 void
1615 EngineControl::sample_rate_changed ()
1616 {
1617         DEBUG_ECONTROL ("sample_rate_changed");
1618         /* reset the strings for buffer size to show the correct msec value
1619            (reflecting the new sample rate).
1620          */
1621
1622         show_buffer_duration ();
1623
1624 }
1625
1626 void
1627 EngineControl::buffer_size_changed ()
1628 {
1629         DEBUG_ECONTROL ("buffer_size_changed");
1630         show_buffer_duration ();
1631 }
1632
1633 void
1634 EngineControl::nperiods_changed ()
1635 {
1636         DEBUG_ECONTROL ("nperiods_changed");
1637         show_buffer_duration ();
1638 }
1639
1640 void
1641 EngineControl::show_buffer_duration ()
1642 {
1643         DEBUG_ECONTROL ("show_buffer_duration");
1644         /* buffer sizes  - convert from just samples to samples + msecs for
1645          * the displayed string
1646          */
1647
1648         string bs_text = buffer_size_combo.get_active_text ();
1649         uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1650         uint32_t rate = get_rate();
1651
1652         /* Except for ALSA and Dummy backends, we don't know the number of periods
1653          * per cycle and settings.
1654          *
1655          * jack1 vs jack2 have different default latencies since jack2 start
1656          * in async-mode unless --sync is given which adds an extra cycle
1657          * of latency. The value is not known if jackd is started externally..
1658          *
1659          * So just display the period size, that's also what
1660          * ARDOUR_UI::update_sample_rate() does for the status bar.
1661          * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1662          * but still, that's the buffer period, not [round-trip] latency)
1663          */
1664         char buf[32];
1665         snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1666         buffer_size_duration_label.set_text (buf);
1667 }
1668
1669 void
1670 EngineControl::midi_option_changed ()
1671 {
1672         DEBUG_ECONTROL ("midi_option_changed");
1673         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1674         assert (backend);
1675
1676         backend->set_midi_option (get_midi_option());
1677
1678         vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1679
1680         //_midi_devices.clear(); // TODO merge with state-saved settings..
1681         _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1682         std::vector<MidiDeviceSettings> new_devices;
1683
1684         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1685                 MidiDeviceSettings mds = find_midi_device (i->name);
1686                 if (i->available && !mds) {
1687                         uint32_t input_latency = 0;
1688                         uint32_t output_latency = 0;
1689                         if (_can_set_midi_latencies) {
1690                                 input_latency = backend->systemic_midi_input_latency (i->name);
1691                                 output_latency = backend->systemic_midi_output_latency (i->name);
1692                         }
1693                         bool enabled = backend->midi_device_enabled (i->name);
1694                         MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1695                         new_devices.push_back (ptr);
1696                 } else if (i->available) {
1697                         new_devices.push_back (mds);
1698                 }
1699         }
1700         _midi_devices = new_devices;
1701
1702         if (_midi_devices.empty()) {
1703                 midi_devices_button.hide ();
1704         } else {
1705                 midi_devices_button.show ();
1706         }
1707 }
1708
1709 void
1710 EngineControl::parameter_changed ()
1711 {
1712 }
1713
1714 EngineControl::State
1715 EngineControl::get_matching_state (const string& backend)
1716 {
1717         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1718                 if ((*i)->backend == backend) {
1719                         return (*i);
1720                 }
1721         }
1722         return State();
1723 }
1724
1725 EngineControl::State
1726 EngineControl::get_matching_state (
1727                 const string& backend,
1728                 const string& driver,
1729                 const string& device)
1730 {
1731         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1732                 if ((*i)->backend == backend &&
1733                                 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1734                 {
1735                         return (*i);
1736                 }
1737         }
1738         return State();
1739 }
1740
1741 EngineControl::State
1742 EngineControl::get_matching_state (
1743                 const string& backend,
1744                 const string& driver,
1745                 const string& input_device,
1746                 const string& output_device)
1747 {
1748         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1749                 if ((*i)->backend == backend &&
1750                                 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1751                 {
1752                         return (*i);
1753                 }
1754         }
1755         return State();
1756 }
1757
1758 EngineControl::State
1759 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1760 {
1761         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1762
1763         if (backend) {
1764                 if (backend->use_separate_input_and_output_devices ()) {
1765                         return get_matching_state (backend_combo.get_active_text(),
1766                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1767                                         input_device_combo.get_active_text(),
1768                                         output_device_combo.get_active_text());
1769                 } else {
1770                         return get_matching_state (backend_combo.get_active_text(),
1771                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1772                                         device_combo.get_active_text());
1773                 }
1774         }
1775
1776         return get_matching_state (backend_combo.get_active_text(),
1777                         string(),
1778                         device_combo.get_active_text());
1779 }
1780
1781 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1782                                        const EngineControl::State& state2)
1783 {
1784         if (state1->backend == state2->backend &&
1785                         state1->driver == state2->driver &&
1786                         state1->device == state2->device &&
1787                         state1->input_device == state2->input_device &&
1788                         state1->output_device == state2->output_device) {
1789                 return true;
1790         }
1791         return false;
1792 }
1793
1794 // sort active first, then most recently used to the beginning of the list
1795 bool
1796 EngineControl::state_sort_cmp (const State &a, const State &b) {
1797         if (a->active) {
1798                 return true;
1799         }
1800         else if (b->active) {
1801                 return false;
1802         }
1803         else {
1804                 return a->lru > b->lru;
1805         }
1806 }
1807
1808 EngineControl::State
1809 EngineControl::save_state ()
1810 {
1811         State state;
1812
1813         if (!_have_control) {
1814                 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1815                 if (state) {
1816                         state->lru = time (NULL) ;
1817                         return state;
1818                 }
1819                 state.reset(new StateStruct);
1820                 state->backend = get_backend ();
1821         } else {
1822                 state.reset(new StateStruct);
1823                 store_state (state);
1824         }
1825
1826         for (StateList::iterator i = states.begin(); i != states.end();) {
1827                 if (equivalent_states (*i, state)) {
1828                         i =  states.erase(i);
1829                 } else {
1830                         ++i;
1831                 }
1832         }
1833
1834         states.push_back (state);
1835
1836         states.sort (state_sort_cmp);
1837
1838         return state;
1839 }
1840
1841 void
1842 EngineControl::store_state (State state)
1843 {
1844         state->backend = get_backend ();
1845         state->driver = get_driver ();
1846         state->device = get_device_name ();
1847         state->input_device = get_input_device_name ();
1848         state->output_device = get_output_device_name ();
1849         state->sample_rate = get_rate ();
1850         state->buffer_size = get_buffer_size ();
1851         state->n_periods = get_nperiods ();
1852         state->input_latency = get_input_latency ();
1853         state->output_latency = get_output_latency ();
1854         state->input_channels = get_input_channels ();
1855         state->output_channels = get_output_channels ();
1856         state->midi_option = get_midi_option ();
1857         state->midi_devices = _midi_devices;
1858         state->use_buffered_io = get_use_buffered_io ();
1859         state->lru = time (NULL) ;
1860 }
1861
1862 void
1863 EngineControl::maybe_display_saved_state ()
1864 {
1865         if (!_have_control) {
1866                 return;
1867         }
1868
1869         State state = get_saved_state_for_currently_displayed_backend_and_device ();
1870
1871         if (state) {
1872                 DEBUG_ECONTROL ("Restoring saved state");
1873                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1874
1875                 if (!_desired_sample_rate) {
1876                         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1877                 }
1878                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1879
1880                 set_active_text_if_present (nperiods_combo, to_string(state->n_periods));
1881                 /* call this explicitly because we're ignoring changes to
1882                    the controls at this point.
1883                  */
1884                 show_buffer_duration ();
1885                 input_latency.set_value (state->input_latency);
1886                 output_latency.set_value (state->output_latency);
1887
1888                 use_buffered_io_button.set_active (state->use_buffered_io);
1889
1890                 if (!state->midi_option.empty()) {
1891                         midi_option_combo.set_active_text (state->midi_option);
1892                         _midi_devices = state->midi_devices;
1893                 }
1894         } else {
1895                 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1896         }
1897 }
1898
1899 XMLNode&
1900 EngineControl::get_state ()
1901 {
1902         LocaleGuard lg;
1903
1904         XMLNode* root = new XMLNode ("AudioMIDISetup");
1905         std::string path;
1906
1907         if (!states.empty()) {
1908                 XMLNode* state_nodes = new XMLNode ("EngineStates");
1909
1910                 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1911
1912                         XMLNode* node = new XMLNode ("State");
1913
1914                         node->set_property ("backend", (*i)->backend);
1915                         node->set_property ("driver", (*i)->driver);
1916                         node->set_property ("device", (*i)->device);
1917                         node->set_property ("input-device", (*i)->input_device);
1918                         node->set_property ("output-device", (*i)->output_device);
1919                         node->set_property ("sample-rate", (*i)->sample_rate);
1920                         node->set_property ("buffer-size", (*i)->buffer_size);
1921                         node->set_property ("n-periods", (*i)->n_periods);
1922                         node->set_property ("input-latency", (*i)->input_latency);
1923                         node->set_property ("output-latency", (*i)->output_latency);
1924                         node->set_property ("input-channels", (*i)->input_channels);
1925                         node->set_property ("output-channels", (*i)->output_channels);
1926                         node->set_property ("active", (*i)->active);
1927                         node->set_property ("use-buffered-io", (*i)->use_buffered_io);
1928                         node->set_property ("midi-option", (*i)->midi_option);
1929                         int32_t lru_val = (*i)->active ? time (NULL) : (*i)->lru;
1930                         node->set_property ("lru", lru_val );
1931
1932                         XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1933                         for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1934                                 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1935                                 midi_device_stuff->set_property (X_("name"), (*p)->name);
1936                                 midi_device_stuff->set_property (X_("enabled"), (*p)->enabled);
1937                                 midi_device_stuff->set_property (X_("input-latency"), (*p)->input_latency);
1938                                 midi_device_stuff->set_property (X_("output-latency"), (*p)->output_latency);
1939                                 midi_devices->add_child_nocopy (*midi_device_stuff);
1940                         }
1941                         node->add_child_nocopy (*midi_devices);
1942
1943                         state_nodes->add_child_nocopy (*node);
1944                 }
1945
1946                 root->add_child_nocopy (*state_nodes);
1947         }
1948
1949         return *root;
1950 }
1951
1952 void
1953 EngineControl::set_default_state ()
1954 {
1955         vector<string> backend_names;
1956         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1957
1958         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1959                 backend_names.push_back ((*b)->name);
1960         }
1961         backend_combo.set_active_text (backend_names.front());
1962
1963         // We could set default backends per platform etc here
1964
1965         backend_changed ();
1966 }
1967
1968 bool
1969 EngineControl::set_state (const XMLNode& root)
1970 {
1971         XMLNodeList          clist, cclist;
1972         XMLNodeConstIterator citer, cciter;
1973         XMLNode const * child;
1974         XMLNode const * grandchild;
1975
1976         if (root.name() != "AudioMIDISetup") {
1977                 return false;
1978         }
1979
1980         clist = root.children();
1981
1982         states.clear ();
1983
1984         for (citer = clist.begin(); citer != clist.end(); ++citer) {
1985
1986                 child = *citer;
1987
1988                 if (child->name() != "EngineStates") {
1989                         continue;
1990                 }
1991
1992                 cclist = child->children();
1993
1994                 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1995                         State state (new StateStruct);
1996
1997                         grandchild = *cciter;
1998
1999                         if (grandchild->name() != "State") {
2000                                 continue;
2001                         }
2002
2003                         if (!grandchild->get_property ("backend", state->backend)) {
2004                                 continue;
2005                         }
2006
2007                         // If any of the required properties are not found in the state node
2008                         // then continue/skip to the next engine state
2009                         if (!grandchild->get_property ("driver", state->driver) ||
2010                             !grandchild->get_property ("device", state->device) ||
2011                             !grandchild->get_property ("input-device", state->input_device) ||
2012                             !grandchild->get_property ("output-device", state->output_device) ||
2013                             !grandchild->get_property ("sample-rate", state->sample_rate) ||
2014                             !grandchild->get_property ("buffer-size", state->buffer_size) ||
2015                             !grandchild->get_property ("input-latency", state->input_latency) ||
2016                             !grandchild->get_property ("output-latency", state->output_latency) ||
2017                             !grandchild->get_property ("input-channels", state->input_channels) ||
2018                             !grandchild->get_property ("output-channels", state->output_channels) ||
2019                             !grandchild->get_property ("active", state->active) ||
2020                             !grandchild->get_property ("use-buffered-io", state->use_buffered_io) ||
2021                             !grandchild->get_property ("midi-option", state->midi_option)) {
2022                                 continue;
2023                         }
2024
2025                         if (!grandchild->get_property ("n-periods", state->n_periods)) {
2026                                 // optional (new value in 4.5)
2027                                 state->n_periods = 0;
2028                         }
2029
2030                         state->midi_devices.clear();
2031                         XMLNode* midinode;
2032                         if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2033                                 const XMLNodeList mnc = midinode->children();
2034                                 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2035                                         std::string name;
2036                                         bool enabled;
2037                                         uint32_t input_latency;
2038                                         uint32_t output_latency;
2039
2040                                         if (!(*n)->get_property (X_("name"), name) ||
2041                                             !(*n)->get_property (X_("enabled"), enabled) ||
2042                                             !(*n)->get_property (X_("input-latency"), input_latency) ||
2043                                             !(*n)->get_property (X_("output-latency"), output_latency)) {
2044                                                 continue;
2045                                         }
2046
2047                                         MidiDeviceSettings ptr (
2048                                             new MidiDeviceSetting (name, enabled, input_latency, output_latency));
2049                                         state->midi_devices.push_back (ptr);
2050                                 }
2051                         }
2052
2053                         int32_t lru_val;
2054                         if (grandchild->get_property ("lru", lru_val)) {
2055                                 state->lru = lru_val;
2056                         }
2057
2058 #if 1
2059                         /* remove accumulated duplicates (due to bug in ealier version)
2060                          * this can be removed again before release
2061                          */
2062                         for (StateList::iterator i = states.begin(); i != states.end();) {
2063                                 if ((*i)->backend == state->backend &&
2064                                                 (*i)->driver == state->driver &&
2065                                                 (*i)->device == state->device) {
2066                                         i =  states.erase(i);
2067                                 } else {
2068                                         ++i;
2069                                 }
2070                         }
2071 #endif
2072
2073                         states.push_back (state);
2074                 }
2075         }
2076
2077         /* now see if there was an active state and switch the setup to it */
2078
2079         // purge states of backend that are not available in this built
2080         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2081         vector<std::string> backend_names;
2082
2083         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2084                 backend_names.push_back((*i)->name);
2085         }
2086         for (StateList::iterator i = states.begin(); i != states.end();) {
2087                 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2088                         i = states.erase(i);
2089                 } else {
2090                         ++i;
2091                 }
2092         }
2093
2094         states.sort (state_sort_cmp);
2095
2096         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2097
2098                 if ((*i)->active) {
2099                         return set_current_state (*i);
2100                 }
2101         }
2102         return false;
2103 }
2104
2105 bool
2106 EngineControl::set_current_state (const State& state)
2107 {
2108         DEBUG_ECONTROL ("set_current_state");
2109
2110         boost::shared_ptr<ARDOUR::AudioBackend> backend;
2111
2112         if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2113                   state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2114                 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2115                 // this shouldn't happen as the invalid backend names should have been
2116                 // removed from the list of states.
2117                 return false;
2118         }
2119
2120         // now reflect the change in the backend in the GUI so backend_changed will
2121         // do the right thing
2122         backend_combo.set_active_text (state->backend);
2123
2124         if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2125                 backend_changed ();
2126                 // we don't have control don't restore state
2127                 return true;
2128         }
2129
2130
2131         if (!state->driver.empty ()) {
2132                 if (!backend->requires_driver_selection ()) {
2133                         DEBUG_ECONTROL ("Backend should require driver selection");
2134                         // A backend has changed from having driver selection to not having
2135                         // it or someone has been manually editing a config file and messed
2136                         // it up
2137                         return false;
2138                 }
2139
2140                 if (backend->set_driver (state->driver) != 0) {
2141                         DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2142                         // Driver names for a backend have changed and the name in the
2143                         // config file is now invalid or support for driver is no longer
2144                         // included in the backend
2145                         return false;
2146                 }
2147                 // no need to set the driver_combo as backend_changed will use
2148                 // backend->driver_name to set the active driver
2149         }
2150
2151         if (!state->device.empty ()) {
2152                 if (backend->set_device_name (state->device) != 0) {
2153                         DEBUG_ECONTROL (
2154                             string_compose ("Unable to set device name %1", state->device));
2155                         // device is no longer available on the system
2156                         return false;
2157                 }
2158                 // no need to set active device as it will be picked up in
2159                 // via backend_changed ()/set_device_popdown_strings
2160
2161         } else {
2162                 // backend supports separate input/output devices
2163                 if (backend->set_input_device_name (state->input_device) != 0) {
2164                         DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2165                                                         state->input_device));
2166                         // input device is no longer available on the system
2167                         return false;
2168                 }
2169
2170                 if (backend->set_output_device_name (state->output_device) != 0) {
2171                         DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2172                                                         state->input_device));
2173                         // output device is no longer available on the system
2174                         return false;
2175                 }
2176                 // no need to set active devices as it will be picked up in via
2177                 // backend_changed ()/set_*_device_popdown_strings
2178         }
2179
2180         backend_changed ();
2181
2182         // Now restore the state of the rest of the controls
2183
2184         // We don't use a SignalBlocker as set_current_state is currently only
2185         // called from set_state before any signals are connected. If at some point
2186         // a more general named state mechanism is implemented and
2187         // set_current_state is called while signals are connected then a
2188         // SignalBlocker will need to be instantiated before setting these.
2189
2190         device_combo.set_active_text (state->device);
2191         input_device_combo.set_active_text (state->input_device);
2192         output_device_combo.set_active_text (state->output_device);
2193         if (!_desired_sample_rate) {
2194                 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2195         }
2196         set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2197         set_active_text_if_present (nperiods_combo, to_string (state->n_periods));
2198         input_latency.set_value (state->input_latency);
2199         output_latency.set_value (state->output_latency);
2200         midi_option_combo.set_active_text (state->midi_option);
2201         use_buffered_io_button.set_active (state->use_buffered_io);
2202         return true;
2203 }
2204
2205 int
2206 EngineControl::push_state_to_backend (bool start)
2207 {
2208         DEBUG_ECONTROL ("push_state_to_backend");
2209         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2210         PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2211
2212         if (!backend) {
2213                 return 0;
2214         }
2215
2216         /* figure out what is going to change */
2217
2218         bool restart_required = false;
2219         bool was_running = ARDOUR::AudioEngine::instance()->running();
2220         bool change_driver = false;
2221         bool change_device = false;
2222         bool change_rate = false;
2223         bool change_bufsize = false;
2224         bool change_nperiods = false;
2225         bool change_latency = false;
2226         bool change_channels = false;
2227         bool change_midi = false;
2228         bool change_buffered_io = false;
2229
2230         uint32_t ochan = get_output_channels ();
2231         uint32_t ichan = get_input_channels ();
2232
2233         if (_have_control) {
2234
2235                 if (started_at_least_once) {
2236
2237                         /* we can control the backend */
2238
2239                         if (backend->requires_driver_selection()) {
2240                                 if (get_driver() != backend->driver_name()) {
2241                                         change_driver = true;
2242                                 }
2243                         }
2244
2245                         if (backend->use_separate_input_and_output_devices()) {
2246                                 if (get_input_device_name() != backend->input_device_name()) {
2247                                         change_device = true;
2248                                 }
2249                                 if (get_output_device_name() != backend->output_device_name()) {
2250                                         change_device = true;
2251                                 }
2252                         } else {
2253                                 if (get_device_name() != backend->device_name()) {
2254                                         change_device = true;
2255                                 }
2256                         }
2257
2258                         if (queue_device_changed) {
2259                                 change_device = true;
2260                         }
2261
2262                         if (get_rate() != backend->sample_rate()) {
2263                                 change_rate = true;
2264                         }
2265
2266                         if (get_buffer_size() != backend->buffer_size()) {
2267                                 change_bufsize = true;
2268                         }
2269
2270                         if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2271                                         && get_nperiods() != backend->period_size()) {
2272                                 change_nperiods = true;
2273                         }
2274
2275                         if (get_midi_option() != backend->midi_option()) {
2276                                 change_midi = true;
2277                         }
2278
2279                         if (backend->can_use_buffered_io()) {
2280                                 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2281                                         change_buffered_io = true;
2282                                 }
2283                         }
2284
2285                         /* zero-requested channels means "all available" */
2286
2287                         if (ichan == 0) {
2288                                 ichan = backend->input_channels();
2289                         }
2290
2291                         if (ochan == 0) {
2292                                 ochan = backend->output_channels();
2293                         }
2294
2295                         if (ichan != backend->input_channels()) {
2296                                 change_channels = true;
2297                         }
2298
2299                         if (ochan != backend->output_channels()) {
2300                                 change_channels = true;
2301                         }
2302
2303                         if (get_input_latency() != backend->systemic_input_latency() ||
2304                                         get_output_latency() != backend->systemic_output_latency()) {
2305                                 change_latency = true;
2306                         }
2307                 } else {
2308                         /* backend never started, so we have to force a group
2309                            of settings.
2310                          */
2311                         change_device = true;
2312                         if (backend->requires_driver_selection()) {
2313                                 change_driver = true;
2314                         }
2315                         change_rate = true;
2316                         change_bufsize = true;
2317                         change_channels = true;
2318                         change_latency = true;
2319                         change_midi = true;
2320                         change_buffered_io = backend->can_use_buffered_io();
2321                         change_channels = true;
2322                         change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2323                 }
2324
2325         } else {
2326
2327                 /* we have no control over the backend, meaning that we can
2328                  * only possibly change sample rate and buffer size.
2329                  */
2330
2331
2332                 if (get_rate() != backend->sample_rate()) {
2333                         change_bufsize = true;
2334                 }
2335
2336                 if (get_buffer_size() != backend->buffer_size()) {
2337                         change_bufsize = true;
2338                 }
2339         }
2340
2341         queue_device_changed = false;
2342
2343         if (!_have_control) {
2344
2345                 /* We do not have control over the backend, so the best we can
2346                  * do is try to change the sample rate and/or bufsize and get
2347                  * out of here.
2348                  */
2349
2350                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2351                         return 1;
2352                 }
2353
2354                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2355                         return 1;
2356                 }
2357
2358                 if (change_rate) {
2359                         backend->set_sample_rate (get_rate());
2360                 }
2361
2362                 if (change_bufsize) {
2363                         backend->set_buffer_size (get_buffer_size());
2364                 }
2365
2366                 if (start) {
2367                         if (ARDOUR::AudioEngine::instance()->start ()) {
2368                                 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2369                                 return -1;
2370                         }
2371                 }
2372
2373                 post_push ();
2374
2375                 return 0;
2376         }
2377
2378         /* determine if we need to stop the backend before changing parameters */
2379
2380         if (change_driver || change_device || change_channels || change_nperiods ||
2381                         (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2382                         (change_rate && !backend->can_change_sample_rate_when_running()) ||
2383                         change_midi || change_buffered_io ||
2384                         (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2385                 restart_required = true;
2386         } else {
2387                 restart_required = false;
2388         }
2389
2390
2391         if (was_running) {
2392                 if (restart_required) {
2393                         if (ARDOUR::AudioEngine::instance()->stop()) {
2394                                 return -1;
2395                         }
2396                 }
2397         }
2398
2399         if (change_driver && backend->set_driver (get_driver())) {
2400                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2401                 return -1;
2402         }
2403         if (backend->use_separate_input_and_output_devices()) {
2404                 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2405                         error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2406                         return -1;
2407                 }
2408                 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2409                         error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2410                         return -1;
2411                 }
2412         } else {
2413                 if (change_device && backend->set_device_name (get_device_name())) {
2414                         error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2415                         return -1;
2416                 }
2417         }
2418         if (change_rate && backend->set_sample_rate (get_rate())) {
2419                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2420                 return -1;
2421         }
2422         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2423                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2424                 return -1;
2425         }
2426         if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2427                 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2428                 return -1;
2429         }
2430
2431         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2432                 if (backend->set_input_channels (get_input_channels())) {
2433                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2434                         return -1;
2435                 }
2436                 if (backend->set_output_channels (get_output_channels())) {
2437                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2438                         return -1;
2439                 }
2440         }
2441         if (change_latency) {
2442                 if (backend->set_systemic_input_latency (get_input_latency())) {
2443                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2444                         return -1;
2445                 }
2446                 if (backend->set_systemic_output_latency (get_output_latency())) {
2447                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2448                         return -1;
2449                 }
2450         }
2451
2452         if (change_midi) {
2453                 backend->set_midi_option (get_midi_option());
2454         }
2455
2456         if (change_buffered_io) {
2457                 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2458         }
2459
2460         if (1 /* TODO */) {
2461                 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2462                         if (_measure_midi) {
2463                                 if (*p == _measure_midi) {
2464                                         backend->set_midi_device_enabled ((*p)->name, true);
2465                                 } else {
2466                                         backend->set_midi_device_enabled ((*p)->name, false);
2467                                 }
2468                                 if (backend->can_change_systemic_latency_when_running ()) {
2469                                         backend->set_systemic_midi_input_latency ((*p)->name, 0);
2470                                         backend->set_systemic_midi_output_latency ((*p)->name, 0);
2471                                 }
2472                                 continue;
2473                         }
2474                         backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2475                         if (backend->can_set_systemic_midi_latencies()) {
2476                                 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2477                                 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2478                         }
2479                 }
2480         }
2481
2482         if (start || (was_running && restart_required)) {
2483                 if (ARDOUR::AudioEngine::instance()->start()) {
2484                         return -1;
2485                 }
2486         }
2487
2488         post_push ();
2489
2490         return 0;
2491 }
2492
2493 void
2494 EngineControl::post_push ()
2495 {
2496         /* get a pointer to the current state object, creating one if
2497          * necessary
2498          */
2499
2500         State state = get_saved_state_for_currently_displayed_backend_and_device ();
2501
2502         if (!state) {
2503                 state = save_state ();
2504                 assert (state);
2505         } else {
2506                 store_state(state);
2507         }
2508
2509         states.sort (state_sort_cmp);
2510
2511         /* all off */
2512
2513         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2514                 (*i)->active = false;
2515         }
2516
2517         /* mark this one active (to be used next time the dialog is
2518          * shown)
2519          */
2520
2521         state->active = true;
2522
2523         if (_have_control) { // XXX
2524                 manage_control_app_sensitivity ();
2525         }
2526
2527         /* schedule a redisplay of MIDI ports */
2528         //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2529 }
2530
2531
2532 float
2533 EngineControl::get_rate () const
2534 {
2535         float r = atof (sample_rate_combo.get_active_text ());
2536         /* the string may have been translated with an abbreviation for
2537          * thousands, so use a crude heuristic to fix this.
2538          */
2539         if (r < 1000.0) {
2540                 r *= 1000.0;
2541         }
2542         return r;
2543 }
2544
2545
2546 uint32_t
2547 EngineControl::get_buffer_size () const
2548 {
2549         string txt = buffer_size_combo.get_active_text ();
2550         uint32_t samples;
2551
2552         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2553                 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2554                 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2555                 throw exception ();
2556         }
2557
2558         return samples;
2559 }
2560
2561 uint32_t
2562 EngineControl::get_nperiods () const
2563 {
2564         string txt = nperiods_combo.get_active_text ();
2565         return atoi (txt.c_str());
2566 }
2567
2568 string
2569 EngineControl::get_midi_option () const
2570 {
2571         return midi_option_combo.get_active_text();
2572 }
2573
2574 bool
2575 EngineControl::get_use_buffered_io () const
2576 {
2577         return use_buffered_io_button.get_active();
2578 }
2579
2580 uint32_t
2581 EngineControl::get_input_channels() const
2582 {
2583         if (ARDOUR::Profile->get_mixbus()) {
2584                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2585                 if (!backend) return 0;
2586                 return backend->input_channels();
2587         }
2588         return (uint32_t) input_channels_adjustment.get_value();
2589 }
2590
2591 uint32_t
2592 EngineControl::get_output_channels() const
2593 {
2594         if (ARDOUR::Profile->get_mixbus()) {
2595                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2596                 if (!backend) return 0;
2597                 return backend->input_channels();
2598         }
2599         return (uint32_t) output_channels_adjustment.get_value();
2600 }
2601
2602 uint32_t
2603 EngineControl::get_input_latency() const
2604 {
2605         return (uint32_t) input_latency_adjustment.get_value();
2606 }
2607
2608 uint32_t
2609 EngineControl::get_output_latency() const
2610 {
2611         return (uint32_t) output_latency_adjustment.get_value();
2612 }
2613
2614 string
2615 EngineControl::get_backend () const
2616 {
2617         return backend_combo.get_active_text ();
2618 }
2619
2620 string
2621 EngineControl::get_driver () const
2622 {
2623         if (driver_combo.get_parent()) {
2624                 return driver_combo.get_active_text ();
2625         } else {
2626                 return "";
2627         }
2628 }
2629
2630 string
2631 EngineControl::get_device_name () const
2632 {
2633         return device_combo.get_active_text ();
2634 }
2635
2636 string
2637 EngineControl::get_input_device_name () const
2638 {
2639         return input_device_combo.get_active_text ();
2640 }
2641
2642 string
2643 EngineControl::get_output_device_name () const
2644 {
2645         return output_device_combo.get_active_text ();
2646 }
2647
2648 void
2649 EngineControl::control_app_button_clicked ()
2650 {
2651         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2652
2653         if (!backend) {
2654                 return;
2655         }
2656
2657         backend->launch_control_app ();
2658 }
2659
2660 void
2661 EngineControl::start_stop_button_clicked ()
2662 {
2663         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2664
2665         if (!backend) {
2666                 return;
2667         }
2668
2669         if (ARDOUR::AudioEngine::instance()->running()) {
2670                 ARDOUR::AudioEngine::instance()->stop ();
2671         } else {
2672                 if (!ARDOUR_UI::instance()->session_loaded) {
2673                         hide ();
2674                         ARDOUR::GUIIdle ();
2675                 }
2676                 start_engine ();
2677                 if (!ARDOUR_UI::instance()->session_loaded) {
2678                         ArdourDialog::on_response (RESPONSE_OK);
2679                 }
2680         }
2681 }
2682
2683 void
2684 EngineControl::update_devices_button_clicked ()
2685 {
2686         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2687
2688         if (!backend) {
2689                 return;
2690         }
2691
2692         if (backend->update_devices()) {
2693                 device_list_changed ();
2694         }
2695 }
2696
2697 void
2698 EngineControl::use_buffered_io_button_clicked ()
2699 {
2700         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2701
2702         if (!backend) {
2703                 return;
2704         }
2705
2706         bool set_buffered_io = !use_buffered_io_button.get_active();
2707         use_buffered_io_button.set_active (set_buffered_io);
2708         backend->set_use_buffered_io (set_buffered_io);
2709 }
2710
2711 void
2712 EngineControl::manage_control_app_sensitivity ()
2713 {
2714         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2715
2716         if (!backend) {
2717                 return;
2718         }
2719
2720         string appname = backend->control_app_name();
2721
2722         if (appname.empty()) {
2723                 control_app_button.set_sensitive (false);
2724         } else {
2725                 control_app_button.set_sensitive (true);
2726         }
2727 }
2728
2729 void
2730 EngineControl::set_desired_sample_rate (uint32_t sr)
2731 {
2732         _desired_sample_rate = sr;
2733         if (ARDOUR::AudioEngine::instance ()->running ()
2734                         && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2735                 stop_engine ();
2736         }
2737         device_changed ();
2738 }
2739
2740 void
2741 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2742 {
2743         if (page_num == 0) {
2744                 _measure_midi.reset();
2745                 update_sensitivity ();
2746         }
2747
2748         if (page_num == midi_tab) {
2749                 /* MIDI tab */
2750                 refresh_midi_display ();
2751         }
2752
2753         if (page_num == latency_tab) {
2754                 /* latency tab */
2755
2756                 if (ARDOUR::AudioEngine::instance()->running()) {
2757                         stop_engine (true);
2758                 }
2759
2760                 {
2761                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2762
2763                         /* save any existing latency values */
2764
2765                         uint32_t il = (uint32_t) input_latency.get_value ();
2766                         uint32_t ol = (uint32_t) input_latency.get_value ();
2767
2768                         /* reset to zero so that our new test instance
2769                            will be clean of any existing latency measures.
2770
2771                            NB. this should really be done by the backend
2772                            when stated for latency measurement.
2773                         */
2774
2775                         input_latency.set_value (0);
2776                         output_latency.set_value (0);
2777
2778                         push_state_to_backend (false);
2779
2780                         /* reset control */
2781
2782                         input_latency.set_value (il);
2783                         output_latency.set_value (ol);
2784
2785                 }
2786                 // This should be done in push_state_to_backend()
2787                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2788                         disable_latency_tab ();
2789                 }
2790
2791                 enable_latency_tab ();
2792
2793         } else {
2794                 if (lm_running) {
2795                         end_latency_detection ();
2796                         ARDOUR::AudioEngine::instance()->stop_latency_detection();
2797                 }
2798         }
2799 }
2800
2801 /* latency measurement */
2802
2803 bool
2804 EngineControl::check_audio_latency_measurement ()
2805 {
2806         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2807
2808         if (mtdm->resolve () < 0) {
2809                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2810                 return true;
2811         }
2812
2813         if (mtdm->get_peak () > 0.707f) {
2814                 // get_peak() resets the peak-hold in the detector.
2815                 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2816                 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2817                 return true;
2818         }
2819
2820         if (mtdm->err () > 0.3) {
2821                 mtdm->invert ();
2822                 mtdm->resolve ();
2823         }
2824
2825         char buf[256];
2826         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2827
2828         if (sample_rate == 0) {
2829                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2830                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2831                 return false;
2832         }
2833
2834         int frames_total = mtdm->del();
2835         int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2836
2837         snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2838                         _("Detected roundtrip latency: "),
2839                         frames_total, frames_total * 1000.0f/sample_rate,
2840                         _("Systemic latency: "),
2841                         extra, extra * 1000.0f/sample_rate);
2842
2843         bool solid = true;
2844
2845         if (mtdm->err () > 0.2) {
2846                 strcat (buf, " ");
2847                 strcat (buf, _("(signal detection error)"));
2848                 solid = false;
2849         }
2850
2851         if (mtdm->inv ()) {
2852                 strcat (buf, " ");
2853                 strcat (buf, _("(inverted - bad wiring)"));
2854                 solid = false;
2855         }
2856
2857         lm_results.set_markup (string_compose (results_markup, buf));
2858
2859         if (solid) {
2860                 have_lm_results = true;
2861                 end_latency_detection ();
2862                 lm_use_button.set_sensitive (true);
2863                 return false;
2864         }
2865
2866         return true;
2867 }
2868
2869 bool
2870 EngineControl::check_midi_latency_measurement ()
2871 {
2872         ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2873
2874         if (!mididm->have_signal () || mididm->latency () == 0) {
2875                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2876                 return true;
2877         }
2878
2879         char buf[256];
2880         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2881
2882         if (sample_rate == 0) {
2883                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2884                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2885                 return false;
2886         }
2887
2888         ARDOUR::framecnt_t frames_total = mididm->latency();
2889         ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2890         snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2891                         _("Detected roundtrip latency: "),
2892                         frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2893                         _("Systemic latency: "),
2894                         extra, extra * 1000.0f / sample_rate);
2895
2896         bool solid = true;
2897
2898         if (!mididm->ok ()) {
2899                 strcat (buf, " ");
2900                 strcat (buf, _("(averaging)"));
2901                 solid = false;
2902         }
2903
2904         if (mididm->deviation () > 50.0) {
2905                 strcat (buf, " ");
2906                 strcat (buf, _("(too large jitter)"));
2907                 solid = false;
2908         } else if (mididm->deviation () > 10.0) {
2909                 strcat (buf, " ");
2910                 strcat (buf, _("(large jitter)"));
2911         }
2912
2913         if (solid) {
2914                 have_lm_results = true;
2915                 end_latency_detection ();
2916                 lm_use_button.set_sensitive (true);
2917                 lm_results.set_markup (string_compose (results_markup, buf));
2918                 return false;
2919         } else if (mididm->processed () > 400) {
2920                 have_lm_results = false;
2921                 end_latency_detection ();
2922                 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2923                 return false;
2924         }
2925
2926         lm_results.set_markup (string_compose (results_markup, buf));
2927
2928         return true;
2929 }
2930
2931 void
2932 EngineControl::start_latency_detection ()
2933 {
2934         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2935         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2936
2937         if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2938                 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2939                 if (_measure_midi) {
2940                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2941                 } else {
2942                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2943                 }
2944                 lm_measure_label.set_text (_("Cancel"));
2945                 have_lm_results = false;
2946                 lm_use_button.set_sensitive (false);
2947                 lm_input_channel_combo.set_sensitive (false);
2948                 lm_output_channel_combo.set_sensitive (false);
2949                 lm_running = true;
2950         }
2951 }
2952
2953 void
2954 EngineControl::end_latency_detection ()
2955 {
2956         latency_timeout.disconnect ();
2957         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2958         lm_measure_label.set_text (_("Measure"));
2959         if (!have_lm_results) {
2960                 lm_use_button.set_sensitive (false);
2961         }
2962         lm_input_channel_combo.set_sensitive (true);
2963         lm_output_channel_combo.set_sensitive (true);
2964         lm_running = false;
2965 }
2966
2967 void
2968 EngineControl::latency_button_clicked ()
2969 {
2970         if (!lm_running) {
2971                 start_latency_detection ();
2972         } else {
2973                 end_latency_detection ();
2974         }
2975 }
2976
2977 void
2978 EngineControl::latency_back_button_clicked ()
2979 {
2980         ARDOUR::AudioEngine::instance()->stop(true);
2981         notebook.set_current_page(0);
2982 }
2983
2984 void
2985 EngineControl::use_latency_button_clicked ()
2986 {
2987         if (_measure_midi) {
2988                 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2989                 if (!mididm) {
2990                         return;
2991                 }
2992                 ARDOUR::framecnt_t frames_total = mididm->latency();
2993                 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2994                 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2995                 _measure_midi->input_latency = one_way;
2996                 _measure_midi->output_latency = one_way;
2997                 notebook.set_current_page (midi_tab);
2998         } else {
2999                 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3000
3001                 if (!mtdm) {
3002                         return;
3003                 }
3004
3005                 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3006                 one_way = std::max (0., one_way);
3007
3008                 input_latency_adjustment.set_value (one_way);
3009                 output_latency_adjustment.set_value (one_way);
3010
3011                 /* back to settings page */
3012                 notebook.set_current_page (0);
3013         }
3014 }
3015
3016 bool
3017 EngineControl::on_delete_event (GdkEventAny* ev)
3018 {
3019         if (notebook.get_current_page() == 2) {
3020                 /* currently on latency tab - be sure to clean up */
3021                 end_latency_detection ();
3022         }
3023         return ArdourDialog::on_delete_event (ev);
3024 }
3025
3026 void
3027 EngineControl::engine_running ()
3028 {
3029         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3030         assert (backend);
3031
3032         set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3033         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3034
3035         if (backend->can_set_period_size ()) {
3036                 set_active_text_if_present (nperiods_combo, to_string (backend->period_size()));
3037         }
3038
3039         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3040         connect_disconnect_button.show();
3041
3042         started_at_least_once = true;
3043         if (_have_control) {
3044                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3045         } else {
3046                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3047         }
3048         update_sensitivity();
3049 }
3050
3051 void
3052 EngineControl::engine_stopped ()
3053 {
3054         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3055         assert (backend);
3056
3057         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3058         connect_disconnect_button.show();
3059
3060         if (_have_control) {
3061                 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3062         } else {
3063                 engine_status.set_markup(X_(""));
3064         }
3065
3066         update_sensitivity();
3067 }
3068
3069 void
3070 EngineControl::device_list_changed ()
3071 {
3072         if (ignore_device_changes) {
3073                 return;
3074         }
3075         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3076         list_devices ();
3077         midi_option_changed();
3078 }
3079
3080 void
3081 EngineControl::connect_disconnect_click()
3082 {
3083         if (ARDOUR::AudioEngine::instance()->running()) {
3084                 stop_engine ();
3085         } else {
3086                 if (!ARDOUR_UI::instance()->session_loaded) {
3087                         hide ();
3088                         ARDOUR::GUIIdle ();
3089                 }
3090                 start_engine ();
3091                 if (!ARDOUR_UI::instance()->session_loaded) {
3092                         ArdourDialog::on_response (RESPONSE_OK);
3093                 }
3094         }
3095 }
3096
3097 void
3098 EngineControl::calibrate_audio_latency ()
3099 {
3100         _measure_midi.reset ();
3101         have_lm_results = false;
3102         lm_use_button.set_sensitive (false);
3103         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3104         notebook.set_current_page (latency_tab);
3105 }
3106
3107 void
3108 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3109 {
3110         _measure_midi = s;
3111         have_lm_results = false;
3112         lm_use_button.set_sensitive (false);
3113         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3114         notebook.set_current_page (latency_tab);
3115 }
3116
3117 void
3118 EngineControl::configure_midi_devices ()
3119 {
3120         notebook.set_current_page (midi_tab);
3121 }