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