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