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