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