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