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