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