properly handle FS pitch-bend - closes #7140
[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
1596         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1597         if (backend && backend->match_input_output_devices_or_none ()) {
1598                 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1599
1600                 if (get_output_device_name () != dev_none
1601                                 && get_input_device_name () != dev_none
1602                                 && get_input_device_name () != get_output_device_name ()) {
1603                         block_changed_signals ();
1604                         if (contains_value (output_device_combo, get_input_device_name ())) {
1605                                 output_device_combo.set_active_text (get_input_device_name ());
1606                         } else {
1607                                 assert (contains_value (output_device_combo, dev_none));
1608                                 output_device_combo.set_active_text (dev_none);
1609                         }
1610                         unblock_changed_signals ();
1611                 }
1612         }
1613         device_changed ();
1614 }
1615
1616 void
1617 EngineControl::output_device_changed ()
1618 {
1619         DEBUG_ECONTROL ("output_device_changed");
1620         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1621         if (backend && backend->match_input_output_devices_or_none ()) {
1622                 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1623
1624                 if (get_input_device_name () != dev_none
1625                                 && get_input_device_name () != dev_none
1626                                 && get_input_device_name () != get_output_device_name ()) {
1627                         block_changed_signals ();
1628                         if (contains_value (input_device_combo, get_output_device_name ())) {
1629                                 input_device_combo.set_active_text (get_output_device_name ());
1630                         } else {
1631                                 assert (contains_value (input_device_combo, dev_none));
1632                                 input_device_combo.set_active_text (dev_none);
1633                         }
1634                         unblock_changed_signals ();
1635                 }
1636         }
1637         device_changed ();
1638 }
1639
1640 string
1641 EngineControl::bufsize_as_string (uint32_t sz)
1642 {
1643         return string_compose (P_("%1 sample", "%1 samples", sz), sz);
1644 }
1645
1646 string
1647 EngineControl::nperiods_as_string (uint32_t np)
1648 {
1649         char buf[8];
1650         snprintf (buf, sizeof (buf), "%u", np);
1651         return buf;
1652 }
1653
1654
1655 void
1656 EngineControl::sample_rate_changed ()
1657 {
1658         DEBUG_ECONTROL ("sample_rate_changed");
1659         /* reset the strings for buffer size to show the correct msec value
1660            (reflecting the new sample rate).
1661          */
1662
1663         show_buffer_duration ();
1664
1665 }
1666
1667 void
1668 EngineControl::buffer_size_changed ()
1669 {
1670         DEBUG_ECONTROL ("buffer_size_changed");
1671         show_buffer_duration ();
1672 }
1673
1674 void
1675 EngineControl::nperiods_changed ()
1676 {
1677         DEBUG_ECONTROL ("nperiods_changed");
1678         show_buffer_duration ();
1679 }
1680
1681 void
1682 EngineControl::show_buffer_duration ()
1683 {
1684         DEBUG_ECONTROL ("show_buffer_duration");
1685         /* buffer sizes  - convert from just samples to samples + msecs for
1686          * the displayed string
1687          */
1688
1689         string bs_text = buffer_size_combo.get_active_text ();
1690         uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1691         uint32_t rate = get_rate();
1692
1693         /* Except for ALSA and Dummy backends, we don't know the number of periods
1694          * per cycle and settings.
1695          *
1696          * jack1 vs jack2 have different default latencies since jack2 start
1697          * in async-mode unless --sync is given which adds an extra cycle
1698          * of latency. The value is not known if jackd is started externally..
1699          *
1700          * So just display the period size, that's also what
1701          * ARDOUR_UI::update_sample_rate() does for the status bar.
1702          * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1703          * but still, that's the buffer period, not [round-trip] latency)
1704          */
1705         char buf[32];
1706         snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1707         buffer_size_duration_label.set_text (buf);
1708 }
1709
1710 void
1711 EngineControl::midi_option_changed ()
1712 {
1713         DEBUG_ECONTROL ("midi_option_changed");
1714         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1715         assert (backend);
1716
1717         backend->set_midi_option (get_midi_option());
1718
1719         vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1720
1721         //_midi_devices.clear(); // TODO merge with state-saved settings..
1722         _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1723         std::vector<MidiDeviceSettings> new_devices;
1724
1725         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1726                 MidiDeviceSettings mds = find_midi_device (i->name);
1727                 if (i->available && !mds) {
1728                         uint32_t input_latency = 0;
1729                         uint32_t output_latency = 0;
1730                         if (_can_set_midi_latencies) {
1731                                 input_latency = backend->systemic_midi_input_latency (i->name);
1732                                 output_latency = backend->systemic_midi_output_latency (i->name);
1733                         }
1734                         bool enabled = backend->midi_device_enabled (i->name);
1735                         MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1736                         new_devices.push_back (ptr);
1737                 } else if (i->available) {
1738                         new_devices.push_back (mds);
1739                 }
1740         }
1741         _midi_devices = new_devices;
1742
1743         if (_midi_devices.empty()) {
1744                 midi_devices_button.hide ();
1745         } else {
1746                 midi_devices_button.show ();
1747         }
1748 }
1749
1750 void
1751 EngineControl::parameter_changed ()
1752 {
1753 }
1754
1755 EngineControl::State
1756 EngineControl::get_matching_state (const string& backend)
1757 {
1758         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1759                 if ((*i)->backend == backend) {
1760                         return (*i);
1761                 }
1762         }
1763         return State();
1764 }
1765
1766 EngineControl::State
1767 EngineControl::get_matching_state (
1768                 const string& backend,
1769                 const string& driver,
1770                 const string& device)
1771 {
1772         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1773                 if ((*i)->backend == backend &&
1774                                 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1775                 {
1776                         return (*i);
1777                 }
1778         }
1779         return State();
1780 }
1781
1782 EngineControl::State
1783 EngineControl::get_matching_state (
1784                 const string& backend,
1785                 const string& driver,
1786                 const string& input_device,
1787                 const string& output_device)
1788 {
1789         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1790                 if ((*i)->backend == backend &&
1791                                 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1792                 {
1793                         return (*i);
1794                 }
1795         }
1796         return State();
1797 }
1798
1799 EngineControl::State
1800 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1801 {
1802         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1803
1804         if (backend) {
1805                 if (backend->use_separate_input_and_output_devices ()) {
1806                         return get_matching_state (backend_combo.get_active_text(),
1807                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1808                                         input_device_combo.get_active_text(),
1809                                         output_device_combo.get_active_text());
1810                 } else {
1811                         return get_matching_state (backend_combo.get_active_text(),
1812                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1813                                         device_combo.get_active_text());
1814                 }
1815         }
1816
1817         return get_matching_state (backend_combo.get_active_text(),
1818                         string(),
1819                         device_combo.get_active_text());
1820 }
1821
1822 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1823                                        const EngineControl::State& state2)
1824 {
1825         if (state1->backend == state2->backend &&
1826                         state1->driver == state2->driver &&
1827                         state1->device == state2->device &&
1828                         state1->input_device == state2->input_device &&
1829                         state1->output_device == state2->output_device) {
1830                 return true;
1831         }
1832         return false;
1833 }
1834
1835 bool
1836 EngineControl::state_sort_cmp (const State &a, const State &b) {
1837         if (a->active) {
1838                 return true;
1839         }
1840         else if (b->active) {
1841                 return false;
1842         }
1843         else {
1844                 return a->lru < b->lru;
1845         }
1846 }
1847
1848 EngineControl::State
1849 EngineControl::save_state ()
1850 {
1851         State state;
1852
1853         if (!_have_control) {
1854                 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1855                 if (state) {
1856                         state->lru = time (NULL) ;
1857                         return state;
1858                 }
1859                 state.reset(new StateStruct);
1860                 state->backend = get_backend ();
1861         } else {
1862                 state.reset(new StateStruct);
1863                 store_state (state);
1864         }
1865
1866         for (StateList::iterator i = states.begin(); i != states.end();) {
1867                 if (equivalent_states (*i, state)) {
1868                         i =  states.erase(i);
1869                 } else {
1870                         ++i;
1871                 }
1872         }
1873
1874         states.push_back (state);
1875
1876         states.sort (state_sort_cmp);
1877
1878         return state;
1879 }
1880
1881 void
1882 EngineControl::store_state (State state)
1883 {
1884         state->backend = get_backend ();
1885         state->driver = get_driver ();
1886         state->device = get_device_name ();
1887         state->input_device = get_input_device_name ();
1888         state->output_device = get_output_device_name ();
1889         state->sample_rate = get_rate ();
1890         state->buffer_size = get_buffer_size ();
1891         state->n_periods = get_nperiods ();
1892         state->input_latency = get_input_latency ();
1893         state->output_latency = get_output_latency ();
1894         state->input_channels = get_input_channels ();
1895         state->output_channels = get_output_channels ();
1896         state->midi_option = get_midi_option ();
1897         state->midi_devices = _midi_devices;
1898         state->use_buffered_io = get_use_buffered_io ();
1899         state->lru = time (NULL) ;
1900 }
1901
1902 void
1903 EngineControl::maybe_display_saved_state ()
1904 {
1905         if (!_have_control) {
1906                 return;
1907         }
1908
1909         State state = get_saved_state_for_currently_displayed_backend_and_device ();
1910
1911         if (state) {
1912                 DEBUG_ECONTROL ("Restoring saved state");
1913                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1914
1915                 if (!_desired_sample_rate) {
1916                         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1917                 }
1918                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1919
1920                 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1921                 /* call this explicitly because we're ignoring changes to
1922                    the controls at this point.
1923                  */
1924                 show_buffer_duration ();
1925                 input_latency.set_value (state->input_latency);
1926                 output_latency.set_value (state->output_latency);
1927
1928                 use_buffered_io_button.set_active (state->use_buffered_io);
1929
1930                 if (!state->midi_option.empty()) {
1931                         midi_option_combo.set_active_text (state->midi_option);
1932                         _midi_devices = state->midi_devices;
1933                 }
1934         } else {
1935                 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1936         }
1937 }
1938
1939 XMLNode&
1940 EngineControl::get_state ()
1941 {
1942         LocaleGuard lg;
1943
1944         XMLNode* root = new XMLNode ("AudioMIDISetup");
1945         std::string path;
1946
1947         if (!states.empty()) {
1948                 XMLNode* state_nodes = new XMLNode ("EngineStates");
1949
1950                 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1951
1952                         XMLNode* node = new XMLNode ("State");
1953
1954                         node->add_property ("backend", (*i)->backend);
1955                         node->add_property ("driver", (*i)->driver);
1956                         node->add_property ("device", (*i)->device);
1957                         node->add_property ("input-device", (*i)->input_device);
1958                         node->add_property ("output-device", (*i)->output_device);
1959                         node->add_property ("sample-rate", (*i)->sample_rate);
1960                         node->add_property ("buffer-size", (*i)->buffer_size);
1961                         node->add_property ("n-periods", (*i)->n_periods);
1962                         node->add_property ("input-latency", (*i)->input_latency);
1963                         node->add_property ("output-latency", (*i)->output_latency);
1964                         node->add_property ("input-channels", (*i)->input_channels);
1965                         node->add_property ("output-channels", (*i)->output_channels);
1966                         node->add_property ("active", (*i)->active ? "yes" : "no");
1967                         node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
1968                         node->add_property ("midi-option", (*i)->midi_option);
1969                         node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1970
1971                         XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1972                         for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1973                                 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1974                                 midi_device_stuff->add_property (X_("name"), (*p)->name);
1975                                 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1976                                 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1977                                 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1978                                 midi_devices->add_child_nocopy (*midi_device_stuff);
1979                         }
1980                         node->add_child_nocopy (*midi_devices);
1981
1982                         state_nodes->add_child_nocopy (*node);
1983                 }
1984
1985                 root->add_child_nocopy (*state_nodes);
1986         }
1987
1988         return *root;
1989 }
1990
1991 void
1992 EngineControl::set_default_state ()
1993 {
1994         vector<string> backend_names;
1995         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1996
1997         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1998                 backend_names.push_back ((*b)->name);
1999         }
2000         backend_combo.set_active_text (backend_names.front());
2001
2002         // We could set default backends per platform etc here
2003
2004         backend_changed ();
2005 }
2006
2007 bool
2008 EngineControl::set_state (const XMLNode& root)
2009 {
2010         XMLNodeList          clist, cclist;
2011         XMLNodeConstIterator citer, cciter;
2012         XMLNode const * child;
2013         XMLNode const * grandchild;
2014         XMLProperty const * prop = NULL;
2015
2016         if (root.name() != "AudioMIDISetup") {
2017                 return false;
2018         }
2019
2020         clist = root.children();
2021
2022         states.clear ();
2023
2024         for (citer = clist.begin(); citer != clist.end(); ++citer) {
2025
2026                 child = *citer;
2027
2028                 if (child->name() != "EngineStates") {
2029                         continue;
2030                 }
2031
2032                 cclist = child->children();
2033
2034                 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2035                         State state (new StateStruct);
2036
2037                         grandchild = *cciter;
2038
2039                         if (grandchild->name() != "State") {
2040                                 continue;
2041                         }
2042
2043                         if ((prop = grandchild->property ("backend")) == 0) {
2044                                 continue;
2045                         }
2046                         state->backend = prop->value ();
2047
2048                         if ((prop = grandchild->property ("driver")) == 0) {
2049                                 continue;
2050                         }
2051                         state->driver = prop->value ();
2052
2053                         if ((prop = grandchild->property ("device")) == 0) {
2054                                 continue;
2055                         }
2056                         state->device = prop->value ();
2057
2058                         if ((prop = grandchild->property ("input-device")) == 0) {
2059                                 continue;
2060                         }
2061                         state->input_device = prop->value ();
2062
2063                         if ((prop = grandchild->property ("output-device")) == 0) {
2064                                 continue;
2065                         }
2066                         state->output_device = prop->value ();
2067
2068                         if ((prop = grandchild->property ("sample-rate")) == 0) {
2069                                 continue;
2070                         }
2071                         state->sample_rate = atof (prop->value ());
2072
2073                         if ((prop = grandchild->property ("buffer-size")) == 0) {
2074                                 continue;
2075                         }
2076                         state->buffer_size = atoi (prop->value ());
2077
2078                         if ((prop = grandchild->property ("n-periods")) == 0) {
2079                                 // optional (new value in 4.5)
2080                                 state->n_periods = 0;
2081                         } else {
2082                                 state->n_periods = atoi (prop->value ());
2083                         }
2084
2085                         if ((prop = grandchild->property ("input-latency")) == 0) {
2086                                 continue;
2087                         }
2088                         state->input_latency = atoi (prop->value ());
2089
2090                         if ((prop = grandchild->property ("output-latency")) == 0) {
2091                                 continue;
2092                         }
2093                         state->output_latency = atoi (prop->value ());
2094
2095                         if ((prop = grandchild->property ("input-channels")) == 0) {
2096                                 continue;
2097                         }
2098                         state->input_channels = atoi (prop->value ());
2099
2100                         if ((prop = grandchild->property ("output-channels")) == 0) {
2101                                 continue;
2102                         }
2103                         state->output_channels = atoi (prop->value ());
2104
2105                         if ((prop = grandchild->property ("active")) == 0) {
2106                                 continue;
2107                         }
2108                         state->active = string_is_affirmative (prop->value ());
2109
2110                         if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2111                                 continue;
2112                         }
2113                         state->use_buffered_io = string_is_affirmative (prop->value ());
2114
2115                         if ((prop = grandchild->property ("midi-option")) == 0) {
2116                                 continue;
2117                         }
2118                         state->midi_option = prop->value ();
2119
2120                         state->midi_devices.clear();
2121                         XMLNode* midinode;
2122                         if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2123                                 const XMLNodeList mnc = midinode->children();
2124                                 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2125                                         if ((*n)->property (X_("name")) == 0
2126                                                         || (*n)->property (X_("enabled")) == 0
2127                                                         || (*n)->property (X_("input-latency")) == 0
2128                                                         || (*n)->property (X_("output-latency")) == 0
2129                                                  ) {
2130                                                 continue;
2131                                         }
2132
2133                                         MidiDeviceSettings ptr (new MidiDeviceSetting(
2134                                                                 (*n)->property (X_("name"))->value (),
2135                                                                 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2136                                                                 atoi ((*n)->property (X_("input-latency"))->value ()),
2137                                                                 atoi ((*n)->property (X_("output-latency"))->value ())
2138                                                                 ));
2139                                         state->midi_devices.push_back (ptr);
2140                                 }
2141                         }
2142
2143                         if ((prop = grandchild->property ("lru"))) {
2144                                 state->lru = atoi (prop->value ());
2145                         }
2146
2147 #if 1
2148                         /* remove accumulated duplicates (due to bug in ealier version)
2149                          * this can be removed again before release
2150                          */
2151                         for (StateList::iterator i = states.begin(); i != states.end();) {
2152                                 if ((*i)->backend == state->backend &&
2153                                                 (*i)->driver == state->driver &&
2154                                                 (*i)->device == state->device) {
2155                                         i =  states.erase(i);
2156                                 } else {
2157                                         ++i;
2158                                 }
2159                         }
2160 #endif
2161
2162                         states.push_back (state);
2163                 }
2164         }
2165
2166         /* now see if there was an active state and switch the setup to it */
2167
2168         // purge states of backend that are not available in this built
2169         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2170         vector<std::string> backend_names;
2171
2172         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2173                 backend_names.push_back((*i)->name);
2174         }
2175         for (StateList::iterator i = states.begin(); i != states.end();) {
2176                 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2177                         i = states.erase(i);
2178                 } else {
2179                         ++i;
2180                 }
2181         }
2182
2183         states.sort (state_sort_cmp);
2184
2185         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2186
2187                 if ((*i)->active) {
2188                         return set_current_state (*i);
2189                 }
2190         }
2191         return false;
2192 }
2193
2194 bool
2195 EngineControl::set_current_state (const State& state)
2196 {
2197         DEBUG_ECONTROL ("set_current_state");
2198
2199         boost::shared_ptr<ARDOUR::AudioBackend> backend;
2200
2201         if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2202                   state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2203                 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2204                 // this shouldn't happen as the invalid backend names should have been
2205                 // removed from the list of states.
2206                 return false;
2207         }
2208
2209         // now reflect the change in the backend in the GUI so backend_changed will
2210         // do the right thing
2211         backend_combo.set_active_text (state->backend);
2212
2213         if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2214                 backend_changed ();
2215                 // we don't have control don't restore state
2216                 return true;
2217         }
2218
2219
2220         if (!state->driver.empty ()) {
2221                 if (!backend->requires_driver_selection ()) {
2222                         DEBUG_ECONTROL ("Backend should require driver selection");
2223                         // A backend has changed from having driver selection to not having
2224                         // it or someone has been manually editing a config file and messed
2225                         // it up
2226                         return false;
2227                 }
2228
2229                 if (backend->set_driver (state->driver) != 0) {
2230                         DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2231                         // Driver names for a backend have changed and the name in the
2232                         // config file is now invalid or support for driver is no longer
2233                         // included in the backend
2234                         return false;
2235                 }
2236                 // no need to set the driver_combo as backend_changed will use
2237                 // backend->driver_name to set the active driver
2238         }
2239
2240         if (!state->device.empty ()) {
2241                 if (backend->set_device_name (state->device) != 0) {
2242                         DEBUG_ECONTROL (
2243                             string_compose ("Unable to set device name %1", state->device));
2244                         // device is no longer available on the system
2245                         return false;
2246                 }
2247                 // no need to set active device as it will be picked up in
2248                 // via backend_changed ()/set_device_popdown_strings
2249
2250         } else {
2251                 // backend supports separate input/output devices
2252                 if (backend->set_input_device_name (state->input_device) != 0) {
2253                         DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2254                                                         state->input_device));
2255                         // input device is no longer available on the system
2256                         return false;
2257                 }
2258
2259                 if (backend->set_output_device_name (state->output_device) != 0) {
2260                         DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2261                                                         state->input_device));
2262                         // output device is no longer available on the system
2263                         return false;
2264                 }
2265                 // no need to set active devices as it will be picked up in via
2266                 // backend_changed ()/set_*_device_popdown_strings
2267         }
2268
2269         backend_changed ();
2270
2271         // Now restore the state of the rest of the controls
2272
2273         // We don't use a SignalBlocker as set_current_state is currently only
2274         // called from set_state before any signals are connected. If at some point
2275         // a more general named state mechanism is implemented and
2276         // set_current_state is called while signals are connected then a
2277         // SignalBlocker will need to be instantiated before setting these.
2278
2279         device_combo.set_active_text (state->device);
2280         input_device_combo.set_active_text (state->input_device);
2281         output_device_combo.set_active_text (state->output_device);
2282         if (!_desired_sample_rate) {
2283                 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2284         }
2285         set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2286         set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2287         input_latency.set_value (state->input_latency);
2288         output_latency.set_value (state->output_latency);
2289         midi_option_combo.set_active_text (state->midi_option);
2290         use_buffered_io_button.set_active (state->use_buffered_io);
2291         return true;
2292 }
2293
2294 int
2295 EngineControl::push_state_to_backend (bool start)
2296 {
2297         DEBUG_ECONTROL ("push_state_to_backend");
2298         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2299         PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2300
2301         if (!backend) {
2302                 return 0;
2303         }
2304
2305         /* figure out what is going to change */
2306
2307         bool restart_required = false;
2308         bool was_running = ARDOUR::AudioEngine::instance()->running();
2309         bool change_driver = false;
2310         bool change_device = false;
2311         bool change_rate = false;
2312         bool change_bufsize = false;
2313         bool change_nperiods = false;
2314         bool change_latency = false;
2315         bool change_channels = false;
2316         bool change_midi = false;
2317         bool change_buffered_io = false;
2318
2319         uint32_t ochan = get_output_channels ();
2320         uint32_t ichan = get_input_channels ();
2321
2322         if (_have_control) {
2323
2324                 if (started_at_least_once) {
2325
2326                         /* we can control the backend */
2327
2328                         if (backend->requires_driver_selection()) {
2329                                 if (get_driver() != backend->driver_name()) {
2330                                         change_driver = true;
2331                                 }
2332                         }
2333
2334                         if (backend->use_separate_input_and_output_devices()) {
2335                                 if (get_input_device_name() != backend->input_device_name()) {
2336                                         change_device = true;
2337                                 }
2338                                 if (get_output_device_name() != backend->output_device_name()) {
2339                                         change_device = true;
2340                                 }
2341                         } else {
2342                                 if (get_device_name() != backend->device_name()) {
2343                                         change_device = true;
2344                                 }
2345                         }
2346
2347                         if (queue_device_changed) {
2348                                 change_device = true;
2349                         }
2350
2351                         if (get_rate() != backend->sample_rate()) {
2352                                 change_rate = true;
2353                         }
2354
2355                         if (get_buffer_size() != backend->buffer_size()) {
2356                                 change_bufsize = true;
2357                         }
2358
2359                         if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2360                                         && get_nperiods() != backend->period_size()) {
2361                                 change_nperiods = true;
2362                         }
2363
2364                         if (get_midi_option() != backend->midi_option()) {
2365                                 change_midi = true;
2366                         }
2367
2368                         if (backend->can_use_buffered_io()) {
2369                                 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2370                                         change_buffered_io = true;
2371                                 }
2372                         }
2373
2374                         /* zero-requested channels means "all available" */
2375
2376                         if (ichan == 0) {
2377                                 ichan = backend->input_channels();
2378                         }
2379
2380                         if (ochan == 0) {
2381                                 ochan = backend->output_channels();
2382                         }
2383
2384                         if (ichan != backend->input_channels()) {
2385                                 change_channels = true;
2386                         }
2387
2388                         if (ochan != backend->output_channels()) {
2389                                 change_channels = true;
2390                         }
2391
2392                         if (get_input_latency() != backend->systemic_input_latency() ||
2393                                         get_output_latency() != backend->systemic_output_latency()) {
2394                                 change_latency = true;
2395                         }
2396                 } else {
2397                         /* backend never started, so we have to force a group
2398                            of settings.
2399                          */
2400                         change_device = true;
2401                         if (backend->requires_driver_selection()) {
2402                                 change_driver = true;
2403                         }
2404                         change_rate = true;
2405                         change_bufsize = true;
2406                         change_channels = true;
2407                         change_latency = true;
2408                         change_midi = true;
2409                         change_buffered_io = backend->can_use_buffered_io();
2410                         change_channels = true;
2411                         change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2412                 }
2413
2414         } else {
2415
2416                 /* we have no control over the backend, meaning that we can
2417                  * only possibly change sample rate and buffer size.
2418                  */
2419
2420
2421                 if (get_rate() != backend->sample_rate()) {
2422                         change_bufsize = true;
2423                 }
2424
2425                 if (get_buffer_size() != backend->buffer_size()) {
2426                         change_bufsize = true;
2427                 }
2428         }
2429
2430         queue_device_changed = false;
2431
2432         if (!_have_control) {
2433
2434                 /* We do not have control over the backend, so the best we can
2435                  * do is try to change the sample rate and/or bufsize and get
2436                  * out of here.
2437                  */
2438
2439                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2440                         return 1;
2441                 }
2442
2443                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2444                         return 1;
2445                 }
2446
2447                 if (change_rate) {
2448                         backend->set_sample_rate (get_rate());
2449                 }
2450
2451                 if (change_bufsize) {
2452                         backend->set_buffer_size (get_buffer_size());
2453                 }
2454
2455                 if (start) {
2456                         if (ARDOUR::AudioEngine::instance()->start ()) {
2457                                 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2458                                 return -1;
2459                         }
2460                 }
2461
2462                 post_push ();
2463
2464                 return 0;
2465         }
2466
2467         /* determine if we need to stop the backend before changing parameters */
2468
2469         if (change_driver || change_device || change_channels || change_nperiods ||
2470                         (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2471                         (change_rate && !backend->can_change_sample_rate_when_running()) ||
2472                         change_midi || change_buffered_io ||
2473                         (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2474                 restart_required = true;
2475         } else {
2476                 restart_required = false;
2477         }
2478
2479
2480         if (was_running) {
2481                 if (restart_required) {
2482                         if (ARDOUR::AudioEngine::instance()->stop()) {
2483                                 return -1;
2484                         }
2485                 }
2486         }
2487
2488         if (change_driver && backend->set_driver (get_driver())) {
2489                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2490                 return -1;
2491         }
2492         if (backend->use_separate_input_and_output_devices()) {
2493                 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2494                         error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2495                         return -1;
2496                 }
2497                 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2498                         error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2499                         return -1;
2500                 }
2501         } else {
2502                 if (change_device && backend->set_device_name (get_device_name())) {
2503                         error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2504                         return -1;
2505                 }
2506         }
2507         if (change_rate && backend->set_sample_rate (get_rate())) {
2508                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2509                 return -1;
2510         }
2511         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2512                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2513                 return -1;
2514         }
2515         if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2516                 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2517                 return -1;
2518         }
2519
2520         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2521                 if (backend->set_input_channels (get_input_channels())) {
2522                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2523                         return -1;
2524                 }
2525                 if (backend->set_output_channels (get_output_channels())) {
2526                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2527                         return -1;
2528                 }
2529         }
2530         if (change_latency) {
2531                 if (backend->set_systemic_input_latency (get_input_latency())) {
2532                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2533                         return -1;
2534                 }
2535                 if (backend->set_systemic_output_latency (get_output_latency())) {
2536                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2537                         return -1;
2538                 }
2539         }
2540
2541         if (change_midi) {
2542                 backend->set_midi_option (get_midi_option());
2543         }
2544
2545         if (change_buffered_io) {
2546                 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2547         }
2548
2549         if (1 /* TODO */) {
2550                 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2551                         if (_measure_midi) {
2552                                 if (*p == _measure_midi) {
2553                                         backend->set_midi_device_enabled ((*p)->name, true);
2554                                 } else {
2555                                         backend->set_midi_device_enabled ((*p)->name, false);
2556                                 }
2557                                 if (backend->can_change_systemic_latency_when_running ()) {
2558                                         backend->set_systemic_midi_input_latency ((*p)->name, 0);
2559                                         backend->set_systemic_midi_output_latency ((*p)->name, 0);
2560                                 }
2561                                 continue;
2562                         }
2563                         backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2564                         if (backend->can_set_systemic_midi_latencies()) {
2565                                 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2566                                 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2567                         }
2568                 }
2569         }
2570
2571         if (start || (was_running && restart_required)) {
2572                 if (ARDOUR::AudioEngine::instance()->start()) {
2573                         return -1;
2574                 }
2575         }
2576
2577         post_push ();
2578
2579         return 0;
2580 }
2581
2582 void
2583 EngineControl::post_push ()
2584 {
2585         /* get a pointer to the current state object, creating one if
2586          * necessary
2587          */
2588
2589         State state = get_saved_state_for_currently_displayed_backend_and_device ();
2590
2591         if (!state) {
2592                 state = save_state ();
2593                 assert (state);
2594         } else {
2595                 store_state(state);
2596         }
2597
2598         states.sort (state_sort_cmp);
2599
2600         /* all off */
2601
2602         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2603                 (*i)->active = false;
2604         }
2605
2606         /* mark this one active (to be used next time the dialog is
2607          * shown)
2608          */
2609
2610         state->active = true;
2611
2612         if (_have_control) { // XXX
2613                 manage_control_app_sensitivity ();
2614         }
2615
2616         /* schedule a redisplay of MIDI ports */
2617         //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2618 }
2619
2620
2621 float
2622 EngineControl::get_rate () const
2623 {
2624         float r = atof (sample_rate_combo.get_active_text ());
2625         /* the string may have been translated with an abbreviation for
2626          * thousands, so use a crude heuristic to fix this.
2627          */
2628         if (r < 1000.0) {
2629                 r *= 1000.0;
2630         }
2631         return r;
2632 }
2633
2634
2635 uint32_t
2636 EngineControl::get_buffer_size () const
2637 {
2638         string txt = buffer_size_combo.get_active_text ();
2639         uint32_t samples;
2640
2641         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2642                 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2643                 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2644                 throw exception ();
2645         }
2646
2647         return samples;
2648 }
2649
2650 uint32_t
2651 EngineControl::get_nperiods () const
2652 {
2653         string txt = nperiods_combo.get_active_text ();
2654         return atoi (txt.c_str());
2655 }
2656
2657 string
2658 EngineControl::get_midi_option () const
2659 {
2660         return midi_option_combo.get_active_text();
2661 }
2662
2663 bool
2664 EngineControl::get_use_buffered_io () const
2665 {
2666         return use_buffered_io_button.get_active();
2667 }
2668
2669 uint32_t
2670 EngineControl::get_input_channels() const
2671 {
2672         if (ARDOUR::Profile->get_mixbus()) {
2673                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2674                 if (!backend) return 0;
2675                 return backend->input_channels();
2676         }
2677         return (uint32_t) input_channels_adjustment.get_value();
2678 }
2679
2680 uint32_t
2681 EngineControl::get_output_channels() const
2682 {
2683         if (ARDOUR::Profile->get_mixbus()) {
2684                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2685                 if (!backend) return 0;
2686                 return backend->input_channels();
2687         }
2688         return (uint32_t) output_channels_adjustment.get_value();
2689 }
2690
2691 uint32_t
2692 EngineControl::get_input_latency() const
2693 {
2694         return (uint32_t) input_latency_adjustment.get_value();
2695 }
2696
2697 uint32_t
2698 EngineControl::get_output_latency() const
2699 {
2700         return (uint32_t) output_latency_adjustment.get_value();
2701 }
2702
2703 string
2704 EngineControl::get_backend () const
2705 {
2706         return backend_combo.get_active_text ();
2707 }
2708
2709 string
2710 EngineControl::get_driver () const
2711 {
2712         if (driver_combo.get_parent()) {
2713                 return driver_combo.get_active_text ();
2714         } else {
2715                 return "";
2716         }
2717 }
2718
2719 string
2720 EngineControl::get_device_name () const
2721 {
2722         return device_combo.get_active_text ();
2723 }
2724
2725 string
2726 EngineControl::get_input_device_name () const
2727 {
2728         return input_device_combo.get_active_text ();
2729 }
2730
2731 string
2732 EngineControl::get_output_device_name () const
2733 {
2734         return output_device_combo.get_active_text ();
2735 }
2736
2737 void
2738 EngineControl::control_app_button_clicked ()
2739 {
2740         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2741
2742         if (!backend) {
2743                 return;
2744         }
2745
2746         backend->launch_control_app ();
2747 }
2748
2749 void
2750 EngineControl::start_stop_button_clicked ()
2751 {
2752         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2753
2754         if (!backend) {
2755                 return;
2756         }
2757
2758         if (ARDOUR::AudioEngine::instance()->running()) {
2759                 ARDOUR::AudioEngine::instance()->stop ();
2760         } else {
2761                 start_engine ();
2762         }
2763 }
2764
2765 void
2766 EngineControl::update_devices_button_clicked ()
2767 {
2768         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2769
2770         if (!backend) {
2771                 return;
2772         }
2773
2774         if (backend->update_devices()) {
2775                 device_list_changed ();
2776         }
2777 }
2778
2779 void
2780 EngineControl::use_buffered_io_button_clicked ()
2781 {
2782         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2783
2784         if (!backend) {
2785                 return;
2786         }
2787
2788         bool set_buffered_io = !use_buffered_io_button.get_active();
2789         use_buffered_io_button.set_active (set_buffered_io);
2790         backend->set_use_buffered_io (set_buffered_io);
2791 }
2792
2793 void
2794 EngineControl::manage_control_app_sensitivity ()
2795 {
2796         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2797
2798         if (!backend) {
2799                 return;
2800         }
2801
2802         string appname = backend->control_app_name();
2803
2804         if (appname.empty()) {
2805                 control_app_button.set_sensitive (false);
2806         } else {
2807                 control_app_button.set_sensitive (true);
2808         }
2809 }
2810
2811 void
2812 EngineControl::set_desired_sample_rate (uint32_t sr)
2813 {
2814         _desired_sample_rate = sr;
2815         if (ARDOUR::AudioEngine::instance ()->running ()
2816                         && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2817                 stop_engine ();
2818         }
2819         device_changed ();
2820 }
2821
2822 void
2823 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2824 {
2825         if (page_num == 0) {
2826                 cancel_button->set_sensitive (true);
2827                 _measure_midi.reset();
2828                 update_sensitivity ();
2829         } else {
2830                 cancel_button->set_sensitive (false);
2831                 ok_button->set_sensitive (false);
2832         }
2833
2834         if (page_num == midi_tab) {
2835                 /* MIDI tab */
2836                 refresh_midi_display ();
2837         }
2838
2839         if (page_num == latency_tab) {
2840                 /* latency tab */
2841
2842                 if (ARDOUR::AudioEngine::instance()->running()) {
2843                         stop_engine (true);
2844                 }
2845
2846                 {
2847                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2848
2849                         /* save any existing latency values */
2850
2851                         uint32_t il = (uint32_t) input_latency.get_value ();
2852                         uint32_t ol = (uint32_t) input_latency.get_value ();
2853
2854                         /* reset to zero so that our new test instance
2855                            will be clean of any existing latency measures.
2856
2857                            NB. this should really be done by the backend
2858                            when stated for latency measurement.
2859                         */
2860
2861                         input_latency.set_value (0);
2862                         output_latency.set_value (0);
2863
2864                         push_state_to_backend (false);
2865
2866                         /* reset control */
2867
2868                         input_latency.set_value (il);
2869                         output_latency.set_value (ol);
2870
2871                 }
2872                 // This should be done in push_state_to_backend()
2873                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2874                         disable_latency_tab ();
2875                 }
2876
2877                 enable_latency_tab ();
2878
2879         } else {
2880                 if (lm_running) {
2881                         end_latency_detection ();
2882                         ARDOUR::AudioEngine::instance()->stop_latency_detection();
2883                 }
2884         }
2885 }
2886
2887 /* latency measurement */
2888
2889 bool
2890 EngineControl::check_audio_latency_measurement ()
2891 {
2892         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2893
2894         if (mtdm->resolve () < 0) {
2895                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2896                 return true;
2897         }
2898
2899         if (mtdm->get_peak () > 0.707f) {
2900                 // get_peak() resets the peak-hold in the detector.
2901                 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2902                 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2903                 return true;
2904         }
2905
2906         if (mtdm->err () > 0.3) {
2907                 mtdm->invert ();
2908                 mtdm->resolve ();
2909         }
2910
2911         char buf[256];
2912         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2913
2914         if (sample_rate == 0) {
2915                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2916                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2917                 return false;
2918         }
2919
2920         int frames_total = mtdm->del();
2921         int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2922
2923         snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2924                         _("Detected roundtrip latency: "),
2925                         frames_total, frames_total * 1000.0f/sample_rate,
2926                         _("Systemic latency: "),
2927                         extra, extra * 1000.0f/sample_rate);
2928
2929         bool solid = true;
2930
2931         if (mtdm->err () > 0.2) {
2932                 strcat (buf, " ");
2933                 strcat (buf, _("(signal detection error)"));
2934                 solid = false;
2935         }
2936
2937         if (mtdm->inv ()) {
2938                 strcat (buf, " ");
2939                 strcat (buf, _("(inverted - bad wiring)"));
2940                 solid = false;
2941         }
2942
2943         lm_results.set_markup (string_compose (results_markup, buf));
2944
2945         if (solid) {
2946                 have_lm_results = true;
2947                 end_latency_detection ();
2948                 lm_use_button.set_sensitive (true);
2949                 return false;
2950         }
2951
2952         return true;
2953 }
2954
2955 bool
2956 EngineControl::check_midi_latency_measurement ()
2957 {
2958         ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2959
2960         if (!mididm->have_signal () || mididm->latency () == 0) {
2961                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2962                 return true;
2963         }
2964
2965         char buf[256];
2966         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2967
2968         if (sample_rate == 0) {
2969                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2970                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2971                 return false;
2972         }
2973
2974         ARDOUR::framecnt_t frames_total = mididm->latency();
2975         ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2976         snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2977                         _("Detected roundtrip latency: "),
2978                         frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2979                         _("Systemic latency: "),
2980                         extra, extra * 1000.0f / sample_rate);
2981
2982         bool solid = true;
2983
2984         if (!mididm->ok ()) {
2985                 strcat (buf, " ");
2986                 strcat (buf, _("(averaging)"));
2987                 solid = false;
2988         }
2989
2990         if (mididm->deviation () > 50.0) {
2991                 strcat (buf, " ");
2992                 strcat (buf, _("(too large jitter)"));
2993                 solid = false;
2994         } else if (mididm->deviation () > 10.0) {
2995                 strcat (buf, " ");
2996                 strcat (buf, _("(large jitter)"));
2997         }
2998
2999         if (solid) {
3000                 have_lm_results = true;
3001                 end_latency_detection ();
3002                 lm_use_button.set_sensitive (true);
3003                 lm_results.set_markup (string_compose (results_markup, buf));
3004                 return false;
3005         } else if (mididm->processed () > 400) {
3006                 have_lm_results = false;
3007                 end_latency_detection ();
3008                 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
3009                 return false;
3010         }
3011
3012         lm_results.set_markup (string_compose (results_markup, buf));
3013
3014         return true;
3015 }
3016
3017 void
3018 EngineControl::start_latency_detection ()
3019 {
3020         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
3021         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
3022
3023         if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
3024                 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
3025                 if (_measure_midi) {
3026                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
3027                 } else {
3028                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
3029                 }
3030                 lm_measure_label.set_text (_("Cancel"));
3031                 have_lm_results = false;
3032                 lm_use_button.set_sensitive (false);
3033                 lm_input_channel_combo.set_sensitive (false);
3034                 lm_output_channel_combo.set_sensitive (false);
3035                 lm_running = true;
3036         }
3037 }
3038
3039 void
3040 EngineControl::end_latency_detection ()
3041 {
3042         latency_timeout.disconnect ();
3043         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3044         lm_measure_label.set_text (_("Measure"));
3045         if (!have_lm_results) {
3046                 lm_use_button.set_sensitive (false);
3047         }
3048         lm_input_channel_combo.set_sensitive (true);
3049         lm_output_channel_combo.set_sensitive (true);
3050         lm_running = false;
3051 }
3052
3053 void
3054 EngineControl::latency_button_clicked ()
3055 {
3056         if (!lm_running) {
3057                 start_latency_detection ();
3058         } else {
3059                 end_latency_detection ();
3060         }
3061 }
3062
3063 void
3064 EngineControl::latency_back_button_clicked ()
3065 {
3066         ARDOUR::AudioEngine::instance()->stop(true);
3067         notebook.set_current_page(0);
3068 }
3069
3070 void
3071 EngineControl::use_latency_button_clicked ()
3072 {
3073         if (_measure_midi) {
3074                 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3075                 if (!mididm) {
3076                         return;
3077                 }
3078                 ARDOUR::framecnt_t frames_total = mididm->latency();
3079                 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3080                 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3081                 _measure_midi->input_latency = one_way;
3082                 _measure_midi->output_latency = one_way;
3083                 notebook.set_current_page (midi_tab);
3084         } else {
3085                 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3086
3087                 if (!mtdm) {
3088                         return;
3089                 }
3090
3091                 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3092                 one_way = std::max (0., one_way);
3093
3094                 input_latency_adjustment.set_value (one_way);
3095                 output_latency_adjustment.set_value (one_way);
3096
3097                 /* back to settings page */
3098                 notebook.set_current_page (0);
3099         }
3100 }
3101
3102 bool
3103 EngineControl::on_delete_event (GdkEventAny* ev)
3104 {
3105         if (notebook.get_current_page() == 2) {
3106                 /* currently on latency tab - be sure to clean up */
3107                 end_latency_detection ();
3108         }
3109         return ArdourDialog::on_delete_event (ev);
3110 }
3111
3112 void
3113 EngineControl::engine_running ()
3114 {
3115         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3116         assert (backend);
3117
3118         set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3119         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3120
3121         if (backend->can_set_period_size ()) {
3122                 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3123         }
3124
3125         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3126         connect_disconnect_button.show();
3127
3128         started_at_least_once = true;
3129         if (_have_control) {
3130                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3131         } else {
3132                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3133         }
3134         update_sensitivity();
3135 }
3136
3137 void
3138 EngineControl::engine_stopped ()
3139 {
3140         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3141         assert (backend);
3142
3143         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3144         connect_disconnect_button.show();
3145
3146         if (_have_control) {
3147                 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3148         } else {
3149                 engine_status.set_markup(X_(""));
3150         }
3151
3152         update_sensitivity();
3153 }
3154
3155 void
3156 EngineControl::device_list_changed ()
3157 {
3158         if (ignore_device_changes) {
3159                 return;
3160         }
3161         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3162         list_devices ();
3163         midi_option_changed();
3164 }
3165
3166 void
3167 EngineControl::connect_disconnect_click()
3168 {
3169         if (ARDOUR::AudioEngine::instance()->running()) {
3170                 stop_engine ();
3171         } else {
3172                 start_engine ();
3173         }
3174 }
3175
3176 void
3177 EngineControl::calibrate_audio_latency ()
3178 {
3179         _measure_midi.reset ();
3180         have_lm_results = false;
3181         lm_use_button.set_sensitive (false);
3182         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3183         notebook.set_current_page (latency_tab);
3184 }
3185
3186 void
3187 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3188 {
3189         _measure_midi = s;
3190         have_lm_results = false;
3191         lm_use_button.set_sensitive (false);
3192         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3193         notebook.set_current_page (latency_tab);
3194 }
3195
3196 void
3197 EngineControl::configure_midi_devices ()
3198 {
3199         notebook.set_current_page (midi_tab);
3200 }