lincoln's patch to fix audio setup dialog/jack startup when used with FFADO (#3485)
[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 <vector>
21 #include <cmath>
22 #include <fstream>
23 #include <map>
24
25 #include <glibmm.h>
26 #include <gtkmm/messagedialog.h>
27 #include "pbd/xml++.h"
28
29 #ifdef __APPLE__
30 #include <CoreAudio/CoreAudio.h>
31 #include <CoreFoundation/CFString.h>
32 #include <sys/param.h>
33 #include <mach-o/dyld.h>
34 #else
35 #include <alsa/asoundlib.h>
36 #endif
37
38 #include "ardour/profile.h"
39 #include <jack/jack.h>
40
41 #include <gtkmm/stock.h>
42 #include <gtkmm2ext/utils.h>
43
44 #include "pbd/convert.h"
45 #include "pbd/error.h"
46 #include "pbd/pathscanner.h"
47
48 #ifdef __APPLE
49 #include <CFBundle.h>
50 #endif
51
52 #include "engine_dialog.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         : periods_adjustment (2, 2, 16, 1, 2),
63           periods_spinner (periods_adjustment),
64           priority_adjustment (60, 10, 90, 1, 10),
65           priority_spinner (priority_adjustment),
66           ports_adjustment (128, 8, 1024, 1, 16),
67           ports_spinner (ports_adjustment),
68           input_latency_adjustment (0, 0, 99999, 1),
69           input_latency (input_latency_adjustment),
70           output_latency_adjustment (0, 0, 99999, 1),
71           output_latency (output_latency_adjustment),
72           realtime_button (_("Realtime")),
73           no_memory_lock_button (_("Do not lock memory")),
74           unlock_memory_button (_("Unlock memory")),
75           soft_mode_button (_("No zombies")),
76           monitor_button (_("Provide monitor ports")),
77           force16bit_button (_("Force 16 bit")),
78           hw_monitor_button (_("H/W monitoring")),
79           hw_meter_button (_("H/W metering")),
80           verbose_output_button (_("Verbose output")),
81           start_button (_("Start")),
82           stop_button (_("Stop")),
83 #ifdef __APPLE__
84           basic_packer (5, 2),
85           options_packer (4, 2),
86           device_packer (4, 2)
87 #else
88           basic_packer (8, 2),
89           options_packer (14, 2),
90           device_packer (6, 2)
91 #endif
92 {
93         using namespace Notebook_Helpers;
94         Label* label;
95         vector<string> strings;
96         int row = 0;
97
98         _used = false;
99
100         strings.push_back (_("8000Hz"));
101         strings.push_back (_("22050Hz"));
102         strings.push_back (_("44100Hz"));
103         strings.push_back (_("48000Hz"));
104         strings.push_back (_("88200Hz"));
105         strings.push_back (_("96000Hz"));
106         strings.push_back (_("192000Hz"));
107         set_popdown_strings (sample_rate_combo, strings);
108         sample_rate_combo.set_active_text ("48000Hz");
109
110         strings.clear ();
111         strings.push_back ("32");
112         strings.push_back ("64");
113         strings.push_back ("128");
114         strings.push_back ("256");
115         strings.push_back ("512");
116         strings.push_back ("1024");
117         strings.push_back ("2048");
118         strings.push_back ("4096");
119         strings.push_back ("8192");
120         set_popdown_strings (period_size_combo, strings);
121         period_size_combo.set_active_text ("1024");
122
123         strings.clear ();
124         strings.push_back (_("None"));
125         strings.push_back (_("Triangular"));
126         strings.push_back (_("Rectangular"));
127         strings.push_back (_("Shaped"));
128         set_popdown_strings (dither_mode_combo, strings);
129         dither_mode_combo.set_active_text (_("None"));
130
131         /* basic parameters */
132
133         basic_packer.set_spacings (6);
134
135         strings.clear ();
136 #ifdef __APPLE__
137         strings.push_back (X_("CoreAudio"));
138 #else
139         strings.push_back (X_("ALSA"));
140         strings.push_back (X_("OSS"));
141         strings.push_back (X_("FreeBoB"));
142         strings.push_back (X_("FFADO"));
143 #endif
144         strings.push_back (X_("NetJACK"));
145         strings.push_back (X_("Dummy"));
146         set_popdown_strings (driver_combo, strings);
147         driver_combo.set_active_text (strings.front());
148
149         driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
150         driver_changed ();
151
152         strings.clear ();
153         strings.push_back (_("Playback/recording on 1 device"));
154         strings.push_back (_("Playback/recording on 2 devices"));
155         strings.push_back (_("Playback only"));
156         strings.push_back (_("Recording only"));
157         set_popdown_strings (audio_mode_combo, strings);
158         audio_mode_combo.set_active_text (strings.front());
159
160         audio_mode_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::audio_mode_changed));
161         audio_mode_changed ();
162
163         strings.clear ();
164         strings.push_back (_("None"));
165         strings.push_back (_("seq"));
166         strings.push_back (_("raw"));
167         set_popdown_strings (midi_driver_combo, strings);
168         midi_driver_combo.set_active_text (strings.front ());
169
170         row = 0;
171
172         label = manage (new Label (_("Driver:")));
173         label->set_alignment (0, 0.5);
174         basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
175         basic_packer.attach (driver_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
176         row++;
177
178         label = manage (new Label (_("Interface:")));
179         label->set_alignment (0, 0.5);
180         basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
181         basic_packer.attach (interface_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
182         row++;
183
184         label = manage (new Label (_("Sample rate:")));
185         label->set_alignment (0, 0.5);
186         basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
187         basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
188         row++;
189
190         label = manage (new Label (_("Buffer size:")));
191         label->set_alignment (0, 0.5);
192         basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
193         basic_packer.attach (period_size_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
194         row++;
195
196 #ifndef __APPLE__
197         label = manage (new Label (_("Number of buffers:")));
198         label->set_alignment (0, 0.5);
199         basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
200         basic_packer.attach (periods_spinner, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
201         periods_spinner.set_value (2);
202         row++;
203 #endif
204
205         label = manage (new Label (_("Approximate latency:")));
206         label->set_alignment (0, 0.5);
207         basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
208         basic_packer.attach (latency_label, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
209         row++;
210
211         sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::redisplay_latency));
212         periods_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &EngineControl::redisplay_latency));
213         period_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::redisplay_latency));
214         redisplay_latency();
215         row++;
216         /* no audio mode with CoreAudio, its duplex or nuthin' */
217
218 #ifndef __APPLE__
219         label = manage (new Label (_("Audio mode:")));
220         label->set_alignment (0, 0.5);
221         basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
222         basic_packer.attach (audio_mode_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
223         row++;
224 #endif
225
226         interface_combo.set_size_request (250, -1);
227         input_device_combo.set_size_request (250, -1);
228         output_device_combo.set_size_request (250, -1);
229
230         /*
231
232         if (engine_running()) {
233                 start_button.set_sensitive (false);
234         } else {
235                 stop_button.set_sensitive (false);
236         }
237
238         start_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::start_engine));
239         stop_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::start_engine));
240         */
241
242         button_box.pack_start (start_button, false, false);
243         button_box.pack_start (stop_button, false, false);
244
245         // basic_packer.attach (button_box, 0, 2, 8, 9, FILL|EXPAND, (AttachOptions) 0);
246
247         /* options */
248
249         options_packer.set_spacings (6);
250         row = 0;
251
252         options_packer.attach (realtime_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
253         ++row;
254
255         realtime_button.set_active (true);
256         realtime_button.signal_toggled().connect (sigc::mem_fun (*this, &EngineControl::realtime_changed));
257         realtime_changed ();
258
259 #if PROVIDE_TOO_MANY_OPTIONS
260
261 #ifndef __APPLE__
262         label = manage (new Label (_("Realtime Priority")));
263         label->set_alignment (1.0, 0.5);
264         options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
265         options_packer.attach (priority_spinner, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
266         ++row;
267         priority_spinner.set_value (60);
268
269         options_packer.attach (no_memory_lock_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
270         ++row;
271         options_packer.attach (unlock_memory_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
272         ++row;
273         options_packer.attach (soft_mode_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
274         ++row;
275         options_packer.attach (monitor_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
276         ++row;
277         options_packer.attach (force16bit_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
278         ++row;
279         options_packer.attach (hw_monitor_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
280         ++row;
281         options_packer.attach (hw_meter_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
282         ++row;
283         options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
284         ++row;
285 #else
286         options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
287         ++row;
288 #endif
289
290         strings.clear ();
291         strings.push_back (_("Ignore"));
292         strings.push_back ("500 msec");
293         strings.push_back ("1 sec");
294         strings.push_back ("2 sec");
295         strings.push_back ("10 sec");
296         set_popdown_strings (timeout_combo, strings);
297         timeout_combo.set_active_text (strings.front ());
298
299         label = manage (new Label (_("Client timeout")));
300         label->set_alignment (1.0, 0.5);
301         options_packer.attach (timeout_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
302         options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
303         ++row;
304
305 #endif /* PROVIDE_TOO_MANY_OPTIONS */
306         label = manage (new Label (_("Number of ports:")));
307         label->set_alignment (0, 0.5);
308         options_packer.attach (ports_spinner, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
309         options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
310         ++row;
311
312         label = manage (new Label (_("MIDI driver:")));
313         label->set_alignment (0, 0.5);
314         options_packer.attach (midi_driver_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
315         options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
316         ++row;
317
318 #ifndef __APPLE__
319         label = manage (new Label (_("Dither:")));
320         label->set_alignment (0, 0.5);
321         options_packer.attach (dither_mode_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
322         options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
323         ++row;
324 #endif
325
326         find_jack_servers (server_strings);
327
328         if (server_strings.empty()) {
329                 fatal << _("No JACK server found anywhere on this system. Please install JACK and restart") << endmsg;
330                 /*NOTREACHED*/
331         }
332
333         set_popdown_strings (serverpath_combo, server_strings);
334         serverpath_combo.set_active_text (server_strings.front());
335
336         if (server_strings.size() > 1) {
337                 label = manage (new Label (_("Server:")));
338                 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
339                 label->set_alignment (0.0, 0.5);
340                 options_packer.attach (serverpath_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
341                 ++row;
342         }
343
344         /* device settings */
345
346         device_packer.set_spacings (6);
347         row = 0;
348
349 #ifndef __APPLE__
350         label = manage (new Label (_("Input device:")));
351         label->set_alignment (0, 0.5);
352         device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
353         device_packer.attach (input_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
354         ++row;
355         label = manage (new Label (_("Output device:")));
356         label->set_alignment (0, 0.5);
357         device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
358         device_packer.attach (output_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
359         ++row;
360 #endif
361         label = manage (new Label (_("Input channels:")));
362         label->set_alignment (0, 0.5);
363         device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
364         device_packer.attach (input_channels, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
365         ++row;
366         label = manage (new Label (_("Output channels:")));
367         label->set_alignment (0, 0.5);
368         device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
369         device_packer.attach (output_channels, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
370         ++row;
371         label = manage (new Label (_("Hardware input latency:")));
372         label->set_alignment (0, 0.5);
373         device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
374         device_packer.attach (input_latency, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
375         label = manage (new Label (_("samples")));
376         label->set_alignment (0, 0.5);
377         device_packer.attach (*label, 2, 3, row, row+1, FILL|EXPAND, (AttachOptions) 0);
378         ++row;
379         label = manage (new Label (_("Hardware output latency:")));
380         label->set_alignment (0, 0.5);
381         device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
382         device_packer.attach (output_latency, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
383         label = manage (new Label (_("samples")));
384         label->set_alignment (0, 0.5);
385         device_packer.attach (*label, 2, 3, row, row+1, FILL|EXPAND, (AttachOptions) 0);
386         ++row;
387
388         basic_hbox.pack_start (basic_packer, false, false);
389         options_hbox.pack_start (options_packer, false, false);
390
391         device_packer.set_border_width (12);
392         options_packer.set_border_width (12);
393         basic_packer.set_border_width (12);
394
395         notebook.pages().push_back (TabElem (basic_hbox, _("Device")));
396         notebook.pages().push_back (TabElem (options_hbox, _("Options")));
397         notebook.pages().push_back (TabElem (device_packer, _("Advanced")));
398         notebook.set_border_width (12);
399
400         set_border_width (12);
401         pack_start (notebook);
402 }
403
404 EngineControl::~EngineControl ()
405 {
406
407 }
408
409 void
410 EngineControl::build_command_line (vector<string>& cmd)
411 {
412         string str;
413         string driver;
414         bool using_alsa = false;
415         bool using_coreaudio = false;
416         bool using_dummy = false;
417         bool using_ffado = false;
418
419         /* first, path to jackd */
420
421         cmd.push_back (serverpath_combo.get_active_text ());
422
423         /* now jackd arguments */
424
425         str = timeout_combo.get_active_text ();
426         
427         if (str != _("Ignore")) {
428
429                 double secs = 0;
430                 uint32_t msecs;
431                 secs = atof (str);
432                 msecs = (uint32_t) floor (secs * 1000.0);
433                 
434                 if (msecs > 0) {
435                         cmd.push_back ("-t");
436                         cmd.push_back (to_string (msecs, std::dec));
437                 }
438         }
439
440         if (no_memory_lock_button.get_active()) {
441                 cmd.push_back ("-m"); /* no munlock */
442         }
443
444         cmd.push_back ("-p"); /* port max */
445         cmd.push_back (to_string ((uint32_t) floor (ports_spinner.get_value()), std::dec));
446
447         if (realtime_button.get_active()) {
448                 cmd.push_back ("-R");
449                 cmd.push_back ("-P");
450                 cmd.push_back (to_string ((uint32_t) floor (priority_spinner.get_value()), std::dec));
451         } else {
452                 cmd.push_back ("-r"); /* override jackd's default --realtime */
453         }
454
455         if (unlock_memory_button.get_active()) {
456                 cmd.push_back ("-u");
457         }
458
459         if (verbose_output_button.get_active()) {
460                 cmd.push_back ("-v");
461         }
462
463         /* now add fixed arguments (not user-selectable) */
464
465         cmd.push_back ("-T"); // temporary */
466
467         /* next the driver */
468
469         cmd.push_back ("-d");
470
471         driver = driver_combo.get_active_text ();
472         
473         if (driver == X_("ALSA")) {
474                 using_alsa = true;
475                 cmd.push_back ("alsa");
476         } else if (driver == X_("OSS")) {
477                 cmd.push_back ("oss");
478         } else if (driver == X_("CoreAudio")) {
479                 using_coreaudio = true;
480                 cmd.push_back ("coreaudio");
481         } else if (driver == X_("NetJACK")) {
482                 cmd.push_back ("netjack");
483         } else if (driver == X_("FreeBoB")) {
484                 cmd.push_back ("freebob");
485         } else if (driver == X_("FFADO")) {
486                 using_ffado = true;
487                 cmd.push_back ("firewire");
488         } else if ( driver == X_("Dummy")) {
489                 using_dummy = true;
490                 cmd.push_back ("dummy");
491         }
492
493         /* driver arguments */
494
495         if (!using_coreaudio) {
496                 str = audio_mode_combo.get_active_text();
497
498                 if (str == _("Playback/Recording on 1 Device")) {
499
500                         /* relax */
501
502                 } else if (str == _("Playback/Recording on 2 Devices")) {
503
504                         string input_device = get_device_name (driver, input_device_combo.get_active_text());
505                         string output_device = get_device_name (driver, output_device_combo.get_active_text());
506
507                         if (input_device.empty() || output_device.empty()) {
508                                 cmd.clear ();
509                                 return;
510                         }
511
512                         cmd.push_back ("-C");
513                         cmd.push_back (input_device);
514                         
515                         cmd.push_back ("-P");
516                         cmd.push_back (output_device);
517
518                 } else if (str == _("Playback only")) {
519                         cmd.push_back ("-P");
520                 } else if (str == _("Recording only")) {
521                         cmd.push_back ("-C");
522                 }
523
524                 if (!using_dummy) {
525                         cmd.push_back ("-n");
526                         cmd.push_back (to_string ((uint32_t) floor (periods_spinner.get_value()), std::dec));
527                 }
528         }
529
530         cmd.push_back ("-r");
531         cmd.push_back (to_string (get_rate(), std::dec));
532
533         cmd.push_back ("-p");
534         cmd.push_back (period_size_combo.get_active_text());
535         
536         if (using_alsa || using_ffado || using_coreaudio) {
537
538                 double val = input_latency_adjustment.get_value();
539
540                 if (val) {
541                         cmd.push_back ("-I");
542                         cmd.push_back (to_string ((uint32_t) val, std::dec));
543                 }
544
545                 val = output_latency_adjustment.get_value();
546                 
547                 if (val) {
548                         cmd.push_back ("-O");
549                         cmd.push_back (to_string ((uint32_t) val, std::dec));
550                 }
551         }
552
553         if (using_alsa) {
554
555                 if (audio_mode_combo.get_active_text() != _("Playback/Recording on 2 Devices")) {
556
557                         string device = get_device_name (driver, interface_combo.get_active_text());
558                         if (device.empty()) {
559                                 cmd.clear ();
560                                 return;
561                         }
562
563                         cmd.push_back ("-d");
564                         cmd.push_back (device);
565                 }
566
567                 if (hw_meter_button.get_active()) {
568                         cmd.push_back ("-M");
569                 }
570
571                 if (hw_monitor_button.get_active()) {
572                         cmd.push_back ("-H");
573                 }
574
575                 str = dither_mode_combo.get_active_text();
576
577                 if (str == _("None")) {
578                 } else if (str == _("Triangular")) {
579                         cmd.push_back ("-z triangular");
580                 } else if (str == _("Rectangular")) {
581                         cmd.push_back ("-z rectangular");
582                 } else if (str == _("Shaped")) {
583                         cmd.push_back ("-z shaped");
584                 }
585
586                 if (force16bit_button.get_active()) {
587                         cmd.push_back ("-S");
588                 }
589
590                 if (soft_mode_button.get_active()) {
591                         cmd.push_back ("-s");
592                 }
593
594                 str = midi_driver_combo.get_active_text ();
595
596                 if (str == _("seq")) {
597                         cmd.push_back ("-X seq");
598                 } else if (str == _("raw")) {
599                         cmd.push_back ("-X raw");
600                 }
601         } else if (using_coreaudio) {
602
603 #ifdef __APPLE__
604                 // note: older versions of the CoreAudio JACK backend use -n instead of -d here
605
606                 string device = get_device_name (driver, interface_combo.get_active_text());
607                 if (device.empty()) {
608                         cmd.clear ();
609                         return;
610                 }
611
612                 cmd.push_back ("-d");
613                 cmd.push_back (device);
614 #endif
615
616         }
617 }
618
619 bool
620 EngineControl::engine_running ()
621 {
622         jack_status_t status;
623         jack_client_t* c = jack_client_open ("ardourprobe", JackNoStartServer, &status);
624
625         if (status == 0) {
626                 jack_client_close (c);
627                 return true;
628         }
629         return false;
630 }
631
632 int
633 EngineControl::setup_engine ()
634 {
635         vector<string> args;
636         std::string cwd = "/tmp";
637
638         build_command_line (args);
639
640         if (args.empty()) {
641                 return 1; // try again
642         }
643
644         std::string jackdrc_path = Glib::get_home_dir();
645         jackdrc_path += "/.jackdrc";
646
647         ofstream jackdrc (jackdrc_path.c_str());
648         if (!jackdrc) {
649                 error << string_compose (_("cannot open JACK rc file %1 to store parameters"), jackdrc_path) << endmsg;
650                 return -1;
651         }
652         cerr << "JACK COMMAND: ";
653         for (vector<string>::iterator i = args.begin(); i != args.end(); ++i) {
654                 cerr << (*i) << ' ';
655                 jackdrc << (*i) << ' ';
656         }
657         cerr << endl;
658         jackdrc << endl;
659         jackdrc.close ();
660
661         _used = true;
662
663         return 0;
664 }
665
666 void
667 EngineControl::realtime_changed ()
668 {
669 #ifndef __APPLE__
670         priority_spinner.set_sensitive (realtime_button.get_active());
671 #endif
672 }
673
674 void
675 EngineControl::enumerate_devices (const string& driver)
676 {
677         /* note: case matters for the map keys */
678
679         if (driver == "CoreAudio") {
680 #ifdef __APPLE__
681                 devices[driver] = enumerate_coreaudio_devices ();
682 #endif
683
684 #ifndef __APPLE__
685         } else if (driver == "ALSA") {
686                 devices[driver] = enumerate_alsa_devices ();
687         } else if (driver == "FreeBOB") {
688                 devices[driver] = enumerate_freebob_devices ();
689         } else if (driver == "FFADO") {
690                 devices[driver] = enumerate_ffado_devices ();
691         } else if (driver == "OSS") {
692                 devices[driver] = enumerate_oss_devices ();
693         } else if (driver == "Dummy") {
694                 devices[driver] = enumerate_dummy_devices ();
695         } else if (driver == "NetJACK") {
696                 devices[driver] = enumerate_netjack_devices ();
697         }
698 #else
699         }
700 #endif
701 }
702
703 #ifdef __APPLE__
704 static OSStatus
705 getDeviceUIDFromID( AudioDeviceID id, char *name, size_t nsize)
706 {
707         UInt32 size = sizeof(CFStringRef);
708         CFStringRef UI;
709         OSStatus res = AudioDeviceGetProperty(id, 0, false,
710                 kAudioDevicePropertyDeviceUID, &size, &UI);
711         if (res == noErr)
712                 CFStringGetCString(UI,name,nsize,CFStringGetSystemEncoding());
713         CFRelease(UI);
714         return res;
715 }
716
717 vector<string>
718 EngineControl::enumerate_coreaudio_devices ()
719 {
720         vector<string> devs;
721
722         // Find out how many Core Audio devices are there, if any...
723         // (code snippet gently "borrowed" from St?hane Letz jackdmp;)
724         OSStatus err;
725         Boolean isWritable;
726         size_t outSize = sizeof(isWritable);
727
728         backend_devs.clear ();
729
730         err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
731                                            &outSize, &isWritable);
732         if (err == noErr) {
733                 // Calculate the number of device available...
734                 int numCoreDevices = outSize / sizeof(AudioDeviceID);
735                 // Make space for the devices we are about to get...
736                 AudioDeviceID *coreDeviceIDs = new AudioDeviceID [numCoreDevices];
737                 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
738                                                &outSize, (void *) coreDeviceIDs);
739                 if (err == noErr) {
740                         // Look for the CoreAudio device name...
741                         char coreDeviceName[256];
742                         size_t nameSize;
743
744                         for (int i = 0; i < numCoreDevices; i++) {
745
746                                 nameSize = sizeof (coreDeviceName);
747
748                                 /* enforce duplex devices only */
749
750                                 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
751                                                                  0, true, kAudioDevicePropertyStreams,
752                                                                  &outSize, &isWritable);
753
754                                 if (err != noErr || outSize == 0) {
755                                         continue;
756                                 }
757
758                                 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
759                                                                  0, false, kAudioDevicePropertyStreams,
760                                                                  &outSize, &isWritable);
761
762                                 if (err != noErr || outSize == 0) {
763                                         continue;
764                                 }
765
766                                 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
767                                                                  0, true, kAudioDevicePropertyDeviceName,
768                                                                  &outSize, &isWritable);
769                                 if (err == noErr) {
770                                         err = AudioDeviceGetProperty(coreDeviceIDs[i],
771                                                                      0, true, kAudioDevicePropertyDeviceName,
772                                                                      &nameSize, (void *) coreDeviceName);
773                                         if (err == noErr) {
774                                                 char drivername[128];
775
776                                                 // this returns the unique id for the device
777                                                 // that must be used on the commandline for jack
778
779                                                 if (getDeviceUIDFromID(coreDeviceIDs[i], drivername, sizeof (drivername)) == noErr) {
780                                                         devs.push_back (coreDeviceName);
781                                                         backend_devs.push_back (drivername);
782                                                 }
783                                         }
784                                 }
785                         }
786                 }
787                 delete [] coreDeviceIDs;
788         }
789
790
791         if (devs.size() == 0) {
792                 MessageDialog msg (_("\
793 You do not have any audio devices capable of\n\
794 simultaneous playback and recording.\n\n\
795 Please use Applications -> Utilities -> Audio MIDI Setup\n\
796 to create an \"aggregrate\" device, or install a suitable\n\
797 audio interface.\n\n\
798 Please send email to Apple and ask them why new Macs\n\
799 have no duplex audio device.\n\n\
800 Alternatively, if you really want just playback\n\
801 or recording but not both, start JACK before running\n\
802 Ardour and choose the relevant device then."
803                                            ),
804                                    true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
805                 msg.set_title (_("No suitable audio devices"));
806                 msg.set_position (Gtk::WIN_POS_MOUSE);
807                 msg.run ();
808                 exit (1);
809         }
810
811
812         return devs;
813 }
814 #else
815 vector<string>
816 EngineControl::enumerate_alsa_devices ()
817 {
818         vector<string> devs;
819
820         snd_ctl_t *handle;
821         snd_ctl_card_info_t *info;
822         snd_pcm_info_t *pcminfo;
823         snd_ctl_card_info_alloca(&info);
824         snd_pcm_info_alloca(&pcminfo);
825         string devname;
826         int cardnum = -1;
827         int device = -1;
828
829         backend_devs.clear ();
830
831         while (snd_card_next (&cardnum) >= 0 && cardnum >= 0) {
832
833                 devname = "hw:";
834                 devname += to_string (cardnum, std::dec);
835
836                 if (snd_ctl_open (&handle, devname.c_str(), 0) >= 0 && snd_ctl_card_info (handle, info) >= 0) {
837
838                         while (snd_ctl_pcm_next_device (handle, &device) >= 0 && device >= 0) {
839
840                                 snd_pcm_info_set_device (pcminfo, device);
841                                 snd_pcm_info_set_subdevice (pcminfo, 0);
842                                 snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_PLAYBACK);
843
844                                 if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
845                                         devs.push_back (snd_pcm_info_get_name (pcminfo));
846                                         devname += ',';
847                                         devname += to_string (device, std::dec);
848                                         backend_devs.push_back (devname);
849                                 }
850                         }
851
852                         snd_ctl_close(handle);
853                 }
854         }
855
856         return devs;
857 }
858
859 vector<string>
860 EngineControl::enumerate_ffado_devices ()
861 {
862         vector<string> devs;
863         backend_devs.clear ();
864         return devs;
865 }
866
867 vector<string>
868 EngineControl::enumerate_freebob_devices ()
869 {
870         vector<string> devs;
871         return devs;
872 }
873
874 vector<string>
875 EngineControl::enumerate_oss_devices ()
876 {
877         vector<string> devs;
878         return devs;
879 }
880 vector<string>
881 EngineControl::enumerate_dummy_devices ()
882 {
883         vector<string> devs;
884         return devs;
885 }
886 vector<string>
887 EngineControl::enumerate_netjack_devices ()
888 {
889         vector<string> devs;
890         return devs;
891 }
892 #endif
893
894 void
895 EngineControl::driver_changed ()
896 {
897         string driver = driver_combo.get_active_text();
898         string::size_type maxlen = 0;
899         int maxindex = -1;
900         int n = 0;
901
902         enumerate_devices (driver);
903
904         vector<string>& strings = devices[driver];
905
906         if (strings.empty() && driver != "FreeBoB" && driver != "FFADO" && driver != "Dummy") {
907                 error << string_compose (_("No devices found for driver \"%1\""), driver) << endmsg;
908                 return;
909         }
910
911         for (vector<string>::iterator i = strings.begin(); i != strings.end(); ++i, ++n) {
912                 if ((*i).length() > maxlen) {
913                         maxlen = (*i).length();
914                         maxindex = n;
915                 }
916         }
917
918         set_popdown_strings (interface_combo, strings);
919         set_popdown_strings (input_device_combo, strings);
920         set_popdown_strings (output_device_combo, strings);
921
922         if (!strings.empty()) {
923                 interface_combo.set_active_text (strings.front());
924                 input_device_combo.set_active_text (strings.front());
925                 output_device_combo.set_active_text (strings.front());
926         }
927
928         if (driver == "ALSA") {
929                 soft_mode_button.set_sensitive (true);
930                 force16bit_button.set_sensitive (true);
931                 hw_monitor_button.set_sensitive (true);
932                 hw_meter_button.set_sensitive (true);
933                 monitor_button.set_sensitive (true);
934         } else {
935                 soft_mode_button.set_sensitive (false);
936                 force16bit_button.set_sensitive (false);
937                 hw_monitor_button.set_sensitive (false);
938                 hw_meter_button.set_sensitive (false);
939                 monitor_button.set_sensitive (false);
940         }
941 }
942
943 uint32_t
944 EngineControl::get_rate ()
945 {
946         return atoi (sample_rate_combo.get_active_text ());
947 }
948
949 void
950 EngineControl::redisplay_latency ()
951 {
952         uint32_t rate = get_rate();
953 #ifdef __APPLE_
954         float periods = 2;
955 #else
956         float periods = periods_adjustment.get_value();
957 #endif
958         float period_size = atof (period_size_combo.get_active_text());
959
960         char buf[32];
961         snprintf (buf, sizeof(buf), "%.1fmsec", (periods * period_size) / (rate/1000.0));
962
963         latency_label.set_text (buf);
964         latency_label.set_alignment (0, 0.5);
965 }
966
967 void
968 EngineControl::audio_mode_changed ()
969 {
970         std::string str = audio_mode_combo.get_active_text();
971
972         if (str == _("Playback/Recording on 1 Device")) {
973                 input_device_combo.set_sensitive (false);
974                 output_device_combo.set_sensitive (false);
975         } else if (str == _("Playback/Recording on 2 Devices")) {
976                 input_device_combo.set_sensitive (true);
977                 output_device_combo.set_sensitive (true);
978         } else if (str == _("Playback only")) {
979                 output_device_combo.set_sensitive (true);
980         } else if (str == _("Recording only")) {
981                 input_device_combo.set_sensitive (true);
982         }
983 }
984
985 static bool jack_server_filter(const string& str, void */*arg*/)
986 {
987    return str == "jackd" || str == "jackdmp";
988 }
989
990 void
991 EngineControl::find_jack_servers (vector<string>& strings)
992 {
993 #ifdef __APPLE__
994         /* this magic lets us finds the path to the OSX bundle, and then
995            we infer JACK's location from there
996         */
997
998         char execpath[MAXPATHLEN+1];
999         uint32_t pathsz = sizeof (execpath);
1000
1001         _NSGetExecutablePath (execpath, &pathsz);
1002
1003         string path (Glib::path_get_dirname (execpath));
1004         path += "/jackd";
1005
1006         if (Glib::file_test (path, FILE_TEST_EXISTS)) {
1007                 strings.push_back (path);
1008         }
1009
1010         if (getenv ("ARDOUR_WITH_JACK")) {
1011                 /* no other options - only use the JACK we supply */
1012                 if (strings.empty()) {
1013                         fatal << string_compose (_("JACK appears to be missing from the %1 bundle"), PROGRAM_NAME) << endmsg;
1014                         /*NOTREACHED*/
1015                 }
1016                 return;
1017         }
1018 #else
1019         string path;
1020 #endif
1021
1022         PathScanner scanner;
1023         vector<string *> *jack_servers;
1024         std::map<string,int> un;
1025         char *p;
1026         bool need_minimal_path = false;
1027
1028         p = getenv ("PATH");
1029
1030         if (p && *p) {
1031                 path = p;
1032         } else {
1033                 need_minimal_path = true;
1034         }
1035
1036 #ifdef __APPLE__
1037         // many mac users don't have PATH set up to include
1038         // likely installed locations of JACK
1039         need_minimal_path = true;
1040 #endif
1041
1042         if (need_minimal_path) {
1043                 if (path.empty()) {
1044                         path = "/usr/bin:/bin:/usr/local/bin:/opt/local/bin";
1045                 } else {
1046                         path += ":/usr/local/bin:/opt/local/bin";
1047                 }
1048         }
1049
1050 #ifdef __APPLE__
1051         // push it back into the environment so that auto-started JACK can find it.
1052         // XXX why can't we just expect OS X users to have PATH set correctly? we can't ...
1053         setenv ("PATH", path.c_str(), 1);
1054 #endif
1055
1056         jack_servers = scanner (path, jack_server_filter, 0, false, true);
1057
1058         vector<string *>::iterator iter;
1059
1060         for (iter = jack_servers->begin(); iter != jack_servers->end(); iter++) {
1061                 string p = **iter;
1062
1063                 if (un[p]++ == 0) {
1064                         strings.push_back(p);
1065                 }
1066         }
1067 }
1068
1069
1070 string
1071 EngineControl::get_device_name (const string& driver, const string& human_readable)
1072 {
1073         vector<string>::iterator n;
1074         vector<string>::iterator i;
1075
1076         if (human_readable.empty()) {
1077                 /* this can happen if the user's .ardourrc file has a device name from
1078                    another computer system in it
1079                 */
1080                 MessageDialog msg (_("You need to choose an audio device first."));
1081                 msg.run ();
1082                 return string();
1083         }
1084
1085         if (backend_devs.empty()) {
1086                 return human_readable;
1087         }
1088
1089         for (i = devices[driver].begin(), n = backend_devs.begin(); i != devices[driver].end(); ++i, ++n) {
1090                 if (human_readable == (*i)) {
1091                         return (*n);
1092                 }
1093         }
1094
1095         if (i == devices[driver].end()) {
1096                 warning << string_compose (_("Audio device \"%1\" not known on this computer."), human_readable) << endmsg;
1097         }
1098
1099         return string();
1100 }
1101
1102 XMLNode&
1103 EngineControl::get_state ()
1104 {
1105         XMLNode* root = new XMLNode ("AudioSetup");
1106         XMLNode* child;
1107         std::string path;
1108
1109         child = new XMLNode ("periods");
1110         child->add_property ("val", to_string (periods_adjustment.get_value(), std::dec));
1111         root->add_child_nocopy (*child);
1112
1113         child = new XMLNode ("priority");
1114         child->add_property ("val", to_string (priority_adjustment.get_value(), std::dec));
1115         root->add_child_nocopy (*child);
1116
1117         child = new XMLNode ("ports");
1118         child->add_property ("val", to_string (ports_adjustment.get_value(), std::dec));
1119         root->add_child_nocopy (*child);
1120
1121         child = new XMLNode ("inchannels");
1122         child->add_property ("val", to_string (input_channels.get_value(), std::dec));
1123         root->add_child_nocopy (*child);
1124
1125         child = new XMLNode ("outchannels");
1126         child->add_property ("val", to_string (output_channels.get_value(), std::dec));
1127         root->add_child_nocopy (*child);
1128
1129         child = new XMLNode ("inlatency");
1130         child->add_property ("val", to_string (input_latency.get_value(), std::dec));
1131         root->add_child_nocopy (*child);
1132
1133         child = new XMLNode ("outlatency");
1134         child->add_property ("val", to_string (output_latency.get_value(), std::dec));
1135         root->add_child_nocopy (*child);
1136
1137         child = new XMLNode ("realtime");
1138         child->add_property ("val", to_string (realtime_button.get_active(), std::dec));
1139         root->add_child_nocopy (*child);
1140
1141         child = new XMLNode ("nomemorylock");
1142         child->add_property ("val", to_string (no_memory_lock_button.get_active(), std::dec));
1143         root->add_child_nocopy (*child);
1144
1145         child = new XMLNode ("unlockmemory");
1146         child->add_property ("val", to_string (unlock_memory_button.get_active(), std::dec));
1147         root->add_child_nocopy (*child);
1148
1149         child = new XMLNode ("softmode");
1150         child->add_property ("val", to_string (soft_mode_button.get_active(), std::dec));
1151         root->add_child_nocopy (*child);
1152
1153         child = new XMLNode ("force16bit");
1154         child->add_property ("val", to_string (force16bit_button.get_active(), std::dec));
1155         root->add_child_nocopy (*child);
1156
1157         child = new XMLNode ("hwmonitor");
1158         child->add_property ("val", to_string (hw_monitor_button.get_active(), std::dec));
1159         root->add_child_nocopy (*child);
1160
1161         child = new XMLNode ("hwmeter");
1162         child->add_property ("val", to_string (hw_meter_button.get_active(), std::dec));
1163         root->add_child_nocopy (*child);
1164
1165         child = new XMLNode ("verbose");
1166         child->add_property ("val", to_string (verbose_output_button.get_active(), std::dec));
1167         root->add_child_nocopy (*child);
1168
1169         child = new XMLNode ("samplerate");
1170         child->add_property ("val", sample_rate_combo.get_active_text());
1171         root->add_child_nocopy (*child);
1172
1173         child = new XMLNode ("periodsize");
1174         child->add_property ("val", period_size_combo.get_active_text());
1175         root->add_child_nocopy (*child);
1176
1177         child = new XMLNode ("serverpath");
1178         child->add_property ("val", serverpath_combo.get_active_text());
1179         root->add_child_nocopy (*child);
1180
1181         child = new XMLNode ("driver");
1182         child->add_property ("val", driver_combo.get_active_text());
1183         root->add_child_nocopy (*child);
1184
1185         child = new XMLNode ("interface");
1186         child->add_property ("val", interface_combo.get_active_text());
1187         root->add_child_nocopy (*child);
1188
1189         child = new XMLNode ("timeout");
1190         child->add_property ("val", timeout_combo.get_active_text());
1191         root->add_child_nocopy (*child);
1192
1193         child = new XMLNode ("dither");
1194         child->add_property ("val", dither_mode_combo.get_active_text());
1195         root->add_child_nocopy (*child);
1196
1197         child = new XMLNode ("audiomode");
1198         child->add_property ("val", audio_mode_combo.get_active_text());
1199         root->add_child_nocopy (*child);
1200
1201         child = new XMLNode ("inputdevice");
1202         child->add_property ("val", input_device_combo.get_active_text());
1203         root->add_child_nocopy (*child);
1204
1205         child = new XMLNode ("outputdevice");
1206         child->add_property ("val", output_device_combo.get_active_text());
1207         root->add_child_nocopy (*child);
1208
1209         child = new XMLNode ("mididriver");
1210         child->add_property ("val", midi_driver_combo.get_active_text());
1211         root->add_child_nocopy (*child);
1212
1213         return *root;
1214 }
1215
1216 void
1217 EngineControl::set_state (const XMLNode& root)
1218 {
1219         XMLNodeList          clist;
1220         XMLNodeConstIterator citer;
1221         XMLNode* child;
1222         XMLProperty* prop = NULL;
1223         bool using_dummy = false;
1224         bool using_ffado = false;
1225
1226         int val;
1227         string strval;
1228
1229         if ( (child = root.child ("driver"))){
1230                 prop = child->property("val");
1231                 
1232                 if (prop && (prop->value() == "Dummy") ) {
1233                         using_dummy = true;
1234                 }
1235                 if (prop && (prop->value() == "FFADO") ) {
1236                         using_ffado = true;
1237                 }
1238
1239         }
1240
1241         clist = root.children();
1242
1243         for (citer = clist.begin(); citer != clist.end(); ++citer) {
1244
1245                 child = *citer;
1246
1247                 prop = child->property ("val");
1248
1249                 if (!prop || prop->value().empty()) {
1250
1251                         if (((using_dummy || using_ffado) 
1252                                 && ( child->name() == "interface" 
1253                                         || child->name() == "inputdevice" 
1254                                         || child->name() == "outputdevice")) 
1255                                 || child->name() == "timeout")
1256                         {
1257                                 continue;
1258                         }
1259                         
1260                         error << string_compose (_("AudioSetup value for %1 is missing data"), child->name()) << endmsg;
1261                         continue;
1262                 }
1263
1264                 strval = prop->value();
1265
1266                 /* adjustments/spinners */
1267
1268                 if (child->name() == "periods") {
1269                         val = atoi (strval);
1270                         periods_adjustment.set_value(val);
1271                 } else if (child->name() == "priority") {
1272                         val = atoi (strval);
1273                         priority_adjustment.set_value(val);
1274                 } else if (child->name() == "ports") {
1275                         val = atoi (strval);
1276                         ports_adjustment.set_value(val);
1277                 } else if (child->name() == "inchannels") {
1278                         val = atoi (strval);
1279                         input_channels.set_value(val);
1280                 } else if (child->name() == "outchannels") {
1281                         val = atoi (strval);
1282                         output_channels.set_value(val);
1283                 } else if (child->name() == "inlatency") {
1284                         val = atoi (strval);
1285                         input_latency.set_value(val);
1286                 } else if (child->name() == "outlatency") {
1287                         val = atoi (strval);
1288                         output_latency.set_value(val);
1289                 }
1290
1291                 /* buttons */
1292
1293                 else if (child->name() == "realtime") {
1294                         val = atoi (strval);
1295                         realtime_button.set_active(val);
1296                 } else if (child->name() == "nomemorylock") {
1297                         val = atoi (strval);
1298                         no_memory_lock_button.set_active(val);
1299                 } else if (child->name() == "unlockmemory") {
1300                         val = atoi (strval);
1301                         unlock_memory_button.set_active(val);
1302                 } else if (child->name() == "softmode") {
1303                         val = atoi (strval);
1304                         soft_mode_button.set_active(val);
1305                 } else if (child->name() == "force16bit") {
1306                         val = atoi (strval);
1307                         force16bit_button.set_active(val);
1308                 } else if (child->name() == "hwmonitor") {
1309                         val = atoi (strval);
1310                         hw_monitor_button.set_active(val);
1311                 } else if (child->name() == "hwmeter") {
1312                         val = atoi (strval);
1313                         hw_meter_button.set_active(val);
1314                 } else if (child->name() == "verbose") {
1315                         val = atoi (strval);
1316                         verbose_output_button.set_active(val);
1317                 }
1318
1319                 /* combos */
1320
1321                 else if (child->name() == "samplerate") {
1322                         sample_rate_combo.set_active_text(strval);
1323                 } else if (child->name() == "periodsize") {
1324                         period_size_combo.set_active_text(strval);
1325                 } else if (child->name() == "serverpath") {
1326                         
1327                         /* only attempt to set this if we have bothered to look
1328                            up server names already. otherwise this is all
1329                            redundant (actually, all of this dialog/widget
1330                            is redundant in that case ...)
1331                         */
1332                         
1333                         if (!server_strings.empty()) {
1334                                 /* do not allow us to use a server path that doesn't
1335                                    exist on this system. this handles cases where
1336                                    the user has an RC file listing a serverpath
1337                                    from some other machine.
1338                                 */
1339                                 vector<string>::iterator x;
1340                                 for (x = server_strings.begin(); x != server_strings.end(); ++x) {
1341                                         if (*x == strval) {
1342                                                 break;
1343                                         }
1344                                 }
1345                                 if (x != server_strings.end()) {
1346                                         serverpath_combo.set_active_text (strval);
1347                                 } else {
1348                                         warning << string_compose (_("configuration files contain a JACK server path that doesn't exist (%1)"),
1349                                                                    strval)
1350                                                 << endmsg;
1351                                 }
1352                         }
1353                         
1354                 } else if (child->name() == "driver") {
1355                         driver_combo.set_active_text(strval);
1356                 } else if (child->name() == "interface") {
1357                         interface_combo.set_active_text(strval);
1358                 } else if (child->name() == "timeout") {
1359                         timeout_combo.set_active_text(strval);
1360                 } else if (child->name() == "dither") {
1361                         dither_mode_combo.set_active_text(strval);
1362                 } else if (child->name() == "audiomode") {
1363                         audio_mode_combo.set_active_text(strval);
1364                 } else if (child->name() == "inputdevice") {
1365                         input_device_combo.set_active_text(strval);
1366                 } else if (child->name() == "outputdevice") {
1367                         output_device_combo.set_active_text(strval);
1368                 } else if (child->name() == "mididriver") {
1369                         midi_driver_combo.set_active_text(strval);
1370                 }
1371         }
1372 }