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