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