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