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