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