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