c9ebcf4cf2c8693bc035cd772b8ded9206c59210
[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/rc_configuration.h"
44 #include "ardour/types.h"
45
46 #include "pbd/convert.h"
47 #include "pbd/error.h"
48
49 #include "ardour_ui.h"
50 #include "engine_dialog.h"
51 #include "gui_thread.h"
52 #include "utils.h"
53 #include "i18n.h"
54
55 using namespace std;
56 using namespace Gtk;
57 using namespace Gtkmm2ext;
58 using namespace PBD;
59 using namespace Glib;
60
61 EngineControl::EngineControl ()
62         : ArdourDialog (_("Audio/MIDI Setup"))
63         , basic_packer (9, 3)
64         , input_latency_adjustment (0, 0, 99999, 1)
65         , input_latency (input_latency_adjustment)
66         , output_latency_adjustment (0, 0, 99999, 1)
67         , output_latency (output_latency_adjustment)
68         , input_channels_adjustment (0, 0, 256, 1)
69         , input_channels (input_channels_adjustment)
70         , output_channels_adjustment (0, 0, 256, 1)
71         , output_channels (output_channels_adjustment)
72         , ports_adjustment (128, 8, 1024, 1, 16)
73         , ports_spinner (ports_adjustment)
74         , control_app_button (_("Device Control Panel"))
75         , lm_start_stop_label (_("Measure latency"))
76         , lm_use_button (_("Use results"))
77         , lm_table (5, 2)
78         , have_lm_results (false)
79         , midi_refresh_button (_("Refresh list"))
80         , aj_button (_("Start MIDI ALSA/JACK bridge"))
81         , ignore_changes (0)
82         , _desired_sample_rate (0)
83         , no_push (true)
84         , started_at_least_once (false)
85 {
86         using namespace Notebook_Helpers;
87         vector<string> strings;
88         Label* label;
89         AttachOptions xopt = AttachOptions (FILL|EXPAND);
90         int row;
91
92         set_name (X_("AudioMIDISetup"));
93
94         /* the backend combo is the one thing that is ALWAYS visible 
95          */
96
97         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
98
99         if (backends.empty()) {
100                 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));
101                 msg.run ();
102                 throw failed_constructor ();
103         }
104
105         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
106                 strings.push_back ((*b)->name);
107         }
108
109         set_popdown_strings (backend_combo, strings);
110         backend_combo.set_active_text (strings.front());
111         backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
112
113         /* setup basic packing characteristics for the table used on the main
114          * tab of the notebook
115          */
116
117         basic_packer.set_spacings (6);
118         basic_packer.set_border_width (12);
119         basic_packer.set_homogeneous (true);
120
121         /* pack it in */
122
123         basic_hbox.pack_start (basic_packer, false, false);
124
125         /* latency tab */
126
127         /* latency measurement tab */
128         
129         lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
130         
131         row = 0;
132         lm_table.set_row_spacings (12);
133
134         lm_table.attach (lm_title, 0, 2, row, row+1, xopt, (AttachOptions) 0);
135         row++;
136
137         Gtk::Label* preamble;
138
139         preamble = manage (new Label);
140         preamble->set_width_chars (60);
141         preamble->set_line_wrap (true);
142         preamble->set_markup (_("<span weight=\"bold\">Turn down the volume on your hardware to a very low level.</span>"));
143
144         lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
145         row++;
146
147         preamble = manage (new Label);
148         preamble->set_width_chars (60);
149         preamble->set_line_wrap (true);
150         preamble->set_markup (_("Select two channels below and connect them using a cable or (less ideally) a speaker and microphone."));
151
152         lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
153         row++;
154
155         label = manage (new Label (_("Output channel")));
156         lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
157
158         Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
159         misc_align->add (lm_output_channel_combo);
160         lm_table.attach (*misc_align, 1, 2, row, row+1, xopt, (AttachOptions) 0);
161         ++row;
162
163         label = manage (new Label (_("Input channel")));
164         lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
165
166         misc_align = manage (new Alignment (0.0, 0.5));
167         misc_align->add (lm_input_channel_combo);
168         lm_table.attach (*misc_align, 1, 2, row, row+1, FILL, (AttachOptions) 0);
169         ++row;
170
171         xopt = AttachOptions(0);
172
173         lm_measure_button.add (lm_start_stop_label);
174         
175         lm_measure_button.signal_toggled().connect (sigc::mem_fun (*this, &EngineControl::latency_button_toggled));
176         lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
177         lm_use_button.set_sensitive (false);
178
179         preamble = manage (new Label);
180         preamble->set_width_chars (60);
181         preamble->set_line_wrap (true);
182         preamble->set_markup (_("Once the channels are connected, click the \"Measure latency\" button."));
183         lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
184         row++;
185
186         lm_table.attach (lm_measure_button, 0, 2, row, row+1, xopt, (AttachOptions) 0);
187         ++row;
188         lm_table.attach (lm_results, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
189         ++row;
190
191
192         preamble = manage (new Label);
193         preamble->set_width_chars (60);
194         preamble->set_line_wrap (true);
195         preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
196         lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
197         row++;
198
199         lm_table.attach (lm_use_button, 0, 2, row, row+1, xopt, (AttachOptions) 0);
200         ++row;
201
202         lm_results.set_markup ("<i>No measurement results yet</i>");
203
204         lm_vbox.set_border_width (12);
205         lm_vbox.pack_start (lm_table, false, false);
206
207         /* pack it all up */
208
209         notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
210         notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
211         notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
212         notebook.set_border_width (12);
213
214         notebook.set_tab_pos (POS_RIGHT);
215         notebook.show_all ();
216
217         notebook.set_name ("SettingsNotebook");
218
219         /* packup the notebook */
220
221         get_vbox()->set_border_width (12);
222         get_vbox()->pack_start (notebook);
223
224         /* need a special function to print "all available channels" when the
225          * channel counts hit zero.
226          */
227
228         input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
229         output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
230
231         control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
232         manage_control_app_sensitivity ();
233
234         cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
235         ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
236         apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
237
238         /* Pick up any existing audio setup configuration, if appropriate */
239
240         XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
241         
242         ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
243         ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
244         ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
245
246         backend_changed ();
247
248         if (audio_setup) {
249                 set_state (*audio_setup);
250         }
251
252         /* Connect to signals */
253
254         driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
255         sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
256         buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
257         device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed));
258
259         input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
260         output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
261         input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
262         output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
263
264         notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
265
266         no_push = false;
267 }
268
269 void
270 EngineControl::on_response (int response_id)
271 {
272         ArdourDialog::on_response (response_id);
273
274         switch (response_id) {
275         case RESPONSE_APPLY:
276                 push_state_to_backend (true);
277                 break;
278         case RESPONSE_OK:
279                 push_state_to_backend (true);
280                 hide ();
281                 break;
282         case RESPONSE_DELETE_EVENT: {
283                 GdkEventButton ev;
284                 ev.type = GDK_BUTTON_PRESS;
285                 ev.button = 1;
286                 on_delete_event ((GdkEventAny*) &ev);
287                 break;
288         }
289         default:
290                 hide ();
291         }
292 }
293
294 void
295 EngineControl::build_notebook ()
296 {
297         Label* label;
298         AttachOptions xopt = AttachOptions (FILL|EXPAND);
299
300         /* clear the table */
301
302         Gtkmm2ext::container_clear (basic_vbox);
303         Gtkmm2ext::container_clear (basic_packer);
304
305         label = manage (left_aligned_label (_("Audio System:")));
306         basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
307         basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
308         
309         if (_have_control) {
310                 build_full_control_notebook ();
311         } else {
312                 build_no_control_notebook ();
313         }
314
315         basic_vbox.pack_start (basic_hbox, false, false);
316
317         if (_have_control) {
318                 Gtk::HBox* hpacker = manage (new HBox);
319                 hpacker->set_border_width (12);
320                 hpacker->pack_start (control_app_button, false, false);
321                 hpacker->show ();
322                 control_app_button.show();
323                 basic_vbox.pack_start (*hpacker);
324         }
325
326         basic_vbox.show_all ();
327 }
328
329 void
330 EngineControl::build_full_control_notebook ()
331 {
332         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
333         assert (backend);
334
335         using namespace Notebook_Helpers;
336         Label* label;
337         vector<string> strings;
338         AttachOptions xopt = AttachOptions (FILL|EXPAND);
339         int row = 1; // row zero == backend combo
340
341         /* start packing it up */
342
343         if (backend->requires_driver_selection()) {
344                 label = manage (left_aligned_label (_("Driver:")));
345                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
346                 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
347                 row++;
348         }
349
350         label = manage (left_aligned_label (_("Device:")));
351         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
352         basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
353         row++;
354
355         label = manage (left_aligned_label (_("Sample rate:")));
356         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
357         basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
358         row++;
359
360
361         label = manage (left_aligned_label (_("Buffer size:")));
362         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
363         basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
364         buffer_size_duration_label.set_alignment (0.0); /* left-align */
365         basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
366         row++;
367
368         input_channels.set_name ("InputChannels");
369         input_channels.set_flags(Gtk::CAN_FOCUS);
370         input_channels.set_digits(0);
371         input_channels.set_wrap(false);
372         output_channels.set_editable (true);
373
374         label = manage (left_aligned_label (_("Input Channels:")));
375         basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
376         basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
377         ++row;
378
379         output_channels.set_name ("OutputChannels");
380         output_channels.set_flags(Gtk::CAN_FOCUS);
381         output_channels.set_digits(0);
382         output_channels.set_wrap(false);
383         output_channels.set_editable (true);
384
385         label = manage (left_aligned_label (_("Output Channels:")));
386         basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
387         basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
388         ++row;
389
390         input_latency.set_name ("InputLatency");
391         input_latency.set_flags(Gtk::CAN_FOCUS);
392         input_latency.set_digits(0);
393         input_latency.set_wrap(false);
394         input_latency.set_editable (true);
395
396         label = manage (left_aligned_label (_("Hardware input latency:")));
397         basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
398         basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
399         label = manage (left_aligned_label (_("samples")));
400         basic_packer.attach (*label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
401         ++row;
402
403         output_latency.set_name ("OutputLatency");
404         output_latency.set_flags(Gtk::CAN_FOCUS);
405         output_latency.set_digits(0);
406         output_latency.set_wrap(false);
407         output_latency.set_editable (true);
408
409         label = manage (left_aligned_label (_("Hardware output latency:")));
410         basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
411         basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
412         label = manage (left_aligned_label (_("samples")));
413         basic_packer.attach (*label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
414         ++row;
415
416 }
417
418 void
419 EngineControl::build_no_control_notebook ()
420 {
421         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
422         assert (backend);
423
424         using namespace Notebook_Helpers;
425         Label* label;
426         vector<string> strings;
427         AttachOptions xopt = AttachOptions (FILL|EXPAND);
428         int row = 1; // row zero == backend combo
429         const string msg = string_compose (_("The %1 audio backend was configured and started externally.\nThis limits your control over it."), backend->name());
430
431         label = manage (new Label);
432         label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
433         basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
434         row++;
435
436         if (backend->can_change_sample_rate_when_running()) {
437                 label = manage (left_aligned_label (_("Sample rate:")));
438                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
439                 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
440                 row++;
441         }
442
443         if (backend->can_change_buffer_size_when_running()) {
444                 label = manage (left_aligned_label (_("Buffer size:")));
445                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
446                 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
447                 buffer_size_duration_label.set_alignment (0.0); /* left-align */
448                 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
449                 row++;
450         }
451
452         connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
453
454         basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
455         row++;
456 }
457
458 EngineControl::~EngineControl ()
459 {
460
461 }
462
463 void
464 EngineControl::disable_latency_tab ()
465 {
466         vector<string> empty;
467         set_popdown_strings (lm_output_channel_combo, empty);
468         set_popdown_strings (lm_input_channel_combo, empty);
469         lm_measure_button.set_sensitive (false);
470         lm_use_button.set_sensitive (false);
471 }
472
473 void
474 EngineControl::enable_latency_tab ()
475 {
476         vector<string> outputs;
477         ARDOUR::AudioEngine::instance()->get_physical_outputs (ARDOUR::DataType::AUDIO, outputs);
478         set_popdown_strings (lm_output_channel_combo, outputs);
479         lm_output_channel_combo.set_active_text (outputs.front());
480
481         vector<string> inputs;
482         ARDOUR::AudioEngine::instance()->get_physical_inputs (ARDOUR::DataType::AUDIO, inputs);
483         set_popdown_strings (lm_input_channel_combo, inputs);
484         lm_input_channel_combo.set_active_text (inputs.front());
485
486         lm_measure_button.set_sensitive (true);
487 }
488
489 void
490 EngineControl::setup_midi_tab_for_backend ()
491 {
492         string backend = backend_combo.get_active_text ();
493
494         Gtkmm2ext::container_clear (midi_vbox);
495
496         midi_vbox.set_border_width (12);
497         midi_device_table.set_border_width (12);
498
499         if (backend == "JACK") {
500                 setup_midi_tab_for_jack ();
501         }
502
503         midi_vbox.pack_start (midi_device_table, true, true);
504         midi_vbox.pack_start (midi_refresh_button, false, false);
505         midi_vbox.show_all ();
506
507         midi_refresh_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::refresh_midi_display));
508 }
509
510 void
511 EngineControl::setup_midi_tab_for_jack ()
512 {
513         midi_vbox.pack_start (aj_button, false, false);
514 }       
515
516 void
517 EngineControl::refresh_midi_display ()
518 {
519         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
520         assert (backend);
521
522         vector<string> midi_inputs;
523         vector<string> midi_outputs;
524         int row  = 0;
525         AttachOptions xopt = AttachOptions (FILL|EXPAND);
526         Gtk::Label* l;
527
528         Gtkmm2ext::container_clear (midi_device_table);
529
530         backend->get_physical_inputs (ARDOUR::DataType::MIDI, midi_inputs);
531         backend->get_physical_outputs (ARDOUR::DataType::MIDI, midi_outputs);
532
533         midi_device_table.set_spacings (6);
534         midi_device_table.set_homogeneous (true);
535         midi_device_table.resize (midi_inputs.size() + midi_outputs.size() + 3, 1);
536
537         l = manage (new Label);
538         l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Inputs")));
539         midi_device_table.attach (*l, 0, 1, row, row + 1, xopt, AttachOptions (0));
540         l->set_alignment (0, 0.5);
541         row++;
542         l->show ();
543         
544         for (vector<string>::iterator p = midi_inputs.begin(); p != midi_inputs.end(); ++p) {
545                 l = manage (new Label ((*p).substr ((*p).find_last_of (':') + 1)));
546                 l->set_alignment (0, 0.5);
547                 midi_device_table.attach (*l, 0, 1, row, row + 1, xopt, AttachOptions (0));
548                 l->show ();
549                 row++;
550         }
551
552         row++; // extra row of spacing
553
554         l = manage (new Label);
555         l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Outputs")));
556         midi_device_table.attach (*l, 0, 1, row, row + 1, xopt, AttachOptions (0));
557         l->set_alignment (0, 0.5);
558         row++;
559         l->show ();
560
561         for (vector<string>::iterator p = midi_outputs.begin(); p != midi_outputs.end(); ++p) {
562                 l = manage (new Label ((*p).substr ((*p).find_last_of (':') + 1)));
563                 l->set_alignment (0, 0.5);
564                 midi_device_table.attach (*l, 0, 1, row, row + 1, xopt, AttachOptions (0));
565                 l->show ();
566                 row++;
567         }
568 }
569
570 void
571 EngineControl::update_sensitivity ()
572 {
573 }
574
575 void
576 EngineControl::backend_changed ()
577 {
578         if (ignore_changes) {
579                 return;
580         }
581
582         string backend_name = backend_combo.get_active_text();
583         boost::shared_ptr<ARDOUR::AudioBackend> backend;
584
585         if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
586                 /* eh? setting the backend failed... how ? */
587                 return;
588         }
589
590         _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
591
592         build_notebook ();
593         setup_midi_tab_for_backend ();
594
595         if (backend->requires_driver_selection()) {
596                 vector<string> drivers = backend->enumerate_drivers();
597                 
598                 if (!drivers.empty()) {
599                         {
600                                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
601                                 set_popdown_strings (driver_combo, drivers);
602                                 driver_combo.set_active_text (drivers.front());
603                         }
604
605                         driver_changed ();
606                 }
607                 
608         } else {
609                 driver_combo.set_sensitive (false);
610                 /* this will change the device text which will cause a call to
611                  * device changed which will set up parameters
612                  */
613                 list_devices ();
614         }
615         
616         maybe_display_saved_state ();
617 }
618
619 bool
620 EngineControl::print_channel_count (Gtk::SpinButton* sb)
621 {
622         uint32_t cnt = (uint32_t) sb->get_value();
623         if (cnt == 0) {
624                 sb->set_text (_("all available channels"));
625         } else {
626                 char buf[32];
627                 snprintf (buf, sizeof (buf), "%d", cnt);
628                 sb->set_text (buf);
629         }
630         return true;
631 }
632
633 void
634 EngineControl::list_devices ()
635 {
636         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
637         assert (backend);
638
639         /* now fill out devices, mark sample rates, buffer sizes insensitive */
640             
641         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
642         
643         /* NOTE: Ardour currently does not display the "available" field of the
644          * returned devices.
645          *
646          * Doing so would require a different GUI widget than the combo
647          * box/popdown that we currently use, since it has no way to list
648          * items that are not selectable. Something more like a popup menu,
649          * which could have unselectable items, would be appropriate.
650          */
651
652         vector<string> available_devices;
653
654         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
655                 available_devices.push_back (i->name);
656         }
657
658         if (!available_devices.empty()) {
659
660                 update_sensitivity ();
661                                                 
662                 {
663                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
664                         set_popdown_strings (device_combo, available_devices);
665                         device_combo.set_active_text (available_devices.front());
666                 }
667
668                 device_changed ();
669
670                 ok_button->set_sensitive (true);
671                 apply_button->set_sensitive (true);
672
673         } else {
674                 sample_rate_combo.set_sensitive (false);
675                 buffer_size_combo.set_sensitive (false);
676                 input_latency.set_sensitive (false);
677                 output_latency.set_sensitive (false);
678                 input_channels.set_sensitive (false);
679                 output_channels.set_sensitive (false);
680                 ok_button->set_sensitive (false);
681                 apply_button->set_sensitive (false);
682         }
683 }
684
685 void
686 EngineControl::driver_changed ()
687 {
688         if (ignore_changes) {
689                 return;
690         }
691
692         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
693         assert (backend);
694
695         backend->set_driver (driver_combo.get_active_text());
696         list_devices ();
697
698         maybe_display_saved_state ();
699 }
700
701 void
702 EngineControl::device_changed ()
703 {
704         if (ignore_changes) {
705                 return;
706         }
707
708         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
709         assert (backend);
710         string device_name = device_combo.get_active_text ();
711         vector<string> s;
712
713         {
714                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
715
716                 /* don't allow programmatic change to combos to cause a
717                    recursive call to this method.
718                 */
719                 
720                 /* sample rates */
721                 
722                 string desired;
723                 
724                 vector<float> sr;
725
726                 if (_have_control) {
727                         sr = backend->available_sample_rates (device_name);
728                 } else {
729
730                         sr.push_back (8000.0f);
731                         sr.push_back (16000.0f);
732                         sr.push_back (32000.0f);
733                         sr.push_back (44100.0f);
734                         sr.push_back (48000.0f);
735                         sr.push_back (88200.0f);
736                         sr.push_back (96000.0f);
737                         sr.push_back (192000.0f);
738                         sr.push_back (384000.0f);
739                 }
740
741                 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
742                         s.push_back (rate_as_string (*x));
743                         if (*x == _desired_sample_rate) {
744                                 desired = s.back();
745                         }
746                 }
747                 
748                 if (!s.empty()) {
749                         sample_rate_combo.set_sensitive (true);
750                         set_popdown_strings (sample_rate_combo, s);
751
752                         if (desired.empty()) {
753                                 sample_rate_combo.set_active_text (s.front());
754                         } else {
755                                 sample_rate_combo.set_active_text (desired);
756                         }
757
758                 } else {
759                         sample_rate_combo.set_sensitive (false);
760                 }
761
762                 /* buffer sizes */
763                 
764                 vector<uint32_t> bs;
765                 
766                 if (_have_control) {
767                         bs = backend->available_buffer_sizes(device_name);
768                 } else if (backend->can_change_buffer_size_when_running()) {
769                         bs.push_back (8);
770                         bs.push_back (16);
771                         bs.push_back (32);
772                         bs.push_back (64);
773                         bs.push_back (128);
774                         bs.push_back (256);
775                         bs.push_back (512);
776                         bs.push_back (1024);
777                         bs.push_back (2048);
778                         bs.push_back (4096);
779                         bs.push_back (8192);
780                 }
781                 s.clear ();
782                 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
783                         s.push_back (bufsize_as_string (*x));
784                 }
785                 
786                 if (!s.empty()) {
787                         buffer_size_combo.set_sensitive (true);
788                         set_popdown_strings (buffer_size_combo, s);
789                         
790                         buffer_size_combo.set_active_text (s.front());
791                         show_buffer_duration ();
792                 } else {
793                         buffer_size_combo.set_sensitive (false);
794                 }
795
796                 /* XXX theoretically need to set min + max channel counts here
797                  */
798                 
799                 manage_control_app_sensitivity ();
800         }
801
802         /* pick up any saved state for this device */
803
804         maybe_display_saved_state ();
805
806         /* and push it to the backend */
807
808         push_state_to_backend (false);
809 }       
810
811 string
812 EngineControl::bufsize_as_string (uint32_t sz)
813 {
814         /* Translators: "samples" is always plural here, so no
815            need for plural+singular forms.
816         */
817         char buf[32];
818         snprintf (buf, sizeof (buf), _("%u samples"), sz);
819         return buf;
820 }
821
822 void 
823 EngineControl::sample_rate_changed ()
824 {
825         if (ignore_changes) {
826                 return;
827         }
828
829         /* reset the strings for buffer size to show the correct msec value
830            (reflecting the new sample rate).
831         */
832
833         show_buffer_duration ();
834         save_state ();
835
836 }
837
838 void 
839 EngineControl::buffer_size_changed ()
840 {
841         if (ignore_changes) {
842                 return;
843         }
844
845         show_buffer_duration ();
846         save_state ();
847 }
848
849 void
850 EngineControl::show_buffer_duration ()
851 {
852
853         /* buffer sizes  - convert from just samples to samples + msecs for
854          * the displayed string
855          */
856
857         string bs_text = buffer_size_combo.get_active_text ();
858         uint32_t samples = atoi (bs_text); /* will ignore trailing text */
859         uint32_t rate = get_rate();
860
861         /* Translators: "msecs" is ALWAYS plural here, so we do not
862            need singular form as well.
863         */
864         /* Developers: note the hard-coding of a double buffered model
865            in the (2 * samples) computation of latency. we always start
866            the audiobackend in this configuration.
867         */
868         char buf[32];
869         snprintf (buf, sizeof (buf), _("(%.1f msecs)"), (2 * samples) / (rate/1000.0));
870         buffer_size_duration_label.set_text (buf);
871 }
872
873 void
874 EngineControl::parameter_changed ()
875 {
876         if (!ignore_changes) {
877                 save_state ();
878         }
879 }
880
881 EngineControl::State*
882 EngineControl::get_matching_state (const string& backend,
883                                    const string& driver,
884                                    const string& device)
885 {
886         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
887                 if ((*i).backend == backend &&
888                     (*i).driver == driver &&
889                     (*i).device == device) {
890                         return &(*i);
891                 }
892         }
893         return 0;
894 }
895
896 EngineControl::State*
897 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
898 {
899         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
900
901         if (backend) {
902                 return get_matching_state (backend_combo.get_active_text(),
903                                            (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
904                                            device_combo.get_active_text());
905         }
906
907
908         return get_matching_state (backend_combo.get_active_text(),
909                                    string(),
910                                    device_combo.get_active_text());
911 }
912
913 EngineControl::State*
914 EngineControl::save_state ()
915 {
916         if (!_have_control) {
917                 return 0;
918         }
919
920         bool existing = true;
921         State* state = get_saved_state_for_currently_displayed_backend_and_device ();
922
923         if (!state) {
924                 existing = false;
925                 state = new State;
926         }
927         
928         store_state (*state);
929
930         if (!existing) {
931                 states.push_back (*state);
932         }
933
934         return state;
935 }
936
937 void
938 EngineControl::store_state (State& state)
939 {
940         state.backend = get_backend ();
941         state.driver = get_driver ();
942         state.device = get_device_name ();
943         state.sample_rate = get_rate ();
944         state.buffer_size = get_buffer_size ();
945         state.input_latency = get_input_latency ();
946         state.output_latency = get_output_latency ();
947         state.input_channels = get_input_channels ();
948         state.output_channels = get_output_channels ();
949 }
950
951 void
952 EngineControl::maybe_display_saved_state ()
953 {
954         if (!_have_control) {
955                 return;
956         }
957
958         State* state = get_saved_state_for_currently_displayed_backend_and_device ();
959
960         if (state) {
961                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
962
963                 if (!_desired_sample_rate) {
964                         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
965                 }
966                 buffer_size_combo.set_active_text (bufsize_as_string (state->buffer_size));
967                 /* call this explicitly because we're ignoring changes to
968                    the controls at this point.
969                 */
970                 show_buffer_duration ();
971                 input_latency.set_value (state->input_latency);
972                 output_latency.set_value (state->output_latency);
973         }
974 }
975         
976 XMLNode&
977 EngineControl::get_state ()
978 {
979         XMLNode* root = new XMLNode ("AudioMIDISetup");
980         std::string path;
981
982         if (!states.empty()) {
983                 XMLNode* state_nodes = new XMLNode ("EngineStates");
984                 
985                 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
986                         
987                         XMLNode* node = new XMLNode ("State");
988                         
989                         node->add_property ("backend", (*i).backend);
990                         node->add_property ("driver", (*i).driver);
991                         node->add_property ("device", (*i).device);
992                         node->add_property ("sample-rate", (*i).sample_rate);
993                         node->add_property ("buffer-size", (*i).buffer_size);
994                         node->add_property ("input-latency", (*i).input_latency);
995                         node->add_property ("output-latency", (*i).output_latency);
996                         node->add_property ("input-channels", (*i).input_channels);
997                         node->add_property ("output-channels", (*i).output_channels);
998                         node->add_property ("active", (*i).active ? "yes" : "no");
999                         
1000                         state_nodes->add_child_nocopy (*node);
1001                 }
1002                 
1003                 root->add_child_nocopy (*state_nodes);
1004         }
1005
1006         return *root;
1007 }
1008
1009 void
1010 EngineControl::set_state (const XMLNode& root)
1011 {
1012         XMLNodeList          clist, cclist;
1013         XMLNodeConstIterator citer, cciter;
1014         XMLNode* child;
1015         XMLNode* grandchild;
1016         XMLProperty* prop = NULL;
1017
1018         if (root.name() != "AudioMIDISetup") {
1019                 return;
1020         }
1021
1022         clist = root.children();
1023
1024         states.clear ();
1025
1026         for (citer = clist.begin(); citer != clist.end(); ++citer) {
1027
1028                 child = *citer;
1029                 
1030                 if (child->name() != "EngineStates") {
1031                         continue;
1032                 }
1033
1034                 cclist = child->children();
1035
1036                 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1037                         State state;
1038                         
1039                         grandchild = *cciter;
1040
1041                         if (grandchild->name() != "State") {
1042                                 continue;
1043                         }
1044                         
1045                         if ((prop = grandchild->property ("backend")) == 0) {
1046                                 continue;
1047                         }
1048                         state.backend = prop->value ();
1049                         
1050                         if ((prop = grandchild->property ("driver")) == 0) {
1051                                 continue;
1052                         }
1053                         state.driver = prop->value ();
1054                         
1055                         if ((prop = grandchild->property ("device")) == 0) {
1056                                 continue;
1057                         }
1058                         state.device = prop->value ();
1059                         
1060                         if ((prop = grandchild->property ("sample-rate")) == 0) {
1061                                 continue;
1062                         }
1063                         state.sample_rate = atof (prop->value ());
1064                         
1065                         if ((prop = grandchild->property ("buffer-size")) == 0) {
1066                                 continue;
1067                         }
1068                         state.buffer_size = atoi (prop->value ());
1069                         
1070                         if ((prop = grandchild->property ("input-latency")) == 0) {
1071                                 continue;
1072                         }
1073                         state.input_latency = atoi (prop->value ());
1074                         
1075                         if ((prop = grandchild->property ("output-latency")) == 0) {
1076                                 continue;
1077                         }
1078                         state.output_latency = atoi (prop->value ());
1079                         
1080                         if ((prop = grandchild->property ("input-channels")) == 0) {
1081                                 continue;
1082                         }
1083                         state.input_channels = atoi (prop->value ());
1084                         
1085                         if ((prop = grandchild->property ("output-channels")) == 0) {
1086                                 continue;
1087                         }
1088                         state.output_channels = atoi (prop->value ());
1089
1090                         if ((prop = grandchild->property ("active")) == 0) {
1091                                 continue;
1092                         }
1093                         state.active = string_is_affirmative (prop->value ());
1094                         
1095                         states.push_back (state);
1096                 }
1097         }
1098
1099         /* now see if there was an active state and switch the setup to it */
1100         
1101         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1102
1103                 if ((*i).active) {
1104                         ignore_changes++;
1105                         backend_combo.set_active_text ((*i).backend);
1106                         driver_combo.set_active_text ((*i).driver);
1107                         device_combo.set_active_text ((*i).device);
1108                         sample_rate_combo.set_active_text (rate_as_string ((*i).sample_rate));
1109                         buffer_size_combo.set_active_text (bufsize_as_string ((*i).buffer_size));
1110                         input_latency.set_value ((*i).input_latency);
1111                         output_latency.set_value ((*i).output_latency);
1112                         ignore_changes--;
1113                         break;
1114                 }
1115         }
1116 }
1117
1118
1119 int
1120 EngineControl::push_state_to_backend (bool start)
1121 {
1122         if (no_push) {
1123                 return 0;
1124         }
1125
1126         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1127
1128         if (!backend) {
1129                 return 0;
1130         }
1131         
1132         /* figure out what is going to change */
1133
1134         bool restart_required = false;
1135         bool was_running = ARDOUR::AudioEngine::instance()->running();
1136         bool change_driver = false;
1137         bool change_device = false;
1138         bool change_rate = false;
1139         bool change_bufsize = false;
1140         bool change_latency = false;
1141         bool change_channels = false;
1142
1143         uint32_t ochan = get_output_channels ();
1144         uint32_t ichan = get_input_channels ();
1145
1146         if (_have_control) {
1147
1148                 if (started_at_least_once) {
1149                         
1150                         /* we can control the backend */
1151                         
1152                         if (backend->requires_driver_selection()) {
1153                                 if (get_driver() != backend->driver_name()) {
1154                                         change_driver = true;
1155                                 }
1156                         }
1157                         
1158                         if (get_device_name() != backend->device_name()) {
1159                                 change_device = true;
1160                         }
1161                         
1162                         if (get_rate() != backend->sample_rate()) {
1163                                 change_rate = true;
1164                         }
1165                         
1166                         if (get_buffer_size() != backend->buffer_size()) {
1167                                 change_bufsize = true;
1168                         }
1169                         
1170                         /* zero-requested channels means "all available" */
1171
1172                         if (ichan == 0) {
1173                                 ichan = backend->input_channels();
1174                         }
1175                         
1176                         if (ochan == 0) {
1177                                 ochan = backend->output_channels();
1178                         }
1179                         
1180                         if (ichan != backend->input_channels()) {
1181                                 change_channels = true;
1182                         }
1183                         
1184                         if (ochan != backend->output_channels()) {
1185                                 change_channels = true;
1186                         }
1187
1188                         if (get_input_latency() != backend->systemic_input_latency() ||
1189                             get_output_latency() != backend->systemic_output_latency()) {
1190                                 change_latency = true;
1191                         }
1192                 } else {
1193                         /* backend never started, so we have to force a group
1194                            of settings.
1195                         */
1196                         change_driver = true;
1197                         change_device = true;
1198                         change_rate = true;
1199                         change_bufsize = true;
1200                         change_channels = true;
1201                         change_latency = true;
1202                 }
1203
1204         } else {
1205
1206                 /* we have no control over the backend, meaning that we can
1207                  * only possibly change sample rate and buffer size.
1208                  */
1209
1210
1211                 if (get_rate() != backend->sample_rate()) {
1212                         change_bufsize = true;
1213                 }
1214
1215                 if (get_buffer_size() != backend->buffer_size()) {
1216                         change_bufsize = true;
1217                 }
1218         }
1219
1220         if (!_have_control) {
1221
1222                 /* We do not have control over the backend, so the best we can
1223                  * do is try to change the sample rate and/or bufsize and get
1224                  * out of here.
1225                  */
1226
1227                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1228                         return 1;
1229                 }
1230
1231                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1232                         return 1;
1233                 }
1234                 
1235                 if (change_rate) {
1236                         backend->set_sample_rate (get_rate());
1237                 }
1238                 
1239                 if (change_bufsize) {
1240                         backend->set_buffer_size (get_buffer_size());
1241                 }
1242
1243                 post_push ();
1244
1245                 return 0;
1246         } 
1247
1248         /* determine if we need to stop the backend before changing parameters */
1249
1250         if (change_driver || change_device || change_channels || change_latency ||
1251             (change_rate && !backend->can_change_sample_rate_when_running()) ||
1252             (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1253                 restart_required = true;
1254         } else {
1255                 restart_required = false;
1256         }
1257
1258         if (was_running) {
1259
1260                 if (!change_driver && !change_device && !change_channels && !change_latency) {
1261                         /* no changes in any parameters that absolutely require a
1262                          * restart, so check those that might be changeable without a
1263                          * restart
1264                          */
1265                         
1266                         if (change_rate && !backend->can_change_sample_rate_when_running()) {
1267                                 /* can't do this while running ... */
1268                                 restart_required = true;
1269                         }
1270
1271                         if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1272                                 /* can't do this while running ... */
1273                                 restart_required = true;
1274                         }
1275                 }
1276         }
1277
1278         if (was_running) {
1279                 if (restart_required) {
1280                         if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1281                                 return -1;
1282                         }
1283                 }
1284         }
1285                 
1286
1287         if (change_driver && backend->set_driver (get_driver())) {
1288                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1289                 return -1;
1290         }
1291         if (change_device && backend->set_device_name (get_device_name())) {
1292                 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1293                 return -1;
1294         }
1295         if (change_rate && backend->set_sample_rate (get_rate())) {
1296                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1297                 return -1;
1298         }
1299         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1300                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1301                 return -1;
1302         }
1303
1304         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1305                 if (backend->set_input_channels (get_input_channels())) {
1306                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1307                         return -1;
1308                 }
1309                 if (backend->set_output_channels (get_output_channels())) {
1310                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1311                         return -1;
1312                 }
1313         }
1314         if (change_latency) {
1315                 if (backend->set_systemic_input_latency (get_input_latency())) {
1316                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1317                         return -1;
1318                 }
1319                 if (backend->set_systemic_output_latency (get_output_latency())) {
1320                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1321                         return -1;
1322                 }
1323         }
1324                         
1325         if (start || (was_running && restart_required)) {
1326                 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
1327                         return -1;
1328                 }
1329         }
1330         
1331         post_push ();
1332
1333         return 0;
1334 }
1335
1336 void
1337 EngineControl::post_push ()
1338 {
1339         /* get a pointer to the current state object, creating one if
1340          * necessary
1341          */
1342         
1343         if (_have_control) {
1344                 State* state = get_saved_state_for_currently_displayed_backend_and_device ();
1345                 
1346                 if (!state) {
1347                         state = save_state ();
1348                         assert (state);
1349                 }
1350                 
1351                 /* all off */
1352                 
1353                 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1354                         (*i).active = false;
1355                 }
1356                 
1357                 /* mark this one active (to be used next time the dialog is
1358                  * shown)
1359                  */
1360                 
1361                 state->active = true;
1362                 
1363                 manage_control_app_sensitivity ();
1364         }
1365
1366         /* schedule a redisplay of MIDI ports */
1367         
1368         Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
1369 }
1370
1371
1372 float
1373 EngineControl::get_rate () const
1374 {
1375         float r = atof (sample_rate_combo.get_active_text ());
1376         /* the string may have been translated with an abbreviation for
1377          * thousands, so use a crude heuristic to fix this.
1378          */
1379         if (r < 1000.0) {
1380                 r *= 1000.0;
1381         }
1382         return r;
1383 }
1384         
1385
1386 uint32_t
1387 EngineControl::get_buffer_size () const
1388 {
1389         string txt = buffer_size_combo.get_active_text ();
1390         uint32_t samples;
1391
1392         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
1393                 throw exception ();
1394         }
1395
1396         return samples;
1397 }
1398
1399 uint32_t
1400 EngineControl::get_input_channels() const
1401 {
1402         return (uint32_t) input_channels_adjustment.get_value();
1403 }
1404
1405 uint32_t
1406 EngineControl::get_output_channels() const
1407 {
1408         return (uint32_t) output_channels_adjustment.get_value();
1409 }
1410
1411 uint32_t
1412 EngineControl::get_input_latency() const
1413 {
1414         return (uint32_t) input_latency_adjustment.get_value();
1415 }
1416
1417 uint32_t
1418 EngineControl::get_output_latency() const
1419 {
1420         return (uint32_t) output_latency_adjustment.get_value();
1421 }
1422
1423 string
1424 EngineControl::get_backend () const
1425 {
1426         return backend_combo.get_active_text ();
1427 }
1428
1429 string
1430 EngineControl::get_driver () const
1431 {
1432         return driver_combo.get_active_text ();
1433 }
1434
1435 string
1436 EngineControl::get_device_name () const
1437 {
1438         return device_combo.get_active_text ();
1439 }
1440
1441 void
1442 EngineControl::control_app_button_clicked ()
1443 {
1444         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1445         
1446         if (!backend) {
1447                 return;
1448         }
1449         
1450         backend->launch_control_app ();
1451 }
1452
1453 void
1454 EngineControl::manage_control_app_sensitivity ()
1455 {
1456         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1457         
1458         if (!backend) {
1459                 return;
1460         }
1461         
1462         string appname = backend->control_app_name();
1463
1464         if (appname.empty()) {
1465                 control_app_button.set_sensitive (false);
1466         } else {
1467                 control_app_button.set_sensitive (true);
1468         }
1469 }
1470
1471 void
1472 EngineControl::set_desired_sample_rate (uint32_t sr)
1473 {
1474         _desired_sample_rate = sr;
1475         device_changed ();
1476 }
1477
1478 void
1479 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
1480 {
1481         if (page_num == 0) {
1482                 cancel_button->set_sensitive (true);
1483                 ok_button->set_sensitive (true);
1484                 apply_button->set_sensitive (true);
1485         } else {
1486                 cancel_button->set_sensitive (false);
1487                 ok_button->set_sensitive (false);
1488                 apply_button->set_sensitive (false);
1489         }
1490
1491         if (page_num == 1) {
1492                 /* MIDI tab */
1493                 refresh_midi_display ();
1494         }
1495
1496         if (page_num == 2) {
1497                 /* latency tab */
1498
1499                 if (!ARDOUR::AudioEngine::instance()->running()) {
1500                         
1501                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1502                         
1503                         /* save any existing latency values */
1504                         
1505                         uint32_t il = (uint32_t) input_latency.get_value ();
1506                         uint32_t ol = (uint32_t) input_latency.get_value ();
1507
1508                         /* reset to zero so that our new test instance of JACK
1509                            will be clean of any existing latency measures.
1510                         */
1511                         
1512                         input_latency.set_value (0);
1513                         output_latency.set_value (0);
1514                         
1515                         /* reset control */
1516
1517                         input_latency.set_value (il);
1518                         output_latency.set_value (ol);
1519
1520                 } 
1521
1522                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
1523                         disable_latency_tab ();
1524                 }
1525
1526                 enable_latency_tab ();
1527
1528         } else {
1529                 ARDOUR::AudioEngine::instance()->stop_latency_detection();
1530         }
1531 }
1532
1533 /* latency measurement */
1534
1535 bool
1536 EngineControl::check_latency_measurement ()
1537 {
1538         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1539
1540         if (mtdm->resolve () < 0) {
1541                 lm_results.set_markup (string_compose ("<span foreground=\"red\">%1</span>", _("No signal detected ")));
1542                 return true;
1543         }
1544
1545         if (mtdm->err () > 0.3) {
1546                 mtdm->invert ();
1547                 mtdm->resolve ();
1548         }
1549
1550         char buf[128];
1551         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1552
1553         if (sample_rate == 0) {
1554                 lm_results.set_text (_("Disconnected from audio engine"));
1555                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1556                 return false;
1557         }
1558
1559         uint32_t frames_total = mtdm->del();
1560         uint32_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1561
1562         snprintf (buf, sizeof (buf), "%u samples %10.3lf ms", extra, extra * 1000.0f/sample_rate);
1563
1564         bool solid = true;
1565
1566         if (mtdm->err () > 0.2) {
1567                 strcat (buf, " ??");
1568                 solid = false;
1569         }
1570
1571         if (mtdm->inv ()) {
1572                 strcat (buf, " (Inv)");
1573                 solid = false;
1574         }
1575
1576         if (solid) {
1577                 lm_measure_button.set_active (false);
1578                 lm_use_button.set_sensitive (true);
1579                 strcat (buf, " (set)");
1580                 have_lm_results = true;
1581         }
1582         
1583         lm_results.set_text (buf);
1584
1585         return true;
1586 }
1587
1588 void
1589 EngineControl::start_latency_detection ()
1590 {
1591         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
1592         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
1593         ARDOUR::AudioEngine::instance()->start_latency_detection ();
1594         lm_results.set_text (_("Detecting ..."));
1595         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_latency_measurement), 250);
1596         lm_start_stop_label.set_text (_("Cancel measurement"));
1597         have_lm_results = false;
1598         lm_input_channel_combo.set_sensitive (false);
1599         lm_output_channel_combo.set_sensitive (false);
1600 }
1601
1602 void
1603 EngineControl::end_latency_detection ()
1604 {
1605         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1606         latency_timeout.disconnect ();
1607         lm_start_stop_label.set_text (_("Measure latency"));
1608         if (!have_lm_results) {
1609                 lm_results.set_markup ("<i>No measurement results yet</i>");
1610         }
1611         lm_input_channel_combo.set_sensitive (true);
1612         lm_output_channel_combo.set_sensitive (true);
1613 }
1614
1615 void
1616 EngineControl::latency_button_toggled ()
1617 {
1618         if (lm_measure_button.get_active ()) {
1619                 start_latency_detection ();
1620         } else {
1621                 end_latency_detection ();
1622         }
1623 }
1624
1625 void
1626 EngineControl::use_latency_button_clicked ()
1627 {
1628         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1629
1630         if (!mtdm) {
1631                 return;
1632         }
1633
1634         uint32_t frames_total = mtdm->del();
1635         uint32_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1636         uint32_t one_way = extra/2;
1637
1638         input_latency_adjustment.set_value (one_way);
1639         output_latency_adjustment.set_value (one_way);
1640 }
1641
1642 bool
1643 EngineControl::on_delete_event (GdkEventAny* ev)
1644 {
1645         if (notebook.get_current_page() == 2) {
1646                 /* currently on latency tab - be sure to clean up */
1647                 end_latency_detection ();
1648         }
1649         return ArdourDialog::on_delete_event (ev);
1650 }
1651
1652 void
1653 EngineControl::engine_running ()
1654 {
1655         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1656         assert (backend);
1657
1658         buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size()));
1659         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1660
1661         buffer_size_combo.set_sensitive (true);
1662         sample_rate_combo.set_sensitive (true);
1663
1664         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
1665
1666         started_at_least_once = true;
1667 }
1668
1669 void
1670 EngineControl::engine_stopped ()
1671 {
1672         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1673         assert (backend);
1674
1675         buffer_size_combo.set_sensitive (false);
1676         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
1677
1678         sample_rate_combo.set_sensitive (true);
1679         buffer_size_combo.set_sensitive (true);
1680 }
1681         
1682 void
1683 EngineControl::connect_disconnect_click() 
1684 {
1685         if (ARDOUR::AudioEngine::instance()->running()) {
1686                 ARDOUR_UI::instance()->disconnect_from_engine ();
1687         } else {
1688                 ARDOUR_UI::instance()->reconnect_to_engine ();
1689         }
1690 }