refine "Running" message.
[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         , stop_engine_button (_("Stop (Reconfigure)"))
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         stop_engine_button.signal_clicked.connect (mem_fun (*this, &EngineControl::stop_engine_button_clicked));
273         stop_engine_button.set_sensitive (false);
274         stop_engine_button.set_name ("generic button");
275         stop_engine_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 (stop_engine_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         basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
611         row++;
612 }
613
614 void
615 EngineControl::build_no_control_notebook ()
616 {
617         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
618         assert (backend);
619
620         using namespace Notebook_Helpers;
621         Label* label;
622         vector<string> strings;
623         AttachOptions xopt = AttachOptions (FILL|EXPAND);
624         int row = 1; // row zero == backend combo
625         const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
626
627         label = manage (new Label);
628         label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
629         basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
630         row++;
631
632         if (backend->can_change_sample_rate_when_running()) {
633                 label = manage (left_aligned_label (_("Sample rate:")));
634                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
635                 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
636                 row++;
637         }
638
639         if (backend->can_change_buffer_size_when_running()) {
640                 label = manage (left_aligned_label (_("Buffer size:")));
641                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
642                 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
643                 buffer_size_duration_label.set_alignment (0.0); /* left-align */
644                 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
645                 row++;
646         }
647
648         basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
649         row++;
650 }
651
652 EngineControl::~EngineControl ()
653 {
654         ignore_changes = true;
655 }
656
657 void
658 EngineControl::disable_latency_tab ()
659 {
660         vector<string> empty;
661         set_popdown_strings (lm_output_channel_combo, empty);
662         set_popdown_strings (lm_input_channel_combo, empty);
663         lm_measure_button.set_sensitive (false);
664         lm_use_button.set_sensitive (false);
665 }
666
667 void
668 EngineControl::enable_latency_tab ()
669 {
670         vector<string> outputs;
671         vector<string> inputs;
672
673         ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
674         ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
675         ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
676
677         if (!ARDOUR::AudioEngine::instance()->running()) {
678                 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
679                 notebook.set_current_page (0);
680                 msg.run ();
681                 return;
682         }
683         else if (inputs.empty() || outputs.empty()) {
684                 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
685                 notebook.set_current_page (0);
686                 msg.run ();
687                 return;
688         }
689
690         lm_back_button_signal.disconnect();
691         if (_measure_midi) {
692                 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
693                 lm_preamble.hide ();
694         } else {
695                 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
696                 lm_preamble.show ();
697         }
698
699         set_popdown_strings (lm_output_channel_combo, outputs);
700         lm_output_channel_combo.set_active_text (outputs.front());
701         lm_output_channel_combo.set_sensitive (true);
702
703         set_popdown_strings (lm_input_channel_combo, inputs);
704         lm_input_channel_combo.set_active_text (inputs.front());
705         lm_input_channel_combo.set_sensitive (true);
706
707         lm_measure_button.set_sensitive (true);
708 }
709
710 void
711 EngineControl::setup_midi_tab_for_backend ()
712 {
713         string backend = backend_combo.get_active_text ();
714
715         Gtkmm2ext::container_clear (midi_vbox);
716
717         midi_vbox.set_border_width (12);
718         midi_device_table.set_border_width (12);
719
720         if (backend == "JACK") {
721                 setup_midi_tab_for_jack ();
722         }
723
724         midi_vbox.pack_start (midi_device_table, true, true);
725         midi_vbox.pack_start (midi_back_button, false, false);
726         midi_vbox.show_all ();
727 }
728
729 void
730 EngineControl::update_sensitivity ()
731 {
732         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
733         if (!backend) {
734                 ok_button->set_sensitive (false);
735                 apply_button->set_sensitive (false);
736                 stop_engine_button.set_sensitive (false);
737                 return;
738         }
739
740         bool valid = true;
741         size_t devices_available = 0;
742
743         if (backend->use_separate_input_and_output_devices ()) {
744                 devices_available += get_popdown_string_count (input_device_combo);
745                 devices_available += get_popdown_string_count (output_device_combo);
746         } else {
747                 devices_available += get_popdown_string_count (device_combo);
748         }
749
750         if (devices_available == 0) {
751                 valid = false;
752                 input_latency.set_sensitive (false);
753                 output_latency.set_sensitive (false);
754                 input_channels.set_sensitive (false);
755                 output_channels.set_sensitive (false);
756         } else {
757                 input_latency.set_sensitive (true);
758                 output_latency.set_sensitive (true);
759                 input_channels.set_sensitive (true);
760                 output_channels.set_sensitive (true);
761         }
762
763         if (get_popdown_string_count (buffer_size_combo) > 0) {
764                 if (!ARDOUR::AudioEngine::instance()->running()) {
765                         buffer_size_combo.set_sensitive (valid);
766                 } else if (backend->can_change_sample_rate_when_running()) {
767                         buffer_size_combo.set_sensitive (valid || !_have_control);
768                 } else {
769 #if 1
770                         /* TODO
771                          * Currently there is no way to manually stop the
772                          * engine in order to re-configure it.
773                          * This needs to remain sensitive for now.
774                          *
775                          * (it's also handy to implicily
776                          * re-start the engine)
777                          */
778                         buffer_size_combo.set_sensitive (true);
779 #else
780                         buffer_size_combo.set_sensitive (false);
781 #endif
782                 }
783         } else {
784                 buffer_size_combo.set_sensitive (false);
785                 valid = false;
786         }
787
788         if (get_popdown_string_count (sample_rate_combo) > 0) {
789                 if (!ARDOUR::AudioEngine::instance()->running()) {
790                         sample_rate_combo.set_sensitive (true);
791                 } else {
792                         sample_rate_combo.set_sensitive (false);
793                 }
794         } else {
795                 sample_rate_combo.set_sensitive (false);
796                 valid = false;
797         }
798
799         if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
800                 input_device_combo.set_sensitive (false);
801                 output_device_combo.set_sensitive (false);
802                 device_combo.set_sensitive (false);
803                 stop_engine_button.set_sensitive (true);
804                 stop_engine_button.show ();
805         } else {
806                 input_device_combo.set_sensitive (true);
807                 output_device_combo.set_sensitive (true);
808                 device_combo.set_sensitive (true);
809                 stop_engine_button.set_sensitive (false);
810                 stop_engine_button.hide ();
811         }
812
813         if (valid || !_have_control) {
814                 ok_button->set_sensitive (true);
815                 apply_button->set_sensitive (true);
816         } else {
817                 ok_button->set_sensitive (false);
818                 apply_button->set_sensitive (false);
819         }
820 }
821
822 void
823 EngineControl::setup_midi_tab_for_jack ()
824 {
825 }
826
827 void
828 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
829         if (for_input) {
830                 device->input_latency = a->get_value();
831         } else {
832                 device->output_latency = a->get_value();
833         }
834 }
835
836 void
837 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
838         b->set_active (!b->get_active());
839         device->enabled = b->get_active();
840         refresh_midi_display(device->name);
841 }
842
843 void
844 EngineControl::refresh_midi_display (std::string focus)
845 {
846         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
847         assert (backend);
848
849         int row  = 0;
850         AttachOptions xopt = AttachOptions (FILL|EXPAND);
851         Gtk::Label* l;
852
853         Gtkmm2ext::container_clear (midi_device_table);
854
855         midi_device_table.set_spacings (6);
856
857         l = manage (new Label);
858         l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
859         midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
860         l->set_alignment (0.5, 0.5);
861         row++;
862         l->show ();
863
864         l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
865         midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
866         l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
867         midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
868         row++;
869         l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
870         midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
871         l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
872         midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
873         row++;
874
875         for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
876                 ArdourButton *m;
877                 Gtk::Button* b;
878                 Gtk::Adjustment *a;
879                 Gtk::SpinButton *s;
880                 bool enabled = (*p)->enabled;
881
882                 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
883                 m->set_name ("midi device");
884                 m->set_can_focus (Gtk::CAN_FOCUS);
885                 m->add_events (Gdk::BUTTON_RELEASE_MASK);
886                 m->set_active (enabled);
887                 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
888                 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
889                 if ((*p)->name == focus) {
890                         m->grab_focus();
891                 }
892
893                 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
894                 s = manage (new Gtk::SpinButton (*a));
895                 a->set_value ((*p)->input_latency);
896                 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
897                 s->set_sensitive (_can_set_midi_latencies && enabled);
898                 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
899
900                 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
901                 s = manage (new Gtk::SpinButton (*a));
902                 a->set_value ((*p)->output_latency);
903                 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
904                 s->set_sensitive (_can_set_midi_latencies && enabled);
905                 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
906
907                 b = manage (new Button (_("Calibrate")));
908                 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
909                 b->set_sensitive (_can_set_midi_latencies && enabled);
910                 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
911
912                 row++;
913         }
914 }
915
916 void
917 EngineControl::backend_changed ()
918 {
919         SignalBlocker blocker (*this, "backend_changed");
920         string backend_name = backend_combo.get_active_text();
921         boost::shared_ptr<ARDOUR::AudioBackend> backend;
922
923         if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
924                 /* eh? setting the backend failed... how ? */
925                 /* A: stale config contains a backend that does not exist in current build */
926                 return;
927         }
928
929         DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
930
931         _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
932
933         build_notebook ();
934         setup_midi_tab_for_backend ();
935         _midi_devices.clear();
936
937         if (backend->requires_driver_selection()) {
938                 if (set_driver_popdown_strings ()) {
939                         driver_combo.set_sensitive (true);
940                         driver_changed ();
941                 }
942
943         } else {
944                 driver_combo.set_sensitive (false);
945                 /* this will change the device text which will cause a call to
946                  * device changed which will set up parameters
947                  */
948                 list_devices ();
949         }
950
951         update_midi_options ();
952
953         connect_disconnect_button.hide();
954
955         midi_option_changed();
956
957         started_at_least_once = false;
958
959         /* changing the backend implies stopping the engine
960          * ARDOUR::AudioEngine() may or may not emit this signal
961          * depending on previous engine state
962          */
963         engine_stopped (); // set "active/inactive"
964
965         if (!ignore_changes) {
966                 maybe_display_saved_state ();
967         }
968 }
969
970 void
971 EngineControl::update_midi_options ()
972 {
973         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
974         vector<string> midi_options = backend->enumerate_midi_options();
975
976         if (midi_options.size() == 1) {
977                 /* only contains the "none" option */
978                 midi_option_combo.set_sensitive (false);
979         } else {
980                 if (_have_control) {
981                         set_popdown_strings (midi_option_combo, midi_options);
982                         midi_option_combo.set_active_text (midi_options.front());
983                         midi_option_combo.set_sensitive (true);
984                 } else {
985                         midi_option_combo.set_sensitive (false);
986                 }
987         }
988 }
989
990 bool
991 EngineControl::print_channel_count (Gtk::SpinButton* sb)
992 {
993         if (ARDOUR::Profile->get_mixbus()) {
994                 return true;
995         }
996         
997         uint32_t cnt = (uint32_t) sb->get_value();
998         if (cnt == 0) {
999                 sb->set_text (_("all available channels"));
1000         } else {
1001                 char buf[32];
1002                 snprintf (buf, sizeof (buf), "%d", cnt);
1003                 sb->set_text (buf);
1004         }
1005         return true;
1006 }
1007
1008 // @return true if there are drivers available
1009 bool
1010 EngineControl::set_driver_popdown_strings ()
1011 {
1012         DEBUG_ECONTROL ("set_driver_popdown_strings");
1013         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1014         vector<string> drivers = backend->enumerate_drivers();
1015
1016         if (drivers.empty ()) {
1017                 // This is an error...?
1018                 return false;
1019         }
1020
1021         string current_driver = backend->driver_name ();
1022
1023         DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1024
1025         if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1026             drivers.end ()) {
1027
1028                 current_driver = drivers.front ();
1029         }
1030
1031         set_popdown_strings (driver_combo, drivers);
1032         DEBUG_ECONTROL (
1033             string_compose ("driver_combo.set_active_text: %1", current_driver));
1034         driver_combo.set_active_text (current_driver);
1035         return true;
1036 }
1037
1038 // @return true if there are devices available
1039 bool
1040 EngineControl::set_device_popdown_strings ()
1041 {
1042         DEBUG_ECONTROL ("set_device_popdown_strings");
1043         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1044         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1045
1046         /* NOTE: Ardour currently does not display the "available" field of the
1047          * returned devices.
1048          *
1049          * Doing so would require a different GUI widget than the combo
1050          * box/popdown that we currently use, since it has no way to list
1051          * items that are not selectable. Something more like a popup menu,
1052          * which could have unselectable items, would be appropriate.
1053          */
1054
1055         vector<string> available_devices;
1056
1057         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1058                 available_devices.push_back (i->name);
1059         }
1060
1061         if (available_devices.empty ()) {
1062                 return false;
1063         }
1064
1065         string current_device = backend->device_name ();
1066
1067         // Make sure that backend->device_name () is a valid
1068         // device, the backend may not return a valid device if it hasn't
1069         // been set yet.
1070         if (std::find (available_devices.begin (),
1071                        available_devices.end (),
1072                        current_device) == available_devices.end ()) {
1073
1074                 current_device = available_devices.front ();
1075         }
1076
1077         set_popdown_strings (device_combo, available_devices);
1078         DEBUG_ECONTROL (
1079             string_compose ("set device_combo active text: %1", current_device));
1080
1081         device_combo.set_active_text (current_device);
1082         return true;
1083 }
1084
1085 // @return true if there are input devices available
1086 bool
1087 EngineControl::set_input_device_popdown_strings ()
1088 {
1089         DEBUG_ECONTROL ("set_input_device_popdown_strings");
1090         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1091         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1092
1093         vector<string> available_devices;
1094
1095         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1096                 available_devices.push_back (i->name);
1097         }
1098
1099         if (available_devices.empty()) {
1100                 return false;
1101         }
1102
1103         string current_device = backend->input_device_name ();
1104
1105         // Make sure that backend->input_device_name () is a valid
1106         // device, the backend may not return a valid device if it hasn't
1107         // been set yet.
1108         if (std::find (available_devices.begin (),
1109                        available_devices.end (),
1110                        current_device) == available_devices.end ()) {
1111
1112                 current_device = available_devices.front ();
1113         }
1114
1115         set_popdown_strings (input_device_combo, available_devices);
1116
1117         DEBUG_ECONTROL (
1118             string_compose ("set input_device_combo active text: %1", current_device));
1119         input_device_combo.set_active_text (current_device);
1120         return true;
1121 }
1122
1123 // @return true if there are output devices available
1124 bool
1125 EngineControl::set_output_device_popdown_strings ()
1126 {
1127         DEBUG_ECONTROL ("set_output_device_popdown_strings");
1128         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1129         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1130
1131         vector<string> available_devices;
1132
1133         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1134                 available_devices.push_back (i->name);
1135         }
1136
1137         if (available_devices.empty()) {
1138                 return false;
1139         }
1140
1141         string current_device = backend->output_device_name ();
1142
1143         // Make sure that backend->output_device_name () is a valid
1144         // device, the backend may not return a valid device if it hasn't
1145         // been set yet.
1146         if (std::find (available_devices.begin (),
1147                        available_devices.end (),
1148                        current_device) == available_devices.end ()) {
1149
1150                 current_device = available_devices.front ();
1151         }
1152
1153         set_popdown_strings (output_device_combo, available_devices);
1154
1155         DEBUG_ECONTROL (
1156             string_compose ("set output_device_combo active text: %1", current_device));
1157         output_device_combo.set_active_text (current_device);
1158         return true;
1159 }
1160
1161 void
1162 EngineControl::list_devices ()
1163 {
1164         DEBUG_ECONTROL ("list_devices");
1165         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1166         assert (backend);
1167
1168         /* now fill out devices, mark sample rates, buffer sizes insensitive */
1169
1170         bool devices_available = false;
1171
1172         if (backend->use_separate_input_and_output_devices ()) {
1173                 bool input_devices_available = set_input_device_popdown_strings ();
1174                 bool output_devices_available = set_output_device_popdown_strings ();
1175                 devices_available = input_devices_available || output_devices_available;
1176         } else {
1177                 devices_available = set_device_popdown_strings ();
1178         }
1179
1180         if (devices_available) {
1181                 device_changed ();
1182         } else {
1183                 device_combo.clear();
1184                 input_device_combo.clear();
1185                 output_device_combo.clear();
1186         }
1187         update_sensitivity ();
1188 }
1189
1190 void
1191 EngineControl::driver_changed ()
1192 {
1193         SignalBlocker blocker (*this, "driver_changed");
1194         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1195         assert (backend);
1196
1197         backend->set_driver (driver_combo.get_active_text());
1198         list_devices ();
1199
1200         if (!ignore_changes) {
1201                 maybe_display_saved_state ();
1202         }
1203 }
1204
1205 vector<float>
1206 EngineControl::get_sample_rates_for_all_devices ()
1207 {
1208         boost::shared_ptr<ARDOUR::AudioBackend> backend =
1209             ARDOUR::AudioEngine::instance ()->current_backend ();
1210         vector<float> all_rates;
1211
1212         if (backend->use_separate_input_and_output_devices ()) {
1213                 all_rates = backend->available_sample_rates (get_input_device_name (), get_output_device_name ());
1214         } else {
1215                 all_rates = backend->available_sample_rates (get_device_name ());
1216         }
1217         return all_rates;
1218 }
1219
1220 vector<float>
1221 EngineControl::get_default_sample_rates ()
1222 {
1223         vector<float> rates;
1224         rates.push_back (8000.0f);
1225         rates.push_back (16000.0f);
1226         rates.push_back (32000.0f);
1227         rates.push_back (44100.0f);
1228         rates.push_back (48000.0f);
1229         rates.push_back (88200.0f);
1230         rates.push_back (96000.0f);
1231         rates.push_back (192000.0f);
1232         rates.push_back (384000.0f);
1233         return rates;
1234 }
1235
1236 void
1237 EngineControl::set_samplerate_popdown_strings ()
1238 {
1239         DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1240         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1241         string desired;
1242         vector<float> sr;
1243         vector<string> s;
1244
1245         if (_have_control) {
1246                 sr = get_sample_rates_for_all_devices ();
1247         } else {
1248                 sr = get_default_sample_rates ();
1249         }
1250
1251         for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1252                 s.push_back (rate_as_string (*x));
1253                 if (*x == _desired_sample_rate) {
1254                         desired = s.back();
1255                 }
1256         }
1257
1258         set_popdown_strings (sample_rate_combo, s);
1259
1260         if (!s.empty()) {
1261                 if (desired.empty ()) {
1262                         float new_active_sr = backend->default_sample_rate ();
1263
1264                         if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1265                                 new_active_sr = sr.front ();
1266                         }
1267
1268                         sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1269                 } else {
1270                         sample_rate_combo.set_active_text (desired);
1271                 }
1272
1273         }
1274         update_sensitivity ();
1275 }
1276
1277 vector<uint32_t>
1278 EngineControl::get_buffer_sizes_for_all_devices ()
1279 {
1280         boost::shared_ptr<ARDOUR::AudioBackend> backend =
1281             ARDOUR::AudioEngine::instance ()->current_backend ();
1282         vector<uint32_t> all_sizes;
1283
1284         if (backend->use_separate_input_and_output_devices ()) {
1285                 all_sizes = backend->available_buffer_sizes (get_input_device_name (), get_output_device_name ());
1286         } else {
1287                 all_sizes = backend->available_buffer_sizes (get_device_name ());
1288         }
1289         return all_sizes;
1290 }
1291
1292 vector<uint32_t>
1293 EngineControl::get_default_buffer_sizes ()
1294 {
1295         vector<uint32_t> sizes;
1296         sizes.push_back (8);
1297         sizes.push_back (16);
1298         sizes.push_back (32);
1299         sizes.push_back (64);
1300         sizes.push_back (128);
1301         sizes.push_back (256);
1302         sizes.push_back (512);
1303         sizes.push_back (1024);
1304         sizes.push_back (2048);
1305         sizes.push_back (4096);
1306         sizes.push_back (8192);
1307         return sizes;
1308 }
1309
1310 void
1311 EngineControl::set_buffersize_popdown_strings ()
1312 {
1313         DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1314         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1315         vector<uint32_t> bs;
1316         vector<string> s;
1317
1318         if (_have_control) {
1319                 bs = get_buffer_sizes_for_all_devices ();
1320         } else if (backend->can_change_buffer_size_when_running()) {
1321                 bs = get_default_buffer_sizes ();
1322         }
1323
1324         for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1325                 s.push_back (bufsize_as_string (*x));
1326         }
1327
1328         set_popdown_strings (buffer_size_combo, s);
1329
1330         if (!s.empty()) {
1331                 buffer_size_combo.set_active_text (s.front());
1332
1333                 uint32_t period = backend->buffer_size();
1334                 if (0 == period && backend->use_separate_input_and_output_devices ()) {
1335                         period = backend->default_buffer_size (get_input_device_name ());
1336                 }
1337                 if (0 == period && backend->use_separate_input_and_output_devices ()) {
1338                         period = backend->default_buffer_size (get_output_device_name ());
1339                 }
1340                 if (0 == period && !backend->use_separate_input_and_output_devices ()) {
1341                         period = backend->default_buffer_size (get_device_name ());
1342                 }
1343
1344                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1345                 show_buffer_duration ();
1346         }
1347         update_sensitivity ();
1348 }
1349
1350 void
1351 EngineControl::device_changed ()
1352 {
1353         SignalBlocker blocker (*this, "device_changed");
1354         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1355         assert (backend);
1356
1357         string device_name_in;
1358         string device_name_out; // only used if backend support separate I/O devices
1359
1360         if (backend->use_separate_input_and_output_devices()) {
1361                 device_name_in  = get_input_device_name ();
1362                 device_name_out = get_output_device_name ();
1363         } else {
1364                 device_name_in = get_device_name ();
1365         }
1366
1367         /* we set the backend-device to query various device related intormation.
1368          * This has the side effect that backend->device_name() will match
1369          * the device_name and  'change_device' will never be true.
1370          * so work around this by setting...
1371          */
1372         if (backend->use_separate_input_and_output_devices()) {
1373                 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1374                         queue_device_changed = true;
1375                 }
1376         } else {
1377                 if (device_name_in != backend->device_name()) {
1378                         queue_device_changed = true;
1379                 }
1380         }
1381         
1382         //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1383         if (backend->use_separate_input_and_output_devices()) {
1384                 backend->set_input_device_name (device_name_in);
1385                 backend->set_output_device_name (device_name_out);
1386         } else {
1387                 backend->set_device_name(device_name_in);
1388         }
1389
1390         {
1391                 /* don't allow programmatic change to combos to cause a
1392                    recursive call to this method.
1393                  */
1394                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1395
1396                 set_samplerate_popdown_strings ();
1397                 set_buffersize_popdown_strings ();
1398
1399                 /* TODO set min + max channel counts here */
1400
1401                 manage_control_app_sensitivity ();
1402         }
1403
1404         /* pick up any saved state for this device */
1405
1406         if (!ignore_changes) {
1407                 maybe_display_saved_state ();
1408         }
1409 }
1410
1411 void
1412 EngineControl::input_device_changed ()
1413 {
1414         DEBUG_ECONTROL ("input_device_changed");
1415         device_changed ();
1416 }
1417
1418 void
1419 EngineControl::output_device_changed ()
1420 {
1421         DEBUG_ECONTROL ("output_device_changed");
1422         device_changed ();
1423 }
1424
1425 string
1426 EngineControl::bufsize_as_string (uint32_t sz)
1427 {
1428         /* Translators: "samples" is always plural here, so no
1429            need for plural+singular forms.
1430          */
1431         char buf[64];
1432         snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1433         return buf;
1434 }
1435
1436 void
1437 EngineControl::sample_rate_changed ()
1438 {
1439         DEBUG_ECONTROL ("sample_rate_changed");
1440         /* reset the strings for buffer size to show the correct msec value
1441            (reflecting the new sample rate).
1442          */
1443
1444         show_buffer_duration ();
1445
1446 }
1447
1448 void
1449 EngineControl::buffer_size_changed ()
1450 {
1451         DEBUG_ECONTROL ("buffer_size_changed");
1452         show_buffer_duration ();
1453 }
1454
1455 void
1456 EngineControl::show_buffer_duration ()
1457 {
1458         DEBUG_ECONTROL ("show_buffer_duration");
1459         /* buffer sizes  - convert from just samples to samples + msecs for
1460          * the displayed string
1461          */
1462
1463         string bs_text = buffer_size_combo.get_active_text ();
1464         uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1465         uint32_t rate = get_rate();
1466
1467         /* Developers: note the hard-coding of a double buffered model
1468            in the (2 * samples) computation of latency. we always start
1469            the audiobackend in this configuration.
1470          */
1471         /* note to jack1 developers: ardour also always starts the engine
1472          * in async mode (no jack2 --sync option) which adds an extra cycle
1473          * of latency with jack2 (and *3 would be correct)
1474          * The value can also be wrong if jackd is started externally..
1475          *
1476          * At the time of writing the ALSA backend always uses double-buffering *2,
1477          * The Dummy backend *1, and who knows what ASIO really does :)
1478          *
1479          * So just display the period size, that's also what
1480          * ARDOUR_UI::update_sample_rate() does for the status bar.
1481          * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1482          * but still, that's the buffer period, not [round-trip] latency)
1483          */
1484         char buf[32];
1485         snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1486         buffer_size_duration_label.set_text (buf);
1487 }
1488
1489 void
1490 EngineControl::midi_option_changed ()
1491 {
1492         DEBUG_ECONTROL ("midi_option_changed");
1493         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1494         assert (backend);
1495
1496         backend->set_midi_option (get_midi_option());
1497
1498         vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1499
1500         //_midi_devices.clear(); // TODO merge with state-saved settings..
1501         _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1502         std::vector<MidiDeviceSettings> new_devices;
1503
1504         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1505                 MidiDeviceSettings mds = find_midi_device (i->name);
1506                 if (i->available && !mds) {
1507                         uint32_t input_latency = 0;
1508                         uint32_t output_latency = 0;
1509                         if (_can_set_midi_latencies) {
1510                                 input_latency = backend->systemic_midi_input_latency (i->name);
1511                                 output_latency = backend->systemic_midi_output_latency (i->name);
1512                         }
1513                         bool enabled = backend->midi_device_enabled (i->name);
1514                         MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1515                         new_devices.push_back (ptr);
1516                 } else if (i->available) {
1517                         new_devices.push_back (mds);
1518                 }
1519         }
1520         _midi_devices = new_devices;
1521
1522         if (_midi_devices.empty()) {
1523                 midi_devices_button.set_sensitive (false);
1524         } else {
1525                 midi_devices_button.set_sensitive (true);
1526         }
1527 }
1528
1529 void
1530 EngineControl::parameter_changed ()
1531 {
1532 }
1533
1534 EngineControl::State
1535 EngineControl::get_matching_state (
1536                 const string& backend,
1537                 const string& driver,
1538                 const string& device)
1539 {
1540         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1541                 if ((*i)->backend == backend &&
1542                                 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1543                 {
1544                         return (*i);
1545                 }
1546         }
1547         return State();
1548 }
1549
1550 EngineControl::State
1551 EngineControl::get_matching_state (
1552                 const string& backend,
1553                 const string& driver,
1554                 const string& input_device,
1555                 const string& output_device)
1556 {
1557         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1558                 if ((*i)->backend == backend &&
1559                                 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1560                 {
1561                         return (*i);
1562                 }
1563         }
1564         return State();
1565 }
1566
1567 EngineControl::State
1568 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1569 {
1570         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1571
1572         if (backend) {
1573                 if (backend->use_separate_input_and_output_devices ()) {
1574                         return get_matching_state (backend_combo.get_active_text(),
1575                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1576                                         input_device_combo.get_active_text(),
1577                                         output_device_combo.get_active_text());
1578                 } else {
1579                         return get_matching_state (backend_combo.get_active_text(),
1580                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1581                                         device_combo.get_active_text());
1582                 }
1583         }
1584
1585         return get_matching_state (backend_combo.get_active_text(),
1586                         string(),
1587                         device_combo.get_active_text());
1588 }
1589
1590 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1591                                        const EngineControl::State& state2)
1592 {
1593         if (state1->backend == state2->backend &&
1594                         state1->driver == state2->driver &&
1595                         state1->device == state2->device &&
1596                         state1->input_device == state2->input_device &&
1597                         state1->output_device == state2->output_device) {
1598                 return true;
1599         }
1600         return false;
1601 }
1602
1603 EngineControl::State
1604 EngineControl::save_state ()
1605 {
1606         State state;
1607
1608         if (!_have_control) {
1609                 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1610                 if (state) {
1611                         return state;
1612                 }
1613                 state.reset(new StateStruct);
1614                 state->backend = get_backend ();
1615         } else {
1616                 state.reset(new StateStruct);
1617                 store_state (state);
1618         }
1619
1620         for (StateList::iterator i = states.begin(); i != states.end();) {
1621                 if (equivalent_states (*i, state)) {
1622                         i =  states.erase(i);
1623                 } else {
1624                         ++i;
1625                 }
1626         }
1627
1628         states.push_back (state);
1629
1630         return state;
1631 }
1632
1633 void
1634 EngineControl::store_state (State state)
1635 {
1636         state->backend = get_backend ();
1637         state->driver = get_driver ();
1638         state->device = get_device_name ();
1639         state->input_device = get_input_device_name ();
1640         state->output_device = get_output_device_name ();
1641         state->sample_rate = get_rate ();
1642         state->buffer_size = get_buffer_size ();
1643         state->input_latency = get_input_latency ();
1644         state->output_latency = get_output_latency ();
1645         state->input_channels = get_input_channels ();
1646         state->output_channels = get_output_channels ();
1647         state->midi_option = get_midi_option ();
1648         state->midi_devices = _midi_devices;
1649 }
1650
1651 void
1652 EngineControl::maybe_display_saved_state ()
1653 {
1654         if (!_have_control) {
1655                 return;
1656         }
1657
1658         State state = get_saved_state_for_currently_displayed_backend_and_device ();
1659
1660         if (state) {
1661                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1662
1663                 if (!_desired_sample_rate) {
1664                         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1665                 }
1666                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1667                 /* call this explicitly because we're ignoring changes to
1668                    the controls at this point.
1669                  */
1670                 show_buffer_duration ();
1671                 input_latency.set_value (state->input_latency);
1672                 output_latency.set_value (state->output_latency);
1673
1674                 if (!state->midi_option.empty()) {
1675                         midi_option_combo.set_active_text (state->midi_option);
1676                         _midi_devices = state->midi_devices;
1677                 }
1678         }
1679 }
1680
1681 XMLNode&
1682 EngineControl::get_state ()
1683 {
1684         LocaleGuard lg (X_("C"));
1685
1686         XMLNode* root = new XMLNode ("AudioMIDISetup");
1687         std::string path;
1688
1689         if (!states.empty()) {
1690                 XMLNode* state_nodes = new XMLNode ("EngineStates");
1691
1692                 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1693
1694                         XMLNode* node = new XMLNode ("State");
1695
1696                         node->add_property ("backend", (*i)->backend);
1697                         node->add_property ("driver", (*i)->driver);
1698                         node->add_property ("device", (*i)->device);
1699                         node->add_property ("input-device", (*i)->input_device);
1700                         node->add_property ("output-device", (*i)->output_device);
1701                         node->add_property ("sample-rate", (*i)->sample_rate);
1702                         node->add_property ("buffer-size", (*i)->buffer_size);
1703                         node->add_property ("input-latency", (*i)->input_latency);
1704                         node->add_property ("output-latency", (*i)->output_latency);
1705                         node->add_property ("input-channels", (*i)->input_channels);
1706                         node->add_property ("output-channels", (*i)->output_channels);
1707                         node->add_property ("active", (*i)->active ? "yes" : "no");
1708                         node->add_property ("midi-option", (*i)->midi_option);
1709
1710                         XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1711                         for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1712                                 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1713                                 midi_device_stuff->add_property (X_("name"), (*p)->name);
1714                                 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1715                                 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1716                                 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1717                                 midi_devices->add_child_nocopy (*midi_device_stuff);
1718                         }
1719                         node->add_child_nocopy (*midi_devices);
1720
1721                         state_nodes->add_child_nocopy (*node);
1722                 }
1723
1724                 root->add_child_nocopy (*state_nodes);
1725         }
1726
1727         return *root;
1728 }
1729
1730 void
1731 EngineControl::set_default_state ()
1732 {
1733         vector<string> backend_names;
1734         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1735
1736         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1737                 backend_names.push_back ((*b)->name);
1738         }
1739         backend_combo.set_active_text (backend_names.front());
1740
1741         // We could set default backends per platform etc here
1742
1743         backend_changed ();
1744 }
1745
1746 bool
1747 EngineControl::set_state (const XMLNode& root)
1748 {
1749         XMLNodeList          clist, cclist;
1750         XMLNodeConstIterator citer, cciter;
1751         XMLNode* child;
1752         XMLNode* grandchild;
1753         XMLProperty* prop = NULL;
1754
1755         fprintf (stderr, "EngineControl::set_state\n");
1756
1757         if (root.name() != "AudioMIDISetup") {
1758                 return false;
1759         }
1760
1761         clist = root.children();
1762
1763         states.clear ();
1764
1765         for (citer = clist.begin(); citer != clist.end(); ++citer) {
1766
1767                 child = *citer;
1768
1769                 if (child->name() != "EngineStates") {
1770                         continue;
1771                 }
1772
1773                 cclist = child->children();
1774
1775                 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1776                         State state (new StateStruct);
1777
1778                         grandchild = *cciter;
1779
1780                         if (grandchild->name() != "State") {
1781                                 continue;
1782                         }
1783
1784                         if ((prop = grandchild->property ("backend")) == 0) {
1785                                 continue;
1786                         }
1787                         state->backend = prop->value ();
1788
1789                         if ((prop = grandchild->property ("driver")) == 0) {
1790                                 continue;
1791                         }
1792                         state->driver = prop->value ();
1793
1794                         if ((prop = grandchild->property ("device")) == 0) {
1795                                 continue;
1796                         }
1797                         state->device = prop->value ();
1798
1799                         if ((prop = grandchild->property ("input-device")) == 0) {
1800                                 continue;
1801                         }
1802                         state->input_device = prop->value ();
1803
1804                         if ((prop = grandchild->property ("output-device")) == 0) {
1805                                 continue;
1806                         }
1807                         state->output_device = prop->value ();
1808
1809                         if ((prop = grandchild->property ("sample-rate")) == 0) {
1810                                 continue;
1811                         }
1812                         state->sample_rate = atof (prop->value ());
1813
1814                         if ((prop = grandchild->property ("buffer-size")) == 0) {
1815                                 continue;
1816                         }
1817                         state->buffer_size = atoi (prop->value ());
1818
1819                         if ((prop = grandchild->property ("input-latency")) == 0) {
1820                                 continue;
1821                         }
1822                         state->input_latency = atoi (prop->value ());
1823
1824                         if ((prop = grandchild->property ("output-latency")) == 0) {
1825                                 continue;
1826                         }
1827                         state->output_latency = atoi (prop->value ());
1828
1829                         if ((prop = grandchild->property ("input-channels")) == 0) {
1830                                 continue;
1831                         }
1832                         state->input_channels = atoi (prop->value ());
1833
1834                         if ((prop = grandchild->property ("output-channels")) == 0) {
1835                                 continue;
1836                         }
1837                         state->output_channels = atoi (prop->value ());
1838
1839                         if ((prop = grandchild->property ("active")) == 0) {
1840                                 continue;
1841                         }
1842                         state->active = string_is_affirmative (prop->value ());
1843
1844                         if ((prop = grandchild->property ("midi-option")) == 0) {
1845                                 continue;
1846                         }
1847                         state->midi_option = prop->value ();
1848
1849                         state->midi_devices.clear();
1850                         XMLNode* midinode;
1851                         if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1852                                 const XMLNodeList mnc = midinode->children();
1853                                 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1854                                         if ((*n)->property (X_("name")) == 0
1855                                                         || (*n)->property (X_("enabled")) == 0
1856                                                         || (*n)->property (X_("input-latency")) == 0
1857                                                         || (*n)->property (X_("output-latency")) == 0
1858                                                  ) {
1859                                                 continue;
1860                                         }
1861
1862                                         MidiDeviceSettings ptr (new MidiDeviceSetting(
1863                                                                 (*n)->property (X_("name"))->value (),
1864                                                                 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1865                                                                 atoi ((*n)->property (X_("input-latency"))->value ()),
1866                                                                 atoi ((*n)->property (X_("output-latency"))->value ())
1867                                                                 ));
1868                                         state->midi_devices.push_back (ptr);
1869                                 }
1870                         }
1871
1872 #if 1
1873                         /* remove accumulated duplicates (due to bug in ealier version)
1874                          * this can be removed again before release
1875                          */
1876                         for (StateList::iterator i = states.begin(); i != states.end();) {
1877                                 if ((*i)->backend == state->backend &&
1878                                                 (*i)->driver == state->driver &&
1879                                                 (*i)->device == state->device) {
1880                                         i =  states.erase(i);
1881                                 } else {
1882                                         ++i;
1883                                 }
1884                         }
1885 #endif
1886
1887                         states.push_back (state);
1888                 }
1889         }
1890
1891         /* now see if there was an active state and switch the setup to it */
1892
1893         // purge states of backend that are not available in this built
1894         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1895         vector<std::string> backend_names;
1896
1897         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1898                 backend_names.push_back((*i)->name);
1899         }
1900         for (StateList::iterator i = states.begin(); i != states.end();) {
1901                 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1902                         i = states.erase(i);
1903                 } else {
1904                         ++i;
1905                 }
1906         }
1907
1908         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1909
1910                 if ((*i)->active) {
1911                         return set_current_state (*i);
1912                 }
1913         }
1914         return false;
1915 }
1916
1917 bool
1918 EngineControl::set_current_state (const State& state)
1919 {
1920         DEBUG_ECONTROL ("set_current_state");
1921
1922         boost::shared_ptr<ARDOUR::AudioBackend> backend;
1923
1924         if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1925                   state->backend, "ardour", ""))) {
1926                 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1927                 // this shouldn't happen as the invalid backend names should have been
1928                 // removed from the list of states.
1929                 return false;
1930         }
1931
1932         // now reflect the change in the backend in the GUI so backend_changed will
1933         // do the right thing
1934         backend_combo.set_active_text (state->backend);
1935
1936         if (!state->driver.empty ()) {
1937                 if (!backend->requires_driver_selection ()) {
1938                         DEBUG_ECONTROL ("Backend should require driver selection");
1939                         // A backend has changed from having driver selection to not having
1940                         // it or someone has been manually editing a config file and messed
1941                         // it up
1942                         return false;
1943                 }
1944
1945                 if (backend->set_driver (state->driver) != 0) {
1946                         DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
1947                         // Driver names for a backend have changed and the name in the
1948                         // config file is now invalid or support for driver is no longer
1949                         // included in the backend
1950                         return false;
1951                 }
1952                 // no need to set the driver_combo as backend_changed will use
1953                 // backend->driver_name to set the active driver
1954         }
1955
1956         if (!state->device.empty ()) {
1957                 if (backend->set_device_name (state->device) != 0) {
1958                         DEBUG_ECONTROL (
1959                             string_compose ("Unable to set device name %1", state->device));
1960                         // device is no longer available on the system
1961                         return false;
1962                 }
1963                 // no need to set active device as it will be picked up in
1964                 // via backend_changed ()/set_device_popdown_strings
1965
1966         } else {
1967                 // backend supports separate input/output devices
1968                 if (backend->set_input_device_name (state->input_device) != 0) {
1969                         DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
1970                                                         state->input_device));
1971                         // input device is no longer available on the system
1972                         return false;
1973                 }
1974
1975                 if (backend->set_output_device_name (state->output_device) != 0) {
1976                         DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
1977                                                         state->input_device));
1978                         // output device is no longer available on the system
1979                         return false;
1980                 }
1981                 // no need to set active devices as it will be picked up in via
1982                 // backend_changed ()/set_*_device_popdown_strings
1983         }
1984
1985         backend_changed ();
1986
1987         // Now restore the state of the rest of the controls
1988
1989         // We don't use a SignalBlocker as set_current_state is currently only
1990         // called from set_state before any signals are connected. If at some point
1991         // a more general named state mechanism is implemented and
1992         // set_current_state is called while signals are connected then a
1993         // SignalBlocker will need to be instantiated before setting these.
1994
1995         device_combo.set_active_text (state->device);
1996         input_device_combo.set_active_text (state->input_device);
1997         output_device_combo.set_active_text (state->output_device);
1998         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1999         set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2000         input_latency.set_value (state->input_latency);
2001         output_latency.set_value (state->output_latency);
2002         midi_option_combo.set_active_text (state->midi_option);
2003         return true;
2004 }
2005
2006 int
2007 EngineControl::push_state_to_backend (bool start)
2008 {
2009         DEBUG_ECONTROL ("push_state_to_backend");
2010         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2011
2012         if (!backend) {
2013                 return 0;
2014         }
2015
2016         /* figure out what is going to change */
2017
2018         bool restart_required = false;
2019         bool was_running = ARDOUR::AudioEngine::instance()->running();
2020         bool change_driver = false;
2021         bool change_device = false;
2022         bool change_rate = false;
2023         bool change_bufsize = false;
2024         bool change_latency = false;
2025         bool change_channels = false;
2026         bool change_midi = false;
2027
2028         uint32_t ochan = get_output_channels ();
2029         uint32_t ichan = get_input_channels ();
2030
2031         if (_have_control) {
2032
2033                 if (started_at_least_once) {
2034
2035                         /* we can control the backend */
2036
2037                         if (backend->requires_driver_selection()) {
2038                                 if (get_driver() != backend->driver_name()) {
2039                                         change_driver = true;
2040                                 }
2041                         }
2042
2043                         if (backend->use_separate_input_and_output_devices()) {
2044                                 if (get_input_device_name() != backend->input_device_name()) {
2045                                         change_device = true;
2046                                 }
2047                                 if (get_output_device_name() != backend->output_device_name()) {
2048                                         change_device = true;
2049                                 }
2050                         } else {
2051                                 if (get_device_name() != backend->device_name()) {
2052                                         change_device = true;
2053                                 }
2054                         }
2055
2056                         if (queue_device_changed) {
2057                                 change_device = true;
2058                         }
2059
2060                         if (get_rate() != backend->sample_rate()) {
2061                                 change_rate = true;
2062                         }
2063
2064                         if (get_buffer_size() != backend->buffer_size()) {
2065                                 change_bufsize = true;
2066                         }
2067
2068                         if (get_midi_option() != backend->midi_option()) {
2069                                 change_midi = true;
2070                         }
2071
2072                         /* zero-requested channels means "all available" */
2073
2074                         if (ichan == 0) {
2075                                 ichan = backend->input_channels();
2076                         }
2077
2078                         if (ochan == 0) {
2079                                 ochan = backend->output_channels();
2080                         }
2081
2082                         if (ichan != backend->input_channels()) {
2083                                 change_channels = true;
2084                         }
2085
2086                         if (ochan != backend->output_channels()) {
2087                                 change_channels = true;
2088                         }
2089
2090                         if (get_input_latency() != backend->systemic_input_latency() ||
2091                                         get_output_latency() != backend->systemic_output_latency()) {
2092                                 change_latency = true;
2093                         }
2094                 } else {
2095                         /* backend never started, so we have to force a group
2096                            of settings.
2097                          */
2098                         change_device = true;
2099                         if (backend->requires_driver_selection()) {
2100                                 change_driver = true;
2101                         }
2102                         change_rate = true;
2103                         change_bufsize = true;
2104                         change_channels = true;
2105                         change_latency = true;
2106                         change_midi = true;
2107                 }
2108
2109         } else {
2110
2111                 /* we have no control over the backend, meaning that we can
2112                  * only possibly change sample rate and buffer size.
2113                  */
2114
2115
2116                 if (get_rate() != backend->sample_rate()) {
2117                         change_bufsize = true;
2118                 }
2119
2120                 if (get_buffer_size() != backend->buffer_size()) {
2121                         change_bufsize = true;
2122                 }
2123         }
2124
2125         queue_device_changed = false;
2126
2127         if (!_have_control) {
2128
2129                 /* We do not have control over the backend, so the best we can
2130                  * do is try to change the sample rate and/or bufsize and get
2131                  * out of here.
2132                  */
2133
2134                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2135                         return 1;
2136                 }
2137
2138                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2139                         return 1;
2140                 }
2141
2142                 if (change_rate) {
2143                         backend->set_sample_rate (get_rate());
2144                 }
2145
2146                 if (change_bufsize) {
2147                         backend->set_buffer_size (get_buffer_size());
2148                 }
2149
2150                 if (start) {
2151                         if (ARDOUR::AudioEngine::instance()->start ()) {
2152                                 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2153                                 return -1;
2154                         }
2155                 }
2156
2157                 post_push ();
2158
2159                 return 0;
2160         }
2161
2162         /* determine if we need to stop the backend before changing parameters */
2163
2164         if (change_driver || change_device || change_channels || change_latency ||
2165                         (change_rate && !backend->can_change_sample_rate_when_running()) ||
2166                         change_midi ||
2167                         (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2168                 restart_required = true;
2169         } else {
2170                 restart_required = false;
2171         }
2172
2173         if (was_running) {
2174
2175                 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2176                         /* no changes in any parameters that absolutely require a
2177                          * restart, so check those that might be changeable without a
2178                          * restart
2179                          */
2180
2181                         if (change_rate && !backend->can_change_sample_rate_when_running()) {
2182                                 /* can't do this while running ... */
2183                                 restart_required = true;
2184                         }
2185
2186                         if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2187                                 /* can't do this while running ... */
2188                                 restart_required = true;
2189                         }
2190                 }
2191         }
2192
2193         if (was_running) {
2194                 if (restart_required) {
2195                         if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2196                                 return -1;
2197                         }
2198                 }
2199         }
2200
2201
2202         if (change_driver && backend->set_driver (get_driver())) {
2203                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2204                 return -1;
2205         }
2206         if (backend->use_separate_input_and_output_devices()) {
2207                 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2208                         error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2209                         return -1;
2210                 }
2211                 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2212                         error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2213                         return -1;
2214                 }
2215         } else {
2216                 if (change_device && backend->set_device_name (get_device_name())) {
2217                         error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2218                         return -1;
2219                 }
2220         }
2221         if (change_rate && backend->set_sample_rate (get_rate())) {
2222                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2223                 return -1;
2224         }
2225         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2226                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2227                 return -1;
2228         }
2229
2230         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2231                 if (backend->set_input_channels (get_input_channels())) {
2232                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2233                         return -1;
2234                 }
2235                 if (backend->set_output_channels (get_output_channels())) {
2236                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2237                         return -1;
2238                 }
2239         }
2240         if (change_latency) {
2241                 if (backend->set_systemic_input_latency (get_input_latency())) {
2242                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2243                         return -1;
2244                 }
2245                 if (backend->set_systemic_output_latency (get_output_latency())) {
2246                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2247                         return -1;
2248                 }
2249         }
2250
2251         if (change_midi) {
2252                 backend->set_midi_option (get_midi_option());
2253         }
2254
2255         if (1 /* TODO */) {
2256                 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2257                         if (_measure_midi) {
2258                                 if (*p == _measure_midi) {
2259                                         backend->set_midi_device_enabled ((*p)->name, true);
2260                                 } else {
2261                                         backend->set_midi_device_enabled ((*p)->name, false);
2262                                 }
2263                                 continue;
2264                         }
2265                         backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2266                         if (backend->can_set_systemic_midi_latencies()) {
2267                                 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2268                                 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2269                         }
2270                 }
2271         }
2272
2273         if (start || (was_running && restart_required)) {
2274                 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2275                         return -1;
2276                 }
2277         }
2278
2279         post_push ();
2280
2281         return 0;
2282 }
2283
2284 void
2285 EngineControl::post_push ()
2286 {
2287         /* get a pointer to the current state object, creating one if
2288          * necessary
2289          */
2290
2291         State state = get_saved_state_for_currently_displayed_backend_and_device ();
2292
2293         if (!state) {
2294                 state = save_state ();
2295                 assert (state);
2296         } else {
2297                 store_state(state);
2298         }
2299
2300         /* all off */
2301
2302         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2303                 (*i)->active = false;
2304         }
2305
2306         /* mark this one active (to be used next time the dialog is
2307          * shown)
2308          */
2309
2310         state->active = true;
2311
2312         if (_have_control) { // XXX
2313                 manage_control_app_sensitivity ();
2314         }
2315
2316         /* schedule a redisplay of MIDI ports */
2317         //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2318 }
2319
2320
2321 float
2322 EngineControl::get_rate () const
2323 {
2324         float r = atof (sample_rate_combo.get_active_text ());
2325         /* the string may have been translated with an abbreviation for
2326          * thousands, so use a crude heuristic to fix this.
2327          */
2328         if (r < 1000.0) {
2329                 r *= 1000.0;
2330         }
2331         return r;
2332 }
2333
2334
2335 uint32_t
2336 EngineControl::get_buffer_size () const
2337 {
2338         string txt = buffer_size_combo.get_active_text ();
2339         uint32_t samples;
2340
2341         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2342                 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2343                 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2344                 throw exception ();
2345         }
2346
2347         return samples;
2348 }
2349
2350 string
2351 EngineControl::get_midi_option () const
2352 {
2353         return midi_option_combo.get_active_text();
2354 }
2355
2356 uint32_t
2357 EngineControl::get_input_channels() const
2358 {
2359         if (ARDOUR::Profile->get_mixbus()) {
2360                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2361                 if (!backend) return 0;
2362                 return backend->input_channels();
2363         }
2364         return (uint32_t) input_channels_adjustment.get_value();
2365 }
2366
2367 uint32_t
2368 EngineControl::get_output_channels() const
2369 {
2370         if (ARDOUR::Profile->get_mixbus()) {
2371                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2372                 if (!backend) return 0;
2373                 return backend->input_channels();
2374         }
2375         return (uint32_t) output_channels_adjustment.get_value();
2376 }
2377
2378 uint32_t
2379 EngineControl::get_input_latency() const
2380 {
2381         return (uint32_t) input_latency_adjustment.get_value();
2382 }
2383
2384 uint32_t
2385 EngineControl::get_output_latency() const
2386 {
2387         return (uint32_t) output_latency_adjustment.get_value();
2388 }
2389
2390 string
2391 EngineControl::get_backend () const
2392 {
2393         return backend_combo.get_active_text ();
2394 }
2395
2396 string
2397 EngineControl::get_driver () const
2398 {
2399         if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2400                 return driver_combo.get_active_text ();
2401         } else {
2402                 return "";
2403         }
2404 }
2405
2406 string
2407 EngineControl::get_device_name () const
2408 {
2409         return device_combo.get_active_text ();
2410 }
2411
2412 string
2413 EngineControl::get_input_device_name () const
2414 {
2415         return input_device_combo.get_active_text ();
2416 }
2417
2418 string
2419 EngineControl::get_output_device_name () const
2420 {
2421         return output_device_combo.get_active_text ();
2422 }
2423
2424 void
2425 EngineControl::control_app_button_clicked ()
2426 {
2427         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2428
2429         if (!backend) {
2430                 return;
2431         }
2432
2433         backend->launch_control_app ();
2434 }
2435
2436 void
2437 EngineControl::stop_engine_button_clicked ()
2438 {
2439         ARDOUR::AudioEngine::instance()->stop ();
2440 }
2441
2442 void
2443 EngineControl::manage_control_app_sensitivity ()
2444 {
2445         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2446
2447         if (!backend) {
2448                 return;
2449         }
2450
2451         string appname = backend->control_app_name();
2452
2453         if (appname.empty()) {
2454                 control_app_button.set_sensitive (false);
2455         } else {
2456                 control_app_button.set_sensitive (true);
2457         }
2458 }
2459
2460 void
2461 EngineControl::set_desired_sample_rate (uint32_t sr)
2462 {
2463         _desired_sample_rate = sr;
2464         device_changed ();
2465 }
2466
2467 void
2468 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2469 {
2470         if (page_num == 0) {
2471                 cancel_button->set_sensitive (true);
2472                 _measure_midi.reset();
2473                 update_sensitivity ();
2474         } else {
2475                 cancel_button->set_sensitive (false);
2476                 ok_button->set_sensitive (false);
2477                 apply_button->set_sensitive (false);
2478         }
2479
2480         if (page_num == midi_tab) {
2481                 /* MIDI tab */
2482                 refresh_midi_display ();
2483         }
2484
2485         if (page_num == latency_tab) {
2486                 /* latency tab */
2487
2488                 if (ARDOUR::AudioEngine::instance()->running()) {
2489                         // TODO - mark as 'stopped for latency
2490                         ARDOUR_UI::instance()->disconnect_from_engine ();
2491                 }
2492
2493                 {
2494                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2495
2496                         /* save any existing latency values */
2497
2498                         uint32_t il = (uint32_t) input_latency.get_value ();
2499                         uint32_t ol = (uint32_t) input_latency.get_value ();
2500
2501                         /* reset to zero so that our new test instance
2502                            will be clean of any existing latency measures.
2503
2504                            NB. this should really be done by the backend
2505                            when stated for latency measurement.
2506                         */
2507
2508                         input_latency.set_value (0);
2509                         output_latency.set_value (0);
2510
2511                         push_state_to_backend (false);
2512
2513                         /* reset control */
2514
2515                         input_latency.set_value (il);
2516                         output_latency.set_value (ol);
2517
2518                 }
2519                 // This should be done in push_state_to_backend()
2520                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2521                         disable_latency_tab ();
2522                 }
2523
2524                 enable_latency_tab ();
2525
2526         } else {
2527                 if (lm_running) {
2528                         end_latency_detection ();
2529                         ARDOUR::AudioEngine::instance()->stop_latency_detection();
2530                 }
2531         }
2532 }
2533
2534 /* latency measurement */
2535
2536 bool
2537 EngineControl::check_audio_latency_measurement ()
2538 {
2539         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2540
2541         if (mtdm->resolve () < 0) {
2542                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2543                 return true;
2544         }
2545
2546         if (mtdm->err () > 0.3) {
2547                 mtdm->invert ();
2548                 mtdm->resolve ();
2549         }
2550
2551         char buf[256];
2552         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2553
2554         if (sample_rate == 0) {
2555                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2556                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2557                 return false;
2558         }
2559
2560         int frames_total = mtdm->del();
2561         int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2562
2563         snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2564                         _("Detected roundtrip latency: "),
2565                         frames_total, frames_total * 1000.0f/sample_rate,
2566                         _("Systemic latency: "),
2567                         extra, extra * 1000.0f/sample_rate);
2568
2569         bool solid = true;
2570
2571         if (mtdm->err () > 0.2) {
2572                 strcat (buf, " ");
2573                 strcat (buf, _("(signal detection error)"));
2574                 solid = false;
2575         }
2576
2577         if (mtdm->inv ()) {
2578                 strcat (buf, " ");
2579                 strcat (buf, _("(inverted - bad wiring)"));
2580                 solid = false;
2581         }
2582
2583         lm_results.set_markup (string_compose (results_markup, buf));
2584
2585         if (solid) {
2586                 have_lm_results = true;
2587                 end_latency_detection ();
2588                 lm_use_button.set_sensitive (true);
2589                 return false;
2590         }
2591
2592         return true;
2593 }
2594
2595 bool
2596 EngineControl::check_midi_latency_measurement ()
2597 {
2598         ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2599
2600         if (!mididm->have_signal () || mididm->latency () == 0) {
2601                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2602                 return true;
2603         }
2604
2605         char buf[256];
2606         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2607
2608         if (sample_rate == 0) {
2609                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2610                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2611                 return false;
2612         }
2613
2614         ARDOUR::framecnt_t frames_total = mididm->latency();
2615         ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2616         snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2617                         _("Detected roundtrip latency: "),
2618                         frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2619                         _("Systemic latency: "),
2620                         extra, extra * 1000.0f / sample_rate);
2621
2622         bool solid = true;
2623
2624         if (!mididm->ok ()) {
2625                 strcat (buf, " ");
2626                 strcat (buf, _("(averaging)"));
2627                 solid = false;
2628         }
2629
2630         if (mididm->deviation () > 50.0) {
2631                 strcat (buf, " ");
2632                 strcat (buf, _("(too large jitter)"));
2633                 solid = false;
2634         } else if (mididm->deviation () > 10.0) {
2635                 strcat (buf, " ");
2636                 strcat (buf, _("(large jitter)"));
2637         }
2638
2639         if (solid) {
2640                 have_lm_results = true;
2641                 end_latency_detection ();
2642                 lm_use_button.set_sensitive (true);
2643                 lm_results.set_markup (string_compose (results_markup, buf));
2644                 return false;
2645         } else if (mididm->processed () > 400) {
2646                 have_lm_results = false;
2647                 end_latency_detection ();
2648                 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2649                 return false;
2650         }
2651
2652         lm_results.set_markup (string_compose (results_markup, buf));
2653
2654         return true;
2655 }
2656
2657 void
2658 EngineControl::start_latency_detection ()
2659 {
2660         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2661         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2662
2663         if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2664                 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2665                 if (_measure_midi) {
2666                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2667                 } else {
2668                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2669                 }
2670                 lm_measure_label.set_text (_("Cancel"));
2671                 have_lm_results = false;
2672                 lm_use_button.set_sensitive (false);
2673                 lm_input_channel_combo.set_sensitive (false);
2674                 lm_output_channel_combo.set_sensitive (false);
2675                 lm_running = true;
2676         }
2677 }
2678
2679 void
2680 EngineControl::end_latency_detection ()
2681 {
2682         latency_timeout.disconnect ();
2683         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2684         lm_measure_label.set_text (_("Measure"));
2685         if (!have_lm_results) {
2686                 lm_use_button.set_sensitive (false);
2687         }
2688         lm_input_channel_combo.set_sensitive (true);
2689         lm_output_channel_combo.set_sensitive (true);
2690         lm_running = false;
2691 }
2692
2693 void
2694 EngineControl::latency_button_clicked ()
2695 {
2696         if (!lm_running) {
2697                 start_latency_detection ();
2698         } else {
2699                 end_latency_detection ();
2700         }
2701 }
2702
2703 void
2704 EngineControl::use_latency_button_clicked ()
2705 {
2706         if (_measure_midi) {
2707                 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2708                 if (!mididm) {
2709                         return;
2710                 }
2711                 ARDOUR::framecnt_t frames_total = mididm->latency();
2712                 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2713                 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2714                 _measure_midi->input_latency = one_way;
2715                 _measure_midi->output_latency = one_way;
2716                 notebook.set_current_page (midi_tab);
2717         } else {
2718                 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2719
2720                 if (!mtdm) {
2721                         return;
2722                 }
2723
2724                 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2725                 one_way = std::max (0., one_way);
2726
2727                 input_latency_adjustment.set_value (one_way);
2728                 output_latency_adjustment.set_value (one_way);
2729
2730                 /* back to settings page */
2731                 notebook.set_current_page (0);
2732 }
2733         }
2734
2735
2736 bool
2737 EngineControl::on_delete_event (GdkEventAny* ev)
2738 {
2739         if (notebook.get_current_page() == 2) {
2740                 /* currently on latency tab - be sure to clean up */
2741                 end_latency_detection ();
2742         }
2743         return ArdourDialog::on_delete_event (ev);
2744 }
2745
2746 void
2747 EngineControl::engine_running ()
2748 {
2749         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2750         assert (backend);
2751
2752         set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2753         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2754
2755         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2756         connect_disconnect_button.show();
2757
2758         started_at_least_once = true;
2759         if (_have_control) {
2760                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2761         } else {
2762                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2763         }
2764         update_sensitivity();
2765 }
2766
2767 void
2768 EngineControl::engine_stopped ()
2769 {
2770         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2771         assert (backend);
2772
2773         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2774         connect_disconnect_button.show();
2775
2776         engine_status.set_markup(X_(""));
2777         update_sensitivity();
2778 }
2779
2780 void
2781 EngineControl::device_list_changed ()
2782 {
2783         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2784         list_devices ();
2785         midi_option_changed();
2786 }
2787
2788 void
2789 EngineControl::connect_disconnect_click()
2790 {
2791         if (ARDOUR::AudioEngine::instance()->running()) {
2792                 ARDOUR_UI::instance()->disconnect_from_engine ();
2793         } else {
2794                 ARDOUR_UI::instance()->reconnect_to_engine ();
2795         }
2796 }
2797
2798 void
2799 EngineControl::calibrate_audio_latency ()
2800 {
2801         _measure_midi.reset ();
2802         have_lm_results = false;
2803         lm_use_button.set_sensitive (false);
2804         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2805         notebook.set_current_page (latency_tab);
2806 }
2807
2808 void
2809 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2810 {
2811         _measure_midi = s;
2812         have_lm_results = false;
2813         lm_use_button.set_sensitive (false);
2814         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2815         notebook.set_current_page (latency_tab);
2816 }
2817
2818 void
2819 EngineControl::configure_midi_devices ()
2820 {
2821         notebook.set_current_page (midi_tab);
2822 }