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