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