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