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