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