7 #include <gtkmm/messagedialog.h>
11 #include <CoreAudio/CoreAudio.h>
12 #include <CoreFoundation/CFString.h>
13 #include <sys/param.h>
14 #include <mach-o/dyld.h>
16 #include <alsa/asoundlib.h>
19 #include <ardour/profile.h>
20 #include <jack/jack.h>
22 #include <gtkmm/stock.h>
23 #include <gtkmm2ext/utils.h>
25 #include <pbd/convert.h>
26 #include <pbd/error.h>
27 #include <pbd/pathscanner.h>
33 #include "engine_dialog.h"
38 using namespace Gtkmm2ext;
42 EngineControl::EngineControl ()
43 : periods_adjustment (2, 2, 16, 1, 2),
44 periods_spinner (periods_adjustment),
45 priority_adjustment (60, 10, 90, 1, 10),
46 priority_spinner (priority_adjustment),
47 ports_adjustment (128, 8, 1024, 1, 16),
48 ports_spinner (ports_adjustment),
49 realtime_button (_("Realtime")),
50 no_memory_lock_button (_("Do not lock memory")),
51 unlock_memory_button (_("Unlock memory")),
52 soft_mode_button (_("No zombies")),
53 monitor_button (_("Provide monitor ports")),
54 force16bit_button (_("Force 16 bit")),
55 hw_monitor_button (_("H/W monitoring")),
56 hw_meter_button (_("H/W metering")),
57 verbose_output_button (_("Verbose output")),
58 start_button (_("Start")),
59 stop_button (_("Stop")),
62 options_packer (4, 2),
66 options_packer (14, 2),
70 using namespace Notebook_Helpers;
72 vector<string> strings;
77 strings.push_back (_("8000Hz"));
78 strings.push_back (_("22050Hz"));
79 strings.push_back (_("44100Hz"));
80 strings.push_back (_("48000Hz"));
81 strings.push_back (_("88200Hz"));
82 strings.push_back (_("96000Hz"));
83 strings.push_back (_("192000Hz"));
84 set_popdown_strings (sample_rate_combo, strings);
85 sample_rate_combo.set_active_text ("48000Hz");
88 strings.push_back ("32");
89 strings.push_back ("64");
90 strings.push_back ("128");
91 strings.push_back ("256");
92 strings.push_back ("512");
93 strings.push_back ("1024");
94 strings.push_back ("2048");
95 strings.push_back ("4096");
96 strings.push_back ("8192");
97 set_popdown_strings (period_size_combo, strings);
98 period_size_combo.set_active_text ("1024");
101 strings.push_back (_("None"));
102 strings.push_back (_("Triangular"));
103 strings.push_back (_("Rectangular"));
104 strings.push_back (_("Shaped"));
105 set_popdown_strings (dither_mode_combo, strings);
106 dither_mode_combo.set_active_text (_("None"));
108 /* basic parameters */
110 basic_packer.set_spacings (6);
114 strings.push_back (X_("CoreAudio"));
116 strings.push_back (X_("ALSA"));
117 strings.push_back (X_("OSS"));
118 strings.push_back (X_("FFADO"));
120 strings.push_back (X_("NetJACK"));
121 strings.push_back (X_("Dummy"));
122 set_popdown_strings (driver_combo, strings);
123 driver_combo.set_active_text (strings.front());
125 driver_combo.signal_changed().connect (mem_fun (*this, &EngineControl::driver_changed));
129 strings.push_back (_("Playback/Recording on 1 Device"));
130 strings.push_back (_("Playback/Recording on 2 Devices"));
131 strings.push_back (_("Playback only"));
132 strings.push_back (_("Recording only"));
133 set_popdown_strings (audio_mode_combo, strings);
134 audio_mode_combo.set_active_text (strings.front());
136 audio_mode_combo.signal_changed().connect (mem_fun (*this, &EngineControl::audio_mode_changed));
137 audio_mode_changed ();
141 label = manage (new Label (_("Driver")));
142 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
143 basic_packer.attach (driver_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
146 label = manage (new Label (_("Interface")));
147 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
148 basic_packer.attach (interface_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
151 label = manage (new Label (_("Sample Rate")));
152 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
153 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
156 label = manage (new Label (_("Buffer size")));
157 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
158 basic_packer.attach (period_size_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
162 label = manage (new Label (_("Number of buffers")));
163 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
164 basic_packer.attach (periods_spinner, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
165 periods_spinner.set_value (2);
169 label = manage (new Label (_("Approximate latency")));
170 label->set_alignment (0.0, 0.5);
171 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
172 basic_packer.attach (latency_label, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
175 sample_rate_combo.signal_changed().connect (mem_fun (*this, &EngineControl::redisplay_latency));
176 periods_adjustment.signal_value_changed().connect (mem_fun (*this, &EngineControl::redisplay_latency));
177 period_size_combo.signal_changed().connect (mem_fun (*this, &EngineControl::redisplay_latency));
180 /* no audio mode with CoreAudio, its duplex or nuthin' */
183 label = manage (new Label (_("Audio Mode")));
184 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
185 basic_packer.attach (audio_mode_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
189 interface_combo.set_size_request (125, -1);
190 input_device_combo.set_size_request (125, -1);
191 output_device_combo.set_size_request (125, -1);
195 if (engine_running()) {
196 start_button.set_sensitive (false);
198 stop_button.set_sensitive (false);
201 start_button.signal_clicked().connect (mem_fun (*this, &EngineControl::start_engine));
202 stop_button.signal_clicked().connect (mem_fun (*this, &EngineControl::start_engine));
205 button_box.pack_start (start_button, false, false);
206 button_box.pack_start (stop_button, false, false);
208 // basic_packer.attach (button_box, 0, 2, 8, 9, FILL|EXPAND, (AttachOptions) 0);
212 options_packer.set_spacings (6);
215 options_packer.attach (realtime_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
218 realtime_button.signal_toggled().connect (mem_fun (*this, &EngineControl::realtime_changed));
222 label = manage (new Label (_("Realtime Priority")));
223 label->set_alignment (1.0, 0.5);
224 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
225 options_packer.attach (priority_spinner, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
227 priority_spinner.set_value (60);
229 options_packer.attach (no_memory_lock_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
231 options_packer.attach (unlock_memory_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
233 options_packer.attach (soft_mode_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
235 options_packer.attach (monitor_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
237 options_packer.attach (force16bit_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
239 options_packer.attach (hw_monitor_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
241 options_packer.attach (hw_meter_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
243 options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
246 options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
251 strings.push_back (_("Ignore"));
252 strings.push_back ("500 msec");
253 strings.push_back ("1 sec");
254 strings.push_back ("2 sec");
255 strings.push_back ("10 sec");
256 set_popdown_strings (timeout_combo, strings);
257 timeout_combo.set_active_text (strings.front ());
259 label = manage (new Label (_("Client timeout")));
260 label->set_alignment (1.0, 0.5);
261 options_packer.attach (timeout_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
262 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
265 label = manage (new Label (_("Number of ports")));
266 label->set_alignment (1.0, 0.5);
267 options_packer.attach (ports_spinner, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
268 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
272 label = manage (new Label (_("Dither")));
273 label->set_alignment (1.0, 0.5);
274 options_packer.attach (dither_mode_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
275 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
279 find_jack_servers (server_strings);
281 if (server_strings.empty()) {
282 fatal << _("No JACK server found anywhere on this system. Please install JACK and restart") << endmsg;
286 set_popdown_strings (serverpath_combo, server_strings);
287 serverpath_combo.set_active_text (server_strings.front());
289 if (server_strings.size() > 1) {
290 label = manage (new Label (_("Server:")));
291 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
292 label->set_alignment (0.0, 0.5);
293 options_packer.attach (serverpath_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
297 /* device settings */
299 device_packer.set_spacings (6);
303 label = manage (new Label (_("Input device")));
304 label->set_alignment (1.0, 0.5);
305 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
306 device_packer.attach (input_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
308 label = manage (new Label (_("Output device")));
309 label->set_alignment (1.0, 0.5);
310 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
311 device_packer.attach (output_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
314 label = manage (new Label (_("Input channels")));
315 label->set_alignment (1.0, 0.5);
316 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
317 device_packer.attach (input_channels, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
319 label = manage (new Label (_("Output channels")));
320 label->set_alignment (1.0, 0.5);
321 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
322 device_packer.attach (output_channels, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
324 label = manage (new Label (_("Hardware input latency (samples)")));
325 label->set_alignment (1.0, 0.5);
326 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
327 device_packer.attach (input_latency, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
329 label = manage (new Label (_("Hardware output latency (samples)")));
330 label->set_alignment (1.0, 0.5);
331 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
332 device_packer.attach (output_latency, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
335 basic_hbox.pack_start (basic_packer, false, false);
336 options_hbox.pack_start (options_packer, false, false);
338 device_packer.set_border_width (12);
339 options_packer.set_border_width (12);
340 basic_packer.set_border_width (12);
342 notebook.pages().push_back (TabElem (basic_hbox, _("Device")));
343 notebook.pages().push_back (TabElem (options_hbox, _("Options")));
344 notebook.pages().push_back (TabElem (device_packer, _("Advanced")));
345 notebook.set_border_width (12);
347 set_border_width (12);
348 pack_start (notebook);
351 EngineControl::~EngineControl ()
357 EngineControl::build_command_line (vector<string>& cmd)
361 bool using_oss = false;
362 bool using_alsa = false;
363 bool using_coreaudio = false;
364 bool using_netjack = false;
365 bool using_ffado = false;
366 bool using_dummy = false;
368 /* first, path to jackd */
370 cmd.push_back (serverpath_combo.get_active_text ());
372 /* now jackd arguments */
374 str = timeout_combo.get_active_text ();
375 if (str != _("Ignore")) {
379 msecs = (uint32_t) floor (secs * 1000.0);
380 cmd.push_back ("-t");
381 cmd.push_back (to_string (msecs, std::dec));
384 if (no_memory_lock_button.get_active()) {
385 cmd.push_back ("-m"); /* no munlock */
388 cmd.push_back ("-p"); /* port max */
389 cmd.push_back (to_string ((uint32_t) floor (ports_spinner.get_value()), std::dec));
391 if (realtime_button.get_active()) {
392 cmd.push_back ("-R");
393 cmd.push_back ("-P");
394 cmd.push_back (to_string ((uint32_t) floor (priority_spinner.get_value()), std::dec));
397 if (unlock_memory_button.get_active()) {
398 cmd.push_back ("-u");
401 if (verbose_output_button.get_active()) {
402 cmd.push_back ("-v");
405 /* now add fixed arguments (not user-selectable) */
407 cmd.push_back ("-T"); // temporary */
409 /* next the driver */
411 cmd.push_back ("-d");
413 driver = driver_combo.get_active_text ();
414 if (driver == X_("ALSA")) {
416 cmd.push_back ("alsa");
417 } else if (driver == X_("OSS")) {
419 cmd.push_back ("oss");
420 } else if (driver == X_("CoreAudio")) {
421 using_coreaudio = true;
422 cmd.push_back ("coreaudio");
423 } else if (driver == X_("NetJACK")) {
424 using_netjack = true;
425 cmd.push_back ("netjack");
426 } else if (driver == X_("FFADO")) {
429 /* do this until FFADO becomes the standard */
431 char* hack = getenv ("ARDOUR_FIREWIRE_DRIVER_NAME");
434 cmd.push_back (hack);
436 cmd.push_back ("freebob");
439 } else if ( driver == X_("Dummy")) {
441 cmd.push_back ("dummy");
444 /* driver arguments */
446 if (!using_coreaudio) {
447 str = audio_mode_combo.get_active_text();
449 if (str == _("Playback/Recording on 1 Device")) {
453 } else if (str == _("Playback/Recording on 2 Devices")) {
455 cmd.push_back ("-C");
456 cmd.push_back (get_device_name (driver, input_device_combo.get_active_text()));
457 cmd.push_back ("-P");
458 cmd.push_back (get_device_name (driver, output_device_combo.get_active_text()));
460 } else if (str == _("Playback only")) {
461 cmd.push_back ("-P");
462 } else if (str == _("Recording only")) {
463 cmd.push_back ("-C");
466 if (! using_dummy ) {
467 cmd.push_back ("-n");
468 cmd.push_back (to_string ((uint32_t) floor (periods_spinner.get_value()), std::dec));
472 cmd.push_back ("-r");
473 cmd.push_back (to_string (get_rate(), std::dec));
475 cmd.push_back ("-p");
476 cmd.push_back (period_size_combo.get_active_text());
480 if (audio_mode_combo.get_active_text() != _("Playback/Recording on 2 Devices")) {
481 cmd.push_back ("-d");
482 cmd.push_back (get_device_name (driver, interface_combo.get_active_text()));
485 if (hw_meter_button.get_active()) {
486 cmd.push_back ("-M");
489 if (hw_monitor_button.get_active()) {
490 cmd.push_back ("-H");
493 str = dither_mode_combo.get_active_text();
495 if (str == _("None")) {
496 } else if (str == _("Triangular")) {
497 cmd.push_back ("-z triangular");
498 } else if (str == _("Rectangular")) {
499 cmd.push_back ("-z rectangular");
500 } else if (str == _("Shaped")) {
501 cmd.push_back ("-z shaped");
504 if (force16bit_button.get_active()) {
505 cmd.push_back ("-S");
508 if (soft_mode_button.get_active()) {
509 cmd.push_back ("-s");
512 } else if (using_coreaudio) {
515 // note: older versions of the CoreAudio JACK backend use -n instead of -d here
516 cmd.push_back ("-d");
517 cmd.push_back (get_device_name (driver, interface_combo.get_active_text()));
520 } else if (using_oss) {
522 } else if (using_netjack) {
528 EngineControl::engine_running ()
530 jack_status_t status;
531 jack_client_t* c = jack_client_open ("ardourprobe", JackNoStartServer, &status);
534 jack_client_close (c);
541 EngineControl::setup_engine ()
544 std::string cwd = "/tmp";
546 build_command_line (args);
548 Glib::ustring jackdrc_path = Glib::get_home_dir();
549 jackdrc_path += "/.jackdrc";
551 ofstream jackdrc (jackdrc_path.c_str());
553 error << string_compose (_("cannot open JACK rc file %1 to store parameters"), jackdrc_path) << endmsg;
556 cerr << "JACK COMMAND: ";
557 for (vector<string>::iterator i = args.begin(); i != args.end(); ++i) {
559 jackdrc << (*i) << ' ';
571 EngineControl::realtime_changed ()
574 priority_spinner.set_sensitive (realtime_button.get_active());
579 EngineControl::enumerate_devices (const string& driver)
581 /* note: case matters for the map keys */
583 if (driver == "CoreAudio") {
585 devices[driver] = enumerate_coreaudio_devices ();
589 } else if (driver == "ALSA") {
590 devices[driver] = enumerate_alsa_devices ();
591 } else if (driver == "FFADO") {
592 devices[driver] = enumerate_ffado_devices ();
593 } else if (driver == "OSS") {
594 devices[driver] = enumerate_oss_devices ();
595 } else if (driver == "Dummy") {
596 devices[driver] = enumerate_dummy_devices ();
597 } else if (driver == "NetJACK") {
598 devices[driver] = enumerate_netjack_devices ();
607 getDeviceUIDFromID( AudioDeviceID id, char *name, size_t nsize)
609 UInt32 size = sizeof(CFStringRef);
611 OSStatus res = AudioDeviceGetProperty(id, 0, false,
612 kAudioDevicePropertyDeviceUID, &size, &UI);
614 CFStringGetCString(UI,name,nsize,CFStringGetSystemEncoding());
620 EngineControl::enumerate_coreaudio_devices ()
624 // Find out how many Core Audio devices are there, if any...
625 // (code snippet gently "borrowed" from St?hane Letz jackdmp;)
628 size_t outSize = sizeof(isWritable);
630 backend_devs.clear ();
632 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
633 &outSize, &isWritable);
635 // Calculate the number of device available...
636 int numCoreDevices = outSize / sizeof(AudioDeviceID);
637 // Make space for the devices we are about to get...
638 AudioDeviceID *coreDeviceIDs = new AudioDeviceID [numCoreDevices];
639 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
640 &outSize, (void *) coreDeviceIDs);
642 // Look for the CoreAudio device name...
643 char coreDeviceName[256];
646 for (int i = 0; i < numCoreDevices; i++) {
648 nameSize = sizeof (coreDeviceName);
650 /* enforce duplex devices only */
652 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
653 0, true, kAudioDevicePropertyStreams,
654 &outSize, &isWritable);
656 if (err != noErr || outSize == 0) {
660 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
661 0, false, kAudioDevicePropertyStreams,
662 &outSize, &isWritable);
664 if (err != noErr || outSize == 0) {
668 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
669 0, true, kAudioDevicePropertyDeviceName,
670 &outSize, &isWritable);
672 err = AudioDeviceGetProperty(coreDeviceIDs[i],
673 0, true, kAudioDevicePropertyDeviceName,
674 &nameSize, (void *) coreDeviceName);
676 char drivername[128];
678 // this returns the unique id for the device
679 // that must be used on the commandline for jack
681 if (getDeviceUIDFromID(coreDeviceIDs[i], drivername, sizeof (drivername)) == noErr) {
682 devs.push_back (coreDeviceName);
683 backend_devs.push_back (drivername);
689 delete [] coreDeviceIDs;
693 if (devs.size() == 0) {
694 MessageDialog msg (_("\
695 You do not have any audio devices capable of\n\
696 simultaneous playback and recording.\n\n\
697 Please use Applications -> Utilities -> Audio MIDI Setup\n\
698 to create an \"aggregrate\" device, or install a suitable\n\
699 audio interface.\n\n\
700 Please send email to Apple and ask them why new Macs\n\
701 have no duplex audio device.\n\n\
702 Alternatively, if you really want just playback\n\
703 or recording but not both, start JACK before running\n\
704 Ardour and choose the relevant device then."
706 true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
707 msg.set_title (_("No suitable audio devices"));
708 msg.set_position (Gtk::WIN_POS_MOUSE);
718 EngineControl::enumerate_alsa_devices ()
723 snd_ctl_card_info_t *info;
724 snd_pcm_info_t *pcminfo;
725 snd_ctl_card_info_alloca(&info);
726 snd_pcm_info_alloca(&pcminfo);
731 backend_devs.clear ();
733 while (snd_card_next (&cardnum) >= 0 && cardnum >= 0) {
736 devname += to_string (cardnum, std::dec);
738 if (snd_ctl_open (&handle, devname.c_str(), 0) >= 0 && snd_ctl_card_info (handle, info) >= 0) {
740 while (snd_ctl_pcm_next_device (handle, &device) >= 0 && device >= 0) {
742 bool have_playback = false;
743 bool have_capture = false;
745 /* find duplex devices only */
747 snd_pcm_info_set_device (pcminfo, device);
748 snd_pcm_info_set_subdevice (pcminfo, 0);
749 snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_CAPTURE);
751 if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
755 snd_pcm_info_set_device (pcminfo, device);
756 snd_pcm_info_set_subdevice (pcminfo, 0);
757 snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_PLAYBACK);
759 if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
760 have_playback = true;
763 if (have_capture && have_playback) {
764 devs.push_back (snd_pcm_info_get_name (pcminfo));
766 devname += to_string (device, std::dec);
767 backend_devs.push_back (devname);
771 snd_ctl_close(handle);
779 EngineControl::enumerate_ffado_devices ()
782 backend_devs.clear ();
787 EngineControl::enumerate_freebob_devices ()
793 EngineControl::enumerate_oss_devices ()
799 EngineControl::enumerate_dummy_devices ()
805 EngineControl::enumerate_netjack_devices ()
813 EngineControl::driver_changed ()
815 string driver = driver_combo.get_active_text();
816 string::size_type maxlen = 0;
820 enumerate_devices (driver);
822 vector<string>& strings = devices[driver];
824 if (strings.empty() && driver != "FFADO" && driver != "Dummy") {
825 error << string_compose (_("No devices found for driver \"%1\""), driver) << endmsg;
829 for (vector<string>::iterator i = strings.begin(); i != strings.end(); ++i, ++n) {
830 if ((*i).length() > maxlen) {
831 maxlen = (*i).length();
836 set_popdown_strings (interface_combo, strings);
837 set_popdown_strings (input_device_combo, strings);
838 set_popdown_strings (output_device_combo, strings);
840 if (!strings.empty()) {
841 interface_combo.set_active_text (strings.front());
842 input_device_combo.set_active_text (strings.front());
843 output_device_combo.set_active_text (strings.front());
846 if (driver == "ALSA") {
847 soft_mode_button.set_sensitive (true);
848 force16bit_button.set_sensitive (true);
849 hw_monitor_button.set_sensitive (true);
850 hw_meter_button.set_sensitive (true);
851 monitor_button.set_sensitive (true);
853 soft_mode_button.set_sensitive (false);
854 force16bit_button.set_sensitive (false);
855 hw_monitor_button.set_sensitive (false);
856 hw_meter_button.set_sensitive (false);
857 monitor_button.set_sensitive (false);
862 EngineControl::get_rate ()
864 return atoi (sample_rate_combo.get_active_text ());
868 EngineControl::redisplay_latency ()
870 uint32_t rate = get_rate();
874 float periods = periods_adjustment.get_value();
876 float period_size = atof (period_size_combo.get_active_text());
879 snprintf (buf, sizeof(buf), "%.1fmsec", (periods * period_size) / (rate/1000.0));
881 latency_label.set_text (buf);
885 EngineControl::audio_mode_changed ()
887 Glib::ustring str = audio_mode_combo.get_active_text();
889 if (str == _("Playback/Recording on 1 Device")) {
890 input_device_combo.set_sensitive (false);
891 output_device_combo.set_sensitive (false);
892 } else if (str == _("Playback/Recording on 2 Devices")) {
893 input_device_combo.set_sensitive (true);
894 output_device_combo.set_sensitive (true);
895 } else if (str == _("Playback only")) {
896 output_device_combo.set_sensitive (true);
897 } else if (str == _("Recording only")) {
898 input_device_combo.set_sensitive (true);
902 static bool jack_server_filter(const string& str, void *arg)
904 return str == "jackd" || str == "jackdmp";
908 EngineControl::find_jack_servers (vector<string>& strings)
911 /* this magic lets us finds the path to the OSX bundle, and then
912 we infer JACK's location from there
915 char execpath[MAXPATHLEN+1];
916 uint32_t pathsz = sizeof (execpath);
918 _NSGetExecutablePath (execpath, &pathsz);
920 string path (Glib::path_get_dirname (execpath));
923 if (Glib::file_test (path, FILE_TEST_EXISTS)) {
924 strings.push_back (path);
927 if (getenv ("ARDOUR_WITH_JACK")) {
928 /* no other options - only use the JACK we supply */
929 if (strings.empty()) {
930 fatal << _("JACK appears to be missing from the Ardour bundle") << endmsg;
940 vector<string *> *jack_servers;
941 std::map<string,int> un;
943 bool need_minimal_path = false;
950 need_minimal_path = true;
954 // many mac users don't have PATH set up to include
955 // likely installed locations of JACK
956 need_minimal_path = true;
959 if (need_minimal_path) {
961 path = "/usr/bin:/bin:/usr/local/bin:/opt/local/bin";
963 path += ":/usr/local/bin:/opt/local/bin";
968 // push it back into the environment so that auto-started JACK can find it.
969 // XXX why can't we just expect OS X users to have PATH set correctly? we can't ...
970 setenv ("PATH", path.c_str(), 1);
973 jack_servers = scanner (path, jack_server_filter, 0, false, true);
975 vector<string *>::iterator iter;
977 for (iter = jack_servers->begin(); iter != jack_servers->end(); iter++) {
981 strings.push_back(p);
988 EngineControl::get_device_name (const string& driver, const string& human_readable)
990 vector<string>::iterator n;
991 vector<string>::iterator i;
993 if (backend_devs.empty()) {
994 return human_readable;
997 for (i = devices[driver].begin(), n = backend_devs.begin(); i != devices[driver].end(); ++i, ++n) {
998 if (human_readable == (*i)) {
1003 if (i == devices[driver].end()) {
1004 fatal << string_compose (_("programming error: %1"), "true hardware name for ID missing") << endmsg;
1008 /* keep gcc happy */
1014 EngineControl::get_state ()
1016 XMLNode* root = new XMLNode ("AudioSetup");
1020 child = new XMLNode ("periods");
1021 child->add_property ("val", to_string (periods_adjustment.get_value(), std::dec));
1022 root->add_child_nocopy (*child);
1024 child = new XMLNode ("priority");
1025 child->add_property ("val", to_string (priority_adjustment.get_value(), std::dec));
1026 root->add_child_nocopy (*child);
1028 child = new XMLNode ("ports");
1029 child->add_property ("val", to_string (ports_adjustment.get_value(), std::dec));
1030 root->add_child_nocopy (*child);
1032 child = new XMLNode ("inchannels");
1033 child->add_property ("val", to_string (input_channels.get_value(), std::dec));
1034 root->add_child_nocopy (*child);
1036 child = new XMLNode ("outchannels");
1037 child->add_property ("val", to_string (output_channels.get_value(), std::dec));
1038 root->add_child_nocopy (*child);
1040 child = new XMLNode ("inlatency");
1041 child->add_property ("val", to_string (input_latency.get_value(), std::dec));
1042 root->add_child_nocopy (*child);
1044 child = new XMLNode ("outlatency");
1045 child->add_property ("val", to_string (output_latency.get_value(), std::dec));
1046 root->add_child_nocopy (*child);
1048 child = new XMLNode ("realtime");
1049 child->add_property ("val", to_string (realtime_button.get_active(), std::dec));
1050 root->add_child_nocopy (*child);
1052 child = new XMLNode ("nomemorylock");
1053 child->add_property ("val", to_string (no_memory_lock_button.get_active(), std::dec));
1054 root->add_child_nocopy (*child);
1056 child = new XMLNode ("unlockmemory");
1057 child->add_property ("val", to_string (unlock_memory_button.get_active(), std::dec));
1058 root->add_child_nocopy (*child);
1060 child = new XMLNode ("softmode");
1061 child->add_property ("val", to_string (soft_mode_button.get_active(), std::dec));
1062 root->add_child_nocopy (*child);
1064 child = new XMLNode ("force16bit");
1065 child->add_property ("val", to_string (force16bit_button.get_active(), std::dec));
1066 root->add_child_nocopy (*child);
1068 child = new XMLNode ("hwmonitor");
1069 child->add_property ("val", to_string (hw_monitor_button.get_active(), std::dec));
1070 root->add_child_nocopy (*child);
1072 child = new XMLNode ("hwmeter");
1073 child->add_property ("val", to_string (hw_meter_button.get_active(), std::dec));
1074 root->add_child_nocopy (*child);
1076 child = new XMLNode ("verbose");
1077 child->add_property ("val", to_string (verbose_output_button.get_active(), std::dec));
1078 root->add_child_nocopy (*child);
1080 child = new XMLNode ("samplerate");
1081 child->add_property ("val", sample_rate_combo.get_active_text());
1082 root->add_child_nocopy (*child);
1084 child = new XMLNode ("periodsize");
1085 child->add_property ("val", period_size_combo.get_active_text());
1086 root->add_child_nocopy (*child);
1088 child = new XMLNode ("serverpath");
1089 child->add_property ("val", serverpath_combo.get_active_text());
1090 root->add_child_nocopy (*child);
1092 child = new XMLNode ("driver");
1093 child->add_property ("val", driver_combo.get_active_text());
1094 root->add_child_nocopy (*child);
1096 child = new XMLNode ("interface");
1097 child->add_property ("val", interface_combo.get_active_text());
1098 root->add_child_nocopy (*child);
1100 child = new XMLNode ("timeout");
1101 child->add_property ("val", timeout_combo.get_active_text());
1102 root->add_child_nocopy (*child);
1104 child = new XMLNode ("dither");
1105 child->add_property ("val", dither_mode_combo.get_active_text());
1106 root->add_child_nocopy (*child);
1108 child = new XMLNode ("audiomode");
1109 child->add_property ("val", audio_mode_combo.get_active_text());
1110 root->add_child_nocopy (*child);
1112 child = new XMLNode ("inputdevice");
1113 child->add_property ("val", input_device_combo.get_active_text());
1114 root->add_child_nocopy (*child);
1116 child = new XMLNode ("outputdevice");
1117 child->add_property ("val", output_device_combo.get_active_text());
1118 root->add_child_nocopy (*child);
1124 EngineControl::set_state (const XMLNode& root)
1127 XMLNodeConstIterator citer;
1129 XMLProperty* prop = NULL;
1130 bool using_dummy = false;
1135 if ( (child = root.child ("driver"))){
1136 prop = child->property("val");
1137 if (prop && (prop->value() == "Dummy") ) {
1142 clist = root.children();
1144 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1145 if ( prop && (prop->value() == "FFADO" ))
1149 prop = child->property ("val");
1151 if (!prop || prop->value().empty()) {
1153 if ( using_dummy && ( child->name() == "interface" || child->name() == "inputdevice" || child->name() == "outputdevice" ))
1155 error << string_compose (_("AudioSetup value for %1 is missing data"), child->name()) << endmsg;
1159 strval = prop->value();
1161 /* adjustments/spinners */
1163 if (child->name() == "periods") {
1164 val = atoi (strval);
1165 periods_adjustment.set_value(val);
1166 } else if (child->name() == "priority") {
1167 val = atoi (strval);
1168 priority_adjustment.set_value(val);
1169 } else if (child->name() == "ports") {
1170 val = atoi (strval);
1171 ports_adjustment.set_value(val);
1172 } else if (child->name() == "inchannels") {
1173 val = atoi (strval);
1174 input_channels.set_value(val);
1175 } else if (child->name() == "outchannels") {
1176 val = atoi (strval);
1177 output_channels.set_value(val);
1178 } else if (child->name() == "inlatency") {
1179 val = atoi (strval);
1180 input_latency.set_value(val);
1181 } else if (child->name() == "outlatency") {
1182 val = atoi (strval);
1183 output_latency.set_value(val);
1188 else if (child->name() == "realtime") {
1189 val = atoi (strval);
1190 realtime_button.set_active(val);
1191 } else if (child->name() == "nomemorylock") {
1192 val = atoi (strval);
1193 no_memory_lock_button.set_active(val);
1194 } else if (child->name() == "unlockmemory") {
1195 val = atoi (strval);
1196 unlock_memory_button.set_active(val);
1197 } else if (child->name() == "softmode") {
1198 val = atoi (strval);
1199 soft_mode_button.set_active(val);
1200 } else if (child->name() == "force16bit") {
1201 val = atoi (strval);
1202 force16bit_button.set_active(val);
1203 } else if (child->name() == "hwmonitor") {
1204 val = atoi (strval);
1205 hw_monitor_button.set_active(val);
1206 } else if (child->name() == "hwmeter") {
1207 val = atoi (strval);
1208 hw_meter_button.set_active(val);
1209 } else if (child->name() == "verbose") {
1210 val = atoi (strval);
1211 verbose_output_button.set_active(val);
1216 else if (child->name() == "samplerate") {
1217 sample_rate_combo.set_active_text(strval);
1218 } else if (child->name() == "periodsize") {
1219 period_size_combo.set_active_text(strval);
1220 } else if (child->name() == "serverpath") {
1221 /* do not allow us to use a server path that doesn't
1222 exist on this system. this handles cases where
1223 the user has an RC file listing a serverpath
1224 from some other machine.
1226 vector<string>::iterator x;
1227 for (x = server_strings.begin(); x != server_strings.end(); ++x) {
1232 if (x != server_strings.end()) {
1233 serverpath_combo.set_active_text (strval);
1235 warning << string_compose (_("configuration files contain a JACK server path that doesn't exist (%1)"),
1239 } else if (child->name() == "driver") {
1240 driver_combo.set_active_text(strval);
1241 } else if (child->name() == "interface") {
1242 interface_combo.set_active_text(strval);
1243 } else if (child->name() == "timeout") {
1244 timeout_combo.set_active_text(strval);
1245 } else if (child->name() == "dither") {
1246 dither_mode_combo.set_active_text(strval);
1247 } else if (child->name() == "audiomode") {
1248 audio_mode_combo.set_active_text(strval);
1249 } else if (child->name() == "inputdevice") {
1250 input_device_combo.set_active_text(strval);
1251 } else if (child->name() == "outputdevice") {
1252 output_device_combo.set_active_text(strval);