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