Update Japanese translation
[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
783         if (backend->use_separate_input_and_output_devices ()) {
784                 devices_available += get_popdown_string_count (input_device_combo);
785                 devices_available += get_popdown_string_count (output_device_combo);
786         } else {
787                 devices_available += get_popdown_string_count (device_combo);
788         }
789
790         if (devices_available == 0) {
791                 valid = false;
792                 input_latency.set_sensitive (false);
793                 output_latency.set_sensitive (false);
794                 input_channels.set_sensitive (false);
795                 output_channels.set_sensitive (false);
796         } else {
797                 input_latency.set_sensitive (true);
798                 output_latency.set_sensitive (true);
799                 input_channels.set_sensitive (true);
800                 output_channels.set_sensitive (true);
801         }
802
803         if (get_popdown_string_count (buffer_size_combo) > 0) {
804                 if (!ARDOUR::AudioEngine::instance()->running()) {
805                         buffer_size_combo.set_sensitive (valid);
806                 } else if (backend->can_change_sample_rate_when_running()) {
807                         buffer_size_combo.set_sensitive (valid || !_have_control);
808                 } else {
809 #if 1
810                         /* TODO
811                          * Currently there is no way to manually stop the
812                          * engine in order to re-configure it.
813                          * This needs to remain sensitive for now.
814                          *
815                          * (it's also handy to implicily
816                          * re-start the engine)
817                          */
818                         buffer_size_combo.set_sensitive (true);
819 #else
820                         buffer_size_combo.set_sensitive (false);
821 #endif
822                 }
823         } else {
824                 buffer_size_combo.set_sensitive (false);
825                 valid = false;
826         }
827
828         if (get_popdown_string_count (sample_rate_combo) > 0) {
829                 bool allow_to_set_rate = false;
830                 if (!ARDOUR::AudioEngine::instance()->running()) {
831                         if (!ARDOUR_UI::instance()->session_loaded) {
832                                 // engine is not running, no session loaded -> anything goes.
833                                 allow_to_set_rate = true;
834                         } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
835                                 // only allow to change if the current setting is not the native session rate.
836                                 allow_to_set_rate = true;
837                         }
838                 }
839                 sample_rate_combo.set_sensitive (allow_to_set_rate);
840         } else {
841                 sample_rate_combo.set_sensitive (false);
842                 valid = false;
843         }
844
845         if (get_popdown_string_count (nperiods_combo) > 0) {
846                 if (!ARDOUR::AudioEngine::instance()->running()) {
847                         nperiods_combo.set_sensitive (true);
848                 } else {
849                         nperiods_combo.set_sensitive (false);
850                 }
851         } else {
852                 nperiods_combo.set_sensitive (false);
853         }
854
855         if (_have_control) {
856                 start_stop_button.set_sensitive(true);
857                 start_stop_button.show();
858                 if (ARDOUR::AudioEngine::instance()->running()) {
859                         start_stop_button.set_text("Stop");
860                         update_devices_button.set_sensitive(false);
861                         use_buffered_io_button.set_sensitive(false);
862                 } else {
863                         if (backend->can_request_update_devices()) {
864                                 update_devices_button.show();
865                         } else {
866                                 update_devices_button.hide();
867                         }
868                         if (backend->can_use_buffered_io()) {
869                                 use_buffered_io_button.show();
870                         } else {
871                                 use_buffered_io_button.hide();
872                         }
873                         start_stop_button.set_text("Start");
874                         update_devices_button.set_sensitive(true);
875                         use_buffered_io_button.set_sensitive(true);
876                 }
877         } else {
878                 update_devices_button.set_sensitive(false);
879                 update_devices_button.hide();
880                 use_buffered_io_button.set_sensitive(false);
881                 use_buffered_io_button.hide();
882                 start_stop_button.set_sensitive(false);
883                 start_stop_button.hide();
884         }
885
886         if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
887                 input_device_combo.set_sensitive (false);
888                 output_device_combo.set_sensitive (false);
889                 device_combo.set_sensitive (false);
890                 driver_combo.set_sensitive (false);
891         } else {
892                 input_device_combo.set_sensitive (true);
893                 output_device_combo.set_sensitive (true);
894                 device_combo.set_sensitive (true);
895                 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
896                         driver_combo.set_sensitive (true);
897                 } else {
898                         driver_combo.set_sensitive (false);
899                 }
900         }
901 }
902
903 void
904 EngineControl::setup_midi_tab_for_jack ()
905 {
906 }
907
908 void
909 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
910         if (for_input) {
911                 device->input_latency = a->get_value();
912         } else {
913                 device->output_latency = a->get_value();
914         }
915 }
916
917 void
918 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
919         b->set_active (!b->get_active());
920         device->enabled = b->get_active();
921         refresh_midi_display(device->name);
922 }
923
924 void
925 EngineControl::refresh_midi_display (std::string focus)
926 {
927         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
928         assert (backend);
929
930         int row  = 0;
931         AttachOptions xopt = AttachOptions (FILL|EXPAND);
932         Gtk::Label* l;
933
934         Gtkmm2ext::container_clear (midi_device_table);
935
936         midi_device_table.set_spacings (6);
937
938         l = manage (new Label);
939         l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
940         midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
941         l->set_alignment (0.5, 0.5);
942         row++;
943         l->show ();
944
945         l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
946         midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
947         l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
948         midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
949         row++;
950         l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
951         midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
952         l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
953         midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
954         row++;
955
956         for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
957                 ArdourButton *m;
958                 Gtk::Button* b;
959                 Gtk::Adjustment *a;
960                 Gtk::SpinButton *s;
961                 bool enabled = (*p)->enabled;
962
963                 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
964                 m->set_name ("midi device");
965                 m->set_can_focus (Gtk::CAN_FOCUS);
966                 m->add_events (Gdk::BUTTON_RELEASE_MASK);
967                 m->set_active (enabled);
968                 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
969                 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
970                 if ((*p)->name == focus) {
971                         m->grab_focus();
972                 }
973
974                 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
975                 s = manage (new Gtk::SpinButton (*a));
976                 a->set_value ((*p)->input_latency);
977                 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
978                 s->set_sensitive (_can_set_midi_latencies && enabled);
979                 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
980
981                 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
982                 s = manage (new Gtk::SpinButton (*a));
983                 a->set_value ((*p)->output_latency);
984                 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
985                 s->set_sensitive (_can_set_midi_latencies && enabled);
986                 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
987
988                 b = manage (new Button (_("Calibrate")));
989                 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
990                 b->set_sensitive (_can_set_midi_latencies && enabled);
991                 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
992
993                 row++;
994         }
995 }
996
997 void
998 EngineControl::backend_changed ()
999 {
1000         SignalBlocker blocker (*this, "backend_changed");
1001         string backend_name = backend_combo.get_active_text();
1002         boost::shared_ptr<ARDOUR::AudioBackend> backend;
1003
1004         if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1005                 /* eh? setting the backend failed... how ? */
1006                 /* A: stale config contains a backend that does not exist in current build */
1007                 return;
1008         }
1009
1010         DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1011
1012         _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1013
1014         build_notebook ();
1015         setup_midi_tab_for_backend ();
1016         _midi_devices.clear();
1017
1018         if (backend->requires_driver_selection()) {
1019                 if (set_driver_popdown_strings ()) {
1020                         driver_changed ();
1021                 }
1022         } else {
1023                 /* this will change the device text which will cause a call to
1024                  * device changed which will set up parameters
1025                  */
1026                 list_devices ();
1027         }
1028
1029         update_midi_options ();
1030
1031         connect_disconnect_button.hide();
1032
1033         midi_option_changed();
1034
1035         started_at_least_once = false;
1036
1037         /* changing the backend implies stopping the engine
1038          * ARDOUR::AudioEngine() may or may not emit this signal
1039          * depending on previous engine state
1040          */
1041         engine_stopped (); // set "active/inactive"
1042
1043         if (!_have_control) {
1044                 // set settings from backend that we do have control over
1045                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1046         }
1047
1048         if (_have_control && !ignore_changes) {
1049                 // set driver & devices
1050                 State state = get_matching_state (backend_combo.get_active_text());
1051                 if (state) {
1052                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1053                         set_current_state (state);
1054                 }
1055         }
1056
1057         if (!ignore_changes) {
1058                 maybe_display_saved_state ();
1059         }
1060 }
1061
1062 void
1063 EngineControl::update_midi_options ()
1064 {
1065         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1066         vector<string> midi_options = backend->enumerate_midi_options();
1067
1068         if (midi_options.size() == 1) {
1069                 /* only contains the "none" option */
1070                 midi_option_combo.set_sensitive (false);
1071         } else {
1072                 if (_have_control) {
1073                         set_popdown_strings (midi_option_combo, midi_options);
1074                         midi_option_combo.set_active_text (midi_options.front());
1075                         midi_option_combo.set_sensitive (true);
1076                 } else {
1077                         midi_option_combo.set_sensitive (false);
1078                 }
1079         }
1080 }
1081
1082 bool
1083 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1084 {
1085         if (ARDOUR::Profile->get_mixbus()) {
1086                 return true;
1087         }
1088
1089         uint32_t cnt = (uint32_t) sb->get_value();
1090         if (cnt == 0) {
1091                 sb->set_text (_("all available channels"));
1092         } else {
1093                 char buf[32];
1094                 snprintf (buf, sizeof (buf), "%d", cnt);
1095                 sb->set_text (buf);
1096         }
1097         return true;
1098 }
1099
1100 // @return true if there are drivers available
1101 bool
1102 EngineControl::set_driver_popdown_strings ()
1103 {
1104         DEBUG_ECONTROL ("set_driver_popdown_strings");
1105         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1106         vector<string> drivers = backend->enumerate_drivers();
1107
1108         if (drivers.empty ()) {
1109                 // This is an error...?
1110                 return false;
1111         }
1112
1113         string current_driver = backend->driver_name ();
1114
1115         DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1116
1117         if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1118             drivers.end ()) {
1119
1120                 current_driver = drivers.front ();
1121         }
1122
1123         set_popdown_strings (driver_combo, drivers);
1124         DEBUG_ECONTROL (
1125             string_compose ("driver_combo.set_active_text: %1", current_driver));
1126         driver_combo.set_active_text (current_driver);
1127         return true;
1128 }
1129
1130 std::string
1131 EngineControl::get_default_device(const string& current_device_name,
1132                                   const vector<string>& available_devices)
1133 {
1134         // If the current device is available, use it as default
1135         if (std::find (available_devices.begin (),
1136                        available_devices.end (),
1137                        current_device_name) != available_devices.end ()) {
1138
1139                 return current_device_name;
1140         }
1141
1142         using namespace ARDOUR;
1143
1144         string default_device_name =
1145             AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1146
1147         vector<string>::const_iterator i;
1148
1149         // If there is a "Default" device available, use it
1150         for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1151                 if (*i == default_device_name) {
1152                         return *i;
1153                 }
1154         }
1155
1156         string none_device_name =
1157             AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1158
1159         // Use the first device that isn't "None"
1160         for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1161                 if (*i != none_device_name) {
1162                         return *i;
1163                 }
1164         }
1165
1166         // Use "None" if there are no other available
1167         return available_devices.front();
1168 }
1169
1170 // @return true if there are devices available
1171 bool
1172 EngineControl::set_device_popdown_strings ()
1173 {
1174         DEBUG_ECONTROL ("set_device_popdown_strings");
1175         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1176         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1177
1178         /* NOTE: Ardour currently does not display the "available" field of the
1179          * returned devices.
1180          *
1181          * Doing so would require a different GUI widget than the combo
1182          * box/popdown that we currently use, since it has no way to list
1183          * items that are not selectable. Something more like a popup menu,
1184          * which could have unselectable items, would be appropriate.
1185          */
1186
1187         vector<string> available_devices;
1188
1189         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1190                 available_devices.push_back (i->name);
1191         }
1192
1193         if (available_devices.empty ()) {
1194                 return false;
1195         }
1196
1197         set_popdown_strings (device_combo, available_devices);
1198
1199         std::string default_device =
1200             get_default_device(backend->device_name(), available_devices);
1201
1202         DEBUG_ECONTROL (
1203             string_compose ("set device_combo active text: %1", default_device));
1204
1205         device_combo.set_active_text(default_device);
1206         return true;
1207 }
1208
1209 // @return true if there are input devices available
1210 bool
1211 EngineControl::set_input_device_popdown_strings ()
1212 {
1213         DEBUG_ECONTROL ("set_input_device_popdown_strings");
1214         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1215         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1216
1217         vector<string> available_devices;
1218
1219         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1220                 available_devices.push_back (i->name);
1221         }
1222
1223         if (available_devices.empty()) {
1224                 return false;
1225         }
1226
1227         set_popdown_strings (input_device_combo, available_devices);
1228
1229         std::string default_device =
1230             get_default_device(backend->input_device_name(), available_devices);
1231
1232         DEBUG_ECONTROL (
1233             string_compose ("set input_device_combo active text: %1", default_device));
1234         input_device_combo.set_active_text(default_device);
1235         return true;
1236 }
1237
1238 // @return true if there are output devices available
1239 bool
1240 EngineControl::set_output_device_popdown_strings ()
1241 {
1242         DEBUG_ECONTROL ("set_output_device_popdown_strings");
1243         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1244         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1245
1246         vector<string> available_devices;
1247
1248         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1249                 available_devices.push_back (i->name);
1250         }
1251
1252         if (available_devices.empty()) {
1253                 return false;
1254         }
1255
1256         set_popdown_strings (output_device_combo, available_devices);
1257
1258         std::string default_device =
1259             get_default_device(backend->output_device_name(), available_devices);
1260
1261         DEBUG_ECONTROL (
1262             string_compose ("set output_device_combo active text: %1", default_device));
1263         output_device_combo.set_active_text(default_device);
1264         return true;
1265 }
1266
1267 void
1268 EngineControl::list_devices ()
1269 {
1270         DEBUG_ECONTROL ("list_devices");
1271         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1272         assert (backend);
1273
1274         /* now fill out devices, mark sample rates, buffer sizes insensitive */
1275
1276         bool devices_available = false;
1277
1278         if (backend->use_separate_input_and_output_devices ()) {
1279                 bool input_devices_available = set_input_device_popdown_strings ();
1280                 bool output_devices_available = set_output_device_popdown_strings ();
1281                 devices_available = input_devices_available || output_devices_available;
1282         } else {
1283                 devices_available = set_device_popdown_strings ();
1284         }
1285
1286         if (devices_available) {
1287                 device_changed ();
1288         } else {
1289                 device_combo.clear();
1290                 input_device_combo.clear();
1291                 output_device_combo.clear();
1292         }
1293         update_sensitivity ();
1294 }
1295
1296 void
1297 EngineControl::driver_changed ()
1298 {
1299         SignalBlocker blocker (*this, "driver_changed");
1300         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1301         assert (backend);
1302
1303         backend->set_driver (driver_combo.get_active_text());
1304         list_devices ();
1305
1306         // TODO load LRU device(s) for backend + driver combo
1307
1308         if (!ignore_changes) {
1309                 maybe_display_saved_state ();
1310         }
1311 }
1312
1313 vector<float>
1314 EngineControl::get_sample_rates_for_all_devices ()
1315 {
1316         boost::shared_ptr<ARDOUR::AudioBackend> backend =
1317             ARDOUR::AudioEngine::instance ()->current_backend ();
1318         vector<float> all_rates;
1319
1320         if (backend->use_separate_input_and_output_devices ()) {
1321                 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1322         } else {
1323                 all_rates = backend->available_sample_rates (get_device_name ());
1324         }
1325         return all_rates;
1326 }
1327
1328 vector<float>
1329 EngineControl::get_default_sample_rates ()
1330 {
1331         vector<float> rates;
1332         rates.push_back (8000.0f);
1333         rates.push_back (16000.0f);
1334         rates.push_back (32000.0f);
1335         rates.push_back (44100.0f);
1336         rates.push_back (48000.0f);
1337         rates.push_back (88200.0f);
1338         rates.push_back (96000.0f);
1339         rates.push_back (192000.0f);
1340         rates.push_back (384000.0f);
1341         return rates;
1342 }
1343
1344 void
1345 EngineControl::set_samplerate_popdown_strings ()
1346 {
1347         DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1348         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1349         string desired;
1350         vector<float> sr;
1351         vector<string> s;
1352
1353         if (_have_control) {
1354                 sr = get_sample_rates_for_all_devices ();
1355         } else {
1356                 sr = get_default_sample_rates ();
1357         }
1358
1359         for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1360                 s.push_back (rate_as_string (*x));
1361                 if (*x == _desired_sample_rate) {
1362                         desired = s.back();
1363                 }
1364         }
1365
1366         set_popdown_strings (sample_rate_combo, s);
1367
1368         if (!s.empty()) {
1369                 if (ARDOUR::AudioEngine::instance()->running()) {
1370                         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1371                 }
1372                 else if (desired.empty ()) {
1373                         float new_active_sr = backend->default_sample_rate ();
1374
1375                         if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1376                                 new_active_sr = sr.front ();
1377                         }
1378
1379                         sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1380                 } else {
1381                         sample_rate_combo.set_active_text (desired);
1382                 }
1383
1384         }
1385         update_sensitivity ();
1386 }
1387
1388 vector<uint32_t>
1389 EngineControl::get_buffer_sizes_for_all_devices ()
1390 {
1391         boost::shared_ptr<ARDOUR::AudioBackend> backend =
1392             ARDOUR::AudioEngine::instance ()->current_backend ();
1393         vector<uint32_t> all_sizes;
1394
1395         if (backend->use_separate_input_and_output_devices ()) {
1396                 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1397         } else {
1398                 all_sizes = backend->available_buffer_sizes (get_device_name ());
1399         }
1400         return all_sizes;
1401 }
1402
1403 vector<uint32_t>
1404 EngineControl::get_default_buffer_sizes ()
1405 {
1406         vector<uint32_t> sizes;
1407         sizes.push_back (8);
1408         sizes.push_back (16);
1409         sizes.push_back (32);
1410         sizes.push_back (64);
1411         sizes.push_back (128);
1412         sizes.push_back (256);
1413         sizes.push_back (512);
1414         sizes.push_back (1024);
1415         sizes.push_back (2048);
1416         sizes.push_back (4096);
1417         sizes.push_back (8192);
1418         return sizes;
1419 }
1420
1421 void
1422 EngineControl::set_buffersize_popdown_strings ()
1423 {
1424         DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1425         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1426         vector<uint32_t> bs;
1427         vector<string> s;
1428
1429         if (_have_control) {
1430                 bs = get_buffer_sizes_for_all_devices ();
1431         } else if (backend->can_change_buffer_size_when_running()) {
1432                 bs = get_default_buffer_sizes ();
1433         }
1434
1435         for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1436                 s.push_back (bufsize_as_string (*x));
1437         }
1438
1439         uint32_t previous_size = 0;
1440         if (!buffer_size_combo.get_active_text().empty()) {
1441                 previous_size = get_buffer_size ();
1442         }
1443
1444         set_popdown_strings (buffer_size_combo, s);
1445
1446         if (!s.empty()) {
1447
1448                 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1449                         buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1450                 } else {
1451
1452                         buffer_size_combo.set_active_text(s.front());
1453
1454                         uint32_t period = backend->buffer_size();
1455                         if (0 == period && backend->use_separate_input_and_output_devices()) {
1456                                 period = backend->default_buffer_size(get_input_device_name());
1457                         }
1458                         if (0 == period && backend->use_separate_input_and_output_devices()) {
1459                                 period = backend->default_buffer_size(get_output_device_name());
1460                         }
1461                         if (0 == period && !backend->use_separate_input_and_output_devices()) {
1462                                 period = backend->default_buffer_size(get_device_name());
1463                         }
1464
1465                         set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1466                 }
1467                 show_buffer_duration ();
1468         }
1469         update_sensitivity ();
1470 }
1471
1472 void
1473 EngineControl::set_nperiods_popdown_strings ()
1474 {
1475         DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1476         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1477         vector<uint32_t> np;
1478         vector<string> s;
1479
1480         if (backend->can_set_period_size()) {
1481                 np = backend->available_period_sizes (get_driver());
1482         }
1483
1484         for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1485                 s.push_back (nperiods_as_string (*x));
1486         }
1487
1488         set_popdown_strings (nperiods_combo, s);
1489
1490         if (!s.empty()) {
1491                 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX 
1492         }
1493
1494         update_sensitivity ();
1495 }
1496
1497 void
1498 EngineControl::device_changed ()
1499 {
1500         SignalBlocker blocker (*this, "device_changed");
1501         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1502         assert (backend);
1503
1504         string device_name_in;
1505         string device_name_out; // only used if backend support separate I/O devices
1506
1507         if (backend->use_separate_input_and_output_devices()) {
1508                 device_name_in  = get_input_device_name ();
1509                 device_name_out = get_output_device_name ();
1510         } else {
1511                 device_name_in = get_device_name ();
1512         }
1513
1514         /* we set the backend-device to query various device related intormation.
1515          * This has the side effect that backend->device_name() will match
1516          * the device_name and  'change_device' will never be true.
1517          * so work around this by setting...
1518          */
1519         if (backend->use_separate_input_and_output_devices()) {
1520                 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1521                         queue_device_changed = true;
1522                 }
1523         } else {
1524                 if (device_name_in != backend->device_name()) {
1525                         queue_device_changed = true;
1526                 }
1527         }
1528
1529         //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1530         if (backend->use_separate_input_and_output_devices()) {
1531                 backend->set_input_device_name (device_name_in);
1532                 backend->set_output_device_name (device_name_out);
1533         } else {
1534                 backend->set_device_name(device_name_in);
1535         }
1536
1537         {
1538                 /* don't allow programmatic change to combos to cause a
1539                    recursive call to this method.
1540                  */
1541                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1542
1543                 set_samplerate_popdown_strings ();
1544                 set_buffersize_popdown_strings ();
1545                 set_nperiods_popdown_strings ();
1546
1547                 /* TODO set min + max channel counts here */
1548
1549                 manage_control_app_sensitivity ();
1550         }
1551
1552         /* pick up any saved state for this device */
1553
1554         if (!ignore_changes) {
1555                 maybe_display_saved_state ();
1556         }
1557 }
1558
1559 void
1560 EngineControl::input_device_changed ()
1561 {
1562         DEBUG_ECONTROL ("input_device_changed");
1563
1564         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1565         if (backend && backend->match_input_output_devices_or_none ()) {
1566                 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1567
1568                 if (get_output_device_name () != dev_none
1569                                 && get_input_device_name () != dev_none
1570                                 && get_input_device_name () != get_output_device_name ()) {
1571                         block_changed_signals ();
1572                         if (contains_value (output_device_combo, get_input_device_name ())) {
1573                                 output_device_combo.set_active_text (get_input_device_name ());
1574                         } else {
1575                                 assert (contains_value (output_device_combo, dev_none));
1576                                 output_device_combo.set_active_text (dev_none);
1577                         }
1578                         unblock_changed_signals ();
1579                 }
1580         }
1581         device_changed ();
1582 }
1583
1584 void
1585 EngineControl::output_device_changed ()
1586 {
1587         DEBUG_ECONTROL ("output_device_changed");
1588         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1589         if (backend && backend->match_input_output_devices_or_none ()) {
1590                 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1591
1592                 if (get_input_device_name () != dev_none
1593                                 && get_input_device_name () != dev_none
1594                                 && get_input_device_name () != get_output_device_name ()) {
1595                         block_changed_signals ();
1596                         if (contains_value (input_device_combo, get_output_device_name ())) {
1597                                 input_device_combo.set_active_text (get_output_device_name ());
1598                         } else {
1599                                 assert (contains_value (input_device_combo, dev_none));
1600                                 input_device_combo.set_active_text (dev_none);
1601                         }
1602                         unblock_changed_signals ();
1603                 }
1604         }
1605         device_changed ();
1606 }
1607
1608 string
1609 EngineControl::bufsize_as_string (uint32_t sz)
1610 {
1611         return string_compose (P_("%1 sample", "%1 samples", sz), sz);
1612 }
1613
1614 string
1615 EngineControl::nperiods_as_string (uint32_t np)
1616 {
1617         char buf[8];
1618         snprintf (buf, sizeof (buf), "%u", np);
1619         return buf;
1620 }
1621
1622
1623 void
1624 EngineControl::sample_rate_changed ()
1625 {
1626         DEBUG_ECONTROL ("sample_rate_changed");
1627         /* reset the strings for buffer size to show the correct msec value
1628            (reflecting the new sample rate).
1629          */
1630
1631         show_buffer_duration ();
1632
1633 }
1634
1635 void
1636 EngineControl::buffer_size_changed ()
1637 {
1638         DEBUG_ECONTROL ("buffer_size_changed");
1639         show_buffer_duration ();
1640 }
1641
1642 void
1643 EngineControl::nperiods_changed ()
1644 {
1645         DEBUG_ECONTROL ("nperiods_changed");
1646         show_buffer_duration ();
1647 }
1648
1649 void
1650 EngineControl::show_buffer_duration ()
1651 {
1652         DEBUG_ECONTROL ("show_buffer_duration");
1653         /* buffer sizes  - convert from just samples to samples + msecs for
1654          * the displayed string
1655          */
1656
1657         string bs_text = buffer_size_combo.get_active_text ();
1658         uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1659         uint32_t rate = get_rate();
1660
1661         /* Except for ALSA and Dummy backends, we don't know the number of periods
1662          * per cycle and settings.
1663          *
1664          * jack1 vs jack2 have different default latencies since jack2 start
1665          * in async-mode unless --sync is given which adds an extra cycle
1666          * of latency. The value is not known if jackd is started externally..
1667          *
1668          * So just display the period size, that's also what
1669          * ARDOUR_UI::update_sample_rate() does for the status bar.
1670          * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1671          * but still, that's the buffer period, not [round-trip] latency)
1672          */
1673         char buf[32];
1674         snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1675         buffer_size_duration_label.set_text (buf);
1676 }
1677
1678 void
1679 EngineControl::midi_option_changed ()
1680 {
1681         DEBUG_ECONTROL ("midi_option_changed");
1682         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1683         assert (backend);
1684
1685         backend->set_midi_option (get_midi_option());
1686
1687         vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1688
1689         //_midi_devices.clear(); // TODO merge with state-saved settings..
1690         _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1691         std::vector<MidiDeviceSettings> new_devices;
1692
1693         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1694                 MidiDeviceSettings mds = find_midi_device (i->name);
1695                 if (i->available && !mds) {
1696                         uint32_t input_latency = 0;
1697                         uint32_t output_latency = 0;
1698                         if (_can_set_midi_latencies) {
1699                                 input_latency = backend->systemic_midi_input_latency (i->name);
1700                                 output_latency = backend->systemic_midi_output_latency (i->name);
1701                         }
1702                         bool enabled = backend->midi_device_enabled (i->name);
1703                         MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1704                         new_devices.push_back (ptr);
1705                 } else if (i->available) {
1706                         new_devices.push_back (mds);
1707                 }
1708         }
1709         _midi_devices = new_devices;
1710
1711         if (_midi_devices.empty()) {
1712                 midi_devices_button.hide ();
1713         } else {
1714                 midi_devices_button.show ();
1715         }
1716 }
1717
1718 void
1719 EngineControl::parameter_changed ()
1720 {
1721 }
1722
1723 EngineControl::State
1724 EngineControl::get_matching_state (const string& backend)
1725 {
1726         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1727                 if ((*i)->backend == backend) {
1728                         return (*i);
1729                 }
1730         }
1731         return State();
1732 }
1733
1734 EngineControl::State
1735 EngineControl::get_matching_state (
1736                 const string& backend,
1737                 const string& driver,
1738                 const string& device)
1739 {
1740         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1741                 if ((*i)->backend == backend &&
1742                                 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1743                 {
1744                         return (*i);
1745                 }
1746         }
1747         return State();
1748 }
1749
1750 EngineControl::State
1751 EngineControl::get_matching_state (
1752                 const string& backend,
1753                 const string& driver,
1754                 const string& input_device,
1755                 const string& output_device)
1756 {
1757         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1758                 if ((*i)->backend == backend &&
1759                                 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1760                 {
1761                         return (*i);
1762                 }
1763         }
1764         return State();
1765 }
1766
1767 EngineControl::State
1768 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1769 {
1770         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1771
1772         if (backend) {
1773                 if (backend->use_separate_input_and_output_devices ()) {
1774                         return get_matching_state (backend_combo.get_active_text(),
1775                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1776                                         input_device_combo.get_active_text(),
1777                                         output_device_combo.get_active_text());
1778                 } else {
1779                         return get_matching_state (backend_combo.get_active_text(),
1780                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1781                                         device_combo.get_active_text());
1782                 }
1783         }
1784
1785         return get_matching_state (backend_combo.get_active_text(),
1786                         string(),
1787                         device_combo.get_active_text());
1788 }
1789
1790 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1791                                        const EngineControl::State& state2)
1792 {
1793         if (state1->backend == state2->backend &&
1794                         state1->driver == state2->driver &&
1795                         state1->device == state2->device &&
1796                         state1->input_device == state2->input_device &&
1797                         state1->output_device == state2->output_device) {
1798                 return true;
1799         }
1800         return false;
1801 }
1802
1803 bool
1804 EngineControl::state_sort_cmp (const State &a, const State &b) {
1805         if (a->active) {
1806                 return true;
1807         }
1808         else if (b->active) {
1809                 return false;
1810         }
1811         else {
1812                 return a->lru < b->lru;
1813         }
1814 }
1815
1816 EngineControl::State
1817 EngineControl::save_state ()
1818 {
1819         State state;
1820
1821         if (!_have_control) {
1822                 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1823                 if (state) {
1824                         state->lru = time (NULL) ;
1825                         return state;
1826                 }
1827                 state.reset(new StateStruct);
1828                 state->backend = get_backend ();
1829         } else {
1830                 state.reset(new StateStruct);
1831                 store_state (state);
1832         }
1833
1834         for (StateList::iterator i = states.begin(); i != states.end();) {
1835                 if (equivalent_states (*i, state)) {
1836                         i =  states.erase(i);
1837                 } else {
1838                         ++i;
1839                 }
1840         }
1841
1842         states.push_back (state);
1843
1844         states.sort (state_sort_cmp);
1845
1846         return state;
1847 }
1848
1849 void
1850 EngineControl::store_state (State state)
1851 {
1852         state->backend = get_backend ();
1853         state->driver = get_driver ();
1854         state->device = get_device_name ();
1855         state->input_device = get_input_device_name ();
1856         state->output_device = get_output_device_name ();
1857         state->sample_rate = get_rate ();
1858         state->buffer_size = get_buffer_size ();
1859         state->n_periods = get_nperiods ();
1860         state->input_latency = get_input_latency ();
1861         state->output_latency = get_output_latency ();
1862         state->input_channels = get_input_channels ();
1863         state->output_channels = get_output_channels ();
1864         state->midi_option = get_midi_option ();
1865         state->midi_devices = _midi_devices;
1866         state->use_buffered_io = get_use_buffered_io ();
1867         state->lru = time (NULL) ;
1868 }
1869
1870 void
1871 EngineControl::maybe_display_saved_state ()
1872 {
1873         if (!_have_control) {
1874                 return;
1875         }
1876
1877         State state = get_saved_state_for_currently_displayed_backend_and_device ();
1878
1879         if (state) {
1880                 DEBUG_ECONTROL ("Restoring saved state");
1881                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1882
1883                 if (!_desired_sample_rate) {
1884                         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1885                 }
1886                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1887
1888                 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1889                 /* call this explicitly because we're ignoring changes to
1890                    the controls at this point.
1891                  */
1892                 show_buffer_duration ();
1893                 input_latency.set_value (state->input_latency);
1894                 output_latency.set_value (state->output_latency);
1895
1896                 use_buffered_io_button.set_active (state->use_buffered_io);
1897
1898                 if (!state->midi_option.empty()) {
1899                         midi_option_combo.set_active_text (state->midi_option);
1900                         _midi_devices = state->midi_devices;
1901                 }
1902         } else {
1903                 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1904         }
1905 }
1906
1907 XMLNode&
1908 EngineControl::get_state ()
1909 {
1910         LocaleGuard lg;
1911
1912         XMLNode* root = new XMLNode ("AudioMIDISetup");
1913         std::string path;
1914
1915         if (!states.empty()) {
1916                 XMLNode* state_nodes = new XMLNode ("EngineStates");
1917
1918                 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1919
1920                         XMLNode* node = new XMLNode ("State");
1921
1922                         node->add_property ("backend", (*i)->backend);
1923                         node->add_property ("driver", (*i)->driver);
1924                         node->add_property ("device", (*i)->device);
1925                         node->add_property ("input-device", (*i)->input_device);
1926                         node->add_property ("output-device", (*i)->output_device);
1927                         node->add_property ("sample-rate", (*i)->sample_rate);
1928                         node->add_property ("buffer-size", (*i)->buffer_size);
1929                         node->add_property ("n-periods", (*i)->n_periods);
1930                         node->add_property ("input-latency", (*i)->input_latency);
1931                         node->add_property ("output-latency", (*i)->output_latency);
1932                         node->add_property ("input-channels", (*i)->input_channels);
1933                         node->add_property ("output-channels", (*i)->output_channels);
1934                         node->add_property ("active", (*i)->active ? "yes" : "no");
1935                         node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
1936                         node->add_property ("midi-option", (*i)->midi_option);
1937                         node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1938
1939                         XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1940                         for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1941                                 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1942                                 midi_device_stuff->add_property (X_("name"), (*p)->name);
1943                                 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1944                                 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1945                                 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1946                                 midi_devices->add_child_nocopy (*midi_device_stuff);
1947                         }
1948                         node->add_child_nocopy (*midi_devices);
1949
1950                         state_nodes->add_child_nocopy (*node);
1951                 }
1952
1953                 root->add_child_nocopy (*state_nodes);
1954         }
1955
1956         return *root;
1957 }
1958
1959 void
1960 EngineControl::set_default_state ()
1961 {
1962         vector<string> backend_names;
1963         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1964
1965         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1966                 backend_names.push_back ((*b)->name);
1967         }
1968         backend_combo.set_active_text (backend_names.front());
1969
1970         // We could set default backends per platform etc here
1971
1972         backend_changed ();
1973 }
1974
1975 bool
1976 EngineControl::set_state (const XMLNode& root)
1977 {
1978         XMLNodeList          clist, cclist;
1979         XMLNodeConstIterator citer, cciter;
1980         XMLNode const * child;
1981         XMLNode const * grandchild;
1982         XMLProperty const * prop = NULL;
1983
1984         if (root.name() != "AudioMIDISetup") {
1985                 return false;
1986         }
1987
1988         clist = root.children();
1989
1990         states.clear ();
1991
1992         for (citer = clist.begin(); citer != clist.end(); ++citer) {
1993
1994                 child = *citer;
1995
1996                 if (child->name() != "EngineStates") {
1997                         continue;
1998                 }
1999
2000                 cclist = child->children();
2001
2002                 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2003                         State state (new StateStruct);
2004
2005                         grandchild = *cciter;
2006
2007                         if (grandchild->name() != "State") {
2008                                 continue;
2009                         }
2010
2011                         if ((prop = grandchild->property ("backend")) == 0) {
2012                                 continue;
2013                         }
2014                         state->backend = prop->value ();
2015
2016                         if ((prop = grandchild->property ("driver")) == 0) {
2017                                 continue;
2018                         }
2019                         state->driver = prop->value ();
2020
2021                         if ((prop = grandchild->property ("device")) == 0) {
2022                                 continue;
2023                         }
2024                         state->device = prop->value ();
2025
2026                         if ((prop = grandchild->property ("input-device")) == 0) {
2027                                 continue;
2028                         }
2029                         state->input_device = prop->value ();
2030
2031                         if ((prop = grandchild->property ("output-device")) == 0) {
2032                                 continue;
2033                         }
2034                         state->output_device = prop->value ();
2035
2036                         if ((prop = grandchild->property ("sample-rate")) == 0) {
2037                                 continue;
2038                         }
2039                         state->sample_rate = atof (prop->value ());
2040
2041                         if ((prop = grandchild->property ("buffer-size")) == 0) {
2042                                 continue;
2043                         }
2044                         state->buffer_size = atoi (prop->value ());
2045
2046                         if ((prop = grandchild->property ("n-periods")) == 0) {
2047                                 // optional (new value in 4.5)
2048                                 state->n_periods = 0;
2049                         } else {
2050                                 state->n_periods = atoi (prop->value ());
2051                         }
2052
2053                         if ((prop = grandchild->property ("input-latency")) == 0) {
2054                                 continue;
2055                         }
2056                         state->input_latency = atoi (prop->value ());
2057
2058                         if ((prop = grandchild->property ("output-latency")) == 0) {
2059                                 continue;
2060                         }
2061                         state->output_latency = atoi (prop->value ());
2062
2063                         if ((prop = grandchild->property ("input-channels")) == 0) {
2064                                 continue;
2065                         }
2066                         state->input_channels = atoi (prop->value ());
2067
2068                         if ((prop = grandchild->property ("output-channels")) == 0) {
2069                                 continue;
2070                         }
2071                         state->output_channels = atoi (prop->value ());
2072
2073                         if ((prop = grandchild->property ("active")) == 0) {
2074                                 continue;
2075                         }
2076                         state->active = string_is_affirmative (prop->value ());
2077
2078                         if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2079                                 continue;
2080                         }
2081                         state->use_buffered_io = string_is_affirmative (prop->value ());
2082
2083                         if ((prop = grandchild->property ("midi-option")) == 0) {
2084                                 continue;
2085                         }
2086                         state->midi_option = prop->value ();
2087
2088                         state->midi_devices.clear();
2089                         XMLNode* midinode;
2090                         if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2091                                 const XMLNodeList mnc = midinode->children();
2092                                 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2093                                         if ((*n)->property (X_("name")) == 0
2094                                                         || (*n)->property (X_("enabled")) == 0
2095                                                         || (*n)->property (X_("input-latency")) == 0
2096                                                         || (*n)->property (X_("output-latency")) == 0
2097                                                  ) {
2098                                                 continue;
2099                                         }
2100
2101                                         MidiDeviceSettings ptr (new MidiDeviceSetting(
2102                                                                 (*n)->property (X_("name"))->value (),
2103                                                                 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2104                                                                 atoi ((*n)->property (X_("input-latency"))->value ()),
2105                                                                 atoi ((*n)->property (X_("output-latency"))->value ())
2106                                                                 ));
2107                                         state->midi_devices.push_back (ptr);
2108                                 }
2109                         }
2110
2111                         if ((prop = grandchild->property ("lru"))) {
2112                                 state->lru = atoi (prop->value ());
2113                         }
2114
2115 #if 1
2116                         /* remove accumulated duplicates (due to bug in ealier version)
2117                          * this can be removed again before release
2118                          */
2119                         for (StateList::iterator i = states.begin(); i != states.end();) {
2120                                 if ((*i)->backend == state->backend &&
2121                                                 (*i)->driver == state->driver &&
2122                                                 (*i)->device == state->device) {
2123                                         i =  states.erase(i);
2124                                 } else {
2125                                         ++i;
2126                                 }
2127                         }
2128 #endif
2129
2130                         states.push_back (state);
2131                 }
2132         }
2133
2134         /* now see if there was an active state and switch the setup to it */
2135
2136         // purge states of backend that are not available in this built
2137         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2138         vector<std::string> backend_names;
2139
2140         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2141                 backend_names.push_back((*i)->name);
2142         }
2143         for (StateList::iterator i = states.begin(); i != states.end();) {
2144                 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2145                         i = states.erase(i);
2146                 } else {
2147                         ++i;
2148                 }
2149         }
2150
2151         states.sort (state_sort_cmp);
2152
2153         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2154
2155                 if ((*i)->active) {
2156                         return set_current_state (*i);
2157                 }
2158         }
2159         return false;
2160 }
2161
2162 bool
2163 EngineControl::set_current_state (const State& state)
2164 {
2165         DEBUG_ECONTROL ("set_current_state");
2166
2167         boost::shared_ptr<ARDOUR::AudioBackend> backend;
2168
2169         if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2170                   state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2171                 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2172                 // this shouldn't happen as the invalid backend names should have been
2173                 // removed from the list of states.
2174                 return false;
2175         }
2176
2177         // now reflect the change in the backend in the GUI so backend_changed will
2178         // do the right thing
2179         backend_combo.set_active_text (state->backend);
2180
2181         if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2182                 backend_changed ();
2183                 // we don't have control don't restore state
2184                 return true;
2185         }
2186
2187
2188         if (!state->driver.empty ()) {
2189                 if (!backend->requires_driver_selection ()) {
2190                         DEBUG_ECONTROL ("Backend should require driver selection");
2191                         // A backend has changed from having driver selection to not having
2192                         // it or someone has been manually editing a config file and messed
2193                         // it up
2194                         return false;
2195                 }
2196
2197                 if (backend->set_driver (state->driver) != 0) {
2198                         DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2199                         // Driver names for a backend have changed and the name in the
2200                         // config file is now invalid or support for driver is no longer
2201                         // included in the backend
2202                         return false;
2203                 }
2204                 // no need to set the driver_combo as backend_changed will use
2205                 // backend->driver_name to set the active driver
2206         }
2207
2208         if (!state->device.empty ()) {
2209                 if (backend->set_device_name (state->device) != 0) {
2210                         DEBUG_ECONTROL (
2211                             string_compose ("Unable to set device name %1", state->device));
2212                         // device is no longer available on the system
2213                         return false;
2214                 }
2215                 // no need to set active device as it will be picked up in
2216                 // via backend_changed ()/set_device_popdown_strings
2217
2218         } else {
2219                 // backend supports separate input/output devices
2220                 if (backend->set_input_device_name (state->input_device) != 0) {
2221                         DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2222                                                         state->input_device));
2223                         // input device is no longer available on the system
2224                         return false;
2225                 }
2226
2227                 if (backend->set_output_device_name (state->output_device) != 0) {
2228                         DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2229                                                         state->input_device));
2230                         // output device is no longer available on the system
2231                         return false;
2232                 }
2233                 // no need to set active devices as it will be picked up in via
2234                 // backend_changed ()/set_*_device_popdown_strings
2235         }
2236
2237         backend_changed ();
2238
2239         // Now restore the state of the rest of the controls
2240
2241         // We don't use a SignalBlocker as set_current_state is currently only
2242         // called from set_state before any signals are connected. If at some point
2243         // a more general named state mechanism is implemented and
2244         // set_current_state is called while signals are connected then a
2245         // SignalBlocker will need to be instantiated before setting these.
2246
2247         device_combo.set_active_text (state->device);
2248         input_device_combo.set_active_text (state->input_device);
2249         output_device_combo.set_active_text (state->output_device);
2250         if (!_desired_sample_rate) {
2251                 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2252         }
2253         set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2254         set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2255         input_latency.set_value (state->input_latency);
2256         output_latency.set_value (state->output_latency);
2257         midi_option_combo.set_active_text (state->midi_option);
2258         use_buffered_io_button.set_active (state->use_buffered_io);
2259         return true;
2260 }
2261
2262 int
2263 EngineControl::push_state_to_backend (bool start)
2264 {
2265         DEBUG_ECONTROL ("push_state_to_backend");
2266         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2267         PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2268
2269         if (!backend) {
2270                 return 0;
2271         }
2272
2273         /* figure out what is going to change */
2274
2275         bool restart_required = false;
2276         bool was_running = ARDOUR::AudioEngine::instance()->running();
2277         bool change_driver = false;
2278         bool change_device = false;
2279         bool change_rate = false;
2280         bool change_bufsize = false;
2281         bool change_nperiods = false;
2282         bool change_latency = false;
2283         bool change_channels = false;
2284         bool change_midi = false;
2285         bool change_buffered_io = false;
2286
2287         uint32_t ochan = get_output_channels ();
2288         uint32_t ichan = get_input_channels ();
2289
2290         if (_have_control) {
2291
2292                 if (started_at_least_once) {
2293
2294                         /* we can control the backend */
2295
2296                         if (backend->requires_driver_selection()) {
2297                                 if (get_driver() != backend->driver_name()) {
2298                                         change_driver = true;
2299                                 }
2300                         }
2301
2302                         if (backend->use_separate_input_and_output_devices()) {
2303                                 if (get_input_device_name() != backend->input_device_name()) {
2304                                         change_device = true;
2305                                 }
2306                                 if (get_output_device_name() != backend->output_device_name()) {
2307                                         change_device = true;
2308                                 }
2309                         } else {
2310                                 if (get_device_name() != backend->device_name()) {
2311                                         change_device = true;
2312                                 }
2313                         }
2314
2315                         if (queue_device_changed) {
2316                                 change_device = true;
2317                         }
2318
2319                         if (get_rate() != backend->sample_rate()) {
2320                                 change_rate = true;
2321                         }
2322
2323                         if (get_buffer_size() != backend->buffer_size()) {
2324                                 change_bufsize = true;
2325                         }
2326
2327                         if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2328                                         && get_nperiods() != backend->period_size()) {
2329                                 change_nperiods = true;
2330                         }
2331
2332                         if (get_midi_option() != backend->midi_option()) {
2333                                 change_midi = true;
2334                         }
2335
2336                         if (backend->can_use_buffered_io()) {
2337                                 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2338                                         change_buffered_io = true;
2339                                 }
2340                         }
2341
2342                         /* zero-requested channels means "all available" */
2343
2344                         if (ichan == 0) {
2345                                 ichan = backend->input_channels();
2346                         }
2347
2348                         if (ochan == 0) {
2349                                 ochan = backend->output_channels();
2350                         }
2351
2352                         if (ichan != backend->input_channels()) {
2353                                 change_channels = true;
2354                         }
2355
2356                         if (ochan != backend->output_channels()) {
2357                                 change_channels = true;
2358                         }
2359
2360                         if (get_input_latency() != backend->systemic_input_latency() ||
2361                                         get_output_latency() != backend->systemic_output_latency()) {
2362                                 change_latency = true;
2363                         }
2364                 } else {
2365                         /* backend never started, so we have to force a group
2366                            of settings.
2367                          */
2368                         change_device = true;
2369                         if (backend->requires_driver_selection()) {
2370                                 change_driver = true;
2371                         }
2372                         change_rate = true;
2373                         change_bufsize = true;
2374                         change_channels = true;
2375                         change_latency = true;
2376                         change_midi = true;
2377                         change_buffered_io = backend->can_use_buffered_io();
2378                         change_channels = true;
2379                         change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2380                 }
2381
2382         } else {
2383
2384                 /* we have no control over the backend, meaning that we can
2385                  * only possibly change sample rate and buffer size.
2386                  */
2387
2388
2389                 if (get_rate() != backend->sample_rate()) {
2390                         change_bufsize = true;
2391                 }
2392
2393                 if (get_buffer_size() != backend->buffer_size()) {
2394                         change_bufsize = true;
2395                 }
2396         }
2397
2398         queue_device_changed = false;
2399
2400         if (!_have_control) {
2401
2402                 /* We do not have control over the backend, so the best we can
2403                  * do is try to change the sample rate and/or bufsize and get
2404                  * out of here.
2405                  */
2406
2407                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2408                         return 1;
2409                 }
2410
2411                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2412                         return 1;
2413                 }
2414
2415                 if (change_rate) {
2416                         backend->set_sample_rate (get_rate());
2417                 }
2418
2419                 if (change_bufsize) {
2420                         backend->set_buffer_size (get_buffer_size());
2421                 }
2422
2423                 if (start) {
2424                         if (ARDOUR::AudioEngine::instance()->start ()) {
2425                                 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2426                                 return -1;
2427                         }
2428                 }
2429
2430                 post_push ();
2431
2432                 return 0;
2433         }
2434
2435         /* determine if we need to stop the backend before changing parameters */
2436
2437         if (change_driver || change_device || change_channels || change_nperiods ||
2438                         (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2439                         (change_rate && !backend->can_change_sample_rate_when_running()) ||
2440                         change_midi || change_buffered_io ||
2441                         (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2442                 restart_required = true;
2443         } else {
2444                 restart_required = false;
2445         }
2446
2447
2448         if (was_running) {
2449                 if (restart_required) {
2450                         if (ARDOUR::AudioEngine::instance()->stop()) {
2451                                 return -1;
2452                         }
2453                 }
2454         }
2455
2456         if (change_driver && backend->set_driver (get_driver())) {
2457                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2458                 return -1;
2459         }
2460         if (backend->use_separate_input_and_output_devices()) {
2461                 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2462                         error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2463                         return -1;
2464                 }
2465                 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2466                         error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2467                         return -1;
2468                 }
2469         } else {
2470                 if (change_device && backend->set_device_name (get_device_name())) {
2471                         error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2472                         return -1;
2473                 }
2474         }
2475         if (change_rate && backend->set_sample_rate (get_rate())) {
2476                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2477                 return -1;
2478         }
2479         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2480                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2481                 return -1;
2482         }
2483         if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2484                 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2485                 return -1;
2486         }
2487
2488         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2489                 if (backend->set_input_channels (get_input_channels())) {
2490                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2491                         return -1;
2492                 }
2493                 if (backend->set_output_channels (get_output_channels())) {
2494                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2495                         return -1;
2496                 }
2497         }
2498         if (change_latency) {
2499                 if (backend->set_systemic_input_latency (get_input_latency())) {
2500                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2501                         return -1;
2502                 }
2503                 if (backend->set_systemic_output_latency (get_output_latency())) {
2504                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2505                         return -1;
2506                 }
2507         }
2508
2509         if (change_midi) {
2510                 backend->set_midi_option (get_midi_option());
2511         }
2512
2513         if (change_buffered_io) {
2514                 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2515         }
2516
2517         if (1 /* TODO */) {
2518                 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2519                         if (_measure_midi) {
2520                                 if (*p == _measure_midi) {
2521                                         backend->set_midi_device_enabled ((*p)->name, true);
2522                                 } else {
2523                                         backend->set_midi_device_enabled ((*p)->name, false);
2524                                 }
2525                                 if (backend->can_change_systemic_latency_when_running ()) {
2526                                         backend->set_systemic_midi_input_latency ((*p)->name, 0);
2527                                         backend->set_systemic_midi_output_latency ((*p)->name, 0);
2528                                 }
2529                                 continue;
2530                         }
2531                         backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2532                         if (backend->can_set_systemic_midi_latencies()) {
2533                                 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2534                                 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2535                         }
2536                 }
2537         }
2538
2539         if (start || (was_running && restart_required)) {
2540                 if (ARDOUR::AudioEngine::instance()->start()) {
2541                         return -1;
2542                 }
2543         }
2544
2545         post_push ();
2546
2547         return 0;
2548 }
2549
2550 void
2551 EngineControl::post_push ()
2552 {
2553         /* get a pointer to the current state object, creating one if
2554          * necessary
2555          */
2556
2557         State state = get_saved_state_for_currently_displayed_backend_and_device ();
2558
2559         if (!state) {
2560                 state = save_state ();
2561                 assert (state);
2562         } else {
2563                 store_state(state);
2564         }
2565
2566         states.sort (state_sort_cmp);
2567
2568         /* all off */
2569
2570         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2571                 (*i)->active = false;
2572         }
2573
2574         /* mark this one active (to be used next time the dialog is
2575          * shown)
2576          */
2577
2578         state->active = true;
2579
2580         if (_have_control) { // XXX
2581                 manage_control_app_sensitivity ();
2582         }
2583
2584         /* schedule a redisplay of MIDI ports */
2585         //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2586 }
2587
2588
2589 float
2590 EngineControl::get_rate () const
2591 {
2592         float r = atof (sample_rate_combo.get_active_text ());
2593         /* the string may have been translated with an abbreviation for
2594          * thousands, so use a crude heuristic to fix this.
2595          */
2596         if (r < 1000.0) {
2597                 r *= 1000.0;
2598         }
2599         return r;
2600 }
2601
2602
2603 uint32_t
2604 EngineControl::get_buffer_size () const
2605 {
2606         string txt = buffer_size_combo.get_active_text ();
2607         uint32_t samples;
2608
2609         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2610                 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2611                 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2612                 throw exception ();
2613         }
2614
2615         return samples;
2616 }
2617
2618 uint32_t
2619 EngineControl::get_nperiods () const
2620 {
2621         string txt = nperiods_combo.get_active_text ();
2622         return atoi (txt.c_str());
2623 }
2624
2625 string
2626 EngineControl::get_midi_option () const
2627 {
2628         return midi_option_combo.get_active_text();
2629 }
2630
2631 bool
2632 EngineControl::get_use_buffered_io () const
2633 {
2634         return use_buffered_io_button.get_active();
2635 }
2636
2637 uint32_t
2638 EngineControl::get_input_channels() const
2639 {
2640         if (ARDOUR::Profile->get_mixbus()) {
2641                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2642                 if (!backend) return 0;
2643                 return backend->input_channels();
2644         }
2645         return (uint32_t) input_channels_adjustment.get_value();
2646 }
2647
2648 uint32_t
2649 EngineControl::get_output_channels() const
2650 {
2651         if (ARDOUR::Profile->get_mixbus()) {
2652                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2653                 if (!backend) return 0;
2654                 return backend->input_channels();
2655         }
2656         return (uint32_t) output_channels_adjustment.get_value();
2657 }
2658
2659 uint32_t
2660 EngineControl::get_input_latency() const
2661 {
2662         return (uint32_t) input_latency_adjustment.get_value();
2663 }
2664
2665 uint32_t
2666 EngineControl::get_output_latency() const
2667 {
2668         return (uint32_t) output_latency_adjustment.get_value();
2669 }
2670
2671 string
2672 EngineControl::get_backend () const
2673 {
2674         return backend_combo.get_active_text ();
2675 }
2676
2677 string
2678 EngineControl::get_driver () const
2679 {
2680         if (driver_combo.get_parent()) {
2681                 return driver_combo.get_active_text ();
2682         } else {
2683                 return "";
2684         }
2685 }
2686
2687 string
2688 EngineControl::get_device_name () const
2689 {
2690         return device_combo.get_active_text ();
2691 }
2692
2693 string
2694 EngineControl::get_input_device_name () const
2695 {
2696         return input_device_combo.get_active_text ();
2697 }
2698
2699 string
2700 EngineControl::get_output_device_name () const
2701 {
2702         return output_device_combo.get_active_text ();
2703 }
2704
2705 void
2706 EngineControl::control_app_button_clicked ()
2707 {
2708         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2709
2710         if (!backend) {
2711                 return;
2712         }
2713
2714         backend->launch_control_app ();
2715 }
2716
2717 void
2718 EngineControl::start_stop_button_clicked ()
2719 {
2720         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2721
2722         if (!backend) {
2723                 return;
2724         }
2725
2726         if (ARDOUR::AudioEngine::instance()->running()) {
2727                 ARDOUR::AudioEngine::instance()->stop ();
2728         } else {
2729                 if (!ARDOUR_UI::instance()->session_loaded) {
2730                         hide ();
2731                 }
2732                 start_engine ();
2733                 if (!ARDOUR_UI::instance()->session_loaded) {
2734                         ArdourDialog::on_response (RESPONSE_OK);
2735                         if (Splash::instance()) {
2736                                 Splash::instance()->pop_front ();
2737                         }
2738                 }
2739         }
2740 }
2741
2742 void
2743 EngineControl::update_devices_button_clicked ()
2744 {
2745         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2746
2747         if (!backend) {
2748                 return;
2749         }
2750
2751         if (backend->update_devices()) {
2752                 device_list_changed ();
2753         }
2754 }
2755
2756 void
2757 EngineControl::use_buffered_io_button_clicked ()
2758 {
2759         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2760
2761         if (!backend) {
2762                 return;
2763         }
2764
2765         bool set_buffered_io = !use_buffered_io_button.get_active();
2766         use_buffered_io_button.set_active (set_buffered_io);
2767         backend->set_use_buffered_io (set_buffered_io);
2768 }
2769
2770 void
2771 EngineControl::manage_control_app_sensitivity ()
2772 {
2773         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2774
2775         if (!backend) {
2776                 return;
2777         }
2778
2779         string appname = backend->control_app_name();
2780
2781         if (appname.empty()) {
2782                 control_app_button.set_sensitive (false);
2783         } else {
2784                 control_app_button.set_sensitive (true);
2785         }
2786 }
2787
2788 void
2789 EngineControl::set_desired_sample_rate (uint32_t sr)
2790 {
2791         _desired_sample_rate = sr;
2792         if (ARDOUR::AudioEngine::instance ()->running ()
2793                         && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2794                 stop_engine ();
2795         }
2796         device_changed ();
2797 }
2798
2799 void
2800 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2801 {
2802         if (page_num == 0) {
2803                 _measure_midi.reset();
2804                 update_sensitivity ();
2805         }
2806
2807         if (page_num == midi_tab) {
2808                 /* MIDI tab */
2809                 refresh_midi_display ();
2810         }
2811
2812         if (page_num == latency_tab) {
2813                 /* latency tab */
2814
2815                 if (ARDOUR::AudioEngine::instance()->running()) {
2816                         stop_engine (true);
2817                 }
2818
2819                 {
2820                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2821
2822                         /* save any existing latency values */
2823
2824                         uint32_t il = (uint32_t) input_latency.get_value ();
2825                         uint32_t ol = (uint32_t) input_latency.get_value ();
2826
2827                         /* reset to zero so that our new test instance
2828                            will be clean of any existing latency measures.
2829
2830                            NB. this should really be done by the backend
2831                            when stated for latency measurement.
2832                         */
2833
2834                         input_latency.set_value (0);
2835                         output_latency.set_value (0);
2836
2837                         push_state_to_backend (false);
2838
2839                         /* reset control */
2840
2841                         input_latency.set_value (il);
2842                         output_latency.set_value (ol);
2843
2844                 }
2845                 // This should be done in push_state_to_backend()
2846                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2847                         disable_latency_tab ();
2848                 }
2849
2850                 enable_latency_tab ();
2851
2852         } else {
2853                 if (lm_running) {
2854                         end_latency_detection ();
2855                         ARDOUR::AudioEngine::instance()->stop_latency_detection();
2856                 }
2857         }
2858 }
2859
2860 /* latency measurement */
2861
2862 bool
2863 EngineControl::check_audio_latency_measurement ()
2864 {
2865         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2866
2867         if (mtdm->resolve () < 0) {
2868                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2869                 return true;
2870         }
2871
2872         if (mtdm->get_peak () > 0.707f) {
2873                 // get_peak() resets the peak-hold in the detector.
2874                 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2875                 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2876                 return true;
2877         }
2878
2879         if (mtdm->err () > 0.3) {
2880                 mtdm->invert ();
2881                 mtdm->resolve ();
2882         }
2883
2884         char buf[256];
2885         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2886
2887         if (sample_rate == 0) {
2888                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2889                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2890                 return false;
2891         }
2892
2893         int frames_total = mtdm->del();
2894         int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2895
2896         snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2897                         _("Detected roundtrip latency: "),
2898                         frames_total, frames_total * 1000.0f/sample_rate,
2899                         _("Systemic latency: "),
2900                         extra, extra * 1000.0f/sample_rate);
2901
2902         bool solid = true;
2903
2904         if (mtdm->err () > 0.2) {
2905                 strcat (buf, " ");
2906                 strcat (buf, _("(signal detection error)"));
2907                 solid = false;
2908         }
2909
2910         if (mtdm->inv ()) {
2911                 strcat (buf, " ");
2912                 strcat (buf, _("(inverted - bad wiring)"));
2913                 solid = false;
2914         }
2915
2916         lm_results.set_markup (string_compose (results_markup, buf));
2917
2918         if (solid) {
2919                 have_lm_results = true;
2920                 end_latency_detection ();
2921                 lm_use_button.set_sensitive (true);
2922                 return false;
2923         }
2924
2925         return true;
2926 }
2927
2928 bool
2929 EngineControl::check_midi_latency_measurement ()
2930 {
2931         ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2932
2933         if (!mididm->have_signal () || mididm->latency () == 0) {
2934                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2935                 return true;
2936         }
2937
2938         char buf[256];
2939         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2940
2941         if (sample_rate == 0) {
2942                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2943                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2944                 return false;
2945         }
2946
2947         ARDOUR::framecnt_t frames_total = mididm->latency();
2948         ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2949         snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2950                         _("Detected roundtrip latency: "),
2951                         frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2952                         _("Systemic latency: "),
2953                         extra, extra * 1000.0f / sample_rate);
2954
2955         bool solid = true;
2956
2957         if (!mididm->ok ()) {
2958                 strcat (buf, " ");
2959                 strcat (buf, _("(averaging)"));
2960                 solid = false;
2961         }
2962
2963         if (mididm->deviation () > 50.0) {
2964                 strcat (buf, " ");
2965                 strcat (buf, _("(too large jitter)"));
2966                 solid = false;
2967         } else if (mididm->deviation () > 10.0) {
2968                 strcat (buf, " ");
2969                 strcat (buf, _("(large jitter)"));
2970         }
2971
2972         if (solid) {
2973                 have_lm_results = true;
2974                 end_latency_detection ();
2975                 lm_use_button.set_sensitive (true);
2976                 lm_results.set_markup (string_compose (results_markup, buf));
2977                 return false;
2978         } else if (mididm->processed () > 400) {
2979                 have_lm_results = false;
2980                 end_latency_detection ();
2981                 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2982                 return false;
2983         }
2984
2985         lm_results.set_markup (string_compose (results_markup, buf));
2986
2987         return true;
2988 }
2989
2990 void
2991 EngineControl::start_latency_detection ()
2992 {
2993         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2994         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2995
2996         if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2997                 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2998                 if (_measure_midi) {
2999                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
3000                 } else {
3001                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
3002                 }
3003                 lm_measure_label.set_text (_("Cancel"));
3004                 have_lm_results = false;
3005                 lm_use_button.set_sensitive (false);
3006                 lm_input_channel_combo.set_sensitive (false);
3007                 lm_output_channel_combo.set_sensitive (false);
3008                 lm_running = true;
3009         }
3010 }
3011
3012 void
3013 EngineControl::end_latency_detection ()
3014 {
3015         latency_timeout.disconnect ();
3016         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3017         lm_measure_label.set_text (_("Measure"));
3018         if (!have_lm_results) {
3019                 lm_use_button.set_sensitive (false);
3020         }
3021         lm_input_channel_combo.set_sensitive (true);
3022         lm_output_channel_combo.set_sensitive (true);
3023         lm_running = false;
3024 }
3025
3026 void
3027 EngineControl::latency_button_clicked ()
3028 {
3029         if (!lm_running) {
3030                 start_latency_detection ();
3031         } else {
3032                 end_latency_detection ();
3033         }
3034 }
3035
3036 void
3037 EngineControl::latency_back_button_clicked ()
3038 {
3039         ARDOUR::AudioEngine::instance()->stop(true);
3040         notebook.set_current_page(0);
3041 }
3042
3043 void
3044 EngineControl::use_latency_button_clicked ()
3045 {
3046         if (_measure_midi) {
3047                 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3048                 if (!mididm) {
3049                         return;
3050                 }
3051                 ARDOUR::framecnt_t frames_total = mididm->latency();
3052                 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3053                 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3054                 _measure_midi->input_latency = one_way;
3055                 _measure_midi->output_latency = one_way;
3056                 notebook.set_current_page (midi_tab);
3057         } else {
3058                 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3059
3060                 if (!mtdm) {
3061                         return;
3062                 }
3063
3064                 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3065                 one_way = std::max (0., one_way);
3066
3067                 input_latency_adjustment.set_value (one_way);
3068                 output_latency_adjustment.set_value (one_way);
3069
3070                 /* back to settings page */
3071                 notebook.set_current_page (0);
3072         }
3073 }
3074
3075 bool
3076 EngineControl::on_delete_event (GdkEventAny* ev)
3077 {
3078         if (notebook.get_current_page() == 2) {
3079                 /* currently on latency tab - be sure to clean up */
3080                 end_latency_detection ();
3081         }
3082         return ArdourDialog::on_delete_event (ev);
3083 }
3084
3085 void
3086 EngineControl::engine_running ()
3087 {
3088         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3089         assert (backend);
3090
3091         set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3092         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3093
3094         if (backend->can_set_period_size ()) {
3095                 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3096         }
3097
3098         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3099         connect_disconnect_button.show();
3100
3101         started_at_least_once = true;
3102         if (_have_control) {
3103                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3104         } else {
3105                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3106         }
3107         update_sensitivity();
3108 }
3109
3110 void
3111 EngineControl::engine_stopped ()
3112 {
3113         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3114         assert (backend);
3115
3116         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3117         connect_disconnect_button.show();
3118
3119         if (_have_control) {
3120                 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3121         } else {
3122                 engine_status.set_markup(X_(""));
3123         }
3124
3125         update_sensitivity();
3126 }
3127
3128 void
3129 EngineControl::device_list_changed ()
3130 {
3131         if (ignore_device_changes) {
3132                 return;
3133         }
3134         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3135         list_devices ();
3136         midi_option_changed();
3137 }
3138
3139 void
3140 EngineControl::connect_disconnect_click()
3141 {
3142         if (ARDOUR::AudioEngine::instance()->running()) {
3143                 stop_engine ();
3144         } else {
3145                 if (!ARDOUR_UI::instance()->session_loaded) {
3146                         hide ();
3147                 }
3148                 start_engine ();
3149                 if (!ARDOUR_UI::instance()->session_loaded) {
3150                         ArdourDialog::on_response (RESPONSE_OK);
3151                         if (Splash::instance()) {
3152                                 Splash::instance()->pop_front ();
3153                         }
3154                 }
3155         }
3156 }
3157
3158 void
3159 EngineControl::calibrate_audio_latency ()
3160 {
3161         _measure_midi.reset ();
3162         have_lm_results = false;
3163         lm_use_button.set_sensitive (false);
3164         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3165         notebook.set_current_page (latency_tab);
3166 }
3167
3168 void
3169 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3170 {
3171         _measure_midi = s;
3172         have_lm_results = false;
3173         lm_use_button.set_sensitive (false);
3174         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3175         notebook.set_current_page (latency_tab);
3176 }
3177
3178 void
3179 EngineControl::configure_midi_devices ()
3180 {
3181         notebook.set_current_page (midi_tab);
3182 }