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