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