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