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