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