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