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