10 #include <CoreAudio/CoreAudio.h>
11 #include <CoreFoundation/CFString.h>
12 #include <sys/param.h>
13 #include <mach-o/dyld.h>
15 #include <alsa/asoundlib.h>
18 #include <ardour/profile.h>
19 #include <jack/jack.h>
21 #include <gtkmm/stock.h>
22 #include <gtkmm2ext/utils.h>
24 #include <pbd/convert.h>
25 #include <pbd/error.h>
26 #include <pbd/pathscanner.h>
32 #include "engine_dialog.h"
37 using namespace Gtkmm2ext;
41 EngineControl::EngineControl ()
42 : periods_adjustment (2, 2, 16, 1, 2),
43 periods_spinner (periods_adjustment),
44 priority_adjustment (60, 10, 90, 1, 10),
45 priority_spinner (priority_adjustment),
46 ports_adjustment (128, 8, 1024, 1, 16),
47 ports_spinner (ports_adjustment),
48 realtime_button (_("Realtime")),
49 no_memory_lock_button (_("Do not lock memory")),
50 unlock_memory_button (_("Unlock memory")),
51 soft_mode_button (_("No zombies")),
52 monitor_button (_("Provide monitor ports")),
53 force16bit_button (_("Force 16 bit")),
54 hw_monitor_button (_("H/W monitoring")),
55 hw_meter_button (_("H/W metering")),
56 verbose_output_button (_("Verbose output")),
57 start_button (_("Start")),
58 stop_button (_("Stop")),
61 options_packer (4, 2),
65 options_packer (14, 2),
69 using namespace Notebook_Helpers;
71 vector<string> strings;
76 strings.push_back (_("8000Hz"));
77 strings.push_back (_("22050Hz"));
78 strings.push_back (_("44100Hz"));
79 strings.push_back (_("48000Hz"));
80 strings.push_back (_("88200Hz"));
81 strings.push_back (_("96000Hz"));
82 strings.push_back (_("192000Hz"));
83 set_popdown_strings (sample_rate_combo, strings);
84 sample_rate_combo.set_active_text ("48000Hz");
87 strings.push_back ("32");
88 strings.push_back ("64");
89 strings.push_back ("128");
90 strings.push_back ("256");
91 strings.push_back ("512");
92 strings.push_back ("1024");
93 strings.push_back ("2048");
94 strings.push_back ("4096");
95 strings.push_back ("8192");
96 set_popdown_strings (period_size_combo, strings);
97 period_size_combo.set_active_text ("1024");
100 strings.push_back (_("None"));
101 strings.push_back (_("Triangular"));
102 strings.push_back (_("Rectangular"));
103 strings.push_back (_("Shaped"));
104 set_popdown_strings (dither_mode_combo, strings);
105 dither_mode_combo.set_active_text (_("None"));
107 /* basic parameters */
109 basic_packer.set_spacings (6);
113 strings.push_back (X_("CoreAudio"));
115 strings.push_back (X_("ALSA"));
116 strings.push_back (X_("OSS"));
117 strings.push_back (X_("FFADO"));
119 strings.push_back (X_("NetJACK"));
120 strings.push_back (X_("Dummy"));
121 set_popdown_strings (driver_combo, strings);
122 driver_combo.set_active_text (strings.front());
124 /* figure out available devices and set up interface_combo */
126 enumerate_devices ();
127 driver_combo.signal_changed().connect (mem_fun (*this, &EngineControl::driver_changed));
131 strings.push_back (_("Playback/Recording on 1 Device"));
132 strings.push_back (_("Playback/Recording on 2 Devices"));
133 strings.push_back (_("Playback only"));
134 strings.push_back (_("Recording only"));
135 set_popdown_strings (audio_mode_combo, strings);
136 audio_mode_combo.set_active_text (strings.front());
138 audio_mode_combo.signal_changed().connect (mem_fun (*this, &EngineControl::audio_mode_changed));
139 audio_mode_changed ();
143 label = manage (new Label (_("Driver")));
144 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
145 basic_packer.attach (driver_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
148 label = manage (new Label (_("Interface")));
149 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
150 basic_packer.attach (interface_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
153 label = manage (new Label (_("Sample Rate")));
154 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
155 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
158 label = manage (new Label (_("Buffer size")));
159 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
160 basic_packer.attach (period_size_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
164 label = manage (new Label (_("Number of buffers")));
165 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
166 basic_packer.attach (periods_spinner, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
167 periods_spinner.set_value (2);
171 label = manage (new Label (_("Approximate latency")));
172 label->set_alignment (0.0, 0.5);
173 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
174 basic_packer.attach (latency_label, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
177 sample_rate_combo.signal_changed().connect (mem_fun (*this, &EngineControl::redisplay_latency));
178 periods_adjustment.signal_value_changed().connect (mem_fun (*this, &EngineControl::redisplay_latency));
179 period_size_combo.signal_changed().connect (mem_fun (*this, &EngineControl::redisplay_latency));
182 /* no audio mode with CoreAudio, its duplex or nuthin' */
185 label = manage (new Label (_("Audio Mode")));
186 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
187 basic_packer.attach (audio_mode_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
191 interface_combo.set_size_request (125, -1);
192 input_device_combo.set_size_request (125, -1);
193 output_device_combo.set_size_request (125, -1);
197 if (engine_running()) {
198 start_button.set_sensitive (false);
200 stop_button.set_sensitive (false);
203 start_button.signal_clicked().connect (mem_fun (*this, &EngineControl::start_engine));
204 stop_button.signal_clicked().connect (mem_fun (*this, &EngineControl::start_engine));
207 button_box.pack_start (start_button, false, false);
208 button_box.pack_start (stop_button, false, false);
210 // basic_packer.attach (button_box, 0, 2, 8, 9, FILL|EXPAND, (AttachOptions) 0);
214 options_packer.set_spacings (6);
217 options_packer.attach (realtime_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
220 realtime_button.signal_toggled().connect (mem_fun (*this, &EngineControl::realtime_changed));
224 label = manage (new Label (_("Realtime Priority")));
225 label->set_alignment (1.0, 0.5);
226 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
227 options_packer.attach (priority_spinner, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
229 priority_spinner.set_value (60);
231 options_packer.attach (no_memory_lock_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
233 options_packer.attach (unlock_memory_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
235 options_packer.attach (soft_mode_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
237 options_packer.attach (monitor_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
239 options_packer.attach (force16bit_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
241 options_packer.attach (hw_monitor_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
243 options_packer.attach (hw_meter_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
245 options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
248 options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
253 strings.push_back (_("Ignore"));
254 strings.push_back ("500 msec");
255 strings.push_back ("1 sec");
256 strings.push_back ("2 sec");
257 strings.push_back ("10 sec");
258 set_popdown_strings (timeout_combo, strings);
259 timeout_combo.set_active_text (strings.front ());
261 label = manage (new Label (_("Client timeout")));
262 label->set_alignment (1.0, 0.5);
263 options_packer.attach (timeout_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
264 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
267 label = manage (new Label (_("Number of ports")));
268 label->set_alignment (1.0, 0.5);
269 options_packer.attach (ports_spinner, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
270 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
274 label = manage (new Label (_("Dither")));
275 label->set_alignment (1.0, 0.5);
276 options_packer.attach (dither_mode_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
277 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
281 find_jack_servers (server_strings);
283 if (server_strings.empty()) {
284 fatal << _("No JACK server found anywhere on this system. Please install JACK and restart") << endmsg;
288 set_popdown_strings (serverpath_combo, server_strings);
289 serverpath_combo.set_active_text (server_strings.front());
291 if (server_strings.size() > 1) {
292 label = manage (new Label (_("Server:")));
293 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
294 label->set_alignment (0.0, 0.5);
295 options_packer.attach (serverpath_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
299 /* device settings */
301 device_packer.set_spacings (6);
305 label = manage (new Label (_("Input device")));
306 label->set_alignment (1.0, 0.5);
307 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
308 device_packer.attach (input_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
310 label = manage (new Label (_("Output device")));
311 label->set_alignment (1.0, 0.5);
312 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
313 device_packer.attach (output_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
316 label = manage (new Label (_("Input channels")));
317 label->set_alignment (1.0, 0.5);
318 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
319 device_packer.attach (input_channels, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
321 label = manage (new Label (_("Output channels")));
322 label->set_alignment (1.0, 0.5);
323 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
324 device_packer.attach (output_channels, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
326 label = manage (new Label (_("Hardware input latency (samples)")));
327 label->set_alignment (1.0, 0.5);
328 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
329 device_packer.attach (input_latency, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
331 label = manage (new Label (_("Hardware output latency (samples)")));
332 label->set_alignment (1.0, 0.5);
333 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
334 device_packer.attach (output_latency, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
337 basic_hbox.pack_start (basic_packer, false, false);
338 options_hbox.pack_start (options_packer, false, false);
340 device_packer.set_border_width (12);
341 options_packer.set_border_width (12);
342 basic_packer.set_border_width (12);
344 notebook.pages().push_back (TabElem (basic_hbox, _("Device")));
345 notebook.pages().push_back (TabElem (options_hbox, _("Options")));
346 notebook.pages().push_back (TabElem (device_packer, _("Advanced")));
347 notebook.set_border_width (12);
349 set_border_width (12);
350 pack_start (notebook);
353 EngineControl::~EngineControl ()
359 EngineControl::build_command_line (vector<string>& cmd)
363 bool using_oss = false;
364 bool using_alsa = false;
365 bool using_coreaudio = false;
366 bool using_netjack = false;
367 bool using_ffado = false;
368 bool using_dummy = false;
370 /* first, path to jackd */
372 cmd.push_back (serverpath_combo.get_active_text ());
374 /* now jackd arguments */
376 str = timeout_combo.get_active_text ();
377 if (str != _("Ignore")) {
381 msecs = (uint32_t) floor (secs * 1000.0);
382 cmd.push_back ("-t");
383 cmd.push_back (to_string (msecs, std::dec));
386 if (no_memory_lock_button.get_active()) {
387 cmd.push_back ("-m"); /* no munlock */
390 cmd.push_back ("-p"); /* port max */
391 cmd.push_back (to_string ((uint32_t) floor (ports_spinner.get_value()), std::dec));
393 if (realtime_button.get_active()) {
394 cmd.push_back ("-R");
395 cmd.push_back ("-P");
396 cmd.push_back (to_string ((uint32_t) floor (priority_spinner.get_value()), std::dec));
399 if (unlock_memory_button.get_active()) {
400 cmd.push_back ("-u");
403 if (verbose_output_button.get_active()) {
404 cmd.push_back ("-v");
407 /* now add fixed arguments (not user-selectable) */
409 cmd.push_back ("-T"); // temporary */
411 /* next the driver */
413 cmd.push_back ("-d");
415 driver = driver_combo.get_active_text ();
416 if (driver == X_("ALSA")) {
418 cmd.push_back ("alsa");
419 } else if (driver == X_("OSS")) {
421 cmd.push_back ("oss");
422 } else if (driver == X_("CoreAudio")) {
423 using_coreaudio = true;
424 cmd.push_back ("coreaudio");
425 } else if (driver == X_("NetJACK")) {
426 using_netjack = true;
427 cmd.push_back ("netjack");
428 } else if (driver == X_("FFADO")) {
430 cmd.push_back ("ffado");
431 } else if ( driver == X_("Dummy")) {
433 cmd.push_back ("dummy");
436 /* driver arguments */
438 if (!using_coreaudio) {
439 str = audio_mode_combo.get_active_text();
441 if (str == _("Playback/Recording on 1 Device")) {
445 } else if (str == _("Playback/Recording on 2 Devices")) {
447 cmd.push_back ("-C");
448 cmd.push_back (get_device_name (driver, input_device_combo.get_active_text()));
449 cmd.push_back ("-P");
450 cmd.push_back (get_device_name (driver, output_device_combo.get_active_text()));
452 } else if (str == _("Playback only")) {
453 cmd.push_back ("-P");
454 } else if (str == _("Recording only")) {
455 cmd.push_back ("-C");
458 if (! using_dummy ) {
459 cmd.push_back ("-n");
460 cmd.push_back (to_string ((uint32_t) floor (periods_spinner.get_value()), std::dec));
464 cmd.push_back ("-r");
465 cmd.push_back (to_string (get_rate(), std::dec));
467 cmd.push_back ("-p");
468 cmd.push_back (period_size_combo.get_active_text());
472 if (audio_mode_combo.get_active_text() != _("Playback/Recording on 2 Devices")) {
473 cmd.push_back ("-d");
474 cmd.push_back (get_device_name (driver, interface_combo.get_active_text()));
477 if (hw_meter_button.get_active()) {
478 cmd.push_back ("-M");
481 if (hw_monitor_button.get_active()) {
482 cmd.push_back ("-H");
485 str = dither_mode_combo.get_active_text();
487 if (str == _("None")) {
488 } else if (str == _("Triangular")) {
489 cmd.push_back ("-z triangular");
490 } else if (str == _("Rectangular")) {
491 cmd.push_back ("-z rectangular");
492 } else if (str == _("Shaped")) {
493 cmd.push_back ("-z shaped");
496 if (force16bit_button.get_active()) {
497 cmd.push_back ("-S");
500 if (soft_mode_button.get_active()) {
501 cmd.push_back ("-s");
504 } else if (using_coreaudio) {
507 // note: older versions of the CoreAudio JACK backend use -n instead of -d here
508 cmd.push_back ("-d");
509 cmd.push_back (get_device_name (driver, interface_combo.get_active_text()));
512 } else if (using_oss) {
514 } else if (using_netjack) {
520 EngineControl::engine_running ()
522 jack_status_t status;
523 jack_client_t* c = jack_client_open ("ardourprobe", JackNoStartServer, &status);
526 jack_client_close (c);
533 EngineControl::setup_engine ()
536 std::string cwd = "/tmp";
538 build_command_line (args);
540 Glib::ustring jackdrc_path = Glib::get_home_dir();
541 jackdrc_path += "/.jackdrc";
543 ofstream jackdrc (jackdrc_path.c_str());
545 error << string_compose (_("cannot open JACK rc file %1 to store parameters"), jackdrc_path) << endmsg;
549 for (vector<string>::iterator i = args.begin(); i != args.end(); ++i) {
550 jackdrc << (*i) << ' ';
561 EngineControl::realtime_changed ()
564 priority_spinner.set_sensitive (realtime_button.get_active());
569 EngineControl::enumerate_devices ()
571 /* note: case matters for the map keys */
574 devices["CoreAudio"] = enumerate_coreaudio_devices ();
576 devices["ALSA"] = enumerate_alsa_devices ();
577 devices["FFADO"] = enumerate_ffado_devices ();
578 devices["OSS"] = enumerate_oss_devices ();
579 devices["Dummy"] = enumerate_dummy_devices ();
580 devices["NetJACK"] = enumerate_netjack_devices ();
586 getDeviceUIDFromID( AudioDeviceID id, char *name, size_t nsize)
588 UInt32 size = sizeof(CFStringRef);
590 OSStatus res = AudioDeviceGetProperty(id, 0, false,
591 kAudioDevicePropertyDeviceUID, &size, &UI);
593 CFStringGetCString(UI,name,nsize,CFStringGetSystemEncoding());
599 EngineControl::enumerate_coreaudio_devices ()
603 // Find out how many Core Audio devices are there, if any...
604 // (code snippet gently "borrowed" from St?hane Letz jackdmp;)
607 size_t outSize = sizeof(isWritable);
609 backend_devs.clear ();
611 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
612 &outSize, &isWritable);
614 // Calculate the number of device available...
615 int numCoreDevices = outSize / sizeof(AudioDeviceID);
616 // Make space for the devices we are about to get...
617 AudioDeviceID *coreDeviceIDs = new AudioDeviceID [numCoreDevices];
618 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
619 &outSize, (void *) coreDeviceIDs);
621 // Look for the CoreAudio device name...
622 char coreDeviceName[256];
624 for (int i = 0; i < numCoreDevices; i++) {
626 nameSize = sizeof (coreDeviceName);
628 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
629 0, true, kAudioDevicePropertyDeviceName,
630 &outSize, &isWritable);
632 err = AudioDeviceGetProperty(coreDeviceIDs[i],
633 0, true, kAudioDevicePropertyDeviceName,
634 &nameSize, (void *) coreDeviceName);
636 char drivername[128];
638 // this returns the unique id for the device
639 // that must be used on the commandline for jack
641 if (getDeviceUIDFromID(coreDeviceIDs[i], drivername, sizeof (drivername)) == noErr) {
642 devs.push_back (coreDeviceName);
643 backend_devs.push_back (drivername);
649 delete [] coreDeviceIDs;
656 EngineControl::enumerate_alsa_devices ()
661 snd_ctl_card_info_t *info;
662 snd_pcm_info_t *pcminfo;
663 snd_ctl_card_info_alloca(&info);
664 snd_pcm_info_alloca(&pcminfo);
669 backend_devs.clear ();
671 while (snd_card_next (&cardnum) >= 0 && cardnum >= 0) {
674 devname += to_string (cardnum, std::dec);
676 if (snd_ctl_open (&handle, devname.c_str(), 0) >= 0 && snd_ctl_card_info (handle, info) >= 0) {
678 while (snd_ctl_pcm_next_device (handle, &device) >= 0 && device >= 0) {
680 bool have_playback = false;
681 bool have_capture = false;
683 /* find duplex devices only */
685 snd_pcm_info_set_device (pcminfo, device);
686 snd_pcm_info_set_subdevice (pcminfo, 0);
687 snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_CAPTURE);
689 if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
693 snd_pcm_info_set_device (pcminfo, device);
694 snd_pcm_info_set_subdevice (pcminfo, 0);
695 snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_PLAYBACK);
697 if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
698 have_playback = true;
701 if (have_capture && have_playback) {
702 devs.push_back (snd_pcm_info_get_name (pcminfo));
704 devname += to_string (device, std::dec);
705 backend_devs.push_back (devname);
709 snd_ctl_close(handle);
717 EngineControl::enumerate_ffado_devices ()
723 EngineControl::enumerate_oss_devices ()
729 EngineControl::enumerate_dummy_devices ()
735 EngineControl::enumerate_netjack_devices ()
743 EngineControl::driver_changed ()
745 string driver = driver_combo.get_active_text();
746 vector<string>& strings = devices[driver];
747 string::size_type maxlen = 0;
751 for (vector<string>::iterator i = strings.begin(); i != strings.end(); ++i, ++n) {
752 if ((*i).length() > maxlen) {
753 maxlen = (*i).length();
758 set_popdown_strings (interface_combo, strings);
759 set_popdown_strings (input_device_combo, strings);
760 set_popdown_strings (output_device_combo, strings);
762 if (!strings.empty()) {
763 interface_combo.set_active_text (strings.front());
764 input_device_combo.set_active_text (strings.front());
765 output_device_combo.set_active_text (strings.front());
768 if (driver == "ALSA") {
769 soft_mode_button.set_sensitive (true);
770 force16bit_button.set_sensitive (true);
771 hw_monitor_button.set_sensitive (true);
772 hw_meter_button.set_sensitive (true);
773 monitor_button.set_sensitive (true);
775 soft_mode_button.set_sensitive (false);
776 force16bit_button.set_sensitive (false);
777 hw_monitor_button.set_sensitive (false);
778 hw_meter_button.set_sensitive (false);
779 monitor_button.set_sensitive (false);
784 EngineControl::get_rate ()
786 return atoi (sample_rate_combo.get_active_text ());
790 EngineControl::redisplay_latency ()
792 uint32_t rate = get_rate();
796 float periods = periods_adjustment.get_value();
798 float period_size = atof (period_size_combo.get_active_text());
801 snprintf (buf, sizeof(buf), "%.1fmsec", (periods * period_size) / (rate/1000.0));
803 latency_label.set_text (buf);
807 EngineControl::audio_mode_changed ()
809 Glib::ustring str = audio_mode_combo.get_active_text();
811 if (str == _("Playback/Recording on 1 Device")) {
812 input_device_combo.set_sensitive (false);
813 output_device_combo.set_sensitive (false);
814 } else if (str == _("Playback/Recording on 2 Devices")) {
815 input_device_combo.set_sensitive (true);
816 output_device_combo.set_sensitive (true);
817 } else if (str == _("Playback only")) {
818 output_device_combo.set_sensitive (true);
819 } else if (str == _("Recording only")) {
820 input_device_combo.set_sensitive (true);
824 static bool jack_server_filter(const string& str, void *arg)
826 return str == "jackd" || str == "jackdmp";
830 EngineControl::find_jack_servers (vector<string>& strings)
833 /* this magic lets us finds the path to the OSX bundle, and then
834 we infer JACK's location from there
837 char execpath[MAXPATHLEN+1];
838 uint32_t pathsz = sizeof (execpath);
840 _NSGetExecutablePath (execpath, &pathsz);
842 Glib::ustring path (Glib::path_get_dirname (execpath));
845 if (Glib::file_test (path, FILE_TEST_EXISTS)) {
846 strings.push_back (path);
849 if (getenv ("ARDOUR_WITH_JACK")) {
850 /* no other options - only use the JACK we supply */
851 if (strings.empty()) {
852 fatal << _("JACK appears to be missing from the Ardour bundle") << endmsg;
860 vector<string *> *jack_servers;
861 std::map<string,int> un;
863 path = getenv ("PATH");
865 jack_servers = scanner(path, jack_server_filter, 0, false, true);
867 vector<string *>::iterator iter;
869 for (iter = jack_servers->begin(); iter != jack_servers->end(); iter++) {
873 strings.push_back(p);
880 EngineControl::get_device_name (const string& driver, const string& human_readable)
882 vector<string>::iterator n;
883 vector<string>::iterator i;
885 if (backend_devs.empty()) {
886 return human_readable;
889 for (i = devices[driver].begin(), n = backend_devs.begin(); i != devices[driver].end(); ++i, ++n) {
890 if (human_readable == (*i)) {
895 if (i == devices[driver].end()) {
896 fatal << string_compose (_("programming error: %1"), "true hardware name for ID missing") << endmsg;
906 EngineControl::get_state ()
908 XMLNode* root = new XMLNode ("AudioSetup");
912 child = new XMLNode ("periods");
913 child->add_property ("val", to_string (periods_adjustment.get_value(), std::dec));
914 root->add_child_nocopy (*child);
916 child = new XMLNode ("priority");
917 child->add_property ("val", to_string (priority_adjustment.get_value(), std::dec));
918 root->add_child_nocopy (*child);
920 child = new XMLNode ("ports");
921 child->add_property ("val", to_string (ports_adjustment.get_value(), std::dec));
922 root->add_child_nocopy (*child);
924 child = new XMLNode ("inchannels");
925 child->add_property ("val", to_string (input_channels.get_value(), std::dec));
926 root->add_child_nocopy (*child);
928 child = new XMLNode ("outchannels");
929 child->add_property ("val", to_string (output_channels.get_value(), std::dec));
930 root->add_child_nocopy (*child);
932 child = new XMLNode ("inlatency");
933 child->add_property ("val", to_string (input_latency.get_value(), std::dec));
934 root->add_child_nocopy (*child);
936 child = new XMLNode ("outlatency");
937 child->add_property ("val", to_string (output_latency.get_value(), std::dec));
938 root->add_child_nocopy (*child);
940 child = new XMLNode ("realtime");
941 child->add_property ("val", to_string (realtime_button.get_active(), std::dec));
942 root->add_child_nocopy (*child);
944 child = new XMLNode ("nomemorylock");
945 child->add_property ("val", to_string (no_memory_lock_button.get_active(), std::dec));
946 root->add_child_nocopy (*child);
948 child = new XMLNode ("unlockmemory");
949 child->add_property ("val", to_string (unlock_memory_button.get_active(), std::dec));
950 root->add_child_nocopy (*child);
952 child = new XMLNode ("softmode");
953 child->add_property ("val", to_string (soft_mode_button.get_active(), std::dec));
954 root->add_child_nocopy (*child);
956 child = new XMLNode ("force16bit");
957 child->add_property ("val", to_string (force16bit_button.get_active(), std::dec));
958 root->add_child_nocopy (*child);
960 child = new XMLNode ("hwmonitor");
961 child->add_property ("val", to_string (hw_monitor_button.get_active(), std::dec));
962 root->add_child_nocopy (*child);
964 child = new XMLNode ("hwmeter");
965 child->add_property ("val", to_string (hw_meter_button.get_active(), std::dec));
966 root->add_child_nocopy (*child);
968 child = new XMLNode ("verbose");
969 child->add_property ("val", to_string (verbose_output_button.get_active(), std::dec));
970 root->add_child_nocopy (*child);
972 child = new XMLNode ("samplerate");
973 child->add_property ("val", sample_rate_combo.get_active_text());
974 root->add_child_nocopy (*child);
976 child = new XMLNode ("periodsize");
977 child->add_property ("val", period_size_combo.get_active_text());
978 root->add_child_nocopy (*child);
980 child = new XMLNode ("serverpath");
981 child->add_property ("val", serverpath_combo.get_active_text());
982 root->add_child_nocopy (*child);
984 child = new XMLNode ("driver");
985 child->add_property ("val", driver_combo.get_active_text());
986 root->add_child_nocopy (*child);
988 child = new XMLNode ("interface");
989 child->add_property ("val", interface_combo.get_active_text());
990 root->add_child_nocopy (*child);
992 child = new XMLNode ("timeout");
993 child->add_property ("val", timeout_combo.get_active_text());
994 root->add_child_nocopy (*child);
996 child = new XMLNode ("dither");
997 child->add_property ("val", dither_mode_combo.get_active_text());
998 root->add_child_nocopy (*child);
1000 child = new XMLNode ("audiomode");
1001 child->add_property ("val", audio_mode_combo.get_active_text());
1002 root->add_child_nocopy (*child);
1004 child = new XMLNode ("inputdevice");
1005 child->add_property ("val", input_device_combo.get_active_text());
1006 root->add_child_nocopy (*child);
1008 child = new XMLNode ("outputdevice");
1009 child->add_property ("val", output_device_combo.get_active_text());
1010 root->add_child_nocopy (*child);
1016 EngineControl::set_state (const XMLNode& root)
1019 XMLNodeConstIterator citer;
1023 bool using_dummy = false;
1028 if ( (child = root.child("driver"))){
1029 prop = child->property("val");
1030 if (prop && (prop->value() == "Dummy") ) {
1035 clist = root.children();
1037 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1041 prop = child->property ("val");
1043 if (!prop || prop->value().empty()) {
1044 if ( using_dummy && ( child->name() == "interface" || child->name() == "inputdevice" || child->name() == "outputdevice" ))
1046 error << string_compose (_("AudioSetup value for %1 is missing data"), child->name()) << endmsg;
1050 strval = prop->value();
1052 /* adjustments/spinners */
1054 if (child->name() == "periods") {
1055 val = atoi (strval);
1056 periods_adjustment.set_value(val);
1057 } else if (child->name() == "priority") {
1058 val = atoi (strval);
1059 priority_adjustment.set_value(val);
1060 } else if (child->name() == "ports") {
1061 val = atoi (strval);
1062 ports_adjustment.set_value(val);
1063 } else if (child->name() == "inchannels") {
1064 val = atoi (strval);
1065 input_channels.set_value(val);
1066 } else if (child->name() == "outchannels") {
1067 val = atoi (strval);
1068 output_channels.set_value(val);
1069 } else if (child->name() == "inlatency") {
1070 val = atoi (strval);
1071 input_latency.set_value(val);
1072 } else if (child->name() == "outlatency") {
1073 val = atoi (strval);
1074 output_latency.set_value(val);
1079 else if (child->name() == "realtime") {
1080 val = atoi (strval);
1081 realtime_button.set_active(val);
1082 } else if (child->name() == "nomemorylock") {
1083 val = atoi (strval);
1084 no_memory_lock_button.set_active(val);
1085 } else if (child->name() == "unlockmemory") {
1086 val = atoi (strval);
1087 unlock_memory_button.set_active(val);
1088 } else if (child->name() == "softmode") {
1089 val = atoi (strval);
1090 soft_mode_button.set_active(val);
1091 } else if (child->name() == "force16bit") {
1092 val = atoi (strval);
1093 force16bit_button.set_active(val);
1094 } else if (child->name() == "hwmonitor") {
1095 val = atoi (strval);
1096 hw_monitor_button.set_active(val);
1097 } else if (child->name() == "hwmeter") {
1098 val = atoi (strval);
1099 hw_meter_button.set_active(val);
1100 } else if (child->name() == "verbose") {
1101 val = atoi (strval);
1102 verbose_output_button.set_active(val);
1107 else if (child->name() == "samplerate") {
1108 sample_rate_combo.set_active_text(strval);
1109 } else if (child->name() == "periodsize") {
1110 period_size_combo.set_active_text(strval);
1111 } else if (child->name() == "serverpath") {
1112 /* do not allow us to use a server path that doesn't
1113 exist on this system. this handles cases where
1114 the user has an RC file listing a serverpath
1115 from some other machine.
1117 vector<string>::iterator x;
1118 for (x = server_strings.begin(); x != server_strings.end(); ++x) {
1123 if (x != server_strings.end()) {
1124 serverpath_combo.set_active_text (strval);
1126 warning << string_compose (_("configuration files contain a JACK server path that doesn't exist (%1)"),
1130 } else if (child->name() == "driver") {
1131 driver_combo.set_active_text(strval);
1132 } else if (child->name() == "interface") {
1133 interface_combo.set_active_text(strval);
1134 } else if (child->name() == "timeout") {
1135 timeout_combo.set_active_text(strval);
1136 } else if (child->name() == "dither") {
1137 dither_mode_combo.set_active_text(strval);
1138 } else if (child->name() == "audiomode") {
1139 audio_mode_combo.set_active_text(strval);
1140 } else if (child->name() == "inputdevice") {
1141 input_device_combo.set_active_text(strval);
1142 } else if (child->name() == "outputdevice") {
1143 output_device_combo.set_active_text(strval);