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