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