quick checks on empty control lists, to avoid unnecessary work
[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 "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         /* Translators: "samples" is always plural here, so no
1600            need for plural+singular forms.
1601          */
1602         char buf[64];
1603         snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1604         return buf;
1605 }
1606
1607 string
1608 EngineControl::nperiods_as_string (uint32_t np)
1609 {
1610         char buf[8];
1611         snprintf (buf, sizeof (buf), "%u", np);
1612         return buf;
1613 }
1614
1615
1616 void
1617 EngineControl::sample_rate_changed ()
1618 {
1619         DEBUG_ECONTROL ("sample_rate_changed");
1620         /* reset the strings for buffer size to show the correct msec value
1621            (reflecting the new sample rate).
1622          */
1623
1624         show_buffer_duration ();
1625
1626 }
1627
1628 void
1629 EngineControl::buffer_size_changed ()
1630 {
1631         DEBUG_ECONTROL ("buffer_size_changed");
1632         show_buffer_duration ();
1633 }
1634
1635 void
1636 EngineControl::nperiods_changed ()
1637 {
1638         DEBUG_ECONTROL ("nperiods_changed");
1639         show_buffer_duration ();
1640 }
1641
1642 void
1643 EngineControl::show_buffer_duration ()
1644 {
1645         DEBUG_ECONTROL ("show_buffer_duration");
1646         /* buffer sizes  - convert from just samples to samples + msecs for
1647          * the displayed string
1648          */
1649
1650         string bs_text = buffer_size_combo.get_active_text ();
1651         uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1652         uint32_t rate = get_rate();
1653
1654         /* Except for ALSA and Dummy backends, we don't know the number of periods
1655          * per cycle and settings.
1656          *
1657          * jack1 vs jack2 have different default latencies since jack2 start
1658          * in async-mode unless --sync is given which adds an extra cycle
1659          * of latency. The value is not known if jackd is started externally..
1660          *
1661          * So just display the period size, that's also what
1662          * ARDOUR_UI::update_sample_rate() does for the status bar.
1663          * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1664          * but still, that's the buffer period, not [round-trip] latency)
1665          */
1666         char buf[32];
1667         snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1668         buffer_size_duration_label.set_text (buf);
1669 }
1670
1671 void
1672 EngineControl::midi_option_changed ()
1673 {
1674         DEBUG_ECONTROL ("midi_option_changed");
1675         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1676         assert (backend);
1677
1678         backend->set_midi_option (get_midi_option());
1679
1680         vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1681
1682         //_midi_devices.clear(); // TODO merge with state-saved settings..
1683         _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1684         std::vector<MidiDeviceSettings> new_devices;
1685
1686         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1687                 MidiDeviceSettings mds = find_midi_device (i->name);
1688                 if (i->available && !mds) {
1689                         uint32_t input_latency = 0;
1690                         uint32_t output_latency = 0;
1691                         if (_can_set_midi_latencies) {
1692                                 input_latency = backend->systemic_midi_input_latency (i->name);
1693                                 output_latency = backend->systemic_midi_output_latency (i->name);
1694                         }
1695                         bool enabled = backend->midi_device_enabled (i->name);
1696                         MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1697                         new_devices.push_back (ptr);
1698                 } else if (i->available) {
1699                         new_devices.push_back (mds);
1700                 }
1701         }
1702         _midi_devices = new_devices;
1703
1704         if (_midi_devices.empty()) {
1705                 midi_devices_button.hide ();
1706         } else {
1707                 midi_devices_button.show ();
1708         }
1709 }
1710
1711 void
1712 EngineControl::parameter_changed ()
1713 {
1714 }
1715
1716 EngineControl::State
1717 EngineControl::get_matching_state (const string& backend)
1718 {
1719         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1720                 if ((*i)->backend == backend) {
1721                         return (*i);
1722                 }
1723         }
1724         return State();
1725 }
1726
1727 EngineControl::State
1728 EngineControl::get_matching_state (
1729                 const string& backend,
1730                 const string& driver,
1731                 const string& device)
1732 {
1733         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1734                 if ((*i)->backend == backend &&
1735                                 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1736                 {
1737                         return (*i);
1738                 }
1739         }
1740         return State();
1741 }
1742
1743 EngineControl::State
1744 EngineControl::get_matching_state (
1745                 const string& backend,
1746                 const string& driver,
1747                 const string& input_device,
1748                 const string& output_device)
1749 {
1750         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1751                 if ((*i)->backend == backend &&
1752                                 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1753                 {
1754                         return (*i);
1755                 }
1756         }
1757         return State();
1758 }
1759
1760 EngineControl::State
1761 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1762 {
1763         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1764
1765         if (backend) {
1766                 if (backend->use_separate_input_and_output_devices ()) {
1767                         return get_matching_state (backend_combo.get_active_text(),
1768                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1769                                         input_device_combo.get_active_text(),
1770                                         output_device_combo.get_active_text());
1771                 } else {
1772                         return get_matching_state (backend_combo.get_active_text(),
1773                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1774                                         device_combo.get_active_text());
1775                 }
1776         }
1777
1778         return get_matching_state (backend_combo.get_active_text(),
1779                         string(),
1780                         device_combo.get_active_text());
1781 }
1782
1783 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1784                                        const EngineControl::State& state2)
1785 {
1786         if (state1->backend == state2->backend &&
1787                         state1->driver == state2->driver &&
1788                         state1->device == state2->device &&
1789                         state1->input_device == state2->input_device &&
1790                         state1->output_device == state2->output_device) {
1791                 return true;
1792         }
1793         return false;
1794 }
1795
1796 bool
1797 EngineControl::state_sort_cmp (const State &a, const State &b) {
1798         if (a->active) {
1799                 return true;
1800         }
1801         else if (b->active) {
1802                 return false;
1803         }
1804         else {
1805                 return a->lru < b->lru;
1806         }
1807 }
1808
1809 EngineControl::State
1810 EngineControl::save_state ()
1811 {
1812         State state;
1813
1814         if (!_have_control) {
1815                 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1816                 if (state) {
1817                         state->lru = time (NULL) ;
1818                         return state;
1819                 }
1820                 state.reset(new StateStruct);
1821                 state->backend = get_backend ();
1822         } else {
1823                 state.reset(new StateStruct);
1824                 store_state (state);
1825         }
1826
1827         for (StateList::iterator i = states.begin(); i != states.end();) {
1828                 if (equivalent_states (*i, state)) {
1829                         i =  states.erase(i);
1830                 } else {
1831                         ++i;
1832                 }
1833         }
1834
1835         states.push_back (state);
1836
1837         states.sort (state_sort_cmp);
1838
1839         return state;
1840 }
1841
1842 void
1843 EngineControl::store_state (State state)
1844 {
1845         state->backend = get_backend ();
1846         state->driver = get_driver ();
1847         state->device = get_device_name ();
1848         state->input_device = get_input_device_name ();
1849         state->output_device = get_output_device_name ();
1850         state->sample_rate = get_rate ();
1851         state->buffer_size = get_buffer_size ();
1852         state->n_periods = get_nperiods ();
1853         state->input_latency = get_input_latency ();
1854         state->output_latency = get_output_latency ();
1855         state->input_channels = get_input_channels ();
1856         state->output_channels = get_output_channels ();
1857         state->midi_option = get_midi_option ();
1858         state->midi_devices = _midi_devices;
1859         state->use_buffered_io = get_use_buffered_io ();
1860         state->lru = time (NULL) ;
1861 }
1862
1863 void
1864 EngineControl::maybe_display_saved_state ()
1865 {
1866         if (!_have_control) {
1867                 return;
1868         }
1869
1870         State state = get_saved_state_for_currently_displayed_backend_and_device ();
1871
1872         if (state) {
1873                 DEBUG_ECONTROL ("Restoring saved state");
1874                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1875
1876                 if (!_desired_sample_rate) {
1877                         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1878                 }
1879                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1880
1881                 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1882                 /* call this explicitly because we're ignoring changes to
1883                    the controls at this point.
1884                  */
1885                 show_buffer_duration ();
1886                 input_latency.set_value (state->input_latency);
1887                 output_latency.set_value (state->output_latency);
1888
1889                 use_buffered_io_button.set_active (state->use_buffered_io);
1890
1891                 if (!state->midi_option.empty()) {
1892                         midi_option_combo.set_active_text (state->midi_option);
1893                         _midi_devices = state->midi_devices;
1894                 }
1895         } else {
1896                 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1897         }
1898 }
1899
1900 XMLNode&
1901 EngineControl::get_state ()
1902 {
1903         LocaleGuard lg;
1904
1905         XMLNode* root = new XMLNode ("AudioMIDISetup");
1906         std::string path;
1907
1908         if (!states.empty()) {
1909                 XMLNode* state_nodes = new XMLNode ("EngineStates");
1910
1911                 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1912
1913                         XMLNode* node = new XMLNode ("State");
1914
1915                         node->add_property ("backend", (*i)->backend);
1916                         node->add_property ("driver", (*i)->driver);
1917                         node->add_property ("device", (*i)->device);
1918                         node->add_property ("input-device", (*i)->input_device);
1919                         node->add_property ("output-device", (*i)->output_device);
1920                         node->add_property ("sample-rate", (*i)->sample_rate);
1921                         node->add_property ("buffer-size", (*i)->buffer_size);
1922                         node->add_property ("n-periods", (*i)->n_periods);
1923                         node->add_property ("input-latency", (*i)->input_latency);
1924                         node->add_property ("output-latency", (*i)->output_latency);
1925                         node->add_property ("input-channels", (*i)->input_channels);
1926                         node->add_property ("output-channels", (*i)->output_channels);
1927                         node->add_property ("active", (*i)->active ? "yes" : "no");
1928                         node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
1929                         node->add_property ("midi-option", (*i)->midi_option);
1930                         node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1931
1932                         XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1933                         for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1934                                 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1935                                 midi_device_stuff->add_property (X_("name"), (*p)->name);
1936                                 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1937                                 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1938                                 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1939                                 midi_devices->add_child_nocopy (*midi_device_stuff);
1940                         }
1941                         node->add_child_nocopy (*midi_devices);
1942
1943                         state_nodes->add_child_nocopy (*node);
1944                 }
1945
1946                 root->add_child_nocopy (*state_nodes);
1947         }
1948
1949         return *root;
1950 }
1951
1952 void
1953 EngineControl::set_default_state ()
1954 {
1955         vector<string> backend_names;
1956         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1957
1958         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1959                 backend_names.push_back ((*b)->name);
1960         }
1961         backend_combo.set_active_text (backend_names.front());
1962
1963         // We could set default backends per platform etc here
1964
1965         backend_changed ();
1966 }
1967
1968 bool
1969 EngineControl::set_state (const XMLNode& root)
1970 {
1971         XMLNodeList          clist, cclist;
1972         XMLNodeConstIterator citer, cciter;
1973         XMLNode const * child;
1974         XMLNode const * grandchild;
1975         XMLProperty const * prop = NULL;
1976
1977         fprintf (stderr, "EngineControl::set_state\n");
1978
1979         if (root.name() != "AudioMIDISetup") {
1980                 return false;
1981         }
1982
1983         clist = root.children();
1984
1985         states.clear ();
1986
1987         for (citer = clist.begin(); citer != clist.end(); ++citer) {
1988
1989                 child = *citer;
1990
1991                 if (child->name() != "EngineStates") {
1992                         continue;
1993                 }
1994
1995                 cclist = child->children();
1996
1997                 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1998                         State state (new StateStruct);
1999
2000                         grandchild = *cciter;
2001
2002                         if (grandchild->name() != "State") {
2003                                 continue;
2004                         }
2005
2006                         if ((prop = grandchild->property ("backend")) == 0) {
2007                                 continue;
2008                         }
2009                         state->backend = prop->value ();
2010
2011                         if ((prop = grandchild->property ("driver")) == 0) {
2012                                 continue;
2013                         }
2014                         state->driver = prop->value ();
2015
2016                         if ((prop = grandchild->property ("device")) == 0) {
2017                                 continue;
2018                         }
2019                         state->device = prop->value ();
2020
2021                         if ((prop = grandchild->property ("input-device")) == 0) {
2022                                 continue;
2023                         }
2024                         state->input_device = prop->value ();
2025
2026                         if ((prop = grandchild->property ("output-device")) == 0) {
2027                                 continue;
2028                         }
2029                         state->output_device = prop->value ();
2030
2031                         if ((prop = grandchild->property ("sample-rate")) == 0) {
2032                                 continue;
2033                         }
2034                         state->sample_rate = atof (prop->value ());
2035
2036                         if ((prop = grandchild->property ("buffer-size")) == 0) {
2037                                 continue;
2038                         }
2039                         state->buffer_size = atoi (prop->value ());
2040
2041                         if ((prop = grandchild->property ("n-periods")) == 0) {
2042                                 // optional (new value in 4.5)
2043                                 state->n_periods = 0;
2044                         } else {
2045                                 state->n_periods = atoi (prop->value ());
2046                         }
2047
2048                         if ((prop = grandchild->property ("input-latency")) == 0) {
2049                                 continue;
2050                         }
2051                         state->input_latency = atoi (prop->value ());
2052
2053                         if ((prop = grandchild->property ("output-latency")) == 0) {
2054                                 continue;
2055                         }
2056                         state->output_latency = atoi (prop->value ());
2057
2058                         if ((prop = grandchild->property ("input-channels")) == 0) {
2059                                 continue;
2060                         }
2061                         state->input_channels = atoi (prop->value ());
2062
2063                         if ((prop = grandchild->property ("output-channels")) == 0) {
2064                                 continue;
2065                         }
2066                         state->output_channels = atoi (prop->value ());
2067
2068                         if ((prop = grandchild->property ("active")) == 0) {
2069                                 continue;
2070                         }
2071                         state->active = string_is_affirmative (prop->value ());
2072
2073                         if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2074                                 continue;
2075                         }
2076                         state->use_buffered_io = string_is_affirmative (prop->value ());
2077
2078                         if ((prop = grandchild->property ("midi-option")) == 0) {
2079                                 continue;
2080                         }
2081                         state->midi_option = prop->value ();
2082
2083                         state->midi_devices.clear();
2084                         XMLNode* midinode;
2085                         if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2086                                 const XMLNodeList mnc = midinode->children();
2087                                 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2088                                         if ((*n)->property (X_("name")) == 0
2089                                                         || (*n)->property (X_("enabled")) == 0
2090                                                         || (*n)->property (X_("input-latency")) == 0
2091                                                         || (*n)->property (X_("output-latency")) == 0
2092                                                  ) {
2093                                                 continue;
2094                                         }
2095
2096                                         MidiDeviceSettings ptr (new MidiDeviceSetting(
2097                                                                 (*n)->property (X_("name"))->value (),
2098                                                                 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2099                                                                 atoi ((*n)->property (X_("input-latency"))->value ()),
2100                                                                 atoi ((*n)->property (X_("output-latency"))->value ())
2101                                                                 ));
2102                                         state->midi_devices.push_back (ptr);
2103                                 }
2104                         }
2105
2106                         if ((prop = grandchild->property ("lru"))) {
2107                                 state->lru = atoi (prop->value ());
2108                         }
2109
2110 #if 1
2111                         /* remove accumulated duplicates (due to bug in ealier version)
2112                          * this can be removed again before release
2113                          */
2114                         for (StateList::iterator i = states.begin(); i != states.end();) {
2115                                 if ((*i)->backend == state->backend &&
2116                                                 (*i)->driver == state->driver &&
2117                                                 (*i)->device == state->device) {
2118                                         i =  states.erase(i);
2119                                 } else {
2120                                         ++i;
2121                                 }
2122                         }
2123 #endif
2124
2125                         states.push_back (state);
2126                 }
2127         }
2128
2129         /* now see if there was an active state and switch the setup to it */
2130
2131         // purge states of backend that are not available in this built
2132         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2133         vector<std::string> backend_names;
2134
2135         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2136                 backend_names.push_back((*i)->name);
2137         }
2138         for (StateList::iterator i = states.begin(); i != states.end();) {
2139                 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2140                         i = states.erase(i);
2141                 } else {
2142                         ++i;
2143                 }
2144         }
2145
2146         states.sort (state_sort_cmp);
2147
2148         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2149
2150                 if ((*i)->active) {
2151                         return set_current_state (*i);
2152                 }
2153         }
2154         return false;
2155 }
2156
2157 bool
2158 EngineControl::set_current_state (const State& state)
2159 {
2160         DEBUG_ECONTROL ("set_current_state");
2161
2162         boost::shared_ptr<ARDOUR::AudioBackend> backend;
2163
2164         if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2165                   state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2166                 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2167                 // this shouldn't happen as the invalid backend names should have been
2168                 // removed from the list of states.
2169                 return false;
2170         }
2171
2172         // now reflect the change in the backend in the GUI so backend_changed will
2173         // do the right thing
2174         backend_combo.set_active_text (state->backend);
2175
2176         if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2177                 backend_changed ();
2178                 // we don't have control don't restore state
2179                 return true;
2180         }
2181
2182
2183         if (!state->driver.empty ()) {
2184                 if (!backend->requires_driver_selection ()) {
2185                         DEBUG_ECONTROL ("Backend should require driver selection");
2186                         // A backend has changed from having driver selection to not having
2187                         // it or someone has been manually editing a config file and messed
2188                         // it up
2189                         return false;
2190                 }
2191
2192                 if (backend->set_driver (state->driver) != 0) {
2193                         DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2194                         // Driver names for a backend have changed and the name in the
2195                         // config file is now invalid or support for driver is no longer
2196                         // included in the backend
2197                         return false;
2198                 }
2199                 // no need to set the driver_combo as backend_changed will use
2200                 // backend->driver_name to set the active driver
2201         }
2202
2203         if (!state->device.empty ()) {
2204                 if (backend->set_device_name (state->device) != 0) {
2205                         DEBUG_ECONTROL (
2206                             string_compose ("Unable to set device name %1", state->device));
2207                         // device is no longer available on the system
2208                         return false;
2209                 }
2210                 // no need to set active device as it will be picked up in
2211                 // via backend_changed ()/set_device_popdown_strings
2212
2213         } else {
2214                 // backend supports separate input/output devices
2215                 if (backend->set_input_device_name (state->input_device) != 0) {
2216                         DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2217                                                         state->input_device));
2218                         // input device is no longer available on the system
2219                         return false;
2220                 }
2221
2222                 if (backend->set_output_device_name (state->output_device) != 0) {
2223                         DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2224                                                         state->input_device));
2225                         // output device is no longer available on the system
2226                         return false;
2227                 }
2228                 // no need to set active devices as it will be picked up in via
2229                 // backend_changed ()/set_*_device_popdown_strings
2230         }
2231
2232         backend_changed ();
2233
2234         // Now restore the state of the rest of the controls
2235
2236         // We don't use a SignalBlocker as set_current_state is currently only
2237         // called from set_state before any signals are connected. If at some point
2238         // a more general named state mechanism is implemented and
2239         // set_current_state is called while signals are connected then a
2240         // SignalBlocker will need to be instantiated before setting these.
2241
2242         device_combo.set_active_text (state->device);
2243         input_device_combo.set_active_text (state->input_device);
2244         output_device_combo.set_active_text (state->output_device);
2245         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2246         set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2247         set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2248         input_latency.set_value (state->input_latency);
2249         output_latency.set_value (state->output_latency);
2250         midi_option_combo.set_active_text (state->midi_option);
2251         use_buffered_io_button.set_active (state->use_buffered_io);
2252         return true;
2253 }
2254
2255 int
2256 EngineControl::push_state_to_backend (bool start)
2257 {
2258         DEBUG_ECONTROL ("push_state_to_backend");
2259         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2260         PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2261
2262         if (!backend) {
2263                 return 0;
2264         }
2265
2266         /* figure out what is going to change */
2267
2268         bool restart_required = false;
2269         bool was_running = ARDOUR::AudioEngine::instance()->running();
2270         bool change_driver = false;
2271         bool change_device = false;
2272         bool change_rate = false;
2273         bool change_bufsize = false;
2274         bool change_nperiods = false;
2275         bool change_latency = false;
2276         bool change_channels = false;
2277         bool change_midi = false;
2278         bool change_buffered_io = false;
2279
2280         uint32_t ochan = get_output_channels ();
2281         uint32_t ichan = get_input_channels ();
2282
2283         if (_have_control) {
2284
2285                 if (started_at_least_once) {
2286
2287                         /* we can control the backend */
2288
2289                         if (backend->requires_driver_selection()) {
2290                                 if (get_driver() != backend->driver_name()) {
2291                                         change_driver = true;
2292                                 }
2293                         }
2294
2295                         if (backend->use_separate_input_and_output_devices()) {
2296                                 if (get_input_device_name() != backend->input_device_name()) {
2297                                         change_device = true;
2298                                 }
2299                                 if (get_output_device_name() != backend->output_device_name()) {
2300                                         change_device = true;
2301                                 }
2302                         } else {
2303                                 if (get_device_name() != backend->device_name()) {
2304                                         change_device = true;
2305                                 }
2306                         }
2307
2308                         if (queue_device_changed) {
2309                                 change_device = true;
2310                         }
2311
2312                         if (get_rate() != backend->sample_rate()) {
2313                                 change_rate = true;
2314                         }
2315
2316                         if (get_buffer_size() != backend->buffer_size()) {
2317                                 change_bufsize = true;
2318                         }
2319
2320                         if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2321                                         && get_nperiods() != backend->period_size()) {
2322                                 change_nperiods = true;
2323                         }
2324
2325                         if (get_midi_option() != backend->midi_option()) {
2326                                 change_midi = true;
2327                         }
2328
2329                         if (backend->can_use_buffered_io()) {
2330                                 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2331                                         change_buffered_io = true;
2332                                 }
2333                         }
2334
2335                         /* zero-requested channels means "all available" */
2336
2337                         if (ichan == 0) {
2338                                 ichan = backend->input_channels();
2339                         }
2340
2341                         if (ochan == 0) {
2342                                 ochan = backend->output_channels();
2343                         }
2344
2345                         if (ichan != backend->input_channels()) {
2346                                 change_channels = true;
2347                         }
2348
2349                         if (ochan != backend->output_channels()) {
2350                                 change_channels = true;
2351                         }
2352
2353                         if (get_input_latency() != backend->systemic_input_latency() ||
2354                                         get_output_latency() != backend->systemic_output_latency()) {
2355                                 change_latency = true;
2356                         }
2357                 } else {
2358                         /* backend never started, so we have to force a group
2359                            of settings.
2360                          */
2361                         change_device = true;
2362                         if (backend->requires_driver_selection()) {
2363                                 change_driver = true;
2364                         }
2365                         change_rate = true;
2366                         change_bufsize = true;
2367                         change_channels = true;
2368                         change_latency = true;
2369                         change_midi = true;
2370                         change_buffered_io = backend->can_use_buffered_io();
2371                         change_channels = true;
2372                         change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2373                 }
2374
2375         } else {
2376
2377                 /* we have no control over the backend, meaning that we can
2378                  * only possibly change sample rate and buffer size.
2379                  */
2380
2381
2382                 if (get_rate() != backend->sample_rate()) {
2383                         change_bufsize = true;
2384                 }
2385
2386                 if (get_buffer_size() != backend->buffer_size()) {
2387                         change_bufsize = true;
2388                 }
2389         }
2390
2391         queue_device_changed = false;
2392
2393         if (!_have_control) {
2394
2395                 /* We do not have control over the backend, so the best we can
2396                  * do is try to change the sample rate and/or bufsize and get
2397                  * out of here.
2398                  */
2399
2400                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2401                         return 1;
2402                 }
2403
2404                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2405                         return 1;
2406                 }
2407
2408                 if (change_rate) {
2409                         backend->set_sample_rate (get_rate());
2410                 }
2411
2412                 if (change_bufsize) {
2413                         backend->set_buffer_size (get_buffer_size());
2414                 }
2415
2416                 if (start) {
2417                         if (ARDOUR::AudioEngine::instance()->start ()) {
2418                                 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2419                                 return -1;
2420                         }
2421                 }
2422
2423                 post_push ();
2424
2425                 return 0;
2426         }
2427
2428         /* determine if we need to stop the backend before changing parameters */
2429
2430         if (change_driver || change_device || change_channels || change_nperiods ||
2431                         (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2432                         (change_rate && !backend->can_change_sample_rate_when_running()) ||
2433                         change_midi || change_buffered_io ||
2434                         (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2435                 restart_required = true;
2436         } else {
2437                 restart_required = false;
2438         }
2439
2440
2441         if (was_running) {
2442                 if (restart_required) {
2443                         if (ARDOUR::AudioEngine::instance()->stop()) {
2444                                 return -1;
2445                         }
2446                 }
2447         }
2448
2449         if (change_driver && backend->set_driver (get_driver())) {
2450                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2451                 return -1;
2452         }
2453         if (backend->use_separate_input_and_output_devices()) {
2454                 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2455                         error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2456                         return -1;
2457                 }
2458                 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2459                         error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2460                         return -1;
2461                 }
2462         } else {
2463                 if (change_device && backend->set_device_name (get_device_name())) {
2464                         error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2465                         return -1;
2466                 }
2467         }
2468         if (change_rate && backend->set_sample_rate (get_rate())) {
2469                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2470                 return -1;
2471         }
2472         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2473                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2474                 return -1;
2475         }
2476         if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2477                 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2478                 return -1;
2479         }
2480
2481         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2482                 if (backend->set_input_channels (get_input_channels())) {
2483                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2484                         return -1;
2485                 }
2486                 if (backend->set_output_channels (get_output_channels())) {
2487                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2488                         return -1;
2489                 }
2490         }
2491         if (change_latency) {
2492                 if (backend->set_systemic_input_latency (get_input_latency())) {
2493                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2494                         return -1;
2495                 }
2496                 if (backend->set_systemic_output_latency (get_output_latency())) {
2497                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2498                         return -1;
2499                 }
2500         }
2501
2502         if (change_midi) {
2503                 backend->set_midi_option (get_midi_option());
2504         }
2505
2506         if (change_buffered_io) {
2507                 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2508         }
2509
2510         if (1 /* TODO */) {
2511                 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2512                         if (_measure_midi) {
2513                                 if (*p == _measure_midi) {
2514                                         backend->set_midi_device_enabled ((*p)->name, true);
2515                                 } else {
2516                                         backend->set_midi_device_enabled ((*p)->name, false);
2517                                 }
2518                                 if (backend->can_change_systemic_latency_when_running ()) {
2519                                         backend->set_systemic_midi_input_latency ((*p)->name, 0);
2520                                         backend->set_systemic_midi_output_latency ((*p)->name, 0);
2521                                 }
2522                                 continue;
2523                         }
2524                         backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2525                         if (backend->can_set_systemic_midi_latencies()) {
2526                                 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2527                                 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2528                         }
2529                 }
2530         }
2531
2532         if (start || (was_running && restart_required)) {
2533                 if (ARDOUR::AudioEngine::instance()->start()) {
2534                         return -1;
2535                 }
2536         }
2537
2538         post_push ();
2539
2540         return 0;
2541 }
2542
2543 void
2544 EngineControl::post_push ()
2545 {
2546         /* get a pointer to the current state object, creating one if
2547          * necessary
2548          */
2549
2550         State state = get_saved_state_for_currently_displayed_backend_and_device ();
2551
2552         if (!state) {
2553                 state = save_state ();
2554                 assert (state);
2555         } else {
2556                 store_state(state);
2557         }
2558
2559         states.sort (state_sort_cmp);
2560
2561         /* all off */
2562
2563         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2564                 (*i)->active = false;
2565         }
2566
2567         /* mark this one active (to be used next time the dialog is
2568          * shown)
2569          */
2570
2571         state->active = true;
2572
2573         if (_have_control) { // XXX
2574                 manage_control_app_sensitivity ();
2575         }
2576
2577         /* schedule a redisplay of MIDI ports */
2578         //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2579 }
2580
2581
2582 float
2583 EngineControl::get_rate () const
2584 {
2585         float r = atof (sample_rate_combo.get_active_text ());
2586         /* the string may have been translated with an abbreviation for
2587          * thousands, so use a crude heuristic to fix this.
2588          */
2589         if (r < 1000.0) {
2590                 r *= 1000.0;
2591         }
2592         return r;
2593 }
2594
2595
2596 uint32_t
2597 EngineControl::get_buffer_size () const
2598 {
2599         string txt = buffer_size_combo.get_active_text ();
2600         uint32_t samples;
2601
2602         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2603                 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2604                 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2605                 throw exception ();
2606         }
2607
2608         return samples;
2609 }
2610
2611 uint32_t
2612 EngineControl::get_nperiods () const
2613 {
2614         string txt = nperiods_combo.get_active_text ();
2615         return atoi (txt.c_str());
2616 }
2617
2618 string
2619 EngineControl::get_midi_option () const
2620 {
2621         return midi_option_combo.get_active_text();
2622 }
2623
2624 bool
2625 EngineControl::get_use_buffered_io () const
2626 {
2627         return use_buffered_io_button.get_active();
2628 }
2629
2630 uint32_t
2631 EngineControl::get_input_channels() const
2632 {
2633         if (ARDOUR::Profile->get_mixbus()) {
2634                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2635                 if (!backend) return 0;
2636                 return backend->input_channels();
2637         }
2638         return (uint32_t) input_channels_adjustment.get_value();
2639 }
2640
2641 uint32_t
2642 EngineControl::get_output_channels() const
2643 {
2644         if (ARDOUR::Profile->get_mixbus()) {
2645                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2646                 if (!backend) return 0;
2647                 return backend->input_channels();
2648         }
2649         return (uint32_t) output_channels_adjustment.get_value();
2650 }
2651
2652 uint32_t
2653 EngineControl::get_input_latency() const
2654 {
2655         return (uint32_t) input_latency_adjustment.get_value();
2656 }
2657
2658 uint32_t
2659 EngineControl::get_output_latency() const
2660 {
2661         return (uint32_t) output_latency_adjustment.get_value();
2662 }
2663
2664 string
2665 EngineControl::get_backend () const
2666 {
2667         return backend_combo.get_active_text ();
2668 }
2669
2670 string
2671 EngineControl::get_driver () const
2672 {
2673         if (driver_combo.get_parent()) {
2674                 return driver_combo.get_active_text ();
2675         } else {
2676                 return "";
2677         }
2678 }
2679
2680 string
2681 EngineControl::get_device_name () const
2682 {
2683         return device_combo.get_active_text ();
2684 }
2685
2686 string
2687 EngineControl::get_input_device_name () const
2688 {
2689         return input_device_combo.get_active_text ();
2690 }
2691
2692 string
2693 EngineControl::get_output_device_name () const
2694 {
2695         return output_device_combo.get_active_text ();
2696 }
2697
2698 void
2699 EngineControl::control_app_button_clicked ()
2700 {
2701         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2702
2703         if (!backend) {
2704                 return;
2705         }
2706
2707         backend->launch_control_app ();
2708 }
2709
2710 void
2711 EngineControl::start_stop_button_clicked ()
2712 {
2713         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2714
2715         if (!backend) {
2716                 return;
2717         }
2718
2719         if (ARDOUR::AudioEngine::instance()->running()) {
2720                 ARDOUR::AudioEngine::instance()->stop ();
2721         } else {
2722                 start_engine ();
2723         }
2724 }
2725
2726 void
2727 EngineControl::update_devices_button_clicked ()
2728 {
2729         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2730
2731         if (!backend) {
2732                 return;
2733         }
2734
2735         if (backend->update_devices()) {
2736                 device_list_changed ();
2737         }
2738 }
2739
2740 void
2741 EngineControl::use_buffered_io_button_clicked ()
2742 {
2743         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2744
2745         if (!backend) {
2746                 return;
2747         }
2748
2749         bool set_buffered_io = !use_buffered_io_button.get_active();
2750         use_buffered_io_button.set_active (set_buffered_io);
2751         backend->set_use_buffered_io (set_buffered_io);
2752 }
2753
2754 void
2755 EngineControl::manage_control_app_sensitivity ()
2756 {
2757         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2758
2759         if (!backend) {
2760                 return;
2761         }
2762
2763         string appname = backend->control_app_name();
2764
2765         if (appname.empty()) {
2766                 control_app_button.set_sensitive (false);
2767         } else {
2768                 control_app_button.set_sensitive (true);
2769         }
2770 }
2771
2772 void
2773 EngineControl::set_desired_sample_rate (uint32_t sr)
2774 {
2775         _desired_sample_rate = sr;
2776         if (ARDOUR::AudioEngine::instance ()->running ()
2777                         && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2778                 stop_engine ();
2779         }
2780         device_changed ();
2781 }
2782
2783 void
2784 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2785 {
2786         if (page_num == 0) {
2787                 cancel_button->set_sensitive (true);
2788                 _measure_midi.reset();
2789                 update_sensitivity ();
2790         } else {
2791                 cancel_button->set_sensitive (false);
2792                 ok_button->set_sensitive (false);
2793         }
2794
2795         if (page_num == midi_tab) {
2796                 /* MIDI tab */
2797                 refresh_midi_display ();
2798         }
2799
2800         if (page_num == latency_tab) {
2801                 /* latency tab */
2802
2803                 if (ARDOUR::AudioEngine::instance()->running()) {
2804                         stop_engine (true);
2805                 }
2806
2807                 {
2808                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2809
2810                         /* save any existing latency values */
2811
2812                         uint32_t il = (uint32_t) input_latency.get_value ();
2813                         uint32_t ol = (uint32_t) input_latency.get_value ();
2814
2815                         /* reset to zero so that our new test instance
2816                            will be clean of any existing latency measures.
2817
2818                            NB. this should really be done by the backend
2819                            when stated for latency measurement.
2820                         */
2821
2822                         input_latency.set_value (0);
2823                         output_latency.set_value (0);
2824
2825                         push_state_to_backend (false);
2826
2827                         /* reset control */
2828
2829                         input_latency.set_value (il);
2830                         output_latency.set_value (ol);
2831
2832                 }
2833                 // This should be done in push_state_to_backend()
2834                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2835                         disable_latency_tab ();
2836                 }
2837
2838                 enable_latency_tab ();
2839
2840         } else {
2841                 if (lm_running) {
2842                         end_latency_detection ();
2843                         ARDOUR::AudioEngine::instance()->stop_latency_detection();
2844                 }
2845         }
2846 }
2847
2848 /* latency measurement */
2849
2850 bool
2851 EngineControl::check_audio_latency_measurement ()
2852 {
2853         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2854
2855         if (mtdm->resolve () < 0) {
2856                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2857                 return true;
2858         }
2859
2860         if (mtdm->get_peak () > 0.707f) {
2861                 // get_peak() resets the peak-hold in the detector.
2862                 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2863                 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2864                 return true;
2865         }
2866
2867         if (mtdm->err () > 0.3) {
2868                 mtdm->invert ();
2869                 mtdm->resolve ();
2870         }
2871
2872         char buf[256];
2873         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2874
2875         if (sample_rate == 0) {
2876                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2877                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2878                 return false;
2879         }
2880
2881         int frames_total = mtdm->del();
2882         int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2883
2884         snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2885                         _("Detected roundtrip latency: "),
2886                         frames_total, frames_total * 1000.0f/sample_rate,
2887                         _("Systemic latency: "),
2888                         extra, extra * 1000.0f/sample_rate);
2889
2890         bool solid = true;
2891
2892         if (mtdm->err () > 0.2) {
2893                 strcat (buf, " ");
2894                 strcat (buf, _("(signal detection error)"));
2895                 solid = false;
2896         }
2897
2898         if (mtdm->inv ()) {
2899                 strcat (buf, " ");
2900                 strcat (buf, _("(inverted - bad wiring)"));
2901                 solid = false;
2902         }
2903
2904         lm_results.set_markup (string_compose (results_markup, buf));
2905
2906         if (solid) {
2907                 have_lm_results = true;
2908                 end_latency_detection ();
2909                 lm_use_button.set_sensitive (true);
2910                 return false;
2911         }
2912
2913         return true;
2914 }
2915
2916 bool
2917 EngineControl::check_midi_latency_measurement ()
2918 {
2919         ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2920
2921         if (!mididm->have_signal () || mididm->latency () == 0) {
2922                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2923                 return true;
2924         }
2925
2926         char buf[256];
2927         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2928
2929         if (sample_rate == 0) {
2930                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2931                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2932                 return false;
2933         }
2934
2935         ARDOUR::framecnt_t frames_total = mididm->latency();
2936         ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2937         snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2938                         _("Detected roundtrip latency: "),
2939                         frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2940                         _("Systemic latency: "),
2941                         extra, extra * 1000.0f / sample_rate);
2942
2943         bool solid = true;
2944
2945         if (!mididm->ok ()) {
2946                 strcat (buf, " ");
2947                 strcat (buf, _("(averaging)"));
2948                 solid = false;
2949         }
2950
2951         if (mididm->deviation () > 50.0) {
2952                 strcat (buf, " ");
2953                 strcat (buf, _("(too large jitter)"));
2954                 solid = false;
2955         } else if (mididm->deviation () > 10.0) {
2956                 strcat (buf, " ");
2957                 strcat (buf, _("(large jitter)"));
2958         }
2959
2960         if (solid) {
2961                 have_lm_results = true;
2962                 end_latency_detection ();
2963                 lm_use_button.set_sensitive (true);
2964                 lm_results.set_markup (string_compose (results_markup, buf));
2965                 return false;
2966         } else if (mididm->processed () > 400) {
2967                 have_lm_results = false;
2968                 end_latency_detection ();
2969                 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2970                 return false;
2971         }
2972
2973         lm_results.set_markup (string_compose (results_markup, buf));
2974
2975         return true;
2976 }
2977
2978 void
2979 EngineControl::start_latency_detection ()
2980 {
2981         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2982         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2983
2984         if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2985                 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2986                 if (_measure_midi) {
2987                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2988                 } else {
2989                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2990                 }
2991                 lm_measure_label.set_text (_("Cancel"));
2992                 have_lm_results = false;
2993                 lm_use_button.set_sensitive (false);
2994                 lm_input_channel_combo.set_sensitive (false);
2995                 lm_output_channel_combo.set_sensitive (false);
2996                 lm_running = true;
2997         }
2998 }
2999
3000 void
3001 EngineControl::end_latency_detection ()
3002 {
3003         latency_timeout.disconnect ();
3004         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3005         lm_measure_label.set_text (_("Measure"));
3006         if (!have_lm_results) {
3007                 lm_use_button.set_sensitive (false);
3008         }
3009         lm_input_channel_combo.set_sensitive (true);
3010         lm_output_channel_combo.set_sensitive (true);
3011         lm_running = false;
3012 }
3013
3014 void
3015 EngineControl::latency_button_clicked ()
3016 {
3017         if (!lm_running) {
3018                 start_latency_detection ();
3019         } else {
3020                 end_latency_detection ();
3021         }
3022 }
3023
3024 void
3025 EngineControl::latency_back_button_clicked ()
3026 {
3027         ARDOUR::AudioEngine::instance()->stop(true);
3028         notebook.set_current_page(0);
3029 }
3030
3031 void
3032 EngineControl::use_latency_button_clicked ()
3033 {
3034         if (_measure_midi) {
3035                 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3036                 if (!mididm) {
3037                         return;
3038                 }
3039                 ARDOUR::framecnt_t frames_total = mididm->latency();
3040                 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3041                 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3042                 _measure_midi->input_latency = one_way;
3043                 _measure_midi->output_latency = one_way;
3044                 notebook.set_current_page (midi_tab);
3045         } else {
3046                 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3047
3048                 if (!mtdm) {
3049                         return;
3050                 }
3051
3052                 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3053                 one_way = std::max (0., one_way);
3054
3055                 input_latency_adjustment.set_value (one_way);
3056                 output_latency_adjustment.set_value (one_way);
3057
3058                 /* back to settings page */
3059                 notebook.set_current_page (0);
3060         }
3061 }
3062
3063 bool
3064 EngineControl::on_delete_event (GdkEventAny* ev)
3065 {
3066         if (notebook.get_current_page() == 2) {
3067                 /* currently on latency tab - be sure to clean up */
3068                 end_latency_detection ();
3069         }
3070         return ArdourDialog::on_delete_event (ev);
3071 }
3072
3073 void
3074 EngineControl::engine_running ()
3075 {
3076         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3077         assert (backend);
3078
3079         set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3080         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3081
3082         if (backend->can_set_period_size ()) {
3083                 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3084         }
3085
3086         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3087         connect_disconnect_button.show();
3088
3089         started_at_least_once = true;
3090         if (_have_control) {
3091                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3092         } else {
3093                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3094         }
3095         update_sensitivity();
3096 }
3097
3098 void
3099 EngineControl::engine_stopped ()
3100 {
3101         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3102         assert (backend);
3103
3104         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3105         connect_disconnect_button.show();
3106
3107         if (_have_control) {
3108                 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3109         } else {
3110                 engine_status.set_markup(X_(""));
3111         }
3112
3113         update_sensitivity();
3114 }
3115
3116 void
3117 EngineControl::device_list_changed ()
3118 {
3119         if (ignore_device_changes) {
3120                 return;
3121         }
3122         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3123         list_devices ();
3124         midi_option_changed();
3125 }
3126
3127 void
3128 EngineControl::connect_disconnect_click()
3129 {
3130         if (ARDOUR::AudioEngine::instance()->running()) {
3131                 stop_engine ();
3132         } else {
3133                 start_engine ();
3134         }
3135 }
3136
3137 void
3138 EngineControl::calibrate_audio_latency ()
3139 {
3140         _measure_midi.reset ();
3141         have_lm_results = false;
3142         lm_use_button.set_sensitive (false);
3143         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3144         notebook.set_current_page (latency_tab);
3145 }
3146
3147 void
3148 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3149 {
3150         _measure_midi = s;
3151         have_lm_results = false;
3152         lm_use_button.set_sensitive (false);
3153         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3154         notebook.set_current_page (latency_tab);
3155 }
3156
3157 void
3158 EngineControl::configure_midi_devices ()
3159 {
3160         notebook.set_current_page (midi_tab);
3161 }