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