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