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