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