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