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