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