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