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