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