Set active text in buffer_size combo in EngineControl dialog
[ardour.git] / gtk2_ardour / engine_dialog.cc
1 /*
2     Copyright (C) 2010 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <exception>
21 #include <vector>
22 #include <cmath>
23 #include <fstream>
24 #include <map>
25
26 #include <boost/scoped_ptr.hpp>
27
28 #include <gtkmm/messagedialog.h>
29
30 #include "pbd/error.h"
31 #include "pbd/xml++.h"
32 #include "pbd/unwind.h"
33 #include "pbd/failed_constructor.h"
34
35 #include <gtkmm/alignment.h>
36 #include <gtkmm/stock.h>
37 #include <gtkmm/notebook.h>
38 #include <gtkmm2ext/utils.h>
39
40 #include "ardour/audio_backend.h"
41 #include "ardour/audioengine.h"
42 #include "ardour/mtdm.h"
43 #include "ardour/mididm.h"
44 #include "ardour/rc_configuration.h"
45 #include "ardour/types.h"
46 #include "ardour/profile.h"
47
48 #include "pbd/convert.h"
49 #include "pbd/error.h"
50
51 #include "opts.h"
52 #include "ardour_ui.h"
53 #include "engine_dialog.h"
54 #include "gui_thread.h"
55 #include "utils.h"
56 #include "i18n.h"
57
58 using namespace std;
59 using namespace Gtk;
60 using namespace Gtkmm2ext;
61 using namespace PBD;
62 using namespace Glib;
63 using namespace ARDOUR_UI_UTILS;
64
65 static const unsigned int midi_tab = 2;
66 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
67
68 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
69
70 EngineControl::EngineControl ()
71         : ArdourDialog (_("Audio/MIDI Setup"))
72         , engine_status ("")
73         , basic_packer (9, 4)
74         , input_latency_adjustment (0, 0, 99999, 1)
75         , input_latency (input_latency_adjustment)
76         , output_latency_adjustment (0, 0, 99999, 1)
77         , output_latency (output_latency_adjustment)
78         , input_channels_adjustment (0, 0, 256, 1)
79         , input_channels (input_channels_adjustment)
80         , output_channels_adjustment (0, 0, 256, 1)
81         , output_channels (output_channels_adjustment)
82         , ports_adjustment (128, 8, 1024, 1, 16)
83         , ports_spinner (ports_adjustment)
84         , control_app_button (_("Device Control Panel"))
85         , midi_devices_button (_("Midi Device Setup"))
86         , lm_measure_label (_("Measure"))
87         , lm_use_button (_("Use results"))
88         , lm_back_button (_("Back to settings ... (ignore results)"))
89         , lm_button_audio (_("Calibrate Audio"))
90         , lm_table (12, 3)
91         , have_lm_results (false)
92         , lm_running (false)
93         , midi_back_button (_("Back to settings"))
94         , ignore_changes (0)
95         , _desired_sample_rate (0)
96         , started_at_least_once (false)
97         , queue_device_changed (false)
98 {
99         using namespace Notebook_Helpers;
100         vector<string> backend_names;
101         Label* label;
102         AttachOptions xopt = AttachOptions (FILL|EXPAND);
103         int row;
104
105         set_name (X_("AudioMIDISetup"));
106
107         /* the backend combo is the one thing that is ALWAYS visible */
108
109         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
110
111         if (backends.empty()) {
112                 MessageDialog msg (string_compose (_("No audio/MIDI backends detected. %1 cannot run\n\n(This is a build/packaging/system error. It should never happen.)"), PROGRAM_NAME));
113                 msg.run ();
114                 throw failed_constructor ();
115         }
116
117         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
118                 backend_names.push_back ((*b)->name);
119         }
120
121         set_popdown_strings (backend_combo, backend_names);
122
123         /* setup basic packing characteristics for the table used on the main
124          * tab of the notebook
125          */
126
127         basic_packer.set_spacings (6);
128         basic_packer.set_border_width (12);
129         basic_packer.set_homogeneous (false);
130
131         /* pack it in */
132
133         basic_hbox.pack_start (basic_packer, false, false);
134
135         /* latency measurement tab */
136
137         lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
138
139         row = 0;
140         lm_table.set_row_spacings (12);
141         lm_table.set_col_spacings (6);
142         lm_table.set_homogeneous (false);
143
144         lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
145         row++;
146
147         lm_preamble.set_width_chars (60);
148         lm_preamble.set_line_wrap (true);
149         lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
150
151         lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
152         row++;
153
154         Gtk::Label* preamble;
155         preamble = manage (new Label);
156         preamble->set_width_chars (60);
157         preamble->set_line_wrap (true);
158         preamble->set_markup (_("Select two channels below and connect them using a cable."));
159
160         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
161         row++;
162
163         label = manage (new Label (_("Output channel")));
164         lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
165
166         Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
167         misc_align->add (lm_output_channel_combo);
168         lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
169         ++row;
170
171         label = manage (new Label (_("Input channel")));
172         lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
173
174         misc_align = manage (new Alignment (0.0, 0.5));
175         misc_align->add (lm_input_channel_combo);
176         lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
177         ++row;
178
179         xopt = AttachOptions(0);
180
181         lm_measure_label.set_padding (10, 10);
182         lm_measure_button.add (lm_measure_label);
183         lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
184         lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
185         lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
186
187         lm_use_button.set_sensitive (false);
188
189         /* Increase the default spacing around the labels of these three
190          * buttons
191          */
192
193         Gtk::Misc* l;
194
195         if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
196                 l->set_padding (10, 10);
197         }
198
199         if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
200                 l->set_padding (10, 10);
201         }
202
203         preamble = manage (new Label);
204         preamble->set_width_chars (60);
205         preamble->set_line_wrap (true);
206         preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
207         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
208         row++;
209
210         preamble = manage (new Label);
211         preamble->set_width_chars (60);
212         preamble->set_line_wrap (true);
213         preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
214         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
215
216         ++row; // skip a row in the table
217         ++row; // skip a row in the table
218
219         lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
220
221         ++row; // skip a row in the table
222         ++row; // skip a row in the table
223
224         lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
225         lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
226         lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
227
228         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
229
230         lm_vbox.set_border_width (12);
231         lm_vbox.pack_start (lm_table, false, false);
232
233         midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
234
235         /* pack it all up */
236
237         notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
238         notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
239         notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
240         notebook.set_border_width (12);
241
242         notebook.set_show_tabs (false);
243         notebook.show_all ();
244
245         notebook.set_name ("SettingsNotebook");
246
247         /* packup the notebook */
248
249         get_vbox()->set_border_width (12);
250         get_vbox()->pack_start (notebook);
251
252         get_action_area()->pack_start (engine_status);
253         engine_status.show();
254
255         /* need a special function to print "all available channels" when the
256          * channel counts hit zero.
257          */
258
259         input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
260         output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
261
262         midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
263         midi_devices_button.set_sensitive (false);
264         midi_devices_button.set_name ("generic button");
265         midi_devices_button.set_can_focus(true);
266
267         control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
268         manage_control_app_sensitivity ();
269
270         cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
271         apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
272         ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
273
274         /* Pick up any existing audio setup configuration, if appropriate */
275
276         XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
277
278         ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
279         ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
280         ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
281         ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
282
283         if (audio_setup) {
284                 set_state (*audio_setup);
285         }
286
287         if (backend_combo.get_active_text().empty()) {
288                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
289                 backend_combo.set_active_text (backend_names.front());
290         }
291
292         backend_changed ();
293
294         /* in case the setting the backend failed, e.g. stale config, from set_state(), try again */
295         if (0 == ARDOUR::AudioEngine::instance()->current_backend()) {
296                 backend_combo.set_active_text (backend_names.back());
297                 /* ignore: don't save state */
298                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
299                 backend_changed ();
300         }
301
302
303         /* Connect to signals */
304
305         backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
306         driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
307         sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
308         buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
309         device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed));
310         midi_option_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::midi_option_changed));
311
312         input_device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::input_device_changed));
313         output_device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::output_device_changed));
314
315         input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
316         output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
317         input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
318         output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
319
320         notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
321
322         connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
323         connect_disconnect_button.set_no_show_all();
324
325 }
326
327 void
328 EngineControl::on_show ()
329 {
330         ArdourDialog::on_show ();
331         if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
332                 // re-check _have_control (jackd running) see #6041
333                 backend_changed ();
334         }
335         device_changed ();
336         input_device_changed ();
337         output_device_changed ();
338         ok_button->grab_focus();
339 }
340
341 void
342 EngineControl::on_response (int response_id)
343 {
344         ArdourDialog::on_response (response_id);
345
346         switch (response_id) {
347                 case RESPONSE_APPLY:
348                         push_state_to_backend (true);
349                         break;
350                 case RESPONSE_OK:
351 #ifdef PLATFORM_WINDOWS
352                         // For some reason we don't understand, 'hide()'
353                         // needs to get called first in Windows
354                         hide ();
355
356                         // But if there's no session open, this can produce
357                         // a long gap when nothing appears to be happening.
358                         // Let's show the splash image while we're waiting.
359                         if ( !ARDOUR_COMMAND_LINE::no_splash ) {
360                                 if ( ARDOUR_UI::instance() ) {
361                                         if ( !ARDOUR_UI::instance()->session_loaded ) {
362                                                 ARDOUR_UI::instance()->show_splash();
363                                         }
364                                 }
365                         }
366                         push_state_to_backend (true);
367                         break;
368 #else
369                         push_state_to_backend (true);
370                         hide ();
371                         break;
372 #endif
373                 case RESPONSE_DELETE_EVENT:
374                         {
375                                 GdkEventButton ev;
376                                 ev.type = GDK_BUTTON_PRESS;
377                                 ev.button = 1;
378                                 on_delete_event ((GdkEventAny*) &ev);
379                                 break;
380                         }
381                 default:
382                         hide ();
383         }
384 }
385
386 void
387 EngineControl::build_notebook ()
388 {
389         Label* label;
390         AttachOptions xopt = AttachOptions (FILL|EXPAND);
391
392         /* clear the table */
393
394         Gtkmm2ext::container_clear (basic_vbox);
395         Gtkmm2ext::container_clear (basic_packer);
396
397         if (control_app_button.get_parent()) {
398                 control_app_button.get_parent()->remove (control_app_button);
399         }
400
401         label = manage (left_aligned_label (_("Audio System:")));
402         basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
403         basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
404
405         lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
406         lm_button_audio.set_name ("generic button");
407         lm_button_audio.set_can_focus(true);
408
409         if (_have_control) {
410                 build_full_control_notebook ();
411         } else {
412                 build_no_control_notebook ();
413         }
414
415         basic_vbox.pack_start (basic_hbox, false, false);
416
417         {
418                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
419                 basic_vbox.show_all ();
420         }
421 }
422
423 void
424 EngineControl::build_full_control_notebook ()
425 {
426         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
427         assert (backend);
428
429         using namespace Notebook_Helpers;
430         Label* label;
431         vector<string> strings;
432         AttachOptions xopt = AttachOptions (FILL|EXPAND);
433         int row = 1; // row zero == backend combo
434
435         /* start packing it up */
436
437         if (backend->requires_driver_selection()) {
438                 label = manage (left_aligned_label (_("Driver:")));
439                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
440                 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
441                 row++;
442         }
443
444         if (backend->use_separate_input_and_output_devices()) {
445                 label = manage (left_aligned_label (_("Input Device:")));
446                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
447                 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
448                 row++;
449                 label = manage (left_aligned_label (_("Output Device:")));
450                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
451                 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
452                 row++;
453                 // reset so it isn't used in state comparisons
454                 device_combo.set_active_text ("");
455         } else {
456                 label = manage (left_aligned_label (_("Device:")));
457                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
458                 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
459                 row++;
460                 // reset these so they don't get used in state comparisons
461                 input_device_combo.set_active_text ("");
462                 output_device_combo.set_active_text ("");
463         }
464
465         label = manage (left_aligned_label (_("Sample rate:")));
466         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
467         basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
468         row++;
469
470
471         label = manage (left_aligned_label (_("Buffer size:")));
472         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
473         basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
474         buffer_size_duration_label.set_alignment (0.0); /* left-align */
475         basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
476
477         /* button spans 2 rows */
478
479         basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
480         row++;
481
482         input_channels.set_name ("InputChannels");
483         input_channels.set_flags (Gtk::CAN_FOCUS);
484         input_channels.set_digits (0);
485         input_channels.set_wrap (false);
486         output_channels.set_editable (true);
487
488         if (!ARDOUR::Profile->get_mixbus()) {
489                 label = manage (left_aligned_label (_("Input Channels:")));
490                 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
491                 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
492                 ++row;
493         }
494         
495         output_channels.set_name ("OutputChannels");
496         output_channels.set_flags (Gtk::CAN_FOCUS);
497         output_channels.set_digits (0);
498         output_channels.set_wrap (false);
499         output_channels.set_editable (true);
500
501         if (!ARDOUR::Profile->get_mixbus()) {
502                 label = manage (left_aligned_label (_("Output Channels:")));
503                 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
504                 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
505                 ++row;
506         }
507         
508         input_latency.set_name ("InputLatency");
509         input_latency.set_flags (Gtk::CAN_FOCUS);
510         input_latency.set_digits (0);
511         input_latency.set_wrap (false);
512         input_latency.set_editable (true);
513
514         label = manage (left_aligned_label (_("Hardware input latency:")));
515         basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
516         basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
517         label = manage (left_aligned_label (_("samples")));
518         basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
519         ++row;
520
521         output_latency.set_name ("OutputLatency");
522         output_latency.set_flags (Gtk::CAN_FOCUS);
523         output_latency.set_digits (0);
524         output_latency.set_wrap (false);
525         output_latency.set_editable (true);
526
527         label = manage (left_aligned_label (_("Hardware output latency:")));
528         basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
529         basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
530         label = manage (left_aligned_label (_("samples")));
531         basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
532
533         /* button spans 2 rows */
534
535         basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
536         ++row;
537
538         label = manage (left_aligned_label (_("MIDI System:")));
539         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
540         basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
541         basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
542         row++;
543 }
544
545 void
546 EngineControl::build_no_control_notebook ()
547 {
548         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
549         assert (backend);
550
551         using namespace Notebook_Helpers;
552         Label* label;
553         vector<string> strings;
554         AttachOptions xopt = AttachOptions (FILL|EXPAND);
555         int row = 1; // row zero == backend combo
556         const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
557
558         label = manage (new Label);
559         label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
560         basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
561         row++;
562
563         if (backend->can_change_sample_rate_when_running()) {
564                 label = manage (left_aligned_label (_("Sample rate:")));
565                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
566                 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
567                 row++;
568         }
569
570         if (backend->can_change_buffer_size_when_running()) {
571                 label = manage (left_aligned_label (_("Buffer size:")));
572                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
573                 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
574                 buffer_size_duration_label.set_alignment (0.0); /* left-align */
575                 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
576                 row++;
577         }
578
579         basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
580         row++;
581 }
582
583 EngineControl::~EngineControl ()
584 {
585         ignore_changes = true;
586 }
587
588 void
589 EngineControl::disable_latency_tab ()
590 {
591         vector<string> empty;
592         set_popdown_strings (lm_output_channel_combo, empty);
593         set_popdown_strings (lm_input_channel_combo, empty);
594         lm_measure_button.set_sensitive (false);
595         lm_use_button.set_sensitive (false);
596 }
597
598 void
599 EngineControl::enable_latency_tab ()
600 {
601         vector<string> outputs;
602         vector<string> inputs;
603
604         ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
605         ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
606         ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
607
608         if (!ARDOUR::AudioEngine::instance()->running()) {
609                 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
610                 notebook.set_current_page (0);
611                 msg.run ();
612                 return;
613         }
614         else if (inputs.empty() || outputs.empty()) {
615                 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
616                 notebook.set_current_page (0);
617                 msg.run ();
618                 return;
619         }
620
621         lm_back_button_signal.disconnect();
622         if (_measure_midi) {
623                 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
624                 lm_preamble.hide ();
625         } else {
626                 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
627                 lm_preamble.show ();
628         }
629
630         set_popdown_strings (lm_output_channel_combo, outputs);
631         lm_output_channel_combo.set_active_text (outputs.front());
632         lm_output_channel_combo.set_sensitive (true);
633
634         set_popdown_strings (lm_input_channel_combo, inputs);
635         lm_input_channel_combo.set_active_text (inputs.front());
636         lm_input_channel_combo.set_sensitive (true);
637
638         lm_measure_button.set_sensitive (true);
639 }
640
641 void
642 EngineControl::setup_midi_tab_for_backend ()
643 {
644         string backend = backend_combo.get_active_text ();
645
646         Gtkmm2ext::container_clear (midi_vbox);
647
648         midi_vbox.set_border_width (12);
649         midi_device_table.set_border_width (12);
650
651         if (backend == "JACK") {
652                 setup_midi_tab_for_jack ();
653         }
654
655         midi_vbox.pack_start (midi_device_table, true, true);
656         midi_vbox.pack_start (midi_back_button, false, false);
657         midi_vbox.show_all ();
658 }
659
660 void
661 EngineControl::setup_midi_tab_for_jack ()
662 {
663 }
664
665 void
666 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
667         if (for_input) {
668                 device->input_latency = a->get_value();
669         } else {
670                 device->output_latency = a->get_value();
671         }
672 }
673
674 void
675 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
676         b->set_active (!b->get_active());
677         device->enabled = b->get_active();
678         refresh_midi_display(device->name);
679 }
680
681 void
682 EngineControl::refresh_midi_display (std::string focus)
683 {
684         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
685         assert (backend);
686
687         int row  = 0;
688         AttachOptions xopt = AttachOptions (FILL|EXPAND);
689         Gtk::Label* l;
690
691         Gtkmm2ext::container_clear (midi_device_table);
692
693         midi_device_table.set_spacings (6);
694
695         l = manage (new Label);
696         l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
697         midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
698         l->set_alignment (0.5, 0.5);
699         row++;
700         l->show ();
701
702         l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
703         midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
704         l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
705         midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
706         row++;
707         l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
708         midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
709         l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
710         midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
711         row++;
712
713         for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
714                 ArdourButton *m;
715                 Gtk::Button* b;
716                 Gtk::Adjustment *a;
717                 Gtk::SpinButton *s;
718                 bool enabled = (*p)->enabled;
719
720                 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
721                 m->set_name ("midi device");
722                 m->set_can_focus (Gtk::CAN_FOCUS);
723                 m->add_events (Gdk::BUTTON_RELEASE_MASK);
724                 m->set_active (enabled);
725                 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
726                 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
727                 if ((*p)->name == focus) {
728                         m->grab_focus();
729                 }
730
731                 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
732                 s = manage (new Gtk::SpinButton (*a));
733                 a->set_value ((*p)->input_latency);
734                 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
735                 s->set_sensitive (_can_set_midi_latencies && enabled);
736                 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
737
738                 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
739                 s = manage (new Gtk::SpinButton (*a));
740                 a->set_value ((*p)->output_latency);
741                 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
742                 s->set_sensitive (_can_set_midi_latencies && enabled);
743                 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
744
745                 b = manage (new Button (_("Calibrate")));
746                 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
747                 b->set_sensitive (_can_set_midi_latencies && enabled);
748                 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
749
750                 row++;
751         }
752 }
753
754 void
755 EngineControl::update_sensitivity ()
756 {
757 }
758
759 void
760 EngineControl::backend_changed ()
761 {
762         string backend_name = backend_combo.get_active_text();
763         boost::shared_ptr<ARDOUR::AudioBackend> backend;
764
765         if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
766                 /* eh? setting the backend failed... how ? */
767                 /* A: stale config contains a backend that does not exist in current build */
768                 return;
769         }
770
771         _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
772
773         build_notebook ();
774         setup_midi_tab_for_backend ();
775         _midi_devices.clear();
776
777         if (backend->requires_driver_selection()) {
778                 vector<string> drivers = backend->enumerate_drivers();
779                 driver_combo.set_sensitive (true);
780
781                 if (!drivers.empty()) {
782                         {
783                                 string current_driver;
784                                 current_driver = backend->driver_name ();
785
786                                 // driver might not have been set yet
787                                 if (current_driver == "") {
788                                         current_driver = driver_combo.get_active_text ();
789                                         if (current_driver == "")
790                                                 // driver has never been set, make sure it's not blank
791                                                 current_driver = drivers.front ();
792                                 }
793
794                                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
795                                 set_popdown_strings (driver_combo, drivers);
796                                 driver_combo.set_active_text (current_driver);
797                         }
798
799                         driver_changed ();
800                 }
801
802         } else {
803                 driver_combo.set_sensitive (false);
804                 /* this will change the device text which will cause a call to
805                  * device changed which will set up parameters
806                  */
807                 list_devices ();
808         }
809
810         vector<string> midi_options = backend->enumerate_midi_options();
811
812         if (midi_options.size() == 1) {
813                 /* only contains the "none" option */
814                 midi_option_combo.set_sensitive (false);
815         } else {
816                 if (_have_control) {
817                         set_popdown_strings (midi_option_combo, midi_options);
818                         midi_option_combo.set_active_text (midi_options.front());
819                         midi_option_combo.set_sensitive (true);
820                 } else {
821                         midi_option_combo.set_sensitive (false);
822                 }
823         }
824
825         connect_disconnect_button.hide();
826
827         midi_option_changed();
828
829         started_at_least_once = false;
830
831         if (!ignore_changes) {
832                 maybe_display_saved_state ();
833         }
834 }
835
836 bool
837 EngineControl::print_channel_count (Gtk::SpinButton* sb)
838 {
839         if (ARDOUR::Profile->get_mixbus()) {
840                 return true;
841         }
842         
843         uint32_t cnt = (uint32_t) sb->get_value();
844         if (cnt == 0) {
845                 sb->set_text (_("all available channels"));
846         } else {
847                 char buf[32];
848                 snprintf (buf, sizeof (buf), "%d", cnt);
849                 sb->set_text (buf);
850         }
851         return true;
852 }
853
854 bool
855 EngineControl::set_driver_popdown_strings ()
856 {
857         string backend_name = backend_combo.get_active_text();
858         boost::shared_ptr<ARDOUR::AudioBackend> backend;
859
860         if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
861                 /* eh? setting the backend failed... how ? */
862                 /* A: stale config contains a backend that does not exist in current build */
863                 return false;
864         }
865
866         vector<string> drivers = backend->enumerate_drivers();
867         set_popdown_strings (driver_combo, drivers);
868         return true;
869 }
870
871 // @return true if there are devices available
872 bool
873 EngineControl::set_device_popdown_strings ()
874 {
875         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
876         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
877
878         /* NOTE: Ardour currently does not display the "available" field of the
879          * returned devices.
880          *
881          * Doing so would require a different GUI widget than the combo
882          * box/popdown that we currently use, since it has no way to list
883          * items that are not selectable. Something more like a popup menu,
884          * which could have unselectable items, would be appropriate.
885          */
886
887         vector<string> available_devices;
888
889         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
890                 available_devices.push_back (i->name);
891         }
892
893
894         if (!available_devices.empty()) {
895                 update_sensitivity ();
896
897                 {
898                         string current_device, found_device;
899                         current_device = device_combo.get_active_text ();
900                         if (current_device == "") {
901                                 current_device = backend->device_name ();
902                         }
903
904                         // Make sure that the active text is still relevant for this
905                         // device (it might only be relevant to the previous device!!)
906                         for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
907                                 if (*i == current_device)
908                                         found_device = current_device;
909                         }
910                         if (found_device == "")
911                                 // device has never been set (or was not relevant
912                                 // for this backend) Let's make sure it's not blank
913                                 current_device = available_devices.front ();
914
915                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
916                         set_popdown_strings (device_combo, available_devices);
917
918                         device_combo.set_active_text (current_device);
919                 }
920
921                 device_changed ();
922                 return true;
923         }
924         return false;
925 }
926
927 // @return true if there are input devices available
928 bool
929 EngineControl::set_input_device_popdown_strings ()
930 {
931         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
932         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
933
934         vector<string> available_devices;
935
936         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
937                 available_devices.push_back (i->name);
938         }
939
940         if (!available_devices.empty()) {
941                 update_sensitivity ();
942
943                 {
944                         string current_device, found_device;
945                         current_device = input_device_combo.get_active_text ();
946                         if (current_device == "") {
947                                 current_device = backend->input_device_name ();
948                         }
949
950                         // Make sure that the active text is still relevant for this
951                         // device (it might only be relevant to the previous device!!)
952                         for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
953                                 if (*i == current_device)
954                                         found_device = current_device;
955                         }
956                         if (found_device == "")
957                                 // device has never been set (or was not relevant
958                                 // for this backend) Let's make sure it's not blank
959                                 current_device = available_devices.front ();
960
961                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
962                         set_popdown_strings (input_device_combo, available_devices);
963
964                         input_device_combo.set_active_text (current_device);
965                 }
966
967                 input_device_changed ();
968                 return true;
969         }
970
971         return false;
972 }
973
974 // @return true if there are output devices available
975 bool
976 EngineControl::set_output_device_popdown_strings ()
977 {
978         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
979         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
980
981         vector<string> available_devices;
982
983         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
984                 available_devices.push_back (i->name);
985         }
986
987         if (!available_devices.empty()) {
988                 update_sensitivity ();
989
990                 {
991                         string current_device, found_device;
992                         current_device = output_device_combo.get_active_text ();
993                         if (current_device == "") {
994                                 current_device = backend->output_device_name ();
995                         }
996
997                         // Make sure that the active text is still relevant for this
998                         // device (it might only be relevant to the previous device!!)
999                         for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
1000                                 if (*i == current_device)
1001                                         found_device = current_device;
1002                         }
1003                         if (found_device == "")
1004                                 // device has never been set (or was not relevant
1005                                 // for this backend) Let's make sure it's not blank
1006                                 current_device = available_devices.front ();
1007
1008                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1009                         set_popdown_strings (output_device_combo, available_devices);
1010
1011                         output_device_combo.set_active_text (current_device);
1012                 }
1013
1014                 output_device_changed ();
1015                 return true;
1016         }
1017
1018         return false;
1019 }
1020
1021 void
1022 EngineControl::list_devices ()
1023 {
1024         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1025         assert (backend);
1026
1027         /* now fill out devices, mark sample rates, buffer sizes insensitive */
1028
1029         bool devices_available = false;
1030
1031         if (backend->use_separate_input_and_output_devices ()) {
1032                 bool input_devices_available = set_input_device_popdown_strings ();
1033                 bool output_devices_available = set_output_device_popdown_strings ();
1034                 devices_available = input_devices_available || output_devices_available;
1035         } else {
1036                 devices_available = set_device_popdown_strings ();
1037         }
1038
1039         if (devices_available) {
1040                 input_latency.set_sensitive (true);
1041                 output_latency.set_sensitive (true);
1042                 input_channels.set_sensitive (true);
1043                 output_channels.set_sensitive (true);
1044
1045                 ok_button->set_sensitive (true);
1046                 apply_button->set_sensitive (true);
1047
1048         } else {
1049                 device_combo.clear();
1050                 input_device_combo.clear();
1051                 output_device_combo.clear();
1052                 sample_rate_combo.set_sensitive (false);
1053                 buffer_size_combo.set_sensitive (false);
1054                 input_latency.set_sensitive (false);
1055                 output_latency.set_sensitive (false);
1056                 input_channels.set_sensitive (false);
1057                 output_channels.set_sensitive (false);
1058                 if (_have_control) {
1059                         ok_button->set_sensitive (false);
1060                         apply_button->set_sensitive (false);
1061                 } else {
1062                         ok_button->set_sensitive (true);
1063                         apply_button->set_sensitive (true);
1064                         if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
1065                                 sample_rate_combo.set_sensitive (true);
1066                         }
1067                         if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
1068                                 buffer_size_combo.set_sensitive (true);
1069                         }
1070
1071                 }
1072         }
1073 }
1074
1075 void
1076 EngineControl::driver_changed ()
1077 {
1078         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1079         assert (backend);
1080
1081         backend->set_driver (driver_combo.get_active_text());
1082         list_devices ();
1083
1084         if (!ignore_changes) {
1085                 maybe_display_saved_state ();
1086         }
1087 }
1088
1089 void
1090 EngineControl::set_samplerate_popdown_strings (const std::string& device_name)
1091 {
1092         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1093         string desired;
1094         vector<float> sr;
1095         vector<string> s;
1096
1097         if (_have_control) {
1098                 sr = backend->available_sample_rates (device_name);
1099         } else {
1100
1101                 sr.push_back (8000.0f);
1102                 sr.push_back (16000.0f);
1103                 sr.push_back (32000.0f);
1104                 sr.push_back (44100.0f);
1105                 sr.push_back (48000.0f);
1106                 sr.push_back (88200.0f);
1107                 sr.push_back (96000.0f);
1108                 sr.push_back (192000.0f);
1109                 sr.push_back (384000.0f);
1110         }
1111
1112         for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1113                 s.push_back (rate_as_string (*x));
1114                 if (*x == _desired_sample_rate) {
1115                         desired = s.back();
1116                 }
1117         }
1118
1119         if (!s.empty()) {
1120                 sample_rate_combo.set_sensitive (true);
1121                 set_popdown_strings (sample_rate_combo, s);
1122
1123                 if (desired.empty()) {
1124                         sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
1125                 } else {
1126                         sample_rate_combo.set_active_text (desired);
1127                 }
1128
1129         } else {
1130                 sample_rate_combo.set_sensitive (false);
1131         }
1132 }
1133
1134 void
1135 EngineControl::set_buffersize_popdown_strings (const std::string& device_name)
1136 {
1137         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1138         vector<uint32_t> bs;
1139         vector<string> s;
1140
1141         if (_have_control) {
1142                 bs = backend->available_buffer_sizes (device_name);
1143         } else if (backend->can_change_buffer_size_when_running()) {
1144                 bs.push_back (8);
1145                 bs.push_back (16);
1146                 bs.push_back (32);
1147                 bs.push_back (64);
1148                 bs.push_back (128);
1149                 bs.push_back (256);
1150                 bs.push_back (512);
1151                 bs.push_back (1024);
1152                 bs.push_back (2048);
1153                 bs.push_back (4096);
1154                 bs.push_back (8192);
1155         }
1156         s.clear ();
1157         for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1158                 s.push_back (bufsize_as_string (*x));
1159         }
1160
1161         if (!s.empty()) {
1162                 buffer_size_combo.set_sensitive (true);
1163                 set_popdown_strings (buffer_size_combo, s);
1164                 buffer_size_combo.set_active_text (s.front());
1165
1166                 uint32_t period = backend->buffer_size();
1167                 if (0 == period) {
1168                         period = backend->default_buffer_size(device_name);
1169                 }
1170                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1171                 show_buffer_duration ();
1172         } else {
1173                 buffer_size_combo.set_sensitive (false);
1174         }
1175 }
1176
1177 void
1178 EngineControl::device_changed ()
1179 {
1180         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1181         assert (backend);
1182
1183         string device_name_in;
1184         string device_name_out; // only used if backend support separate I/O devices
1185
1186         if (backend->use_separate_input_and_output_devices()) {
1187                 device_name_in  = get_input_device_name ();
1188                 device_name_out = get_output_device_name ();
1189         } else {
1190                 device_name_in = get_device_name ();
1191         }
1192
1193         /* we set the backend-device to query various device related intormation.
1194          * This has the side effect that backend->device_name() will match
1195          * the device_name and  'change_device' will never be true.
1196          * so work around this by setting...
1197          */
1198         if (backend->use_separate_input_and_output_devices()) {
1199                 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1200                         queue_device_changed = true;
1201                 }
1202         } else {
1203                 if (device_name_in != backend->device_name()) {
1204                         queue_device_changed = true;
1205                 }
1206         }
1207         
1208         //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1209         if (backend->use_separate_input_and_output_devices()) {
1210                 backend->set_input_device_name (device_name_in);
1211                 backend->set_output_device_name (device_name_out);
1212         } else {
1213                 backend->set_device_name(device_name_in);
1214         }
1215
1216         {
1217                 /* don't allow programmatic change to combos to cause a
1218                    recursive call to this method.
1219                  */
1220                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1221
1222                 /* backends that support separate devices, need to ignore
1223                  * the device-name - and use the devies set above
1224                  */
1225                 set_samplerate_popdown_strings (device_name_in);
1226                 set_buffersize_popdown_strings (device_name_in);
1227                 /* XXX theoretically need to set min + max channel counts here
1228                 */
1229
1230                 manage_control_app_sensitivity ();
1231         }
1232
1233         /* pick up any saved state for this device */
1234
1235         if (!ignore_changes) {
1236                 maybe_display_saved_state ();
1237         }
1238 }
1239
1240 void
1241 EngineControl::input_device_changed ()
1242 {
1243         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1244         assert (backend);
1245         string input_device_name = input_device_combo.get_active_text ();
1246
1247         if (!ignore_changes && input_device_name != backend->input_device_name()) {
1248                 queue_device_changed = true;
1249         }
1250
1251         backend->set_input_device_name(input_device_name);
1252
1253         {
1254                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1255
1256                 set_samplerate_popdown_strings (input_device_name);
1257                 set_buffersize_popdown_strings (input_device_name);
1258                 /* XXX theoretically need to set min + max channel counts here
1259                 */
1260
1261                 manage_control_app_sensitivity ();
1262         }
1263
1264         /* pick up any saved state for this device */
1265
1266         if (!ignore_changes) {
1267                 maybe_display_saved_state ();
1268         }
1269 }
1270
1271 void
1272 EngineControl::output_device_changed ()
1273 {
1274         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1275         assert (backend);
1276         string output_device_name = output_device_combo.get_active_text ();
1277
1278         if (!ignore_changes && output_device_name != backend->output_device_name()) {
1279                 queue_device_changed = true;
1280         }
1281
1282         backend->set_output_device_name(output_device_name);
1283
1284         {
1285                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1286
1287                 set_samplerate_popdown_strings (output_device_name);
1288                 set_buffersize_popdown_strings (output_device_name);
1289                 /* XXX theoretically need to set min + max channel counts here
1290                 */
1291
1292                 manage_control_app_sensitivity ();
1293         }
1294
1295         /* pick up any saved state for this device */
1296
1297         if (!ignore_changes) {
1298                 maybe_display_saved_state ();
1299         }
1300 }
1301
1302 string
1303 EngineControl::bufsize_as_string (uint32_t sz)
1304 {
1305         /* Translators: "samples" is always plural here, so no
1306            need for plural+singular forms.
1307          */
1308         char buf[64];
1309         snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1310         return buf;
1311 }
1312
1313 void
1314 EngineControl::sample_rate_changed ()
1315 {
1316         /* reset the strings for buffer size to show the correct msec value
1317            (reflecting the new sample rate).
1318          */
1319
1320         show_buffer_duration ();
1321
1322 }
1323
1324 void
1325 EngineControl::buffer_size_changed ()
1326 {
1327         show_buffer_duration ();
1328 }
1329
1330 void
1331 EngineControl::show_buffer_duration ()
1332 {
1333
1334         /* buffer sizes  - convert from just samples to samples + msecs for
1335          * the displayed string
1336          */
1337
1338         string bs_text = buffer_size_combo.get_active_text ();
1339         uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1340         uint32_t rate = get_rate();
1341
1342         /* Developers: note the hard-coding of a double buffered model
1343            in the (2 * samples) computation of latency. we always start
1344            the audiobackend in this configuration.
1345          */
1346         /* note to jack1 developers: ardour also always starts the engine
1347          * in async mode (no jack2 --sync option) which adds an extra cycle
1348          * of latency with jack2 (and *3 would be correct)
1349          * The value can also be wrong if jackd is started externally..
1350          *
1351          * At the time of writing the ALSA backend always uses double-buffering *2,
1352          * The Dummy backend *1, and who knows what ASIO really does :)
1353          *
1354          * So just display the period size, that's also what
1355          * ARDOUR_UI::update_sample_rate() does for the status bar.
1356          * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1357          * but still, that's the buffer period, not [round-trip] latency)
1358          */
1359         char buf[32];
1360         snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1361         buffer_size_duration_label.set_text (buf);
1362 }
1363
1364 void
1365 EngineControl::midi_option_changed ()
1366 {
1367         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1368         assert (backend);
1369
1370         backend->set_midi_option (get_midi_option());
1371
1372         vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1373
1374         //_midi_devices.clear(); // TODO merge with state-saved settings..
1375         _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1376         std::vector<MidiDeviceSettings> new_devices;
1377
1378         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1379                 MidiDeviceSettings mds = find_midi_device (i->name);
1380                 if (i->available && !mds) {
1381                         uint32_t input_latency = 0;
1382                         uint32_t output_latency = 0;
1383                         if (_can_set_midi_latencies) {
1384                                 input_latency = backend->systemic_midi_input_latency (i->name);
1385                                 output_latency = backend->systemic_midi_output_latency (i->name);
1386                         }
1387                         bool enabled = backend->midi_device_enabled (i->name);
1388                         MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1389                         new_devices.push_back (ptr);
1390                 } else if (i->available) {
1391                         new_devices.push_back (mds);
1392                 }
1393         }
1394         _midi_devices = new_devices;
1395
1396         if (_midi_devices.empty()) {
1397                 midi_devices_button.set_sensitive (false);
1398         } else {
1399                 midi_devices_button.set_sensitive (true);
1400         }
1401 }
1402
1403 void
1404 EngineControl::parameter_changed ()
1405 {
1406 }
1407
1408 EngineControl::State
1409 EngineControl::get_matching_state (
1410                 const string& backend,
1411                 const string& driver,
1412                 const string& device)
1413 {
1414         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1415                 if ((*i)->backend == backend &&
1416                                 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1417                 {
1418                         return (*i);
1419                 }
1420         }
1421         return State();
1422 }
1423
1424 EngineControl::State
1425 EngineControl::get_matching_state (
1426                 const string& backend,
1427                 const string& driver,
1428                 const string& input_device,
1429                 const string& output_device)
1430 {
1431         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1432                 if ((*i)->backend == backend &&
1433                                 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1434                 {
1435                         return (*i);
1436                 }
1437         }
1438         return State();
1439 }
1440
1441 EngineControl::State
1442 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1443 {
1444         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1445
1446         if (backend) {
1447                 if (backend->use_separate_input_and_output_devices ()) {
1448                         return get_matching_state (backend_combo.get_active_text(),
1449                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1450                                         input_device_combo.get_active_text(),
1451                                         output_device_combo.get_active_text());
1452                 } else {
1453                         return get_matching_state (backend_combo.get_active_text(),
1454                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1455                                         device_combo.get_active_text());
1456                 }
1457         }
1458
1459         return get_matching_state (backend_combo.get_active_text(),
1460                         string(),
1461                         device_combo.get_active_text());
1462 }
1463
1464 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1465                                        const EngineControl::State& state2)
1466 {
1467         if (state1->backend == state2->backend &&
1468                         state1->driver == state2->driver &&
1469                         state1->device == state2->device &&
1470                         state1->input_device == state2->input_device &&
1471                         state1->output_device == state2->output_device) {
1472                 return true;
1473         }
1474         return false;
1475 }
1476
1477 EngineControl::State
1478 EngineControl::save_state ()
1479 {
1480         State state;
1481
1482         if (!_have_control) {
1483                 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1484                 if (state) {
1485                         return state;
1486                 }
1487                 state.reset(new StateStruct);
1488                 state->backend = get_backend ();
1489         } else {
1490                 state.reset(new StateStruct);
1491                 store_state (state);
1492         }
1493
1494         for (StateList::iterator i = states.begin(); i != states.end();) {
1495                 if (equivalent_states (*i, state)) {
1496                         i =  states.erase(i);
1497                 } else {
1498                         ++i;
1499                 }
1500         }
1501
1502         states.push_back (state);
1503
1504         return state;
1505 }
1506
1507 void
1508 EngineControl::store_state (State state)
1509 {
1510         state->backend = get_backend ();
1511         state->driver = get_driver ();
1512         state->device = get_device_name ();
1513         state->input_device = get_input_device_name ();
1514         state->output_device = get_output_device_name ();
1515         state->sample_rate = get_rate ();
1516         state->buffer_size = get_buffer_size ();
1517         state->input_latency = get_input_latency ();
1518         state->output_latency = get_output_latency ();
1519         state->input_channels = get_input_channels ();
1520         state->output_channels = get_output_channels ();
1521         state->midi_option = get_midi_option ();
1522         state->midi_devices = _midi_devices;
1523 }
1524
1525 void
1526 EngineControl::maybe_display_saved_state ()
1527 {
1528         if (!_have_control) {
1529                 return;
1530         }
1531
1532         State state = get_saved_state_for_currently_displayed_backend_and_device ();
1533
1534         if (state) {
1535                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1536
1537                 if (!_desired_sample_rate) {
1538                         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1539                 }
1540                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1541                 /* call this explicitly because we're ignoring changes to
1542                    the controls at this point.
1543                  */
1544                 show_buffer_duration ();
1545                 input_latency.set_value (state->input_latency);
1546                 output_latency.set_value (state->output_latency);
1547
1548                 if (!state->midi_option.empty()) {
1549                         midi_option_combo.set_active_text (state->midi_option);
1550                         _midi_devices = state->midi_devices;
1551                 }
1552         }
1553 }
1554
1555 XMLNode&
1556 EngineControl::get_state ()
1557 {
1558         LocaleGuard lg (X_("C"));
1559
1560         XMLNode* root = new XMLNode ("AudioMIDISetup");
1561         std::string path;
1562
1563         if (!states.empty()) {
1564                 XMLNode* state_nodes = new XMLNode ("EngineStates");
1565
1566                 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1567
1568                         XMLNode* node = new XMLNode ("State");
1569
1570                         node->add_property ("backend", (*i)->backend);
1571                         node->add_property ("driver", (*i)->driver);
1572                         node->add_property ("device", (*i)->device);
1573                         node->add_property ("input-device", (*i)->input_device);
1574                         node->add_property ("output-device", (*i)->output_device);
1575                         node->add_property ("sample-rate", (*i)->sample_rate);
1576                         node->add_property ("buffer-size", (*i)->buffer_size);
1577                         node->add_property ("input-latency", (*i)->input_latency);
1578                         node->add_property ("output-latency", (*i)->output_latency);
1579                         node->add_property ("input-channels", (*i)->input_channels);
1580                         node->add_property ("output-channels", (*i)->output_channels);
1581                         node->add_property ("active", (*i)->active ? "yes" : "no");
1582                         node->add_property ("midi-option", (*i)->midi_option);
1583
1584                         XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1585                         for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1586                                 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1587                                 midi_device_stuff->add_property (X_("name"), (*p)->name);
1588                                 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1589                                 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1590                                 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1591                                 midi_devices->add_child_nocopy (*midi_device_stuff);
1592                         }
1593                         node->add_child_nocopy (*midi_devices);
1594
1595                         state_nodes->add_child_nocopy (*node);
1596                 }
1597
1598                 root->add_child_nocopy (*state_nodes);
1599         }
1600
1601         return *root;
1602 }
1603
1604 void
1605 EngineControl::set_state (const XMLNode& root)
1606 {
1607         XMLNodeList          clist, cclist;
1608         XMLNodeConstIterator citer, cciter;
1609         XMLNode* child;
1610         XMLNode* grandchild;
1611         XMLProperty* prop = NULL;
1612
1613         fprintf (stderr, "EngineControl::set_state\n");
1614
1615         if (root.name() != "AudioMIDISetup") {
1616                 return;
1617         }
1618
1619         clist = root.children();
1620
1621         states.clear ();
1622
1623         for (citer = clist.begin(); citer != clist.end(); ++citer) {
1624
1625                 child = *citer;
1626
1627                 if (child->name() != "EngineStates") {
1628                         continue;
1629                 }
1630
1631                 cclist = child->children();
1632
1633                 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1634                         State state (new StateStruct);
1635
1636                         grandchild = *cciter;
1637
1638                         if (grandchild->name() != "State") {
1639                                 continue;
1640                         }
1641
1642                         if ((prop = grandchild->property ("backend")) == 0) {
1643                                 continue;
1644                         }
1645                         state->backend = prop->value ();
1646
1647                         if ((prop = grandchild->property ("driver")) == 0) {
1648                                 continue;
1649                         }
1650                         state->driver = prop->value ();
1651
1652                         if ((prop = grandchild->property ("device")) == 0) {
1653                                 continue;
1654                         }
1655                         state->device = prop->value ();
1656
1657                         if ((prop = grandchild->property ("input-device")) == 0) {
1658                                 continue;
1659                         }
1660                         state->input_device = prop->value ();
1661
1662                         if ((prop = grandchild->property ("output-device")) == 0) {
1663                                 continue;
1664                         }
1665                         state->output_device = prop->value ();
1666
1667                         if ((prop = grandchild->property ("sample-rate")) == 0) {
1668                                 continue;
1669                         }
1670                         state->sample_rate = atof (prop->value ());
1671
1672                         if ((prop = grandchild->property ("buffer-size")) == 0) {
1673                                 continue;
1674                         }
1675                         state->buffer_size = atoi (prop->value ());
1676
1677                         if ((prop = grandchild->property ("input-latency")) == 0) {
1678                                 continue;
1679                         }
1680                         state->input_latency = atoi (prop->value ());
1681
1682                         if ((prop = grandchild->property ("output-latency")) == 0) {
1683                                 continue;
1684                         }
1685                         state->output_latency = atoi (prop->value ());
1686
1687                         if ((prop = grandchild->property ("input-channels")) == 0) {
1688                                 continue;
1689                         }
1690                         state->input_channels = atoi (prop->value ());
1691
1692                         if ((prop = grandchild->property ("output-channels")) == 0) {
1693                                 continue;
1694                         }
1695                         state->output_channels = atoi (prop->value ());
1696
1697                         if ((prop = grandchild->property ("active")) == 0) {
1698                                 continue;
1699                         }
1700                         state->active = string_is_affirmative (prop->value ());
1701
1702                         if ((prop = grandchild->property ("midi-option")) == 0) {
1703                                 continue;
1704                         }
1705                         state->midi_option = prop->value ();
1706
1707                         state->midi_devices.clear();
1708                         XMLNode* midinode;
1709                         if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1710                                 const XMLNodeList mnc = midinode->children();
1711                                 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1712                                         if ((*n)->property (X_("name")) == 0
1713                                                         || (*n)->property (X_("enabled")) == 0
1714                                                         || (*n)->property (X_("input-latency")) == 0
1715                                                         || (*n)->property (X_("output-latency")) == 0
1716                                                  ) {
1717                                                 continue;
1718                                         }
1719
1720                                         MidiDeviceSettings ptr (new MidiDeviceSetting(
1721                                                                 (*n)->property (X_("name"))->value (),
1722                                                                 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1723                                                                 atoi ((*n)->property (X_("input-latency"))->value ()),
1724                                                                 atoi ((*n)->property (X_("output-latency"))->value ())
1725                                                                 ));
1726                                         state->midi_devices.push_back (ptr);
1727                                 }
1728                         }
1729
1730 #if 1
1731                         /* remove accumulated duplicates (due to bug in ealier version)
1732                          * this can be removed again before release
1733                          */
1734                         for (StateList::iterator i = states.begin(); i != states.end();) {
1735                                 if ((*i)->backend == state->backend &&
1736                                                 (*i)->driver == state->driver &&
1737                                                 (*i)->device == state->device) {
1738                                         i =  states.erase(i);
1739                                 } else {
1740                                         ++i;
1741                                 }
1742                         }
1743 #endif
1744
1745                         states.push_back (state);
1746                 }
1747         }
1748
1749         /* now see if there was an active state and switch the setup to it */
1750
1751         // purge states of backend that are not available in this built
1752         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1753         vector<std::string> backend_names;
1754
1755         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1756                 backend_names.push_back((*i)->name);
1757         }
1758         for (StateList::iterator i = states.begin(); i != states.end();) {
1759                 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1760                         i = states.erase(i);
1761                 } else {
1762                         ++i;
1763                 }
1764         }
1765
1766         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1767
1768                 if ((*i)->active) {
1769                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1770                         backend_combo.set_active_text ((*i)->backend);
1771
1772                         /* The driver popdown strings need to be populated now so that
1773                          * set_active_text will actually set a valid entry. Then
1774                          * backend_changed() will populate all the other combo's so they
1775                          * can also be set to valid entries and the state will be restored
1776                          * correctly.
1777                          */
1778                         set_driver_popdown_strings ();
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 }