can now start JACK based on config 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 <glibmm.h>
29 #include <gtkmm/messagedialog.h>
30
31 #include "pbd/error.h"
32 #include "pbd/xml++.h"
33
34 #include <gtkmm/stock.h>
35 #include <gtkmm2ext/utils.h>
36
37 #include "ardour/audio_backend.h"
38 #include "ardour/audioengine.h"
39 #include "ardour/rc_configuration.h"
40
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43
44 #include "engine_dialog.h"
45 #include "i18n.h"
46
47 using namespace std;
48 using namespace Gtk;
49 using namespace Gtkmm2ext;
50 using namespace PBD;
51 using namespace Glib;
52
53 EngineControl::EngineControl ()
54         : input_latency_adjustment (0, 0, 99999, 1)
55         , input_latency (input_latency_adjustment)
56         , output_latency_adjustment (0, 0, 99999, 1)
57         , output_latency (output_latency_adjustment)
58         , input_channels_adjustment (2, 0, 256, 1)
59         , input_channels (input_channels_adjustment)
60         , output_channels_adjustment (2, 0, 256, 1)
61         , output_channels (output_channels_adjustment)
62         , ports_adjustment (128, 8, 1024, 1, 16)
63         , ports_spinner (ports_adjustment)
64         , realtime_button (_("Realtime"))
65 #ifdef __APPLE___
66         , basic_packer (6, 2)
67         , options_packer (4, 2)
68         , device_packer (4, 2)
69 #else
70         , basic_packer (9, 2)
71         , options_packer (14, 2)
72         , device_packer (6, 2)
73 #endif
74 {
75         using namespace Notebook_Helpers;
76         Label* label;
77         vector<string> strings;
78         int row = 0;
79
80         _used = false;
81
82         /* basic parameters */
83
84         basic_packer.set_spacings (6);
85
86         strings.clear ();
87
88         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
89         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
90                 strings.push_back ((*b)->name);
91         }
92
93         set_popdown_strings (backend_combo, strings);
94         backend_combo.set_active_text (strings.front());
95
96         backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
97         backend_changed ();
98
99         driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
100
101         strings.clear ();
102         strings.push_back (_("Playback/recording on 1 device"));
103         strings.push_back (_("Playback/recording on 2 devices"));
104         strings.push_back (_("Playback only"));
105         strings.push_back (_("Recording only"));
106         set_popdown_strings (audio_mode_combo, strings);
107         audio_mode_combo.set_active_text (strings.front());
108
109         audio_mode_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::audio_mode_changed));
110         audio_mode_changed ();
111
112         strings.clear ();
113         strings.push_back (_("None"));
114         strings.push_back (_("seq"));
115         strings.push_back (_("raw"));
116         set_popdown_strings (midi_driver_combo, strings);
117         midi_driver_combo.set_active_text (strings.front ());
118
119         row = 0;
120
121         label = manage (left_aligned_label (_("Audio Driver:")));
122         basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
123         basic_packer.attach (backend_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
124         row++;
125
126         label = manage (left_aligned_label (_("Driver:")));
127         basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
128         basic_packer.attach (driver_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
129         row++;
130
131         label = manage (left_aligned_label (_("Audio Interface:")));
132         basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
133         basic_packer.attach (interface_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
134         row++;
135
136         label = manage (left_aligned_label (_("Sample rate:")));
137         basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
138         basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
139         row++;
140
141         label = manage (left_aligned_label (_("Buffer size:")));
142         basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
143         basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
144         row++;
145
146         label = manage (left_aligned_label (_("Approximate latency:")));
147         basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
148         basic_packer.attach (latency_label, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
149         row++;
150
151         sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::redisplay_latency));
152         buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::redisplay_latency));
153         redisplay_latency();
154         row++;
155         /* no audio mode with CoreAudio, its duplex or nuthin' */
156
157 #if !defined(__APPLE__) && !defined(__FreeBSD__)
158         label = manage (left_aligned_label (_("Audio mode:")));
159         basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
160         basic_packer.attach (audio_mode_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
161         row++;
162 #endif
163
164         interface_combo.set_size_request (250, -1);
165         input_device_combo.set_size_request (250, -1);
166         output_device_combo.set_size_request (250, -1);
167
168         interface_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::interface_changed));
169
170         /* options */
171
172         options_packer.set_spacings (6);
173         row = 0;
174
175         options_packer.attach (realtime_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
176         ++row;
177
178         realtime_button.set_active (true);
179
180         label = manage (left_aligned_label (_("Number of ports:")));
181         options_packer.attach (ports_spinner, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
182         options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
183         ++row;
184
185         label = manage (left_aligned_label (_("MIDI driver:")));
186         options_packer.attach (midi_driver_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
187         options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
188         ++row;
189
190 #if !defined(__APPLE__) && !defined(__FreeBSD__)
191         label = manage (left_aligned_label (_("Dither:")));
192         options_packer.attach (dither_mode_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
193         options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
194         ++row;
195 #endif
196
197         /* device settings */
198
199         device_packer.set_spacings (6);
200         row = 0;
201
202 #if !defined(__APPLE__) && !defined(__FreeBSD__)
203         label = manage (left_aligned_label (_("Input device:")));
204         device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
205         device_packer.attach (input_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
206         ++row;
207         label = manage (left_aligned_label (_("Output device:")));
208         device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
209         device_packer.attach (output_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
210         ++row;
211 #endif
212         label = manage (left_aligned_label (_("Hardware input latency:")));
213         device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
214         device_packer.attach (input_latency, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
215         label = manage (left_aligned_label (_("samples")));
216         device_packer.attach (*label, 2, 3, row, row+1, FILL|EXPAND, (AttachOptions) 0);
217         ++row;
218         label = manage (left_aligned_label (_("Hardware output latency:")));
219         device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
220         device_packer.attach (output_latency, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
221         label = manage (left_aligned_label (_("samples")));
222         device_packer.attach (*label, 2, 3, row, row+1, FILL|EXPAND, (AttachOptions) 0);
223         ++row;
224
225         basic_hbox.pack_start (basic_packer, false, false);
226         options_hbox.pack_start (options_packer, false, false);
227
228         device_packer.set_border_width (12);
229         options_packer.set_border_width (12);
230         basic_packer.set_border_width (12);
231
232         notebook.pages().push_back (TabElem (basic_hbox, _("Device")));
233         notebook.pages().push_back (TabElem (options_hbox, _("Options")));
234         notebook.pages().push_back (TabElem (device_packer, _("Advanced")));
235         notebook.set_border_width (12);
236
237         set_border_width (12);
238         pack_start (notebook);
239
240         /* Pick up any existing audio setup configuration, if appropriate */
241
242         XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioSetup");
243         
244         if (audio_setup) {
245                 set_state (*audio_setup);
246         }
247 }
248
249 EngineControl::~EngineControl ()
250 {
251
252 }
253
254 void
255 EngineControl::backend_changed ()
256 {
257         string backend_name = backend_combo.get_active_text();
258         boost::shared_ptr<ARDOUR::AudioBackend> backend;
259
260         if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
261                 /* eh? */
262                 return;
263         }
264
265         if (backend->requires_driver_selection()) {
266                 vector<string> drivers = backend->enumerate_drivers();
267                 set_popdown_strings (driver_combo, drivers);
268                 driver_combo.set_active_text (drivers.front());
269                 driver_changed ();
270         } else {
271                 list_devices ();
272         }
273 }
274
275 void
276 EngineControl::list_devices ()
277 {
278         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
279         assert (backend);
280
281         /* now fill out devices, mark sample rates, buffer sizes insensitive */
282             
283         vector<string> devices = backend->enumerate_devices ();
284         
285         set_popdown_strings (interface_combo, devices);
286         interface_combo.set_active_text (devices.front());
287         set_popdown_strings (input_device_combo, devices);
288         input_device_combo.set_active_text (devices.front());
289         set_popdown_strings (output_device_combo, devices);
290         output_device_combo.set_active_text (devices.front());
291         
292         interface_changed ();
293 }
294         
295 void
296 EngineControl::driver_changed ()
297 {
298         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
299         assert (backend);
300
301         backend->set_driver (driver_combo.get_active_text());
302         list_devices ();
303 }
304
305 void
306 EngineControl::interface_changed ()
307 {
308         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
309         assert (backend);
310         string device_name = interface_combo.get_active_text ();
311         vector<string> s;
312
313         /* sample rates */
314
315         vector<float> sr = backend->available_sample_rates (device_name);
316         for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
317                 char buf[32];
318                 if (fmod (*x, 1000.0f)) {
319                         snprintf (buf, sizeof (buf), "%.1f kHz", (*x)/1000.0);
320                 } else {
321                         snprintf (buf, sizeof (buf), "%.0f kHz", (*x)/1000.0);
322                 }
323                 s.push_back (buf);
324         }
325
326         set_popdown_strings (sample_rate_combo, s);
327         sample_rate_combo.set_active_text (s.front());
328
329         /* buffer sizes */
330
331         s.clear ();
332         vector<uint32_t> bs = backend->available_buffer_sizes(device_name);
333         for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
334                 char buf[32];
335                 snprintf (buf, sizeof (buf), "%u", *x);
336                 s.push_back (buf);
337         }
338
339         set_popdown_strings (buffer_size_combo, s);
340         buffer_size_combo.set_active_text (s.front());
341 }       
342
343 void
344 EngineControl::redisplay_latency ()
345 {
346         uint32_t rate = get_rate();
347         float period_size = atof (buffer_size_combo.get_active_text());
348
349         char buf[32];
350         snprintf (buf, sizeof(buf), "%.1fmsec", (2 * period_size) / (rate/1000.0));
351
352         latency_label.set_text (buf);
353         latency_label.set_alignment (0, 0.5);
354 }
355
356 void
357 EngineControl::audio_mode_changed ()
358 {
359         std::string str = audio_mode_combo.get_active_text();
360
361         if (str == _("Playback/recording on 1 device")) {
362                 input_device_combo.set_sensitive (false);
363                 output_device_combo.set_sensitive (false);
364         } else if (str == _("Playback/recording on 2 devices")) {
365                 input_device_combo.set_sensitive (true);
366                 output_device_combo.set_sensitive (true);
367         } else if (str == _("Playback only")) {
368                 output_device_combo.set_sensitive (true);
369                 input_device_combo.set_sensitive (false);
370         } else if (str == _("Recording only")) {
371                 input_device_combo.set_sensitive (true);
372                 output_device_combo.set_sensitive (false);
373         }
374 }
375
376 XMLNode&
377 EngineControl::get_state ()
378 {
379         XMLNode* root = new XMLNode ("AudioSetup");
380         XMLNode* child;
381         std::string path;
382
383 #if 0
384         child = new XMLNode ("periods");
385         child->add_property ("val", to_string (periods_adjustment.get_value(), std::dec));
386         root->add_child_nocopy (*child);
387
388         child = new XMLNode ("ports");
389         child->add_property ("val", to_string (ports_adjustment.get_value(), std::dec));
390         root->add_child_nocopy (*child);
391
392         child = new XMLNode ("inlatency");
393         child->add_property ("val", to_string (input_latency.get_value(), std::dec));
394         root->add_child_nocopy (*child);
395
396         child = new XMLNode ("outlatency");
397         child->add_property ("val", to_string (output_latency.get_value(), std::dec));
398         root->add_child_nocopy (*child);
399
400         child = new XMLNode ("realtime");
401         child->add_property ("val", to_string (realtime_button.get_active(), std::dec));
402         root->add_child_nocopy (*child);
403
404         child = new XMLNode ("nomemorylock");
405         child->add_property ("val", to_string (no_memory_lock_button.get_active(), std::dec));
406         root->add_child_nocopy (*child);
407
408         child = new XMLNode ("unlockmemory");
409         child->add_property ("val", to_string (unlock_memory_button.get_active(), std::dec));
410         root->add_child_nocopy (*child);
411
412         child = new XMLNode ("softmode");
413         child->add_property ("val", to_string (soft_mode_button.get_active(), std::dec));
414         root->add_child_nocopy (*child);
415
416         child = new XMLNode ("force16bit");
417         child->add_property ("val", to_string (force16bit_button.get_active(), std::dec));
418         root->add_child_nocopy (*child);
419
420         child = new XMLNode ("hwmonitor");
421         child->add_property ("val", to_string (hw_monitor_button.get_active(), std::dec));
422         root->add_child_nocopy (*child);
423
424         child = new XMLNode ("hwmeter");
425         child->add_property ("val", to_string (hw_meter_button.get_active(), std::dec));
426         root->add_child_nocopy (*child);
427
428         child = new XMLNode ("verbose");
429         child->add_property ("val", to_string (verbose_output_button.get_active(), std::dec));
430         root->add_child_nocopy (*child);
431
432         child = new XMLNode ("samplerate");
433         child->add_property ("val", sample_rate_combo.get_active_text());
434         root->add_child_nocopy (*child);
435
436         child = new XMLNode ("periodsize");
437         child->add_property ("val", period_size_combo.get_active_text());
438         root->add_child_nocopy (*child);
439
440         child = new XMLNode ("serverpath");
441         child->add_property ("val", serverpath_combo.get_active_text());
442         root->add_child_nocopy (*child);
443
444         child = new XMLNode ("driver");
445         child->add_property ("val", driver_combo.get_active_text());
446         root->add_child_nocopy (*child);
447
448         child = new XMLNode ("interface");
449         child->add_property ("val", interface_combo.get_active_text());
450         root->add_child_nocopy (*child);
451
452         child = new XMLNode ("timeout");
453         child->add_property ("val", timeout_combo.get_active_text());
454         root->add_child_nocopy (*child);
455
456         child = new XMLNode ("dither");
457         child->add_property ("val", dither_mode_combo.get_active_text());
458         root->add_child_nocopy (*child);
459
460         child = new XMLNode ("audiomode");
461         child->add_property ("val", audio_mode_combo.get_active_text());
462         root->add_child_nocopy (*child);
463
464         child = new XMLNode ("inputdevice");
465         child->add_property ("val", input_device_combo.get_active_text());
466         root->add_child_nocopy (*child);
467
468         child = new XMLNode ("outputdevice");
469         child->add_property ("val", output_device_combo.get_active_text());
470         root->add_child_nocopy (*child);
471
472         child = new XMLNode ("mididriver");
473         child->add_property ("val", midi_driver_combo.get_active_text());
474         root->add_child_nocopy (*child);
475 #endif
476         return *root;
477 }
478
479 void
480 EngineControl::set_state (const XMLNode& root)
481 {
482 #if 0
483         XMLNodeList          clist;
484         XMLNodeConstIterator citer;
485         XMLNode* child;
486         XMLProperty* prop = NULL;
487         bool using_dummy = false;
488         bool using_ffado = false;
489
490         int val;
491         string strval;
492
493         if ( (child = root.child ("driver"))){
494                 prop = child->property("val");
495
496                 if (prop && (prop->value() == "Dummy") ) {
497                         using_dummy = true;
498                 }
499                 if (prop && (prop->value() == "FFADO") ) {
500                         using_ffado = true;
501                 }
502
503         }
504
505         clist = root.children();
506
507         for (citer = clist.begin(); citer != clist.end(); ++citer) {
508
509                 child = *citer;
510
511                 prop = child->property ("val");
512
513                 if (!prop || prop->value().empty()) {
514
515                         if (((using_dummy || using_ffado)
516                                 && ( child->name() == "interface"
517                                         || child->name() == "inputdevice"
518                                         || child->name() == "outputdevice"))
519                                 || child->name() == "timeout")
520                         {
521                                 continue;
522                         }
523
524                         error << string_compose (_("AudioSetup value for %1 is missing data"), child->name()) << endmsg;
525                         continue;
526                 }
527
528                 strval = prop->value();
529
530                 /* adjustments/spinners */
531
532                 if (child->name() == "periods") {
533                         val = atoi (strval);
534                         periods_adjustment.set_value(val);
535                 } else if (child->name() == "ports") {
536                         val = atoi (strval);
537                         ports_adjustment.set_value(val);
538                 } else if (child->name() == "inlatency") {
539                         val = atoi (strval);
540                         input_latency.set_value(val);
541                 } else if (child->name() == "outlatency") {
542                         val = atoi (strval);
543                         output_latency.set_value(val);
544                 }
545
546                 /* buttons */
547
548                 else if (child->name() == "realtime") {
549                         val = atoi (strval);
550                         realtime_button.set_active(val);
551                 } else if (child->name() == "nomemorylock") {
552                         val = atoi (strval);
553                         no_memory_lock_button.set_active(val);
554                 } else if (child->name() == "unlockmemory") {
555                         val = atoi (strval);
556                         unlock_memory_button.set_active(val);
557                 } else if (child->name() == "softmode") {
558                         val = atoi (strval);
559                         soft_mode_button.set_active(val);
560                 } else if (child->name() == "force16bit") {
561                         val = atoi (strval);
562                         force16bit_button.set_active(val);
563                 } else if (child->name() == "hwmonitor") {
564                         val = atoi (strval);
565                         hw_monitor_button.set_active(val);
566                 } else if (child->name() == "hwmeter") {
567                         val = atoi (strval);
568                         hw_meter_button.set_active(val);
569                 } else if (child->name() == "verbose") {
570                         val = atoi (strval);
571                         verbose_output_button.set_active(val);
572                 }
573
574                 /* combos */
575
576                 else if (child->name() == "samplerate") {
577                         sample_rate_combo.set_active_text(strval);
578                 } else if (child->name() == "periodsize") {
579                         period_size_combo.set_active_text(strval);
580                 } else if (child->name() == "serverpath") {
581
582                         /* only attempt to set this if we have bothered to look
583                            up server names already. otherwise this is all
584                            redundant (actually, all of this dialog/widget
585                            is redundant in that case ...)
586                         */
587
588                         if (!server_strings.empty()) {
589                                 /* do not allow us to use a server path that doesn't
590                                    exist on this system. this handles cases where
591                                    the user has an RC file listing a serverpath
592                                    from some other machine.
593                                 */
594                                 vector<string>::iterator x;
595                                 for (x = server_strings.begin(); x != server_strings.end(); ++x) {
596                                         if (*x == strval) {
597                                                 break;
598                                         }
599                                 }
600                                 if (x != server_strings.end()) {
601                                         serverpath_combo.set_active_text (strval);
602                                 } else {
603                                         warning << string_compose (_("configuration files contain a JACK server path that doesn't exist (%1)"),
604                                                                    strval)
605                                                 << endmsg;
606                                 }
607                         }
608
609                 } else if (child->name() == "driver") {
610                         driver_combo.set_active_text(strval);
611                 } else if (child->name() == "interface") {
612                         interface_combo.set_active_text(strval);
613                 } else if (child->name() == "timeout") {
614                         timeout_combo.set_active_text(strval);
615                 } else if (child->name() == "dither") {
616                         dither_mode_combo.set_active_text(strval);
617                 } else if (child->name() == "audiomode") {
618                         audio_mode_combo.set_active_text(strval);
619                 } else if (child->name() == "inputdevice") {
620                         input_device_combo.set_active_text(strval);
621                 } else if (child->name() == "outputdevice") {
622                         output_device_combo.set_active_text(strval);
623                 } else if (child->name() == "mididriver") {
624                         midi_driver_combo.set_active_text(strval);
625                 }
626         }
627 #endif
628 }
629
630 int
631 EngineControl::setup_engine (bool start)
632 {
633         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
634         assert (backend);
635
636         /* grab the parameters from the GUI and apply them */
637
638         try {
639                 if (backend->requires_driver_selection()) {
640                         if (backend->set_driver (get_driver())) {
641                                 return -1;
642                         }
643                 }
644
645                 if (backend->set_device_name (get_device_name())) {
646                         return -1;
647                 }
648
649                 if (backend->set_sample_rate (get_rate())) {
650                         error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
651                         return -1;
652                 }
653                 if (backend->set_buffer_size (get_buffer_size())) {
654                         error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
655                         return -1;
656                 }
657                 if (backend->set_input_channels (get_input_channels())) {
658                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
659                         return -1;
660                 }
661                 if (backend->set_output_channels (get_output_channels())) {
662                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
663                         return -1;
664                 }
665                 if (backend->set_systemic_input_latency (get_input_latency())) {
666                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
667                         return -1;
668                 }
669                 if (backend->set_systemic_output_latency (get_output_latency())) {
670                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
671                         return -1;
672                 }
673
674                 if (start) {
675                         return ARDOUR::AudioEngine::instance()->start();
676                 }
677
678                 return 0;
679
680         } catch (...) {
681                 cerr << "exception thrown...\n";
682                 return -1;
683         }
684 }
685
686 uint32_t
687 EngineControl::get_rate () const
688 {
689         double r = atof (sample_rate_combo.get_active_text ());
690         /* the string may have been translated with an abbreviation for
691          * thousands, so use a crude heuristic to fix this.
692          */
693         if (r < 1000.0) {
694                 r *= 1000.0;
695         }
696         return lrint (r);
697 }
698
699 uint32_t
700 EngineControl::get_buffer_size () const
701 {
702         string txt = buffer_size_combo.get_active_text ();
703         uint32_t samples;
704
705         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
706                 throw exception ();
707         }
708
709         return samples;
710 }
711
712 uint32_t
713 EngineControl::get_input_channels() const
714 {
715         return (uint32_t) input_channels_adjustment.get_value();
716 }
717
718 uint32_t
719 EngineControl::get_output_channels() const
720 {
721         return (uint32_t) output_channels_adjustment.get_value();
722 }
723
724 uint32_t
725 EngineControl::get_input_latency() const
726 {
727         return (uint32_t) input_latency_adjustment.get_value();
728 }
729
730 uint32_t
731 EngineControl::get_output_latency() const
732 {
733         return (uint32_t) output_latency_adjustment.get_value();
734 }
735
736 string
737 EngineControl::get_driver () const
738 {
739         return driver_combo.get_active_text ();
740 }
741
742 string
743 EngineControl::get_device_name () const
744 {
745         return interface_combo.get_active_text ();
746 }
747