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