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