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