Don't call AudioBackend::enumerate_drivers for Backend states without driver selection
[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                 buffer_size_combo.set_active_text (s.front());
1165
1166                 uint32_t period = backend->buffer_size();
1167                 if (0 == period) {
1168                         period = backend->default_buffer_size(device_name);
1169                 }
1170                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1171                 show_buffer_duration ();
1172         } else {
1173                 buffer_size_combo.set_sensitive (false);
1174         }
1175 }
1176
1177 void
1178 EngineControl::device_changed ()
1179 {
1180         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1181         assert (backend);
1182
1183         string device_name_in;
1184         string device_name_out; // only used if backend support separate I/O devices
1185
1186         if (backend->use_separate_input_and_output_devices()) {
1187                 device_name_in  = get_input_device_name ();
1188                 device_name_out = get_output_device_name ();
1189         } else {
1190                 device_name_in = get_device_name ();
1191         }
1192
1193         /* we set the backend-device to query various device related intormation.
1194          * This has the side effect that backend->device_name() will match
1195          * the device_name and  'change_device' will never be true.
1196          * so work around this by setting...
1197          */
1198         if (backend->use_separate_input_and_output_devices()) {
1199                 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1200                         queue_device_changed = true;
1201                 }
1202         } else {
1203                 if (device_name_in != backend->device_name()) {
1204                         queue_device_changed = true;
1205                 }
1206         }
1207         
1208         //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1209         if (backend->use_separate_input_and_output_devices()) {
1210                 backend->set_input_device_name (device_name_in);
1211                 backend->set_output_device_name (device_name_out);
1212         } else {
1213                 backend->set_device_name(device_name_in);
1214         }
1215
1216         {
1217                 /* don't allow programmatic change to combos to cause a
1218                    recursive call to this method.
1219                  */
1220                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1221
1222                 /* backends that support separate devices, need to ignore
1223                  * the device-name - and use the devies set above
1224                  */
1225                 set_samplerate_popdown_strings (device_name_in);
1226                 set_buffersize_popdown_strings (device_name_in);
1227                 /* XXX theoretically need to set min + max channel counts here
1228                 */
1229
1230                 manage_control_app_sensitivity ();
1231         }
1232
1233         /* pick up any saved state for this device */
1234
1235         if (!ignore_changes) {
1236                 maybe_display_saved_state ();
1237         }
1238 }
1239
1240 void
1241 EngineControl::input_device_changed ()
1242 {
1243         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1244         assert (backend);
1245         string input_device_name = input_device_combo.get_active_text ();
1246
1247         if (!ignore_changes && input_device_name != backend->input_device_name()) {
1248                 queue_device_changed = true;
1249         }
1250
1251         backend->set_input_device_name(input_device_name);
1252
1253         {
1254                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1255
1256                 set_samplerate_popdown_strings (input_device_name);
1257                 set_buffersize_popdown_strings (input_device_name);
1258                 /* XXX theoretically need to set min + max channel counts here
1259                 */
1260
1261                 manage_control_app_sensitivity ();
1262         }
1263
1264         /* pick up any saved state for this device */
1265
1266         if (!ignore_changes) {
1267                 maybe_display_saved_state ();
1268         }
1269 }
1270
1271 void
1272 EngineControl::output_device_changed ()
1273 {
1274         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1275         assert (backend);
1276         string output_device_name = output_device_combo.get_active_text ();
1277
1278         if (!ignore_changes && output_device_name != backend->output_device_name()) {
1279                 queue_device_changed = true;
1280         }
1281
1282         backend->set_output_device_name(output_device_name);
1283
1284         {
1285                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1286
1287                 set_samplerate_popdown_strings (output_device_name);
1288                 set_buffersize_popdown_strings (output_device_name);
1289                 /* XXX theoretically need to set min + max channel counts here
1290                 */
1291
1292                 manage_control_app_sensitivity ();
1293         }
1294
1295         /* pick up any saved state for this device */
1296
1297         if (!ignore_changes) {
1298                 maybe_display_saved_state ();
1299         }
1300 }
1301
1302 string
1303 EngineControl::bufsize_as_string (uint32_t sz)
1304 {
1305         /* Translators: "samples" is always plural here, so no
1306            need for plural+singular forms.
1307          */
1308         char buf[64];
1309         snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1310         return buf;
1311 }
1312
1313 void
1314 EngineControl::sample_rate_changed ()
1315 {
1316         /* reset the strings for buffer size to show the correct msec value
1317            (reflecting the new sample rate).
1318          */
1319
1320         show_buffer_duration ();
1321
1322 }
1323
1324 void
1325 EngineControl::buffer_size_changed ()
1326 {
1327         show_buffer_duration ();
1328 }
1329
1330 void
1331 EngineControl::show_buffer_duration ()
1332 {
1333
1334         /* buffer sizes  - convert from just samples to samples + msecs for
1335          * the displayed string
1336          */
1337
1338         string bs_text = buffer_size_combo.get_active_text ();
1339         uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1340         uint32_t rate = get_rate();
1341
1342         /* Developers: note the hard-coding of a double buffered model
1343            in the (2 * samples) computation of latency. we always start
1344            the audiobackend in this configuration.
1345          */
1346         /* note to jack1 developers: ardour also always starts the engine
1347          * in async mode (no jack2 --sync option) which adds an extra cycle
1348          * of latency with jack2 (and *3 would be correct)
1349          * The value can also be wrong if jackd is started externally..
1350          *
1351          * At the time of writing the ALSA backend always uses double-buffering *2,
1352          * The Dummy backend *1, and who knows what ASIO really does :)
1353          *
1354          * So just display the period size, that's also what
1355          * ARDOUR_UI::update_sample_rate() does for the status bar.
1356          * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1357          * but still, that's the buffer period, not [round-trip] latency)
1358          */
1359         char buf[32];
1360         snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1361         buffer_size_duration_label.set_text (buf);
1362 }
1363
1364 void
1365 EngineControl::midi_option_changed ()
1366 {
1367         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1368         assert (backend);
1369
1370         backend->set_midi_option (get_midi_option());
1371
1372         vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1373
1374         //_midi_devices.clear(); // TODO merge with state-saved settings..
1375         _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1376         std::vector<MidiDeviceSettings> new_devices;
1377
1378         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1379                 MidiDeviceSettings mds = find_midi_device (i->name);
1380                 if (i->available && !mds) {
1381                         uint32_t input_latency = 0;
1382                         uint32_t output_latency = 0;
1383                         if (_can_set_midi_latencies) {
1384                                 input_latency = backend->systemic_midi_input_latency (i->name);
1385                                 output_latency = backend->systemic_midi_output_latency (i->name);
1386                         }
1387                         bool enabled = backend->midi_device_enabled (i->name);
1388                         MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1389                         new_devices.push_back (ptr);
1390                 } else if (i->available) {
1391                         new_devices.push_back (mds);
1392                 }
1393         }
1394         _midi_devices = new_devices;
1395
1396         if (_midi_devices.empty()) {
1397                 midi_devices_button.set_sensitive (false);
1398         } else {
1399                 midi_devices_button.set_sensitive (true);
1400         }
1401 }
1402
1403 void
1404 EngineControl::parameter_changed ()
1405 {
1406 }
1407
1408 EngineControl::State
1409 EngineControl::get_matching_state (
1410                 const string& backend,
1411                 const string& driver,
1412                 const string& device)
1413 {
1414         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1415                 if ((*i)->backend == backend &&
1416                                 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1417                 {
1418                         return (*i);
1419                 }
1420         }
1421         return State();
1422 }
1423
1424 EngineControl::State
1425 EngineControl::get_matching_state (
1426                 const string& backend,
1427                 const string& driver,
1428                 const string& input_device,
1429                 const string& output_device)
1430 {
1431         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1432                 if ((*i)->backend == backend &&
1433                                 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1434                 {
1435                         return (*i);
1436                 }
1437         }
1438         return State();
1439 }
1440
1441 EngineControl::State
1442 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1443 {
1444         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1445
1446         if (backend) {
1447                 if (backend->use_separate_input_and_output_devices ()) {
1448                         return get_matching_state (backend_combo.get_active_text(),
1449                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1450                                         input_device_combo.get_active_text(),
1451                                         output_device_combo.get_active_text());
1452                 } else {
1453                         return get_matching_state (backend_combo.get_active_text(),
1454                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1455                                         device_combo.get_active_text());
1456                 }
1457         }
1458
1459         return get_matching_state (backend_combo.get_active_text(),
1460                         string(),
1461                         device_combo.get_active_text());
1462 }
1463
1464 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1465                                        const EngineControl::State& state2)
1466 {
1467         if (state1->backend == state2->backend &&
1468                         state1->driver == state2->driver &&
1469                         state1->device == state2->device &&
1470                         state1->input_device == state2->input_device &&
1471                         state1->output_device == state2->output_device) {
1472                 return true;
1473         }
1474         return false;
1475 }
1476
1477 EngineControl::State
1478 EngineControl::save_state ()
1479 {
1480         State state;
1481
1482         if (!_have_control) {
1483                 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1484                 if (state) {
1485                         return state;
1486                 }
1487                 state.reset(new StateStruct);
1488                 state->backend = get_backend ();
1489         } else {
1490                 state.reset(new StateStruct);
1491                 store_state (state);
1492         }
1493
1494         for (StateList::iterator i = states.begin(); i != states.end();) {
1495                 if (equivalent_states (*i, state)) {
1496                         i =  states.erase(i);
1497                 } else {
1498                         ++i;
1499                 }
1500         }
1501
1502         states.push_back (state);
1503
1504         return state;
1505 }
1506
1507 void
1508 EngineControl::store_state (State state)
1509 {
1510         state->backend = get_backend ();
1511         state->driver = get_driver ();
1512         state->device = get_device_name ();
1513         state->input_device = get_input_device_name ();
1514         state->output_device = get_output_device_name ();
1515         state->sample_rate = get_rate ();
1516         state->buffer_size = get_buffer_size ();
1517         state->input_latency = get_input_latency ();
1518         state->output_latency = get_output_latency ();
1519         state->input_channels = get_input_channels ();
1520         state->output_channels = get_output_channels ();
1521         state->midi_option = get_midi_option ();
1522         state->midi_devices = _midi_devices;
1523 }
1524
1525 void
1526 EngineControl::maybe_display_saved_state ()
1527 {
1528         if (!_have_control) {
1529                 return;
1530         }
1531
1532         State state = get_saved_state_for_currently_displayed_backend_and_device ();
1533
1534         if (state) {
1535                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1536
1537                 if (!_desired_sample_rate) {
1538                         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1539                 }
1540                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1541                 /* call this explicitly because we're ignoring changes to
1542                    the controls at this point.
1543                  */
1544                 show_buffer_duration ();
1545                 input_latency.set_value (state->input_latency);
1546                 output_latency.set_value (state->output_latency);
1547
1548                 if (!state->midi_option.empty()) {
1549                         midi_option_combo.set_active_text (state->midi_option);
1550                         _midi_devices = state->midi_devices;
1551                 }
1552         }
1553 }
1554
1555 XMLNode&
1556 EngineControl::get_state ()
1557 {
1558         LocaleGuard lg (X_("C"));
1559
1560         XMLNode* root = new XMLNode ("AudioMIDISetup");
1561         std::string path;
1562
1563         if (!states.empty()) {
1564                 XMLNode* state_nodes = new XMLNode ("EngineStates");
1565
1566                 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1567
1568                         XMLNode* node = new XMLNode ("State");
1569
1570                         node->add_property ("backend", (*i)->backend);
1571                         node->add_property ("driver", (*i)->driver);
1572                         node->add_property ("device", (*i)->device);
1573                         node->add_property ("input-device", (*i)->input_device);
1574                         node->add_property ("output-device", (*i)->output_device);
1575                         node->add_property ("sample-rate", (*i)->sample_rate);
1576                         node->add_property ("buffer-size", (*i)->buffer_size);
1577                         node->add_property ("input-latency", (*i)->input_latency);
1578                         node->add_property ("output-latency", (*i)->output_latency);
1579                         node->add_property ("input-channels", (*i)->input_channels);
1580                         node->add_property ("output-channels", (*i)->output_channels);
1581                         node->add_property ("active", (*i)->active ? "yes" : "no");
1582                         node->add_property ("midi-option", (*i)->midi_option);
1583
1584                         XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1585                         for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1586                                 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1587                                 midi_device_stuff->add_property (X_("name"), (*p)->name);
1588                                 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1589                                 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1590                                 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1591                                 midi_devices->add_child_nocopy (*midi_device_stuff);
1592                         }
1593                         node->add_child_nocopy (*midi_devices);
1594
1595                         state_nodes->add_child_nocopy (*node);
1596                 }
1597
1598                 root->add_child_nocopy (*state_nodes);
1599         }
1600
1601         return *root;
1602 }
1603
1604 void
1605 EngineControl::set_state (const XMLNode& root)
1606 {
1607         XMLNodeList          clist, cclist;
1608         XMLNodeConstIterator citer, cciter;
1609         XMLNode* child;
1610         XMLNode* grandchild;
1611         XMLProperty* prop = NULL;
1612
1613         fprintf (stderr, "EngineControl::set_state\n");
1614
1615         if (root.name() != "AudioMIDISetup") {
1616                 return;
1617         }
1618
1619         clist = root.children();
1620
1621         states.clear ();
1622
1623         for (citer = clist.begin(); citer != clist.end(); ++citer) {
1624
1625                 child = *citer;
1626
1627                 if (child->name() != "EngineStates") {
1628                         continue;
1629                 }
1630
1631                 cclist = child->children();
1632
1633                 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1634                         State state (new StateStruct);
1635
1636                         grandchild = *cciter;
1637
1638                         if (grandchild->name() != "State") {
1639                                 continue;
1640                         }
1641
1642                         if ((prop = grandchild->property ("backend")) == 0) {
1643                                 continue;
1644                         }
1645                         state->backend = prop->value ();
1646
1647                         if ((prop = grandchild->property ("driver")) == 0) {
1648                                 continue;
1649                         }
1650                         state->driver = prop->value ();
1651
1652                         if ((prop = grandchild->property ("device")) == 0) {
1653                                 continue;
1654                         }
1655                         state->device = prop->value ();
1656
1657                         if ((prop = grandchild->property ("input-device")) == 0) {
1658                                 continue;
1659                         }
1660                         state->input_device = prop->value ();
1661
1662                         if ((prop = grandchild->property ("output-device")) == 0) {
1663                                 continue;
1664                         }
1665                         state->output_device = prop->value ();
1666
1667                         if ((prop = grandchild->property ("sample-rate")) == 0) {
1668                                 continue;
1669                         }
1670                         state->sample_rate = atof (prop->value ());
1671
1672                         if ((prop = grandchild->property ("buffer-size")) == 0) {
1673                                 continue;
1674                         }
1675                         state->buffer_size = atoi (prop->value ());
1676
1677                         if ((prop = grandchild->property ("input-latency")) == 0) {
1678                                 continue;
1679                         }
1680                         state->input_latency = atoi (prop->value ());
1681
1682                         if ((prop = grandchild->property ("output-latency")) == 0) {
1683                                 continue;
1684                         }
1685                         state->output_latency = atoi (prop->value ());
1686
1687                         if ((prop = grandchild->property ("input-channels")) == 0) {
1688                                 continue;
1689                         }
1690                         state->input_channels = atoi (prop->value ());
1691
1692                         if ((prop = grandchild->property ("output-channels")) == 0) {
1693                                 continue;
1694                         }
1695                         state->output_channels = atoi (prop->value ());
1696
1697                         if ((prop = grandchild->property ("active")) == 0) {
1698                                 continue;
1699                         }
1700                         state->active = string_is_affirmative (prop->value ());
1701
1702                         if ((prop = grandchild->property ("midi-option")) == 0) {
1703                                 continue;
1704                         }
1705                         state->midi_option = prop->value ();
1706
1707                         state->midi_devices.clear();
1708                         XMLNode* midinode;
1709                         if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1710                                 const XMLNodeList mnc = midinode->children();
1711                                 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1712                                         if ((*n)->property (X_("name")) == 0
1713                                                         || (*n)->property (X_("enabled")) == 0
1714                                                         || (*n)->property (X_("input-latency")) == 0
1715                                                         || (*n)->property (X_("output-latency")) == 0
1716                                                  ) {
1717                                                 continue;
1718                                         }
1719
1720                                         MidiDeviceSettings ptr (new MidiDeviceSetting(
1721                                                                 (*n)->property (X_("name"))->value (),
1722                                                                 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1723                                                                 atoi ((*n)->property (X_("input-latency"))->value ()),
1724                                                                 atoi ((*n)->property (X_("output-latency"))->value ())
1725                                                                 ));
1726                                         state->midi_devices.push_back (ptr);
1727                                 }
1728                         }
1729
1730 #if 1
1731                         /* remove accumulated duplicates (due to bug in ealier version)
1732                          * this can be removed again before release
1733                          */
1734                         for (StateList::iterator i = states.begin(); i != states.end();) {
1735                                 if ((*i)->backend == state->backend &&
1736                                                 (*i)->driver == state->driver &&
1737                                                 (*i)->device == state->device) {
1738                                         i =  states.erase(i);
1739                                 } else {
1740                                         ++i;
1741                                 }
1742                         }
1743 #endif
1744
1745                         states.push_back (state);
1746                 }
1747         }
1748
1749         /* now see if there was an active state and switch the setup to it */
1750
1751         // purge states of backend that are not available in this built
1752         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1753         vector<std::string> backend_names;
1754
1755         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1756                 backend_names.push_back((*i)->name);
1757         }
1758         for (StateList::iterator i = states.begin(); i != states.end();) {
1759                 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1760                         i = states.erase(i);
1761                 } else {
1762                         ++i;
1763                 }
1764         }
1765
1766         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1767
1768                 if ((*i)->active) {
1769                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1770                         backend_combo.set_active_text ((*i)->backend);
1771
1772                         /* The driver popdown strings need to be populated now so that
1773                          * set_active_text will actually set a valid entry. Then
1774                          * backend_changed() will populate all the other combo's so they
1775                          * can also be set to valid entries and the state will be restored
1776                          * correctly.
1777                          */
1778                         if (!(*i)->driver.empty()) {
1779                                 set_driver_popdown_strings ();
1780                         }
1781                         driver_combo.set_active_text ((*i)->driver);
1782                         backend_changed ();
1783
1784                         device_combo.set_active_text ((*i)->device);
1785                         input_device_combo.set_active_text ((*i)->input_device);
1786                         output_device_combo.set_active_text ((*i)->output_device);
1787                         sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1788                         set_active_text_if_present (buffer_size_combo, bufsize_as_string ((*i)->buffer_size));
1789                         input_latency.set_value ((*i)->input_latency);
1790                         output_latency.set_value ((*i)->output_latency);
1791                         midi_option_combo.set_active_text ((*i)->midi_option);
1792                         break;
1793                 }
1794         }
1795 }
1796
1797 int
1798 EngineControl::push_state_to_backend (bool start)
1799 {
1800         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1801
1802         if (!backend) {
1803                 return 0;
1804         }
1805
1806         /* figure out what is going to change */
1807
1808         bool restart_required = false;
1809         bool was_running = ARDOUR::AudioEngine::instance()->running();
1810         bool change_driver = false;
1811         bool change_device = false;
1812         bool change_rate = false;
1813         bool change_bufsize = false;
1814         bool change_latency = false;
1815         bool change_channels = false;
1816         bool change_midi = false;
1817
1818         uint32_t ochan = get_output_channels ();
1819         uint32_t ichan = get_input_channels ();
1820
1821         if (_have_control) {
1822
1823                 if (started_at_least_once) {
1824
1825                         /* we can control the backend */
1826
1827                         if (backend->requires_driver_selection()) {
1828                                 if (get_driver() != backend->driver_name()) {
1829                                         change_driver = true;
1830                                 }
1831                         }
1832
1833                         if (backend->use_separate_input_and_output_devices()) {
1834                                 if (get_input_device_name() != backend->input_device_name()) {
1835                                         change_device = true;
1836                                 }
1837                                 if (get_output_device_name() != backend->output_device_name()) {
1838                                         change_device = true;
1839                                 }
1840                         } else {
1841                                 if (get_device_name() != backend->device_name()) {
1842                                         change_device = true;
1843                                 }
1844                         }
1845
1846                         if (queue_device_changed) {
1847                                 change_device = true;
1848                         }
1849
1850                         if (get_rate() != backend->sample_rate()) {
1851                                 change_rate = true;
1852                         }
1853
1854                         if (get_buffer_size() != backend->buffer_size()) {
1855                                 change_bufsize = true;
1856                         }
1857
1858                         if (get_midi_option() != backend->midi_option()) {
1859                                 change_midi = true;
1860                         }
1861
1862                         /* zero-requested channels means "all available" */
1863
1864                         if (ichan == 0) {
1865                                 ichan = backend->input_channels();
1866                         }
1867
1868                         if (ochan == 0) {
1869                                 ochan = backend->output_channels();
1870                         }
1871
1872                         if (ichan != backend->input_channels()) {
1873                                 change_channels = true;
1874                         }
1875
1876                         if (ochan != backend->output_channels()) {
1877                                 change_channels = true;
1878                         }
1879
1880                         if (get_input_latency() != backend->systemic_input_latency() ||
1881                                         get_output_latency() != backend->systemic_output_latency()) {
1882                                 change_latency = true;
1883                         }
1884                 } else {
1885                         /* backend never started, so we have to force a group
1886                            of settings.
1887                          */
1888                         change_device = true;
1889                         if (backend->requires_driver_selection()) {
1890                                 change_driver = true;
1891                         }
1892                         change_rate = true;
1893                         change_bufsize = true;
1894                         change_channels = true;
1895                         change_latency = true;
1896                         change_midi = true;
1897                 }
1898
1899         } else {
1900
1901                 /* we have no control over the backend, meaning that we can
1902                  * only possibly change sample rate and buffer size.
1903                  */
1904
1905
1906                 if (get_rate() != backend->sample_rate()) {
1907                         change_bufsize = true;
1908                 }
1909
1910                 if (get_buffer_size() != backend->buffer_size()) {
1911                         change_bufsize = true;
1912                 }
1913         }
1914
1915         queue_device_changed = false;
1916
1917         if (!_have_control) {
1918
1919                 /* We do not have control over the backend, so the best we can
1920                  * do is try to change the sample rate and/or bufsize and get
1921                  * out of here.
1922                  */
1923
1924                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1925                         return 1;
1926                 }
1927
1928                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1929                         return 1;
1930                 }
1931
1932                 if (change_rate) {
1933                         backend->set_sample_rate (get_rate());
1934                 }
1935
1936                 if (change_bufsize) {
1937                         backend->set_buffer_size (get_buffer_size());
1938                 }
1939
1940                 if (start) {
1941                         if (ARDOUR::AudioEngine::instance()->start ()) {
1942                                 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1943                                 return -1;
1944                         }
1945                 }
1946
1947                 post_push ();
1948
1949                 return 0;
1950         }
1951
1952         /* determine if we need to stop the backend before changing parameters */
1953
1954         if (change_driver || change_device || change_channels || change_latency ||
1955                         (change_rate && !backend->can_change_sample_rate_when_running()) ||
1956                         change_midi ||
1957                         (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1958                 restart_required = true;
1959         } else {
1960                 restart_required = false;
1961         }
1962
1963         if (was_running) {
1964
1965                 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1966                         /* no changes in any parameters that absolutely require a
1967                          * restart, so check those that might be changeable without a
1968                          * restart
1969                          */
1970
1971                         if (change_rate && !backend->can_change_sample_rate_when_running()) {
1972                                 /* can't do this while running ... */
1973                                 restart_required = true;
1974                         }
1975
1976                         if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1977                                 /* can't do this while running ... */
1978                                 restart_required = true;
1979                         }
1980                 }
1981         }
1982
1983         if (was_running) {
1984                 if (restart_required) {
1985                         if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1986                                 return -1;
1987                         }
1988                 }
1989         }
1990
1991
1992         if (change_driver && backend->set_driver (get_driver())) {
1993                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1994                 return -1;
1995         }
1996         if (backend->use_separate_input_and_output_devices()) {
1997                 if (change_device && backend->set_input_device_name (get_input_device_name())) {
1998                         error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
1999                         return -1;
2000                 }
2001                 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2002                         error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2003                         return -1;
2004                 }
2005         } else {
2006                 if (change_device && backend->set_device_name (get_device_name())) {
2007                         error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2008                         return -1;
2009                 }
2010         }
2011         if (change_rate && backend->set_sample_rate (get_rate())) {
2012                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2013                 return -1;
2014         }
2015         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2016                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2017                 return -1;
2018         }
2019
2020         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2021                 if (backend->set_input_channels (get_input_channels())) {
2022                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2023                         return -1;
2024                 }
2025                 if (backend->set_output_channels (get_output_channels())) {
2026                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2027                         return -1;
2028                 }
2029         }
2030         if (change_latency) {
2031                 if (backend->set_systemic_input_latency (get_input_latency())) {
2032                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2033                         return -1;
2034                 }
2035                 if (backend->set_systemic_output_latency (get_output_latency())) {
2036                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2037                         return -1;
2038                 }
2039         }
2040
2041         if (change_midi) {
2042                 backend->set_midi_option (get_midi_option());
2043         }
2044
2045         if (1 /* TODO */) {
2046                 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2047                         if (_measure_midi) {
2048                                 if (*p == _measure_midi) {
2049                                         backend->set_midi_device_enabled ((*p)->name, true);
2050                                 } else {
2051                                         backend->set_midi_device_enabled ((*p)->name, false);
2052                                 }
2053                                 continue;
2054                         }
2055                         backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2056                         if (backend->can_set_systemic_midi_latencies()) {
2057                                 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2058                                 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2059                         }
2060                 }
2061         }
2062
2063         if (start || (was_running && restart_required)) {
2064                 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2065                         return -1;
2066                 }
2067         }
2068
2069         post_push ();
2070
2071         return 0;
2072 }
2073
2074 void
2075 EngineControl::post_push ()
2076 {
2077         /* get a pointer to the current state object, creating one if
2078          * necessary
2079          */
2080
2081         State state = get_saved_state_for_currently_displayed_backend_and_device ();
2082
2083         if (!state) {
2084                 state = save_state ();
2085                 assert (state);
2086         } else {
2087                 store_state(state);
2088         }
2089
2090         /* all off */
2091
2092         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2093                 (*i)->active = false;
2094         }
2095
2096         /* mark this one active (to be used next time the dialog is
2097          * shown)
2098          */
2099
2100         state->active = true;
2101
2102         if (_have_control) { // XXX
2103                 manage_control_app_sensitivity ();
2104         }
2105
2106         /* schedule a redisplay of MIDI ports */
2107         //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2108 }
2109
2110
2111 float
2112 EngineControl::get_rate () const
2113 {
2114         float r = atof (sample_rate_combo.get_active_text ());
2115         /* the string may have been translated with an abbreviation for
2116          * thousands, so use a crude heuristic to fix this.
2117          */
2118         if (r < 1000.0) {
2119                 r *= 1000.0;
2120         }
2121         return r;
2122 }
2123
2124
2125 uint32_t
2126 EngineControl::get_buffer_size () const
2127 {
2128         string txt = buffer_size_combo.get_active_text ();
2129         uint32_t samples;
2130
2131         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2132                 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2133                 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2134                 throw exception ();
2135         }
2136
2137         return samples;
2138 }
2139
2140 string
2141 EngineControl::get_midi_option () const
2142 {
2143         return midi_option_combo.get_active_text();
2144 }
2145
2146 uint32_t
2147 EngineControl::get_input_channels() const
2148 {
2149         if (ARDOUR::Profile->get_mixbus()) {
2150                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2151                 if (!backend) return 0;
2152                 return backend->input_channels();
2153         }
2154         return (uint32_t) input_channels_adjustment.get_value();
2155 }
2156
2157 uint32_t
2158 EngineControl::get_output_channels() const
2159 {
2160         if (ARDOUR::Profile->get_mixbus()) {
2161                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2162                 if (!backend) return 0;
2163                 return backend->input_channels();
2164         }
2165         return (uint32_t) output_channels_adjustment.get_value();
2166 }
2167
2168 uint32_t
2169 EngineControl::get_input_latency() const
2170 {
2171         return (uint32_t) input_latency_adjustment.get_value();
2172 }
2173
2174 uint32_t
2175 EngineControl::get_output_latency() const
2176 {
2177         return (uint32_t) output_latency_adjustment.get_value();
2178 }
2179
2180 string
2181 EngineControl::get_backend () const
2182 {
2183         return backend_combo.get_active_text ();
2184 }
2185
2186 string
2187 EngineControl::get_driver () const
2188 {
2189         if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2190                 return driver_combo.get_active_text ();
2191         } else {
2192                 return "";
2193         }
2194 }
2195
2196 string
2197 EngineControl::get_device_name () const
2198 {
2199         return device_combo.get_active_text ();
2200 }
2201
2202 string
2203 EngineControl::get_input_device_name () const
2204 {
2205         return input_device_combo.get_active_text ();
2206 }
2207
2208 string
2209 EngineControl::get_output_device_name () const
2210 {
2211         return output_device_combo.get_active_text ();
2212 }
2213
2214 void
2215 EngineControl::control_app_button_clicked ()
2216 {
2217         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2218
2219         if (!backend) {
2220                 return;
2221         }
2222
2223         backend->launch_control_app ();
2224 }
2225
2226 void
2227 EngineControl::manage_control_app_sensitivity ()
2228 {
2229         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2230
2231         if (!backend) {
2232                 return;
2233         }
2234
2235         string appname = backend->control_app_name();
2236
2237         if (appname.empty()) {
2238                 control_app_button.set_sensitive (false);
2239         } else {
2240                 control_app_button.set_sensitive (true);
2241         }
2242 }
2243
2244 void
2245 EngineControl::set_desired_sample_rate (uint32_t sr)
2246 {
2247         _desired_sample_rate = sr;
2248         device_changed ();
2249         input_device_changed ();
2250         output_device_changed ();
2251 }
2252
2253 void
2254 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2255 {
2256         if (page_num == 0) {
2257                 cancel_button->set_sensitive (true);
2258                 ok_button->set_sensitive (true);
2259                 apply_button->set_sensitive (true);
2260                 _measure_midi.reset();
2261         } else {
2262                 cancel_button->set_sensitive (false);
2263                 ok_button->set_sensitive (false);
2264                 apply_button->set_sensitive (false);
2265         }
2266
2267         if (page_num == midi_tab) {
2268                 /* MIDI tab */
2269                 refresh_midi_display ();
2270         }
2271
2272         if (page_num == latency_tab) {
2273                 /* latency tab */
2274
2275                 if (ARDOUR::AudioEngine::instance()->running()) {
2276                         // TODO - mark as 'stopped for latency
2277                         ARDOUR_UI::instance()->disconnect_from_engine ();
2278                 }
2279
2280                 {
2281                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2282
2283                         /* save any existing latency values */
2284
2285                         uint32_t il = (uint32_t) input_latency.get_value ();
2286                         uint32_t ol = (uint32_t) input_latency.get_value ();
2287
2288                         /* reset to zero so that our new test instance
2289                            will be clean of any existing latency measures.
2290
2291                            NB. this should really be done by the backend
2292                            when stated for latency measurement.
2293                         */
2294
2295                         input_latency.set_value (0);
2296                         output_latency.set_value (0);
2297
2298                         push_state_to_backend (false);
2299
2300                         /* reset control */
2301
2302                         input_latency.set_value (il);
2303                         output_latency.set_value (ol);
2304
2305                 }
2306                 // This should be done in push_state_to_backend()
2307                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2308                         disable_latency_tab ();
2309                 }
2310
2311                 enable_latency_tab ();
2312
2313         } else {
2314                 if (lm_running) {
2315                         end_latency_detection ();
2316                         ARDOUR::AudioEngine::instance()->stop_latency_detection();
2317                 }
2318         }
2319 }
2320
2321 /* latency measurement */
2322
2323 bool
2324 EngineControl::check_audio_latency_measurement ()
2325 {
2326         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2327
2328         if (mtdm->resolve () < 0) {
2329                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2330                 return true;
2331         }
2332
2333         if (mtdm->err () > 0.3) {
2334                 mtdm->invert ();
2335                 mtdm->resolve ();
2336         }
2337
2338         char buf[256];
2339         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2340
2341         if (sample_rate == 0) {
2342                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2343                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2344                 return false;
2345         }
2346
2347         int frames_total = mtdm->del();
2348         int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2349
2350         snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2351                         _("Detected roundtrip latency: "),
2352                         frames_total, frames_total * 1000.0f/sample_rate,
2353                         _("Systemic latency: "),
2354                         extra, extra * 1000.0f/sample_rate);
2355
2356         bool solid = true;
2357
2358         if (mtdm->err () > 0.2) {
2359                 strcat (buf, " ");
2360                 strcat (buf, _("(signal detection error)"));
2361                 solid = false;
2362         }
2363
2364         if (mtdm->inv ()) {
2365                 strcat (buf, " ");
2366                 strcat (buf, _("(inverted - bad wiring)"));
2367                 solid = false;
2368         }
2369
2370         lm_results.set_markup (string_compose (results_markup, buf));
2371
2372         if (solid) {
2373                 have_lm_results = true;
2374                 end_latency_detection ();
2375                 lm_use_button.set_sensitive (true);
2376                 return false;
2377         }
2378
2379         return true;
2380 }
2381
2382 bool
2383 EngineControl::check_midi_latency_measurement ()
2384 {
2385         ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2386
2387         if (!mididm->have_signal () || mididm->latency () == 0) {
2388                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2389                 return true;
2390         }
2391
2392         char buf[256];
2393         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2394
2395         if (sample_rate == 0) {
2396                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2397                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2398                 return false;
2399         }
2400
2401         ARDOUR::framecnt_t frames_total = mididm->latency();
2402         ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2403         snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2404                         _("Detected roundtrip latency: "),
2405                         frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2406                         _("Systemic latency: "),
2407                         extra, extra * 1000.0f / sample_rate);
2408
2409         bool solid = true;
2410
2411         if (!mididm->ok ()) {
2412                 strcat (buf, " ");
2413                 strcat (buf, _("(averaging)"));
2414                 solid = false;
2415         }
2416
2417         if (mididm->deviation () > 50.0) {
2418                 strcat (buf, " ");
2419                 strcat (buf, _("(too large jitter)"));
2420                 solid = false;
2421         } else if (mididm->deviation () > 10.0) {
2422                 strcat (buf, " ");
2423                 strcat (buf, _("(large jitter)"));
2424         }
2425
2426         if (solid) {
2427                 have_lm_results = true;
2428                 end_latency_detection ();
2429                 lm_use_button.set_sensitive (true);
2430                 lm_results.set_markup (string_compose (results_markup, buf));
2431                 return false;
2432         } else if (mididm->processed () > 400) {
2433                 have_lm_results = false;
2434                 end_latency_detection ();
2435                 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2436                 return false;
2437         }
2438
2439         lm_results.set_markup (string_compose (results_markup, buf));
2440
2441         return true;
2442 }
2443
2444 void
2445 EngineControl::start_latency_detection ()
2446 {
2447         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2448         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2449
2450         if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2451                 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2452                 if (_measure_midi) {
2453                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2454                 } else {
2455                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2456                 }
2457                 lm_measure_label.set_text (_("Cancel"));
2458                 have_lm_results = false;
2459                 lm_use_button.set_sensitive (false);
2460                 lm_input_channel_combo.set_sensitive (false);
2461                 lm_output_channel_combo.set_sensitive (false);
2462                 lm_running = true;
2463         }
2464 }
2465
2466 void
2467 EngineControl::end_latency_detection ()
2468 {
2469         latency_timeout.disconnect ();
2470         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2471         lm_measure_label.set_text (_("Measure"));
2472         if (!have_lm_results) {
2473                 lm_use_button.set_sensitive (false);
2474         }
2475         lm_input_channel_combo.set_sensitive (true);
2476         lm_output_channel_combo.set_sensitive (true);
2477         lm_running = false;
2478 }
2479
2480 void
2481 EngineControl::latency_button_clicked ()
2482 {
2483         if (!lm_running) {
2484                 start_latency_detection ();
2485         } else {
2486                 end_latency_detection ();
2487         }
2488 }
2489
2490 void
2491 EngineControl::use_latency_button_clicked ()
2492 {
2493         if (_measure_midi) {
2494                 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2495                 if (!mididm) {
2496                         return;
2497                 }
2498                 ARDOUR::framecnt_t frames_total = mididm->latency();
2499                 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2500                 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2501                 _measure_midi->input_latency = one_way;
2502                 _measure_midi->output_latency = one_way;
2503                 notebook.set_current_page (midi_tab);
2504         } else {
2505                 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2506
2507                 if (!mtdm) {
2508                         return;
2509                 }
2510
2511                 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2512                 one_way = std::max (0., one_way);
2513
2514                 input_latency_adjustment.set_value (one_way);
2515                 output_latency_adjustment.set_value (one_way);
2516
2517                 /* back to settings page */
2518                 notebook.set_current_page (0);
2519 }
2520         }
2521
2522
2523 bool
2524 EngineControl::on_delete_event (GdkEventAny* ev)
2525 {
2526         if (notebook.get_current_page() == 2) {
2527                 /* currently on latency tab - be sure to clean up */
2528                 end_latency_detection ();
2529         }
2530         return ArdourDialog::on_delete_event (ev);
2531 }
2532
2533 void
2534 EngineControl::engine_running ()
2535 {
2536         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2537         assert (backend);
2538
2539         set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2540         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2541
2542         buffer_size_combo.set_sensitive (true);
2543         sample_rate_combo.set_sensitive (true);
2544
2545         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2546         connect_disconnect_button.show();
2547
2548         started_at_least_once = true;
2549         engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2550 }
2551
2552 void
2553 EngineControl::engine_stopped ()
2554 {
2555         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2556         assert (backend);
2557
2558         buffer_size_combo.set_sensitive (false);
2559         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2560         connect_disconnect_button.show();
2561
2562         sample_rate_combo.set_sensitive (true);
2563         buffer_size_combo.set_sensitive (true);
2564         engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2565 }
2566
2567 void
2568 EngineControl::device_list_changed ()
2569 {
2570         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2571         list_devices ();
2572         midi_option_changed();
2573 }
2574
2575 void
2576 EngineControl::connect_disconnect_click()
2577 {
2578         if (ARDOUR::AudioEngine::instance()->running()) {
2579                 ARDOUR_UI::instance()->disconnect_from_engine ();
2580         } else {
2581                 ARDOUR_UI::instance()->reconnect_to_engine ();
2582         }
2583 }
2584
2585 void
2586 EngineControl::calibrate_audio_latency ()
2587 {
2588         _measure_midi.reset ();
2589         have_lm_results = false;
2590         lm_use_button.set_sensitive (false);
2591         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2592         notebook.set_current_page (latency_tab);
2593 }
2594
2595 void
2596 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2597 {
2598         _measure_midi = s;
2599         have_lm_results = false;
2600         lm_use_button.set_sensitive (false);
2601         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2602         notebook.set_current_page (latency_tab);
2603 }
2604
2605 void
2606 EngineControl::configure_midi_devices ()
2607 {
2608         notebook.set_current_page (midi_tab);
2609 }