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