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