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