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