remove debug noise
[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         if (root.name() != "AudioMIDISetup") {
1973                 return false;
1974         }
1975
1976         clist = root.children();
1977
1978         states.clear ();
1979
1980         for (citer = clist.begin(); citer != clist.end(); ++citer) {
1981
1982                 child = *citer;
1983
1984                 if (child->name() != "EngineStates") {
1985                         continue;
1986                 }
1987
1988                 cclist = child->children();
1989
1990                 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1991                         State state (new StateStruct);
1992
1993                         grandchild = *cciter;
1994
1995                         if (grandchild->name() != "State") {
1996                                 continue;
1997                         }
1998
1999                         if ((prop = grandchild->property ("backend")) == 0) {
2000                                 continue;
2001                         }
2002                         state->backend = prop->value ();
2003
2004                         if ((prop = grandchild->property ("driver")) == 0) {
2005                                 continue;
2006                         }
2007                         state->driver = prop->value ();
2008
2009                         if ((prop = grandchild->property ("device")) == 0) {
2010                                 continue;
2011                         }
2012                         state->device = prop->value ();
2013
2014                         if ((prop = grandchild->property ("input-device")) == 0) {
2015                                 continue;
2016                         }
2017                         state->input_device = prop->value ();
2018
2019                         if ((prop = grandchild->property ("output-device")) == 0) {
2020                                 continue;
2021                         }
2022                         state->output_device = prop->value ();
2023
2024                         if ((prop = grandchild->property ("sample-rate")) == 0) {
2025                                 continue;
2026                         }
2027                         state->sample_rate = atof (prop->value ());
2028
2029                         if ((prop = grandchild->property ("buffer-size")) == 0) {
2030                                 continue;
2031                         }
2032                         state->buffer_size = atoi (prop->value ());
2033
2034                         if ((prop = grandchild->property ("n-periods")) == 0) {
2035                                 // optional (new value in 4.5)
2036                                 state->n_periods = 0;
2037                         } else {
2038                                 state->n_periods = atoi (prop->value ());
2039                         }
2040
2041                         if ((prop = grandchild->property ("input-latency")) == 0) {
2042                                 continue;
2043                         }
2044                         state->input_latency = atoi (prop->value ());
2045
2046                         if ((prop = grandchild->property ("output-latency")) == 0) {
2047                                 continue;
2048                         }
2049                         state->output_latency = atoi (prop->value ());
2050
2051                         if ((prop = grandchild->property ("input-channels")) == 0) {
2052                                 continue;
2053                         }
2054                         state->input_channels = atoi (prop->value ());
2055
2056                         if ((prop = grandchild->property ("output-channels")) == 0) {
2057                                 continue;
2058                         }
2059                         state->output_channels = atoi (prop->value ());
2060
2061                         if ((prop = grandchild->property ("active")) == 0) {
2062                                 continue;
2063                         }
2064                         state->active = string_is_affirmative (prop->value ());
2065
2066                         if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2067                                 continue;
2068                         }
2069                         state->use_buffered_io = string_is_affirmative (prop->value ());
2070
2071                         if ((prop = grandchild->property ("midi-option")) == 0) {
2072                                 continue;
2073                         }
2074                         state->midi_option = prop->value ();
2075
2076                         state->midi_devices.clear();
2077                         XMLNode* midinode;
2078                         if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2079                                 const XMLNodeList mnc = midinode->children();
2080                                 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2081                                         if ((*n)->property (X_("name")) == 0
2082                                                         || (*n)->property (X_("enabled")) == 0
2083                                                         || (*n)->property (X_("input-latency")) == 0
2084                                                         || (*n)->property (X_("output-latency")) == 0
2085                                                  ) {
2086                                                 continue;
2087                                         }
2088
2089                                         MidiDeviceSettings ptr (new MidiDeviceSetting(
2090                                                                 (*n)->property (X_("name"))->value (),
2091                                                                 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2092                                                                 atoi ((*n)->property (X_("input-latency"))->value ()),
2093                                                                 atoi ((*n)->property (X_("output-latency"))->value ())
2094                                                                 ));
2095                                         state->midi_devices.push_back (ptr);
2096                                 }
2097                         }
2098
2099                         if ((prop = grandchild->property ("lru"))) {
2100                                 state->lru = atoi (prop->value ());
2101                         }
2102
2103 #if 1
2104                         /* remove accumulated duplicates (due to bug in ealier version)
2105                          * this can be removed again before release
2106                          */
2107                         for (StateList::iterator i = states.begin(); i != states.end();) {
2108                                 if ((*i)->backend == state->backend &&
2109                                                 (*i)->driver == state->driver &&
2110                                                 (*i)->device == state->device) {
2111                                         i =  states.erase(i);
2112                                 } else {
2113                                         ++i;
2114                                 }
2115                         }
2116 #endif
2117
2118                         states.push_back (state);
2119                 }
2120         }
2121
2122         /* now see if there was an active state and switch the setup to it */
2123
2124         // purge states of backend that are not available in this built
2125         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2126         vector<std::string> backend_names;
2127
2128         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2129                 backend_names.push_back((*i)->name);
2130         }
2131         for (StateList::iterator i = states.begin(); i != states.end();) {
2132                 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2133                         i = states.erase(i);
2134                 } else {
2135                         ++i;
2136                 }
2137         }
2138
2139         states.sort (state_sort_cmp);
2140
2141         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2142
2143                 if ((*i)->active) {
2144                         return set_current_state (*i);
2145                 }
2146         }
2147         return false;
2148 }
2149
2150 bool
2151 EngineControl::set_current_state (const State& state)
2152 {
2153         DEBUG_ECONTROL ("set_current_state");
2154
2155         boost::shared_ptr<ARDOUR::AudioBackend> backend;
2156
2157         if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2158                   state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2159                 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2160                 // this shouldn't happen as the invalid backend names should have been
2161                 // removed from the list of states.
2162                 return false;
2163         }
2164
2165         // now reflect the change in the backend in the GUI so backend_changed will
2166         // do the right thing
2167         backend_combo.set_active_text (state->backend);
2168
2169         if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2170                 backend_changed ();
2171                 // we don't have control don't restore state
2172                 return true;
2173         }
2174
2175
2176         if (!state->driver.empty ()) {
2177                 if (!backend->requires_driver_selection ()) {
2178                         DEBUG_ECONTROL ("Backend should require driver selection");
2179                         // A backend has changed from having driver selection to not having
2180                         // it or someone has been manually editing a config file and messed
2181                         // it up
2182                         return false;
2183                 }
2184
2185                 if (backend->set_driver (state->driver) != 0) {
2186                         DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2187                         // Driver names for a backend have changed and the name in the
2188                         // config file is now invalid or support for driver is no longer
2189                         // included in the backend
2190                         return false;
2191                 }
2192                 // no need to set the driver_combo as backend_changed will use
2193                 // backend->driver_name to set the active driver
2194         }
2195
2196         if (!state->device.empty ()) {
2197                 if (backend->set_device_name (state->device) != 0) {
2198                         DEBUG_ECONTROL (
2199                             string_compose ("Unable to set device name %1", state->device));
2200                         // device is no longer available on the system
2201                         return false;
2202                 }
2203                 // no need to set active device as it will be picked up in
2204                 // via backend_changed ()/set_device_popdown_strings
2205
2206         } else {
2207                 // backend supports separate input/output devices
2208                 if (backend->set_input_device_name (state->input_device) != 0) {
2209                         DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2210                                                         state->input_device));
2211                         // input device is no longer available on the system
2212                         return false;
2213                 }
2214
2215                 if (backend->set_output_device_name (state->output_device) != 0) {
2216                         DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2217                                                         state->input_device));
2218                         // output device is no longer available on the system
2219                         return false;
2220                 }
2221                 // no need to set active devices as it will be picked up in via
2222                 // backend_changed ()/set_*_device_popdown_strings
2223         }
2224
2225         backend_changed ();
2226
2227         // Now restore the state of the rest of the controls
2228
2229         // We don't use a SignalBlocker as set_current_state is currently only
2230         // called from set_state before any signals are connected. If at some point
2231         // a more general named state mechanism is implemented and
2232         // set_current_state is called while signals are connected then a
2233         // SignalBlocker will need to be instantiated before setting these.
2234
2235         device_combo.set_active_text (state->device);
2236         input_device_combo.set_active_text (state->input_device);
2237         output_device_combo.set_active_text (state->output_device);
2238         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2239         set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2240         set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2241         input_latency.set_value (state->input_latency);
2242         output_latency.set_value (state->output_latency);
2243         midi_option_combo.set_active_text (state->midi_option);
2244         use_buffered_io_button.set_active (state->use_buffered_io);
2245         return true;
2246 }
2247
2248 int
2249 EngineControl::push_state_to_backend (bool start)
2250 {
2251         DEBUG_ECONTROL ("push_state_to_backend");
2252         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2253         PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2254
2255         if (!backend) {
2256                 return 0;
2257         }
2258
2259         /* figure out what is going to change */
2260
2261         bool restart_required = false;
2262         bool was_running = ARDOUR::AudioEngine::instance()->running();
2263         bool change_driver = false;
2264         bool change_device = false;
2265         bool change_rate = false;
2266         bool change_bufsize = false;
2267         bool change_nperiods = false;
2268         bool change_latency = false;
2269         bool change_channels = false;
2270         bool change_midi = false;
2271         bool change_buffered_io = false;
2272
2273         uint32_t ochan = get_output_channels ();
2274         uint32_t ichan = get_input_channels ();
2275
2276         if (_have_control) {
2277
2278                 if (started_at_least_once) {
2279
2280                         /* we can control the backend */
2281
2282                         if (backend->requires_driver_selection()) {
2283                                 if (get_driver() != backend->driver_name()) {
2284                                         change_driver = true;
2285                                 }
2286                         }
2287
2288                         if (backend->use_separate_input_and_output_devices()) {
2289                                 if (get_input_device_name() != backend->input_device_name()) {
2290                                         change_device = true;
2291                                 }
2292                                 if (get_output_device_name() != backend->output_device_name()) {
2293                                         change_device = true;
2294                                 }
2295                         } else {
2296                                 if (get_device_name() != backend->device_name()) {
2297                                         change_device = true;
2298                                 }
2299                         }
2300
2301                         if (queue_device_changed) {
2302                                 change_device = true;
2303                         }
2304
2305                         if (get_rate() != backend->sample_rate()) {
2306                                 change_rate = true;
2307                         }
2308
2309                         if (get_buffer_size() != backend->buffer_size()) {
2310                                 change_bufsize = true;
2311                         }
2312
2313                         if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2314                                         && get_nperiods() != backend->period_size()) {
2315                                 change_nperiods = true;
2316                         }
2317
2318                         if (get_midi_option() != backend->midi_option()) {
2319                                 change_midi = true;
2320                         }
2321
2322                         if (backend->can_use_buffered_io()) {
2323                                 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2324                                         change_buffered_io = true;
2325                                 }
2326                         }
2327
2328                         /* zero-requested channels means "all available" */
2329
2330                         if (ichan == 0) {
2331                                 ichan = backend->input_channels();
2332                         }
2333
2334                         if (ochan == 0) {
2335                                 ochan = backend->output_channels();
2336                         }
2337
2338                         if (ichan != backend->input_channels()) {
2339                                 change_channels = true;
2340                         }
2341
2342                         if (ochan != backend->output_channels()) {
2343                                 change_channels = true;
2344                         }
2345
2346                         if (get_input_latency() != backend->systemic_input_latency() ||
2347                                         get_output_latency() != backend->systemic_output_latency()) {
2348                                 change_latency = true;
2349                         }
2350                 } else {
2351                         /* backend never started, so we have to force a group
2352                            of settings.
2353                          */
2354                         change_device = true;
2355                         if (backend->requires_driver_selection()) {
2356                                 change_driver = true;
2357                         }
2358                         change_rate = true;
2359                         change_bufsize = true;
2360                         change_channels = true;
2361                         change_latency = true;
2362                         change_midi = true;
2363                         change_buffered_io = backend->can_use_buffered_io();
2364                         change_channels = true;
2365                         change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2366                 }
2367
2368         } else {
2369
2370                 /* we have no control over the backend, meaning that we can
2371                  * only possibly change sample rate and buffer size.
2372                  */
2373
2374
2375                 if (get_rate() != backend->sample_rate()) {
2376                         change_bufsize = true;
2377                 }
2378
2379                 if (get_buffer_size() != backend->buffer_size()) {
2380                         change_bufsize = true;
2381                 }
2382         }
2383
2384         queue_device_changed = false;
2385
2386         if (!_have_control) {
2387
2388                 /* We do not have control over the backend, so the best we can
2389                  * do is try to change the sample rate and/or bufsize and get
2390                  * out of here.
2391                  */
2392
2393                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2394                         return 1;
2395                 }
2396
2397                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2398                         return 1;
2399                 }
2400
2401                 if (change_rate) {
2402                         backend->set_sample_rate (get_rate());
2403                 }
2404
2405                 if (change_bufsize) {
2406                         backend->set_buffer_size (get_buffer_size());
2407                 }
2408
2409                 if (start) {
2410                         if (ARDOUR::AudioEngine::instance()->start ()) {
2411                                 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2412                                 return -1;
2413                         }
2414                 }
2415
2416                 post_push ();
2417
2418                 return 0;
2419         }
2420
2421         /* determine if we need to stop the backend before changing parameters */
2422
2423         if (change_driver || change_device || change_channels || change_nperiods ||
2424                         (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2425                         (change_rate && !backend->can_change_sample_rate_when_running()) ||
2426                         change_midi || change_buffered_io ||
2427                         (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2428                 restart_required = true;
2429         } else {
2430                 restart_required = false;
2431         }
2432
2433
2434         if (was_running) {
2435                 if (restart_required) {
2436                         if (ARDOUR::AudioEngine::instance()->stop()) {
2437                                 return -1;
2438                         }
2439                 }
2440         }
2441
2442         if (change_driver && backend->set_driver (get_driver())) {
2443                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2444                 return -1;
2445         }
2446         if (backend->use_separate_input_and_output_devices()) {
2447                 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2448                         error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2449                         return -1;
2450                 }
2451                 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2452                         error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2453                         return -1;
2454                 }
2455         } else {
2456                 if (change_device && backend->set_device_name (get_device_name())) {
2457                         error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2458                         return -1;
2459                 }
2460         }
2461         if (change_rate && backend->set_sample_rate (get_rate())) {
2462                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2463                 return -1;
2464         }
2465         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2466                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2467                 return -1;
2468         }
2469         if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2470                 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2471                 return -1;
2472         }
2473
2474         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2475                 if (backend->set_input_channels (get_input_channels())) {
2476                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2477                         return -1;
2478                 }
2479                 if (backend->set_output_channels (get_output_channels())) {
2480                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2481                         return -1;
2482                 }
2483         }
2484         if (change_latency) {
2485                 if (backend->set_systemic_input_latency (get_input_latency())) {
2486                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2487                         return -1;
2488                 }
2489                 if (backend->set_systemic_output_latency (get_output_latency())) {
2490                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2491                         return -1;
2492                 }
2493         }
2494
2495         if (change_midi) {
2496                 backend->set_midi_option (get_midi_option());
2497         }
2498
2499         if (change_buffered_io) {
2500                 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2501         }
2502
2503         if (1 /* TODO */) {
2504                 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2505                         if (_measure_midi) {
2506                                 if (*p == _measure_midi) {
2507                                         backend->set_midi_device_enabled ((*p)->name, true);
2508                                 } else {
2509                                         backend->set_midi_device_enabled ((*p)->name, false);
2510                                 }
2511                                 if (backend->can_change_systemic_latency_when_running ()) {
2512                                         backend->set_systemic_midi_input_latency ((*p)->name, 0);
2513                                         backend->set_systemic_midi_output_latency ((*p)->name, 0);
2514                                 }
2515                                 continue;
2516                         }
2517                         backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2518                         if (backend->can_set_systemic_midi_latencies()) {
2519                                 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2520                                 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2521                         }
2522                 }
2523         }
2524
2525         if (start || (was_running && restart_required)) {
2526                 if (ARDOUR::AudioEngine::instance()->start()) {
2527                         return -1;
2528                 }
2529         }
2530
2531         post_push ();
2532
2533         return 0;
2534 }
2535
2536 void
2537 EngineControl::post_push ()
2538 {
2539         /* get a pointer to the current state object, creating one if
2540          * necessary
2541          */
2542
2543         State state = get_saved_state_for_currently_displayed_backend_and_device ();
2544
2545         if (!state) {
2546                 state = save_state ();
2547                 assert (state);
2548         } else {
2549                 store_state(state);
2550         }
2551
2552         states.sort (state_sort_cmp);
2553
2554         /* all off */
2555
2556         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2557                 (*i)->active = false;
2558         }
2559
2560         /* mark this one active (to be used next time the dialog is
2561          * shown)
2562          */
2563
2564         state->active = true;
2565
2566         if (_have_control) { // XXX
2567                 manage_control_app_sensitivity ();
2568         }
2569
2570         /* schedule a redisplay of MIDI ports */
2571         //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2572 }
2573
2574
2575 float
2576 EngineControl::get_rate () const
2577 {
2578         float r = atof (sample_rate_combo.get_active_text ());
2579         /* the string may have been translated with an abbreviation for
2580          * thousands, so use a crude heuristic to fix this.
2581          */
2582         if (r < 1000.0) {
2583                 r *= 1000.0;
2584         }
2585         return r;
2586 }
2587
2588
2589 uint32_t
2590 EngineControl::get_buffer_size () const
2591 {
2592         string txt = buffer_size_combo.get_active_text ();
2593         uint32_t samples;
2594
2595         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2596                 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2597                 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2598                 throw exception ();
2599         }
2600
2601         return samples;
2602 }
2603
2604 uint32_t
2605 EngineControl::get_nperiods () const
2606 {
2607         string txt = nperiods_combo.get_active_text ();
2608         return atoi (txt.c_str());
2609 }
2610
2611 string
2612 EngineControl::get_midi_option () const
2613 {
2614         return midi_option_combo.get_active_text();
2615 }
2616
2617 bool
2618 EngineControl::get_use_buffered_io () const
2619 {
2620         return use_buffered_io_button.get_active();
2621 }
2622
2623 uint32_t
2624 EngineControl::get_input_channels() const
2625 {
2626         if (ARDOUR::Profile->get_mixbus()) {
2627                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2628                 if (!backend) return 0;
2629                 return backend->input_channels();
2630         }
2631         return (uint32_t) input_channels_adjustment.get_value();
2632 }
2633
2634 uint32_t
2635 EngineControl::get_output_channels() const
2636 {
2637         if (ARDOUR::Profile->get_mixbus()) {
2638                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2639                 if (!backend) return 0;
2640                 return backend->input_channels();
2641         }
2642         return (uint32_t) output_channels_adjustment.get_value();
2643 }
2644
2645 uint32_t
2646 EngineControl::get_input_latency() const
2647 {
2648         return (uint32_t) input_latency_adjustment.get_value();
2649 }
2650
2651 uint32_t
2652 EngineControl::get_output_latency() const
2653 {
2654         return (uint32_t) output_latency_adjustment.get_value();
2655 }
2656
2657 string
2658 EngineControl::get_backend () const
2659 {
2660         return backend_combo.get_active_text ();
2661 }
2662
2663 string
2664 EngineControl::get_driver () const
2665 {
2666         if (driver_combo.get_parent()) {
2667                 return driver_combo.get_active_text ();
2668         } else {
2669                 return "";
2670         }
2671 }
2672
2673 string
2674 EngineControl::get_device_name () const
2675 {
2676         return device_combo.get_active_text ();
2677 }
2678
2679 string
2680 EngineControl::get_input_device_name () const
2681 {
2682         return input_device_combo.get_active_text ();
2683 }
2684
2685 string
2686 EngineControl::get_output_device_name () const
2687 {
2688         return output_device_combo.get_active_text ();
2689 }
2690
2691 void
2692 EngineControl::control_app_button_clicked ()
2693 {
2694         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2695
2696         if (!backend) {
2697                 return;
2698         }
2699
2700         backend->launch_control_app ();
2701 }
2702
2703 void
2704 EngineControl::start_stop_button_clicked ()
2705 {
2706         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2707
2708         if (!backend) {
2709                 return;
2710         }
2711
2712         if (ARDOUR::AudioEngine::instance()->running()) {
2713                 ARDOUR::AudioEngine::instance()->stop ();
2714         } else {
2715                 start_engine ();
2716         }
2717 }
2718
2719 void
2720 EngineControl::update_devices_button_clicked ()
2721 {
2722         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2723
2724         if (!backend) {
2725                 return;
2726         }
2727
2728         if (backend->update_devices()) {
2729                 device_list_changed ();
2730         }
2731 }
2732
2733 void
2734 EngineControl::use_buffered_io_button_clicked ()
2735 {
2736         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2737
2738         if (!backend) {
2739                 return;
2740         }
2741
2742         bool set_buffered_io = !use_buffered_io_button.get_active();
2743         use_buffered_io_button.set_active (set_buffered_io);
2744         backend->set_use_buffered_io (set_buffered_io);
2745 }
2746
2747 void
2748 EngineControl::manage_control_app_sensitivity ()
2749 {
2750         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2751
2752         if (!backend) {
2753                 return;
2754         }
2755
2756         string appname = backend->control_app_name();
2757
2758         if (appname.empty()) {
2759                 control_app_button.set_sensitive (false);
2760         } else {
2761                 control_app_button.set_sensitive (true);
2762         }
2763 }
2764
2765 void
2766 EngineControl::set_desired_sample_rate (uint32_t sr)
2767 {
2768         _desired_sample_rate = sr;
2769         if (ARDOUR::AudioEngine::instance ()->running ()
2770                         && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2771                 stop_engine ();
2772         }
2773         device_changed ();
2774 }
2775
2776 void
2777 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2778 {
2779         if (page_num == 0) {
2780                 cancel_button->set_sensitive (true);
2781                 _measure_midi.reset();
2782                 update_sensitivity ();
2783         } else {
2784                 cancel_button->set_sensitive (false);
2785                 ok_button->set_sensitive (false);
2786         }
2787
2788         if (page_num == midi_tab) {
2789                 /* MIDI tab */
2790                 refresh_midi_display ();
2791         }
2792
2793         if (page_num == latency_tab) {
2794                 /* latency tab */
2795
2796                 if (ARDOUR::AudioEngine::instance()->running()) {
2797                         stop_engine (true);
2798                 }
2799
2800                 {
2801                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2802
2803                         /* save any existing latency values */
2804
2805                         uint32_t il = (uint32_t) input_latency.get_value ();
2806                         uint32_t ol = (uint32_t) input_latency.get_value ();
2807
2808                         /* reset to zero so that our new test instance
2809                            will be clean of any existing latency measures.
2810
2811                            NB. this should really be done by the backend
2812                            when stated for latency measurement.
2813                         */
2814
2815                         input_latency.set_value (0);
2816                         output_latency.set_value (0);
2817
2818                         push_state_to_backend (false);
2819
2820                         /* reset control */
2821
2822                         input_latency.set_value (il);
2823                         output_latency.set_value (ol);
2824
2825                 }
2826                 // This should be done in push_state_to_backend()
2827                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2828                         disable_latency_tab ();
2829                 }
2830
2831                 enable_latency_tab ();
2832
2833         } else {
2834                 if (lm_running) {
2835                         end_latency_detection ();
2836                         ARDOUR::AudioEngine::instance()->stop_latency_detection();
2837                 }
2838         }
2839 }
2840
2841 /* latency measurement */
2842
2843 bool
2844 EngineControl::check_audio_latency_measurement ()
2845 {
2846         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2847
2848         if (mtdm->resolve () < 0) {
2849                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2850                 return true;
2851         }
2852
2853         if (mtdm->get_peak () > 0.707f) {
2854                 // get_peak() resets the peak-hold in the detector.
2855                 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2856                 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2857                 return true;
2858         }
2859
2860         if (mtdm->err () > 0.3) {
2861                 mtdm->invert ();
2862                 mtdm->resolve ();
2863         }
2864
2865         char buf[256];
2866         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2867
2868         if (sample_rate == 0) {
2869                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2870                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2871                 return false;
2872         }
2873
2874         int frames_total = mtdm->del();
2875         int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2876
2877         snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2878                         _("Detected roundtrip latency: "),
2879                         frames_total, frames_total * 1000.0f/sample_rate,
2880                         _("Systemic latency: "),
2881                         extra, extra * 1000.0f/sample_rate);
2882
2883         bool solid = true;
2884
2885         if (mtdm->err () > 0.2) {
2886                 strcat (buf, " ");
2887                 strcat (buf, _("(signal detection error)"));
2888                 solid = false;
2889         }
2890
2891         if (mtdm->inv ()) {
2892                 strcat (buf, " ");
2893                 strcat (buf, _("(inverted - bad wiring)"));
2894                 solid = false;
2895         }
2896
2897         lm_results.set_markup (string_compose (results_markup, buf));
2898
2899         if (solid) {
2900                 have_lm_results = true;
2901                 end_latency_detection ();
2902                 lm_use_button.set_sensitive (true);
2903                 return false;
2904         }
2905
2906         return true;
2907 }
2908
2909 bool
2910 EngineControl::check_midi_latency_measurement ()
2911 {
2912         ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2913
2914         if (!mididm->have_signal () || mididm->latency () == 0) {
2915                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2916                 return true;
2917         }
2918
2919         char buf[256];
2920         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2921
2922         if (sample_rate == 0) {
2923                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2924                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2925                 return false;
2926         }
2927
2928         ARDOUR::framecnt_t frames_total = mididm->latency();
2929         ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2930         snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2931                         _("Detected roundtrip latency: "),
2932                         frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2933                         _("Systemic latency: "),
2934                         extra, extra * 1000.0f / sample_rate);
2935
2936         bool solid = true;
2937
2938         if (!mididm->ok ()) {
2939                 strcat (buf, " ");
2940                 strcat (buf, _("(averaging)"));
2941                 solid = false;
2942         }
2943
2944         if (mididm->deviation () > 50.0) {
2945                 strcat (buf, " ");
2946                 strcat (buf, _("(too large jitter)"));
2947                 solid = false;
2948         } else if (mididm->deviation () > 10.0) {
2949                 strcat (buf, " ");
2950                 strcat (buf, _("(large jitter)"));
2951         }
2952
2953         if (solid) {
2954                 have_lm_results = true;
2955                 end_latency_detection ();
2956                 lm_use_button.set_sensitive (true);
2957                 lm_results.set_markup (string_compose (results_markup, buf));
2958                 return false;
2959         } else if (mididm->processed () > 400) {
2960                 have_lm_results = false;
2961                 end_latency_detection ();
2962                 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2963                 return false;
2964         }
2965
2966         lm_results.set_markup (string_compose (results_markup, buf));
2967
2968         return true;
2969 }
2970
2971 void
2972 EngineControl::start_latency_detection ()
2973 {
2974         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2975         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2976
2977         if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2978                 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2979                 if (_measure_midi) {
2980                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2981                 } else {
2982                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2983                 }
2984                 lm_measure_label.set_text (_("Cancel"));
2985                 have_lm_results = false;
2986                 lm_use_button.set_sensitive (false);
2987                 lm_input_channel_combo.set_sensitive (false);
2988                 lm_output_channel_combo.set_sensitive (false);
2989                 lm_running = true;
2990         }
2991 }
2992
2993 void
2994 EngineControl::end_latency_detection ()
2995 {
2996         latency_timeout.disconnect ();
2997         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2998         lm_measure_label.set_text (_("Measure"));
2999         if (!have_lm_results) {
3000                 lm_use_button.set_sensitive (false);
3001         }
3002         lm_input_channel_combo.set_sensitive (true);
3003         lm_output_channel_combo.set_sensitive (true);
3004         lm_running = false;
3005 }
3006
3007 void
3008 EngineControl::latency_button_clicked ()
3009 {
3010         if (!lm_running) {
3011                 start_latency_detection ();
3012         } else {
3013                 end_latency_detection ();
3014         }
3015 }
3016
3017 void
3018 EngineControl::latency_back_button_clicked ()
3019 {
3020         ARDOUR::AudioEngine::instance()->stop(true);
3021         notebook.set_current_page(0);
3022 }
3023
3024 void
3025 EngineControl::use_latency_button_clicked ()
3026 {
3027         if (_measure_midi) {
3028                 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3029                 if (!mididm) {
3030                         return;
3031                 }
3032                 ARDOUR::framecnt_t frames_total = mididm->latency();
3033                 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3034                 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3035                 _measure_midi->input_latency = one_way;
3036                 _measure_midi->output_latency = one_way;
3037                 notebook.set_current_page (midi_tab);
3038         } else {
3039                 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3040
3041                 if (!mtdm) {
3042                         return;
3043                 }
3044
3045                 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3046                 one_way = std::max (0., one_way);
3047
3048                 input_latency_adjustment.set_value (one_way);
3049                 output_latency_adjustment.set_value (one_way);
3050
3051                 /* back to settings page */
3052                 notebook.set_current_page (0);
3053         }
3054 }
3055
3056 bool
3057 EngineControl::on_delete_event (GdkEventAny* ev)
3058 {
3059         if (notebook.get_current_page() == 2) {
3060                 /* currently on latency tab - be sure to clean up */
3061                 end_latency_detection ();
3062         }
3063         return ArdourDialog::on_delete_event (ev);
3064 }
3065
3066 void
3067 EngineControl::engine_running ()
3068 {
3069         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3070         assert (backend);
3071
3072         set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3073         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3074
3075         if (backend->can_set_period_size ()) {
3076                 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3077         }
3078
3079         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3080         connect_disconnect_button.show();
3081
3082         started_at_least_once = true;
3083         if (_have_control) {
3084                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3085         } else {
3086                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3087         }
3088         update_sensitivity();
3089 }
3090
3091 void
3092 EngineControl::engine_stopped ()
3093 {
3094         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3095         assert (backend);
3096
3097         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3098         connect_disconnect_button.show();
3099
3100         if (_have_control) {
3101                 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3102         } else {
3103                 engine_status.set_markup(X_(""));
3104         }
3105
3106         update_sensitivity();
3107 }
3108
3109 void
3110 EngineControl::device_list_changed ()
3111 {
3112         if (ignore_device_changes) {
3113                 return;
3114         }
3115         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3116         list_devices ();
3117         midi_option_changed();
3118 }
3119
3120 void
3121 EngineControl::connect_disconnect_click()
3122 {
3123         if (ARDOUR::AudioEngine::instance()->running()) {
3124                 stop_engine ();
3125         } else {
3126                 start_engine ();
3127         }
3128 }
3129
3130 void
3131 EngineControl::calibrate_audio_latency ()
3132 {
3133         _measure_midi.reset ();
3134         have_lm_results = false;
3135         lm_use_button.set_sensitive (false);
3136         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3137         notebook.set_current_page (latency_tab);
3138 }
3139
3140 void
3141 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3142 {
3143         _measure_midi = s;
3144         have_lm_results = false;
3145         lm_use_button.set_sensitive (false);
3146         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3147         notebook.set_current_page (latency_tab);
3148 }
3149
3150 void
3151 EngineControl::configure_midi_devices ()
3152 {
3153         notebook.set_current_page (midi_tab);
3154 }