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