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