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