d8f35b211aa25ea8895daeed12bd42d074bfd629
[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 (_have_control && !ignore_changes) {
1025                 // set driver & devices
1026                 State state = get_matching_state (backend_combo.get_active_text());
1027                 if (state) {
1028                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1029                         set_current_state (state);
1030                 }
1031         }
1032
1033         if (!ignore_changes) {
1034                 maybe_display_saved_state ();
1035         }
1036 }
1037
1038 void
1039 EngineControl::update_midi_options ()
1040 {
1041         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1042         vector<string> midi_options = backend->enumerate_midi_options();
1043
1044         if (midi_options.size() == 1) {
1045                 /* only contains the "none" option */
1046                 midi_option_combo.set_sensitive (false);
1047         } else {
1048                 if (_have_control) {
1049                         set_popdown_strings (midi_option_combo, midi_options);
1050                         midi_option_combo.set_active_text (midi_options.front());
1051                         midi_option_combo.set_sensitive (true);
1052                 } else {
1053                         midi_option_combo.set_sensitive (false);
1054                 }
1055         }
1056 }
1057
1058 bool
1059 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1060 {
1061         if (ARDOUR::Profile->get_mixbus()) {
1062                 return true;
1063         }
1064
1065         uint32_t cnt = (uint32_t) sb->get_value();
1066         if (cnt == 0) {
1067                 sb->set_text (_("all available channels"));
1068         } else {
1069                 char buf[32];
1070                 snprintf (buf, sizeof (buf), "%d", cnt);
1071                 sb->set_text (buf);
1072         }
1073         return true;
1074 }
1075
1076 // @return true if there are drivers available
1077 bool
1078 EngineControl::set_driver_popdown_strings ()
1079 {
1080         DEBUG_ECONTROL ("set_driver_popdown_strings");
1081         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1082         vector<string> drivers = backend->enumerate_drivers();
1083
1084         if (drivers.empty ()) {
1085                 // This is an error...?
1086                 return false;
1087         }
1088
1089         string current_driver = backend->driver_name ();
1090
1091         DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1092
1093         if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1094             drivers.end ()) {
1095
1096                 current_driver = drivers.front ();
1097         }
1098
1099         set_popdown_strings (driver_combo, drivers);
1100         DEBUG_ECONTROL (
1101             string_compose ("driver_combo.set_active_text: %1", current_driver));
1102         driver_combo.set_active_text (current_driver);
1103         return true;
1104 }
1105
1106 std::string
1107 EngineControl::get_default_device(const string& current_device_name,
1108                                   const vector<string>& available_devices)
1109 {
1110         // If the current device is available, use it as default
1111         if (std::find (available_devices.begin (),
1112                        available_devices.end (),
1113                        current_device_name) != available_devices.end ()) {
1114
1115                 return current_device_name;
1116         }
1117
1118         using namespace ARDOUR;
1119
1120         string default_device_name =
1121             AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1122
1123         vector<string>::const_iterator i;
1124
1125         // If there is a "Default" device available, use it
1126         for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1127                 if (*i == default_device_name) {
1128                         return *i;
1129                 }
1130         }
1131
1132         string none_device_name =
1133             AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1134
1135         // Use the first device that isn't "None"
1136         for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1137                 if (*i != none_device_name) {
1138                         return *i;
1139                 }
1140         }
1141
1142         // Use "None" if there are no other available
1143         return available_devices.front();
1144 }
1145
1146 // @return true if there are devices available
1147 bool
1148 EngineControl::set_device_popdown_strings ()
1149 {
1150         DEBUG_ECONTROL ("set_device_popdown_strings");
1151         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1152         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1153
1154         /* NOTE: Ardour currently does not display the "available" field of the
1155          * returned devices.
1156          *
1157          * Doing so would require a different GUI widget than the combo
1158          * box/popdown that we currently use, since it has no way to list
1159          * items that are not selectable. Something more like a popup menu,
1160          * which could have unselectable items, would be appropriate.
1161          */
1162
1163         vector<string> available_devices;
1164
1165         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1166                 available_devices.push_back (i->name);
1167         }
1168
1169         if (available_devices.empty ()) {
1170                 return false;
1171         }
1172
1173         set_popdown_strings (device_combo, available_devices);
1174
1175         std::string default_device =
1176             get_default_device(backend->device_name(), available_devices);
1177
1178         DEBUG_ECONTROL (
1179             string_compose ("set device_combo active text: %1", default_device));
1180
1181         device_combo.set_active_text(default_device);
1182         return true;
1183 }
1184
1185 // @return true if there are input devices available
1186 bool
1187 EngineControl::set_input_device_popdown_strings ()
1188 {
1189         DEBUG_ECONTROL ("set_input_device_popdown_strings");
1190         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1191         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1192
1193         vector<string> available_devices;
1194
1195         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1196                 available_devices.push_back (i->name);
1197         }
1198
1199         if (available_devices.empty()) {
1200                 return false;
1201         }
1202
1203         set_popdown_strings (input_device_combo, available_devices);
1204
1205         std::string default_device =
1206             get_default_device(backend->input_device_name(), available_devices);
1207
1208         DEBUG_ECONTROL (
1209             string_compose ("set input_device_combo active text: %1", default_device));
1210         input_device_combo.set_active_text(default_device);
1211         return true;
1212 }
1213
1214 // @return true if there are output devices available
1215 bool
1216 EngineControl::set_output_device_popdown_strings ()
1217 {
1218         DEBUG_ECONTROL ("set_output_device_popdown_strings");
1219         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1220         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1221
1222         vector<string> available_devices;
1223
1224         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1225                 available_devices.push_back (i->name);
1226         }
1227
1228         if (available_devices.empty()) {
1229                 return false;
1230         }
1231
1232         set_popdown_strings (output_device_combo, available_devices);
1233
1234         std::string default_device =
1235             get_default_device(backend->output_device_name(), available_devices);
1236
1237         DEBUG_ECONTROL (
1238             string_compose ("set output_device_combo active text: %1", default_device));
1239         output_device_combo.set_active_text(default_device);
1240         return true;
1241 }
1242
1243 void
1244 EngineControl::list_devices ()
1245 {
1246         DEBUG_ECONTROL ("list_devices");
1247         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1248         assert (backend);
1249
1250         /* now fill out devices, mark sample rates, buffer sizes insensitive */
1251
1252         bool devices_available = false;
1253
1254         if (backend->use_separate_input_and_output_devices ()) {
1255                 bool input_devices_available = set_input_device_popdown_strings ();
1256                 bool output_devices_available = set_output_device_popdown_strings ();
1257                 devices_available = input_devices_available || output_devices_available;
1258         } else {
1259                 devices_available = set_device_popdown_strings ();
1260         }
1261
1262         if (devices_available) {
1263                 device_changed ();
1264         } else {
1265                 device_combo.clear();
1266                 input_device_combo.clear();
1267                 output_device_combo.clear();
1268         }
1269         update_sensitivity ();
1270 }
1271
1272 void
1273 EngineControl::driver_changed ()
1274 {
1275         SignalBlocker blocker (*this, "driver_changed");
1276         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1277         assert (backend);
1278
1279         backend->set_driver (driver_combo.get_active_text());
1280         list_devices ();
1281
1282         // TODO load LRU device(s) for backend + driver combo
1283
1284         if (!ignore_changes) {
1285                 maybe_display_saved_state ();
1286         }
1287 }
1288
1289 vector<float>
1290 EngineControl::get_sample_rates_for_all_devices ()
1291 {
1292         boost::shared_ptr<ARDOUR::AudioBackend> backend =
1293             ARDOUR::AudioEngine::instance ()->current_backend ();
1294         vector<float> all_rates;
1295
1296         if (backend->use_separate_input_and_output_devices ()) {
1297                 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1298         } else {
1299                 all_rates = backend->available_sample_rates (get_device_name ());
1300         }
1301         return all_rates;
1302 }
1303
1304 vector<float>
1305 EngineControl::get_default_sample_rates ()
1306 {
1307         vector<float> rates;
1308         rates.push_back (8000.0f);
1309         rates.push_back (16000.0f);
1310         rates.push_back (32000.0f);
1311         rates.push_back (44100.0f);
1312         rates.push_back (48000.0f);
1313         rates.push_back (88200.0f);
1314         rates.push_back (96000.0f);
1315         rates.push_back (192000.0f);
1316         rates.push_back (384000.0f);
1317         return rates;
1318 }
1319
1320 void
1321 EngineControl::set_samplerate_popdown_strings ()
1322 {
1323         DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1324         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1325         string desired;
1326         vector<float> sr;
1327         vector<string> s;
1328
1329         if (_have_control) {
1330                 sr = get_sample_rates_for_all_devices ();
1331         } else {
1332                 sr = get_default_sample_rates ();
1333         }
1334
1335         for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1336                 s.push_back (rate_as_string (*x));
1337                 if (*x == _desired_sample_rate) {
1338                         desired = s.back();
1339                 }
1340         }
1341
1342         set_popdown_strings (sample_rate_combo, s);
1343
1344         if (!s.empty()) {
1345                 if (desired.empty ()) {
1346                         float new_active_sr = backend->default_sample_rate ();
1347
1348                         if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1349                                 new_active_sr = sr.front ();
1350                         }
1351
1352                         sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1353                 } else {
1354                         sample_rate_combo.set_active_text (desired);
1355                 }
1356
1357         }
1358         update_sensitivity ();
1359 }
1360
1361 vector<uint32_t>
1362 EngineControl::get_buffer_sizes_for_all_devices ()
1363 {
1364         boost::shared_ptr<ARDOUR::AudioBackend> backend =
1365             ARDOUR::AudioEngine::instance ()->current_backend ();
1366         vector<uint32_t> all_sizes;
1367
1368         if (backend->use_separate_input_and_output_devices ()) {
1369                 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1370         } else {
1371                 all_sizes = backend->available_buffer_sizes (get_device_name ());
1372         }
1373         return all_sizes;
1374 }
1375
1376 vector<uint32_t>
1377 EngineControl::get_default_buffer_sizes ()
1378 {
1379         vector<uint32_t> sizes;
1380         sizes.push_back (8);
1381         sizes.push_back (16);
1382         sizes.push_back (32);
1383         sizes.push_back (64);
1384         sizes.push_back (128);
1385         sizes.push_back (256);
1386         sizes.push_back (512);
1387         sizes.push_back (1024);
1388         sizes.push_back (2048);
1389         sizes.push_back (4096);
1390         sizes.push_back (8192);
1391         return sizes;
1392 }
1393
1394 void
1395 EngineControl::set_buffersize_popdown_strings ()
1396 {
1397         DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1398         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1399         vector<uint32_t> bs;
1400         vector<string> s;
1401
1402         if (_have_control) {
1403                 bs = get_buffer_sizes_for_all_devices ();
1404         } else if (backend->can_change_buffer_size_when_running()) {
1405                 bs = get_default_buffer_sizes ();
1406         }
1407
1408         for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1409                 s.push_back (bufsize_as_string (*x));
1410         }
1411
1412         uint32_t previous_size = 0;
1413         if (!buffer_size_combo.get_active_text().empty()) {
1414                 previous_size = get_buffer_size ();
1415         }
1416
1417         set_popdown_strings (buffer_size_combo, s);
1418
1419         if (!s.empty()) {
1420
1421                 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1422                         buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1423                 } else {
1424
1425                         buffer_size_combo.set_active_text(s.front());
1426
1427                         uint32_t period = backend->buffer_size();
1428                         if (0 == period && backend->use_separate_input_and_output_devices()) {
1429                                 period = backend->default_buffer_size(get_input_device_name());
1430                         }
1431                         if (0 == period && backend->use_separate_input_and_output_devices()) {
1432                                 period = backend->default_buffer_size(get_output_device_name());
1433                         }
1434                         if (0 == period && !backend->use_separate_input_and_output_devices()) {
1435                                 period = backend->default_buffer_size(get_device_name());
1436                         }
1437
1438                         set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1439                 }
1440                 show_buffer_duration ();
1441         }
1442         update_sensitivity ();
1443 }
1444
1445 void
1446 EngineControl::device_changed ()
1447 {
1448         SignalBlocker blocker (*this, "device_changed");
1449         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1450         assert (backend);
1451
1452         string device_name_in;
1453         string device_name_out; // only used if backend support separate I/O devices
1454
1455         if (backend->use_separate_input_and_output_devices()) {
1456                 device_name_in  = get_input_device_name ();
1457                 device_name_out = get_output_device_name ();
1458         } else {
1459                 device_name_in = get_device_name ();
1460         }
1461
1462         /* we set the backend-device to query various device related intormation.
1463          * This has the side effect that backend->device_name() will match
1464          * the device_name and  'change_device' will never be true.
1465          * so work around this by setting...
1466          */
1467         if (backend->use_separate_input_and_output_devices()) {
1468                 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1469                         queue_device_changed = true;
1470                 }
1471         } else {
1472                 if (device_name_in != backend->device_name()) {
1473                         queue_device_changed = true;
1474                 }
1475         }
1476
1477         //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1478         if (backend->use_separate_input_and_output_devices()) {
1479                 backend->set_input_device_name (device_name_in);
1480                 backend->set_output_device_name (device_name_out);
1481         } else {
1482                 backend->set_device_name(device_name_in);
1483         }
1484
1485         {
1486                 /* don't allow programmatic change to combos to cause a
1487                    recursive call to this method.
1488                  */
1489                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1490
1491                 set_samplerate_popdown_strings ();
1492                 set_buffersize_popdown_strings ();
1493
1494                 /* TODO set min + max channel counts here */
1495
1496                 manage_control_app_sensitivity ();
1497         }
1498
1499         /* pick up any saved state for this device */
1500
1501         if (!ignore_changes) {
1502                 maybe_display_saved_state ();
1503         }
1504 }
1505
1506 void
1507 EngineControl::input_device_changed ()
1508 {
1509         DEBUG_ECONTROL ("input_device_changed");
1510         device_changed ();
1511 }
1512
1513 void
1514 EngineControl::output_device_changed ()
1515 {
1516         DEBUG_ECONTROL ("output_device_changed");
1517         device_changed ();
1518 }
1519
1520 string
1521 EngineControl::bufsize_as_string (uint32_t sz)
1522 {
1523         /* Translators: "samples" is always plural here, so no
1524            need for plural+singular forms.
1525          */
1526         char buf[64];
1527         snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1528         return buf;
1529 }
1530
1531 void
1532 EngineControl::sample_rate_changed ()
1533 {
1534         DEBUG_ECONTROL ("sample_rate_changed");
1535         /* reset the strings for buffer size to show the correct msec value
1536            (reflecting the new sample rate).
1537          */
1538
1539         show_buffer_duration ();
1540
1541 }
1542
1543 void
1544 EngineControl::buffer_size_changed ()
1545 {
1546         DEBUG_ECONTROL ("buffer_size_changed");
1547         show_buffer_duration ();
1548 }
1549
1550 void
1551 EngineControl::show_buffer_duration ()
1552 {
1553         DEBUG_ECONTROL ("show_buffer_duration");
1554         /* buffer sizes  - convert from just samples to samples + msecs for
1555          * the displayed string
1556          */
1557
1558         string bs_text = buffer_size_combo.get_active_text ();
1559         uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1560         uint32_t rate = get_rate();
1561
1562         /* Developers: note the hard-coding of a double buffered model
1563            in the (2 * samples) computation of latency. we always start
1564            the audiobackend in this configuration.
1565          */
1566         /* note to jack1 developers: ardour also always starts the engine
1567          * in async mode (no jack2 --sync option) which adds an extra cycle
1568          * of latency with jack2 (and *3 would be correct)
1569          * The value can also be wrong if jackd is started externally..
1570          *
1571          * At the time of writing the ALSA backend always uses double-buffering *2,
1572          * The Dummy backend *1, and who knows what ASIO really does :)
1573          *
1574          * So just display the period size, that's also what
1575          * ARDOUR_UI::update_sample_rate() does for the status bar.
1576          * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1577          * but still, that's the buffer period, not [round-trip] latency)
1578          */
1579         char buf[32];
1580         snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1581         buffer_size_duration_label.set_text (buf);
1582 }
1583
1584 void
1585 EngineControl::midi_option_changed ()
1586 {
1587         DEBUG_ECONTROL ("midi_option_changed");
1588         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1589         assert (backend);
1590
1591         backend->set_midi_option (get_midi_option());
1592
1593         vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1594
1595         //_midi_devices.clear(); // TODO merge with state-saved settings..
1596         _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1597         std::vector<MidiDeviceSettings> new_devices;
1598
1599         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1600                 MidiDeviceSettings mds = find_midi_device (i->name);
1601                 if (i->available && !mds) {
1602                         uint32_t input_latency = 0;
1603                         uint32_t output_latency = 0;
1604                         if (_can_set_midi_latencies) {
1605                                 input_latency = backend->systemic_midi_input_latency (i->name);
1606                                 output_latency = backend->systemic_midi_output_latency (i->name);
1607                         }
1608                         bool enabled = backend->midi_device_enabled (i->name);
1609                         MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1610                         new_devices.push_back (ptr);
1611                 } else if (i->available) {
1612                         new_devices.push_back (mds);
1613                 }
1614         }
1615         _midi_devices = new_devices;
1616
1617         if (_midi_devices.empty()) {
1618                 midi_devices_button.set_sensitive (false);
1619         } else {
1620                 midi_devices_button.set_sensitive (true);
1621         }
1622 }
1623
1624 void
1625 EngineControl::parameter_changed ()
1626 {
1627 }
1628
1629 EngineControl::State
1630 EngineControl::get_matching_state (const string& backend)
1631 {
1632         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1633                 // TODO use LRU for every backend and prefer the active one
1634                 // uniqueness is only guaranteed for backend + driver + device(s)
1635                 if ((*i)->backend == backend) {
1636                         return (*i);
1637                 }
1638         }
1639         return State();
1640 }
1641
1642 EngineControl::State
1643 EngineControl::get_matching_state (
1644                 const string& backend,
1645                 const string& driver,
1646                 const string& device)
1647 {
1648         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1649                 if ((*i)->backend == backend &&
1650                                 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1651                 {
1652                         return (*i);
1653                 }
1654         }
1655         return State();
1656 }
1657
1658 EngineControl::State
1659 EngineControl::get_matching_state (
1660                 const string& backend,
1661                 const string& driver,
1662                 const string& input_device,
1663                 const string& output_device)
1664 {
1665         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1666                 if ((*i)->backend == backend &&
1667                                 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1668                 {
1669                         return (*i);
1670                 }
1671         }
1672         return State();
1673 }
1674
1675 EngineControl::State
1676 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1677 {
1678         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1679
1680         if (backend) {
1681                 if (backend->use_separate_input_and_output_devices ()) {
1682                         return get_matching_state (backend_combo.get_active_text(),
1683                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1684                                         input_device_combo.get_active_text(),
1685                                         output_device_combo.get_active_text());
1686                 } else {
1687                         return get_matching_state (backend_combo.get_active_text(),
1688                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1689                                         device_combo.get_active_text());
1690                 }
1691         }
1692
1693         return get_matching_state (backend_combo.get_active_text(),
1694                         string(),
1695                         device_combo.get_active_text());
1696 }
1697
1698 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1699                                        const EngineControl::State& state2)
1700 {
1701         if (state1->backend == state2->backend &&
1702                         state1->driver == state2->driver &&
1703                         state1->device == state2->device &&
1704                         state1->input_device == state2->input_device &&
1705                         state1->output_device == state2->output_device) {
1706                 return true;
1707         }
1708         return false;
1709 }
1710
1711 EngineControl::State
1712 EngineControl::save_state ()
1713 {
1714         State state;
1715
1716         if (!_have_control) {
1717                 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1718                 if (state) {
1719                         return state;
1720                 }
1721                 state.reset(new StateStruct);
1722                 state->backend = get_backend ();
1723         } else {
1724                 state.reset(new StateStruct);
1725                 store_state (state);
1726         }
1727
1728         for (StateList::iterator i = states.begin(); i != states.end();) {
1729                 if (equivalent_states (*i, state)) {
1730                         i =  states.erase(i);
1731                 } else {
1732                         ++i;
1733                 }
1734         }
1735
1736         states.push_back (state);
1737
1738         return state;
1739 }
1740
1741 void
1742 EngineControl::store_state (State state)
1743 {
1744         state->backend = get_backend ();
1745         state->driver = get_driver ();
1746         state->device = get_device_name ();
1747         state->input_device = get_input_device_name ();
1748         state->output_device = get_output_device_name ();
1749         state->sample_rate = get_rate ();
1750         state->buffer_size = get_buffer_size ();
1751         state->input_latency = get_input_latency ();
1752         state->output_latency = get_output_latency ();
1753         state->input_channels = get_input_channels ();
1754         state->output_channels = get_output_channels ();
1755         state->midi_option = get_midi_option ();
1756         state->midi_devices = _midi_devices;
1757 }
1758
1759 void
1760 EngineControl::maybe_display_saved_state ()
1761 {
1762         if (!_have_control) {
1763                 return;
1764         }
1765
1766         State state = get_saved_state_for_currently_displayed_backend_and_device ();
1767
1768         if (state) {
1769                 DEBUG_ECONTROL ("Restoring saved state");
1770                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1771
1772                 if (!_desired_sample_rate) {
1773                         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1774                 }
1775                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1776                 /* call this explicitly because we're ignoring changes to
1777                    the controls at this point.
1778                  */
1779                 show_buffer_duration ();
1780                 input_latency.set_value (state->input_latency);
1781                 output_latency.set_value (state->output_latency);
1782
1783                 if (!state->midi_option.empty()) {
1784                         midi_option_combo.set_active_text (state->midi_option);
1785                         _midi_devices = state->midi_devices;
1786                 }
1787         } else {
1788                 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1789         }
1790 }
1791
1792 XMLNode&
1793 EngineControl::get_state ()
1794 {
1795         LocaleGuard lg (X_("C"));
1796
1797         XMLNode* root = new XMLNode ("AudioMIDISetup");
1798         std::string path;
1799
1800         if (!states.empty()) {
1801                 XMLNode* state_nodes = new XMLNode ("EngineStates");
1802
1803                 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1804
1805                         XMLNode* node = new XMLNode ("State");
1806
1807                         node->add_property ("backend", (*i)->backend);
1808                         node->add_property ("driver", (*i)->driver);
1809                         node->add_property ("device", (*i)->device);
1810                         node->add_property ("input-device", (*i)->input_device);
1811                         node->add_property ("output-device", (*i)->output_device);
1812                         node->add_property ("sample-rate", (*i)->sample_rate);
1813                         node->add_property ("buffer-size", (*i)->buffer_size);
1814                         node->add_property ("input-latency", (*i)->input_latency);
1815                         node->add_property ("output-latency", (*i)->output_latency);
1816                         node->add_property ("input-channels", (*i)->input_channels);
1817                         node->add_property ("output-channels", (*i)->output_channels);
1818                         node->add_property ("active", (*i)->active ? "yes" : "no");
1819                         node->add_property ("midi-option", (*i)->midi_option);
1820
1821                         XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1822                         for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1823                                 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1824                                 midi_device_stuff->add_property (X_("name"), (*p)->name);
1825                                 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1826                                 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1827                                 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1828                                 midi_devices->add_child_nocopy (*midi_device_stuff);
1829                         }
1830                         node->add_child_nocopy (*midi_devices);
1831
1832                         state_nodes->add_child_nocopy (*node);
1833                 }
1834
1835                 root->add_child_nocopy (*state_nodes);
1836         }
1837
1838         return *root;
1839 }
1840
1841 void
1842 EngineControl::set_default_state ()
1843 {
1844         vector<string> backend_names;
1845         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1846
1847         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1848                 backend_names.push_back ((*b)->name);
1849         }
1850         backend_combo.set_active_text (backend_names.front());
1851
1852         // We could set default backends per platform etc here
1853
1854         backend_changed ();
1855 }
1856
1857 bool
1858 EngineControl::set_state (const XMLNode& root)
1859 {
1860         XMLNodeList          clist, cclist;
1861         XMLNodeConstIterator citer, cciter;
1862         XMLNode* child;
1863         XMLNode* grandchild;
1864         XMLProperty* prop = NULL;
1865
1866         fprintf (stderr, "EngineControl::set_state\n");
1867
1868         if (root.name() != "AudioMIDISetup") {
1869                 return false;
1870         }
1871
1872         clist = root.children();
1873
1874         states.clear ();
1875
1876         for (citer = clist.begin(); citer != clist.end(); ++citer) {
1877
1878                 child = *citer;
1879
1880                 if (child->name() != "EngineStates") {
1881                         continue;
1882                 }
1883
1884                 cclist = child->children();
1885
1886                 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1887                         State state (new StateStruct);
1888
1889                         grandchild = *cciter;
1890
1891                         if (grandchild->name() != "State") {
1892                                 continue;
1893                         }
1894
1895                         if ((prop = grandchild->property ("backend")) == 0) {
1896                                 continue;
1897                         }
1898                         state->backend = prop->value ();
1899
1900                         if ((prop = grandchild->property ("driver")) == 0) {
1901                                 continue;
1902                         }
1903                         state->driver = prop->value ();
1904
1905                         if ((prop = grandchild->property ("device")) == 0) {
1906                                 continue;
1907                         }
1908                         state->device = prop->value ();
1909
1910                         if ((prop = grandchild->property ("input-device")) == 0) {
1911                                 continue;
1912                         }
1913                         state->input_device = prop->value ();
1914
1915                         if ((prop = grandchild->property ("output-device")) == 0) {
1916                                 continue;
1917                         }
1918                         state->output_device = prop->value ();
1919
1920                         if ((prop = grandchild->property ("sample-rate")) == 0) {
1921                                 continue;
1922                         }
1923                         state->sample_rate = atof (prop->value ());
1924
1925                         if ((prop = grandchild->property ("buffer-size")) == 0) {
1926                                 continue;
1927                         }
1928                         state->buffer_size = atoi (prop->value ());
1929
1930                         if ((prop = grandchild->property ("input-latency")) == 0) {
1931                                 continue;
1932                         }
1933                         state->input_latency = atoi (prop->value ());
1934
1935                         if ((prop = grandchild->property ("output-latency")) == 0) {
1936                                 continue;
1937                         }
1938                         state->output_latency = atoi (prop->value ());
1939
1940                         if ((prop = grandchild->property ("input-channels")) == 0) {
1941                                 continue;
1942                         }
1943                         state->input_channels = atoi (prop->value ());
1944
1945                         if ((prop = grandchild->property ("output-channels")) == 0) {
1946                                 continue;
1947                         }
1948                         state->output_channels = atoi (prop->value ());
1949
1950                         if ((prop = grandchild->property ("active")) == 0) {
1951                                 continue;
1952                         }
1953                         state->active = string_is_affirmative (prop->value ());
1954
1955                         if ((prop = grandchild->property ("midi-option")) == 0) {
1956                                 continue;
1957                         }
1958                         state->midi_option = prop->value ();
1959
1960                         state->midi_devices.clear();
1961                         XMLNode* midinode;
1962                         if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1963                                 const XMLNodeList mnc = midinode->children();
1964                                 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1965                                         if ((*n)->property (X_("name")) == 0
1966                                                         || (*n)->property (X_("enabled")) == 0
1967                                                         || (*n)->property (X_("input-latency")) == 0
1968                                                         || (*n)->property (X_("output-latency")) == 0
1969                                                  ) {
1970                                                 continue;
1971                                         }
1972
1973                                         MidiDeviceSettings ptr (new MidiDeviceSetting(
1974                                                                 (*n)->property (X_("name"))->value (),
1975                                                                 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1976                                                                 atoi ((*n)->property (X_("input-latency"))->value ()),
1977                                                                 atoi ((*n)->property (X_("output-latency"))->value ())
1978                                                                 ));
1979                                         state->midi_devices.push_back (ptr);
1980                                 }
1981                         }
1982
1983 #if 1
1984                         /* remove accumulated duplicates (due to bug in ealier version)
1985                          * this can be removed again before release
1986                          */
1987                         for (StateList::iterator i = states.begin(); i != states.end();) {
1988                                 if ((*i)->backend == state->backend &&
1989                                                 (*i)->driver == state->driver &&
1990                                                 (*i)->device == state->device) {
1991                                         i =  states.erase(i);
1992                                 } else {
1993                                         ++i;
1994                                 }
1995                         }
1996 #endif
1997
1998                         states.push_back (state);
1999                 }
2000         }
2001
2002         /* now see if there was an active state and switch the setup to it */
2003
2004         // purge states of backend that are not available in this built
2005         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2006         vector<std::string> backend_names;
2007
2008         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2009                 backend_names.push_back((*i)->name);
2010         }
2011         for (StateList::iterator i = states.begin(); i != states.end();) {
2012                 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2013                         i = states.erase(i);
2014                 } else {
2015                         ++i;
2016                 }
2017         }
2018
2019         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2020
2021                 if ((*i)->active) {
2022                         return set_current_state (*i);
2023                 }
2024         }
2025         return false;
2026 }
2027
2028 bool
2029 EngineControl::set_current_state (const State& state)
2030 {
2031         DEBUG_ECONTROL ("set_current_state");
2032
2033         boost::shared_ptr<ARDOUR::AudioBackend> backend;
2034
2035         if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2036                   state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2037                 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2038                 // this shouldn't happen as the invalid backend names should have been
2039                 // removed from the list of states.
2040                 return false;
2041         }
2042
2043         // now reflect the change in the backend in the GUI so backend_changed will
2044         // do the right thing
2045         backend_combo.set_active_text (state->backend);
2046
2047         if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2048                 backend_changed ();
2049                 // we don't have control don't restore state
2050                 return true;
2051         }
2052
2053
2054         if (!state->driver.empty ()) {
2055                 if (!backend->requires_driver_selection ()) {
2056                         DEBUG_ECONTROL ("Backend should require driver selection");
2057                         // A backend has changed from having driver selection to not having
2058                         // it or someone has been manually editing a config file and messed
2059                         // it up
2060                         return false;
2061                 }
2062
2063                 if (backend->set_driver (state->driver) != 0) {
2064                         DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2065                         // Driver names for a backend have changed and the name in the
2066                         // config file is now invalid or support for driver is no longer
2067                         // included in the backend
2068                         return false;
2069                 }
2070                 // no need to set the driver_combo as backend_changed will use
2071                 // backend->driver_name to set the active driver
2072         }
2073
2074         if (!state->device.empty ()) {
2075                 if (backend->set_device_name (state->device) != 0) {
2076                         DEBUG_ECONTROL (
2077                             string_compose ("Unable to set device name %1", state->device));
2078                         // device is no longer available on the system
2079                         return false;
2080                 }
2081                 // no need to set active device as it will be picked up in
2082                 // via backend_changed ()/set_device_popdown_strings
2083
2084         } else {
2085                 // backend supports separate input/output devices
2086                 if (backend->set_input_device_name (state->input_device) != 0) {
2087                         DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2088                                                         state->input_device));
2089                         // input device is no longer available on the system
2090                         return false;
2091                 }
2092
2093                 if (backend->set_output_device_name (state->output_device) != 0) {
2094                         DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2095                                                         state->input_device));
2096                         // output device is no longer available on the system
2097                         return false;
2098                 }
2099                 // no need to set active devices as it will be picked up in via
2100                 // backend_changed ()/set_*_device_popdown_strings
2101         }
2102
2103         backend_changed ();
2104
2105         // Now restore the state of the rest of the controls
2106
2107         // We don't use a SignalBlocker as set_current_state is currently only
2108         // called from set_state before any signals are connected. If at some point
2109         // a more general named state mechanism is implemented and
2110         // set_current_state is called while signals are connected then a
2111         // SignalBlocker will need to be instantiated before setting these.
2112
2113         device_combo.set_active_text (state->device);
2114         input_device_combo.set_active_text (state->input_device);
2115         output_device_combo.set_active_text (state->output_device);
2116         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2117         set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2118         input_latency.set_value (state->input_latency);
2119         output_latency.set_value (state->output_latency);
2120         midi_option_combo.set_active_text (state->midi_option);
2121         return true;
2122 }
2123
2124 int
2125 EngineControl::push_state_to_backend (bool start)
2126 {
2127         DEBUG_ECONTROL ("push_state_to_backend");
2128         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2129
2130         if (!backend) {
2131                 return 0;
2132         }
2133
2134         /* figure out what is going to change */
2135
2136         bool restart_required = false;
2137         bool was_running = ARDOUR::AudioEngine::instance()->running();
2138         bool change_driver = false;
2139         bool change_device = false;
2140         bool change_rate = false;
2141         bool change_bufsize = false;
2142         bool change_latency = false;
2143         bool change_channels = false;
2144         bool change_midi = false;
2145
2146         uint32_t ochan = get_output_channels ();
2147         uint32_t ichan = get_input_channels ();
2148
2149         if (_have_control) {
2150
2151                 if (started_at_least_once) {
2152
2153                         /* we can control the backend */
2154
2155                         if (backend->requires_driver_selection()) {
2156                                 if (get_driver() != backend->driver_name()) {
2157                                         change_driver = true;
2158                                 }
2159                         }
2160
2161                         if (backend->use_separate_input_and_output_devices()) {
2162                                 if (get_input_device_name() != backend->input_device_name()) {
2163                                         change_device = true;
2164                                 }
2165                                 if (get_output_device_name() != backend->output_device_name()) {
2166                                         change_device = true;
2167                                 }
2168                         } else {
2169                                 if (get_device_name() != backend->device_name()) {
2170                                         change_device = true;
2171                                 }
2172                         }
2173
2174                         if (queue_device_changed) {
2175                                 change_device = true;
2176                         }
2177
2178                         if (get_rate() != backend->sample_rate()) {
2179                                 change_rate = true;
2180                         }
2181
2182                         if (get_buffer_size() != backend->buffer_size()) {
2183                                 change_bufsize = true;
2184                         }
2185
2186                         if (get_midi_option() != backend->midi_option()) {
2187                                 change_midi = true;
2188                         }
2189
2190                         /* zero-requested channels means "all available" */
2191
2192                         if (ichan == 0) {
2193                                 ichan = backend->input_channels();
2194                         }
2195
2196                         if (ochan == 0) {
2197                                 ochan = backend->output_channels();
2198                         }
2199
2200                         if (ichan != backend->input_channels()) {
2201                                 change_channels = true;
2202                         }
2203
2204                         if (ochan != backend->output_channels()) {
2205                                 change_channels = true;
2206                         }
2207
2208                         if (get_input_latency() != backend->systemic_input_latency() ||
2209                                         get_output_latency() != backend->systemic_output_latency()) {
2210                                 change_latency = true;
2211                         }
2212                 } else {
2213                         /* backend never started, so we have to force a group
2214                            of settings.
2215                          */
2216                         change_device = true;
2217                         if (backend->requires_driver_selection()) {
2218                                 change_driver = true;
2219                         }
2220                         change_rate = true;
2221                         change_bufsize = true;
2222                         change_channels = true;
2223                         change_latency = true;
2224                         change_midi = true;
2225                 }
2226
2227         } else {
2228
2229                 /* we have no control over the backend, meaning that we can
2230                  * only possibly change sample rate and buffer size.
2231                  */
2232
2233
2234                 if (get_rate() != backend->sample_rate()) {
2235                         change_bufsize = true;
2236                 }
2237
2238                 if (get_buffer_size() != backend->buffer_size()) {
2239                         change_bufsize = true;
2240                 }
2241         }
2242
2243         queue_device_changed = false;
2244
2245         if (!_have_control) {
2246
2247                 /* We do not have control over the backend, so the best we can
2248                  * do is try to change the sample rate and/or bufsize and get
2249                  * out of here.
2250                  */
2251
2252                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2253                         return 1;
2254                 }
2255
2256                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2257                         return 1;
2258                 }
2259
2260                 if (change_rate) {
2261                         backend->set_sample_rate (get_rate());
2262                 }
2263
2264                 if (change_bufsize) {
2265                         backend->set_buffer_size (get_buffer_size());
2266                 }
2267
2268                 if (start) {
2269                         if (ARDOUR::AudioEngine::instance()->start ()) {
2270                                 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2271                                 return -1;
2272                         }
2273                 }
2274
2275                 post_push ();
2276
2277                 return 0;
2278         }
2279
2280         /* determine if we need to stop the backend before changing parameters */
2281
2282         if (change_driver || change_device || change_channels || change_latency ||
2283                         (change_rate && !backend->can_change_sample_rate_when_running()) ||
2284                         change_midi ||
2285                         (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2286                 restart_required = true;
2287         } else {
2288                 restart_required = false;
2289         }
2290
2291         if (was_running) {
2292
2293                 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2294                         /* no changes in any parameters that absolutely require a
2295                          * restart, so check those that might be changeable without a
2296                          * restart
2297                          */
2298
2299                         if (change_rate && !backend->can_change_sample_rate_when_running()) {
2300                                 /* can't do this while running ... */
2301                                 restart_required = true;
2302                         }
2303
2304                         if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2305                                 /* can't do this while running ... */
2306                                 restart_required = true;
2307                         }
2308                 }
2309         }
2310
2311         if (was_running) {
2312                 if (restart_required) {
2313                         if (ARDOUR::AudioEngine::instance()->stop()) {
2314                                 return -1;
2315                         }
2316                 }
2317         }
2318
2319         if (change_driver && backend->set_driver (get_driver())) {
2320                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2321                 return -1;
2322         }
2323         if (backend->use_separate_input_and_output_devices()) {
2324                 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2325                         error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2326                         return -1;
2327                 }
2328                 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2329                         error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2330                         return -1;
2331                 }
2332         } else {
2333                 if (change_device && backend->set_device_name (get_device_name())) {
2334                         error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2335                         return -1;
2336                 }
2337         }
2338         if (change_rate && backend->set_sample_rate (get_rate())) {
2339                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2340                 return -1;
2341         }
2342         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2343                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2344                 return -1;
2345         }
2346
2347         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2348                 if (backend->set_input_channels (get_input_channels())) {
2349                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2350                         return -1;
2351                 }
2352                 if (backend->set_output_channels (get_output_channels())) {
2353                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2354                         return -1;
2355                 }
2356         }
2357         if (change_latency) {
2358                 if (backend->set_systemic_input_latency (get_input_latency())) {
2359                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2360                         return -1;
2361                 }
2362                 if (backend->set_systemic_output_latency (get_output_latency())) {
2363                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2364                         return -1;
2365                 }
2366         }
2367
2368         if (change_midi) {
2369                 backend->set_midi_option (get_midi_option());
2370         }
2371
2372         if (1 /* TODO */) {
2373                 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2374                         if (_measure_midi) {
2375                                 if (*p == _measure_midi) {
2376                                         backend->set_midi_device_enabled ((*p)->name, true);
2377                                 } else {
2378                                         backend->set_midi_device_enabled ((*p)->name, false);
2379                                 }
2380                                 continue;
2381                         }
2382                         backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2383                         if (backend->can_set_systemic_midi_latencies()) {
2384                                 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2385                                 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2386                         }
2387                 }
2388         }
2389
2390         if (start || (was_running && restart_required)) {
2391                 if (ARDOUR::AudioEngine::instance()->start()) {
2392                         return -1;
2393                 }
2394         }
2395
2396         post_push ();
2397
2398         return 0;
2399 }
2400
2401 void
2402 EngineControl::post_push ()
2403 {
2404         /* get a pointer to the current state object, creating one if
2405          * necessary
2406          */
2407
2408         State state = get_saved_state_for_currently_displayed_backend_and_device ();
2409
2410         if (!state) {
2411                 state = save_state ();
2412                 assert (state);
2413         } else {
2414                 store_state(state);
2415         }
2416
2417         /* all off */
2418
2419         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2420                 (*i)->active = false;
2421         }
2422
2423         /* mark this one active (to be used next time the dialog is
2424          * shown)
2425          */
2426
2427         state->active = true;
2428
2429         if (_have_control) { // XXX
2430                 manage_control_app_sensitivity ();
2431         }
2432
2433         /* schedule a redisplay of MIDI ports */
2434         //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2435 }
2436
2437
2438 float
2439 EngineControl::get_rate () const
2440 {
2441         float r = atof (sample_rate_combo.get_active_text ());
2442         /* the string may have been translated with an abbreviation for
2443          * thousands, so use a crude heuristic to fix this.
2444          */
2445         if (r < 1000.0) {
2446                 r *= 1000.0;
2447         }
2448         return r;
2449 }
2450
2451
2452 uint32_t
2453 EngineControl::get_buffer_size () const
2454 {
2455         string txt = buffer_size_combo.get_active_text ();
2456         uint32_t samples;
2457
2458         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2459                 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2460                 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2461                 throw exception ();
2462         }
2463
2464         return samples;
2465 }
2466
2467 string
2468 EngineControl::get_midi_option () const
2469 {
2470         return midi_option_combo.get_active_text();
2471 }
2472
2473 uint32_t
2474 EngineControl::get_input_channels() const
2475 {
2476         if (ARDOUR::Profile->get_mixbus()) {
2477                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2478                 if (!backend) return 0;
2479                 return backend->input_channels();
2480         }
2481         return (uint32_t) input_channels_adjustment.get_value();
2482 }
2483
2484 uint32_t
2485 EngineControl::get_output_channels() const
2486 {
2487         if (ARDOUR::Profile->get_mixbus()) {
2488                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2489                 if (!backend) return 0;
2490                 return backend->input_channels();
2491         }
2492         return (uint32_t) output_channels_adjustment.get_value();
2493 }
2494
2495 uint32_t
2496 EngineControl::get_input_latency() const
2497 {
2498         return (uint32_t) input_latency_adjustment.get_value();
2499 }
2500
2501 uint32_t
2502 EngineControl::get_output_latency() const
2503 {
2504         return (uint32_t) output_latency_adjustment.get_value();
2505 }
2506
2507 string
2508 EngineControl::get_backend () const
2509 {
2510         return backend_combo.get_active_text ();
2511 }
2512
2513 string
2514 EngineControl::get_driver () const
2515 {
2516         if (driver_combo.get_parent()) {
2517                 return driver_combo.get_active_text ();
2518         } else {
2519                 return "";
2520         }
2521 }
2522
2523 string
2524 EngineControl::get_device_name () const
2525 {
2526         return device_combo.get_active_text ();
2527 }
2528
2529 string
2530 EngineControl::get_input_device_name () const
2531 {
2532         return input_device_combo.get_active_text ();
2533 }
2534
2535 string
2536 EngineControl::get_output_device_name () const
2537 {
2538         return output_device_combo.get_active_text ();
2539 }
2540
2541 void
2542 EngineControl::control_app_button_clicked ()
2543 {
2544         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2545
2546         if (!backend) {
2547                 return;
2548         }
2549
2550         backend->launch_control_app ();
2551 }
2552
2553 void
2554 EngineControl::start_stop_button_clicked ()
2555 {
2556         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2557
2558         if (!backend) {
2559                 return;
2560         }
2561
2562         if (ARDOUR::AudioEngine::instance()->running()) {
2563                 ARDOUR::AudioEngine::instance()->stop ();
2564         } else {
2565                 start_engine ();
2566         }
2567 }
2568
2569 void
2570 EngineControl::update_devices_button_clicked ()
2571 {
2572         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2573
2574         if (!backend) {
2575                 return;
2576         }
2577
2578         if (backend->update_devices()) {
2579                 device_list_changed ();
2580         }
2581 }
2582
2583 void
2584 EngineControl::manage_control_app_sensitivity ()
2585 {
2586         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2587
2588         if (!backend) {
2589                 return;
2590         }
2591
2592         string appname = backend->control_app_name();
2593
2594         if (appname.empty()) {
2595                 control_app_button.set_sensitive (false);
2596         } else {
2597                 control_app_button.set_sensitive (true);
2598         }
2599 }
2600
2601 void
2602 EngineControl::set_desired_sample_rate (uint32_t sr)
2603 {
2604         _desired_sample_rate = sr;
2605         device_changed ();
2606 }
2607
2608 void
2609 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2610 {
2611         if (page_num == 0) {
2612                 cancel_button->set_sensitive (true);
2613                 _measure_midi.reset();
2614                 update_sensitivity ();
2615         } else {
2616                 cancel_button->set_sensitive (false);
2617                 ok_button->set_sensitive (false);
2618         }
2619
2620         if (page_num == midi_tab) {
2621                 /* MIDI tab */
2622                 refresh_midi_display ();
2623         }
2624
2625         if (page_num == latency_tab) {
2626                 /* latency tab */
2627
2628                 if (ARDOUR::AudioEngine::instance()->running()) {
2629                         // TODO - mark as 'stopped for latency
2630                         stop_engine ();
2631                 }
2632
2633                 {
2634                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2635
2636                         /* save any existing latency values */
2637
2638                         uint32_t il = (uint32_t) input_latency.get_value ();
2639                         uint32_t ol = (uint32_t) input_latency.get_value ();
2640
2641                         /* reset to zero so that our new test instance
2642                            will be clean of any existing latency measures.
2643
2644                            NB. this should really be done by the backend
2645                            when stated for latency measurement.
2646                         */
2647
2648                         input_latency.set_value (0);
2649                         output_latency.set_value (0);
2650
2651                         push_state_to_backend (false);
2652
2653                         /* reset control */
2654
2655                         input_latency.set_value (il);
2656                         output_latency.set_value (ol);
2657
2658                 }
2659                 // This should be done in push_state_to_backend()
2660                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2661                         disable_latency_tab ();
2662                 }
2663
2664                 enable_latency_tab ();
2665
2666         } else {
2667                 if (lm_running) {
2668                         end_latency_detection ();
2669                         ARDOUR::AudioEngine::instance()->stop_latency_detection();
2670                 }
2671         }
2672 }
2673
2674 /* latency measurement */
2675
2676 bool
2677 EngineControl::check_audio_latency_measurement ()
2678 {
2679         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2680
2681         if (mtdm->resolve () < 0) {
2682                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2683                 return true;
2684         }
2685
2686         if (mtdm->err () > 0.3) {
2687                 mtdm->invert ();
2688                 mtdm->resolve ();
2689         }
2690
2691         char buf[256];
2692         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2693
2694         if (sample_rate == 0) {
2695                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2696                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2697                 return false;
2698         }
2699
2700         int frames_total = mtdm->del();
2701         int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2702
2703         snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2704                         _("Detected roundtrip latency: "),
2705                         frames_total, frames_total * 1000.0f/sample_rate,
2706                         _("Systemic latency: "),
2707                         extra, extra * 1000.0f/sample_rate);
2708
2709         bool solid = true;
2710
2711         if (mtdm->err () > 0.2) {
2712                 strcat (buf, " ");
2713                 strcat (buf, _("(signal detection error)"));
2714                 solid = false;
2715         }
2716
2717         if (mtdm->inv ()) {
2718                 strcat (buf, " ");
2719                 strcat (buf, _("(inverted - bad wiring)"));
2720                 solid = false;
2721         }
2722
2723         lm_results.set_markup (string_compose (results_markup, buf));
2724
2725         if (solid) {
2726                 have_lm_results = true;
2727                 end_latency_detection ();
2728                 lm_use_button.set_sensitive (true);
2729                 return false;
2730         }
2731
2732         return true;
2733 }
2734
2735 bool
2736 EngineControl::check_midi_latency_measurement ()
2737 {
2738         ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2739
2740         if (!mididm->have_signal () || mididm->latency () == 0) {
2741                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2742                 return true;
2743         }
2744
2745         char buf[256];
2746         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2747
2748         if (sample_rate == 0) {
2749                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2750                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2751                 return false;
2752         }
2753
2754         ARDOUR::framecnt_t frames_total = mididm->latency();
2755         ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2756         snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2757                         _("Detected roundtrip latency: "),
2758                         frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2759                         _("Systemic latency: "),
2760                         extra, extra * 1000.0f / sample_rate);
2761
2762         bool solid = true;
2763
2764         if (!mididm->ok ()) {
2765                 strcat (buf, " ");
2766                 strcat (buf, _("(averaging)"));
2767                 solid = false;
2768         }
2769
2770         if (mididm->deviation () > 50.0) {
2771                 strcat (buf, " ");
2772                 strcat (buf, _("(too large jitter)"));
2773                 solid = false;
2774         } else if (mididm->deviation () > 10.0) {
2775                 strcat (buf, " ");
2776                 strcat (buf, _("(large jitter)"));
2777         }
2778
2779         if (solid) {
2780                 have_lm_results = true;
2781                 end_latency_detection ();
2782                 lm_use_button.set_sensitive (true);
2783                 lm_results.set_markup (string_compose (results_markup, buf));
2784                 return false;
2785         } else if (mididm->processed () > 400) {
2786                 have_lm_results = false;
2787                 end_latency_detection ();
2788                 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2789                 return false;
2790         }
2791
2792         lm_results.set_markup (string_compose (results_markup, buf));
2793
2794         return true;
2795 }
2796
2797 void
2798 EngineControl::start_latency_detection ()
2799 {
2800         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2801         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2802
2803         if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2804                 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2805                 if (_measure_midi) {
2806                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2807                 } else {
2808                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2809                 }
2810                 lm_measure_label.set_text (_("Cancel"));
2811                 have_lm_results = false;
2812                 lm_use_button.set_sensitive (false);
2813                 lm_input_channel_combo.set_sensitive (false);
2814                 lm_output_channel_combo.set_sensitive (false);
2815                 lm_running = true;
2816         }
2817 }
2818
2819 void
2820 EngineControl::end_latency_detection ()
2821 {
2822         latency_timeout.disconnect ();
2823         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2824         lm_measure_label.set_text (_("Measure"));
2825         if (!have_lm_results) {
2826                 lm_use_button.set_sensitive (false);
2827         }
2828         lm_input_channel_combo.set_sensitive (true);
2829         lm_output_channel_combo.set_sensitive (true);
2830         lm_running = false;
2831 }
2832
2833 void
2834 EngineControl::latency_button_clicked ()
2835 {
2836         if (!lm_running) {
2837                 start_latency_detection ();
2838         } else {
2839                 end_latency_detection ();
2840         }
2841 }
2842
2843 void
2844 EngineControl::latency_back_button_clicked ()
2845 {
2846         ARDOUR::AudioEngine::instance()->stop(true);
2847         notebook.set_current_page(0);
2848 }
2849
2850 void
2851 EngineControl::use_latency_button_clicked ()
2852 {
2853         if (_measure_midi) {
2854                 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2855                 if (!mididm) {
2856                         return;
2857                 }
2858                 ARDOUR::framecnt_t frames_total = mididm->latency();
2859                 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2860                 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2861                 _measure_midi->input_latency = one_way;
2862                 _measure_midi->output_latency = one_way;
2863                 notebook.set_current_page (midi_tab);
2864         } else {
2865                 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2866
2867                 if (!mtdm) {
2868                         return;
2869                 }
2870
2871                 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2872                 one_way = std::max (0., one_way);
2873
2874                 input_latency_adjustment.set_value (one_way);
2875                 output_latency_adjustment.set_value (one_way);
2876
2877                 /* back to settings page */
2878                 notebook.set_current_page (0);
2879         }
2880 }
2881
2882 bool
2883 EngineControl::on_delete_event (GdkEventAny* ev)
2884 {
2885         if (notebook.get_current_page() == 2) {
2886                 /* currently on latency tab - be sure to clean up */
2887                 end_latency_detection ();
2888         }
2889         return ArdourDialog::on_delete_event (ev);
2890 }
2891
2892 void
2893 EngineControl::engine_running ()
2894 {
2895         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2896         assert (backend);
2897
2898         set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2899         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2900
2901         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2902         connect_disconnect_button.show();
2903
2904         started_at_least_once = true;
2905         if (_have_control) {
2906                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2907         } else {
2908                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2909         }
2910         update_sensitivity();
2911 }
2912
2913 void
2914 EngineControl::engine_stopped ()
2915 {
2916         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2917         assert (backend);
2918
2919         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2920         connect_disconnect_button.show();
2921
2922         if (_have_control) {
2923                 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
2924         } else {
2925                 engine_status.set_markup(X_(""));
2926         }
2927
2928         update_sensitivity();
2929 }
2930
2931 void
2932 EngineControl::device_list_changed ()
2933 {
2934         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2935         list_devices ();
2936         midi_option_changed();
2937 }
2938
2939 void
2940 EngineControl::connect_disconnect_click()
2941 {
2942         if (ARDOUR::AudioEngine::instance()->running()) {
2943                 stop_engine ();
2944         } else {
2945                 start_engine ();
2946         }
2947 }
2948
2949 void
2950 EngineControl::calibrate_audio_latency ()
2951 {
2952         _measure_midi.reset ();
2953         have_lm_results = false;
2954         lm_use_button.set_sensitive (false);
2955         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2956         notebook.set_current_page (latency_tab);
2957 }
2958
2959 void
2960 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2961 {
2962         _measure_midi = s;
2963         have_lm_results = false;
2964         lm_use_button.set_sensitive (false);
2965         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2966         notebook.set_current_page (latency_tab);
2967 }
2968
2969 void
2970 EngineControl::configure_midi_devices ()
2971 {
2972         notebook.set_current_page (midi_tab);
2973 }