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