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 /* figure out available devices and set up interface_combo */
127 enumerate_devices ();
128 driver_combo.signal_changed().connect (mem_fun (*this, &EngineControl::driver_changed));
132 strings.push_back (_("Playback/Recording on 1 Device"));
133 strings.push_back (_("Playback/Recording on 2 Devices"));
134 strings.push_back (_("Playback only"));
135 strings.push_back (_("Recording only"));
136 set_popdown_strings (audio_mode_combo, strings);
137 audio_mode_combo.set_active_text (strings.front());
139 audio_mode_combo.signal_changed().connect (mem_fun (*this, &EngineControl::audio_mode_changed));
140 audio_mode_changed ();
144 label = manage (new Label (_("Driver")));
145 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
146 basic_packer.attach (driver_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
149 label = manage (new Label (_("Interface")));
150 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
151 basic_packer.attach (interface_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
154 label = manage (new Label (_("Sample Rate")));
155 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
156 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
159 label = manage (new Label (_("Buffer size")));
160 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
161 basic_packer.attach (period_size_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
165 label = manage (new Label (_("Number of buffers")));
166 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
167 basic_packer.attach (periods_spinner, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
168 periods_spinner.set_value (2);
172 label = manage (new Label (_("Approximate latency")));
173 label->set_alignment (0.0, 0.5);
174 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
175 basic_packer.attach (latency_label, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
178 sample_rate_combo.signal_changed().connect (mem_fun (*this, &EngineControl::redisplay_latency));
179 periods_adjustment.signal_value_changed().connect (mem_fun (*this, &EngineControl::redisplay_latency));
180 period_size_combo.signal_changed().connect (mem_fun (*this, &EngineControl::redisplay_latency));
183 /* no audio mode with CoreAudio, its duplex or nuthin' */
186 label = manage (new Label (_("Audio Mode")));
187 basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
188 basic_packer.attach (audio_mode_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
192 interface_combo.set_size_request (125, -1);
193 input_device_combo.set_size_request (125, -1);
194 output_device_combo.set_size_request (125, -1);
198 if (engine_running()) {
199 start_button.set_sensitive (false);
201 stop_button.set_sensitive (false);
204 start_button.signal_clicked().connect (mem_fun (*this, &EngineControl::start_engine));
205 stop_button.signal_clicked().connect (mem_fun (*this, &EngineControl::start_engine));
208 button_box.pack_start (start_button, false, false);
209 button_box.pack_start (stop_button, false, false);
211 // basic_packer.attach (button_box, 0, 2, 8, 9, FILL|EXPAND, (AttachOptions) 0);
215 options_packer.set_spacings (6);
218 options_packer.attach (realtime_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
221 realtime_button.signal_toggled().connect (mem_fun (*this, &EngineControl::realtime_changed));
225 label = manage (new Label (_("Realtime Priority")));
226 label->set_alignment (1.0, 0.5);
227 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
228 options_packer.attach (priority_spinner, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
230 priority_spinner.set_value (60);
232 options_packer.attach (no_memory_lock_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
234 options_packer.attach (unlock_memory_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
236 options_packer.attach (soft_mode_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
238 options_packer.attach (monitor_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
240 options_packer.attach (force16bit_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
242 options_packer.attach (hw_monitor_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
244 options_packer.attach (hw_meter_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);
249 options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
254 strings.push_back (_("Ignore"));
255 strings.push_back ("500 msec");
256 strings.push_back ("1 sec");
257 strings.push_back ("2 sec");
258 strings.push_back ("10 sec");
259 set_popdown_strings (timeout_combo, strings);
260 timeout_combo.set_active_text (strings.front ());
262 label = manage (new Label (_("Client timeout")));
263 label->set_alignment (1.0, 0.5);
264 options_packer.attach (timeout_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
265 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
268 label = manage (new Label (_("Number of ports")));
269 label->set_alignment (1.0, 0.5);
270 options_packer.attach (ports_spinner, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
271 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
275 label = manage (new Label (_("Dither")));
276 label->set_alignment (1.0, 0.5);
277 options_packer.attach (dither_mode_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
278 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
282 find_jack_servers (server_strings);
284 if (server_strings.empty()) {
285 fatal << _("No JACK server found anywhere on this system. Please install JACK and restart") << endmsg;
289 set_popdown_strings (serverpath_combo, server_strings);
290 serverpath_combo.set_active_text (server_strings.front());
292 if (server_strings.size() > 1) {
293 label = manage (new Label (_("Server:")));
294 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
295 label->set_alignment (0.0, 0.5);
296 options_packer.attach (serverpath_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
300 /* device settings */
302 device_packer.set_spacings (6);
306 label = manage (new Label (_("Input device")));
307 label->set_alignment (1.0, 0.5);
308 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
309 device_packer.attach (input_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
311 label = manage (new Label (_("Output device")));
312 label->set_alignment (1.0, 0.5);
313 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
314 device_packer.attach (output_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
317 label = manage (new Label (_("Input channels")));
318 label->set_alignment (1.0, 0.5);
319 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
320 device_packer.attach (input_channels, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
322 label = manage (new Label (_("Output channels")));
323 label->set_alignment (1.0, 0.5);
324 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
325 device_packer.attach (output_channels, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
327 label = manage (new Label (_("Hardware input latency (samples)")));
328 label->set_alignment (1.0, 0.5);
329 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
330 device_packer.attach (input_latency, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
332 label = manage (new Label (_("Hardware output latency (samples)")));
333 label->set_alignment (1.0, 0.5);
334 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
335 device_packer.attach (output_latency, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
338 basic_hbox.pack_start (basic_packer, false, false);
339 options_hbox.pack_start (options_packer, false, false);
341 device_packer.set_border_width (12);
342 options_packer.set_border_width (12);
343 basic_packer.set_border_width (12);
345 notebook.pages().push_back (TabElem (basic_hbox, _("Device")));
346 notebook.pages().push_back (TabElem (options_hbox, _("Options")));
347 notebook.pages().push_back (TabElem (device_packer, _("Advanced")));
348 notebook.set_border_width (12);
350 set_border_width (12);
351 pack_start (notebook);
354 EngineControl::~EngineControl ()
360 EngineControl::build_command_line (vector<string>& cmd)
364 bool using_oss = false;
365 bool using_alsa = false;
366 bool using_coreaudio = false;
367 bool using_netjack = false;
368 bool using_ffado = false;
369 bool using_dummy = false;
371 /* first, path to jackd */
373 cmd.push_back (serverpath_combo.get_active_text ());
375 /* now jackd arguments */
377 str = timeout_combo.get_active_text ();
378 if (str != _("Ignore")) {
382 msecs = (uint32_t) floor (secs * 1000.0);
383 cmd.push_back ("-t");
384 cmd.push_back (to_string (msecs, std::dec));
387 if (no_memory_lock_button.get_active()) {
388 cmd.push_back ("-m"); /* no munlock */
391 cmd.push_back ("-p"); /* port max */
392 cmd.push_back (to_string ((uint32_t) floor (ports_spinner.get_value()), std::dec));
394 if (realtime_button.get_active()) {
395 cmd.push_back ("-R");
396 cmd.push_back ("-P");
397 cmd.push_back (to_string ((uint32_t) floor (priority_spinner.get_value()), std::dec));
400 if (unlock_memory_button.get_active()) {
401 cmd.push_back ("-u");
404 if (verbose_output_button.get_active()) {
405 cmd.push_back ("-v");
408 /* now add fixed arguments (not user-selectable) */
410 cmd.push_back ("-T"); // temporary */
412 /* next the driver */
414 cmd.push_back ("-d");
416 driver = driver_combo.get_active_text ();
417 if (driver == X_("ALSA")) {
419 cmd.push_back ("alsa");
420 } else if (driver == X_("OSS")) {
422 cmd.push_back ("oss");
423 } else if (driver == X_("CoreAudio")) {
424 using_coreaudio = true;
425 cmd.push_back ("coreaudio");
426 } else if (driver == X_("NetJACK")) {
427 using_netjack = true;
428 cmd.push_back ("netjack");
429 } else if (driver == X_("FFADO")) {
431 cmd.push_back ("ffado");
432 } else if ( driver == X_("Dummy")) {
434 cmd.push_back ("dummy");
437 /* driver arguments */
439 if (!using_coreaudio) {
440 str = audio_mode_combo.get_active_text();
442 if (str == _("Playback/Recording on 1 Device")) {
446 } else if (str == _("Playback/Recording on 2 Devices")) {
448 cmd.push_back ("-C");
449 cmd.push_back (get_device_name (driver, input_device_combo.get_active_text()));
450 cmd.push_back ("-P");
451 cmd.push_back (get_device_name (driver, output_device_combo.get_active_text()));
453 } else if (str == _("Playback only")) {
454 cmd.push_back ("-P");
455 } else if (str == _("Recording only")) {
456 cmd.push_back ("-C");
459 if (! using_dummy ) {
460 cmd.push_back ("-n");
461 cmd.push_back (to_string ((uint32_t) floor (periods_spinner.get_value()), std::dec));
465 cmd.push_back ("-r");
466 cmd.push_back (to_string (get_rate(), std::dec));
468 cmd.push_back ("-p");
469 cmd.push_back (period_size_combo.get_active_text());
473 if (audio_mode_combo.get_active_text() != _("Playback/Recording on 2 Devices")) {
474 cmd.push_back ("-d");
475 cmd.push_back (get_device_name (driver, interface_combo.get_active_text()));
478 if (hw_meter_button.get_active()) {
479 cmd.push_back ("-M");
482 if (hw_monitor_button.get_active()) {
483 cmd.push_back ("-H");
486 str = dither_mode_combo.get_active_text();
488 if (str == _("None")) {
489 } else if (str == _("Triangular")) {
490 cmd.push_back ("-z triangular");
491 } else if (str == _("Rectangular")) {
492 cmd.push_back ("-z rectangular");
493 } else if (str == _("Shaped")) {
494 cmd.push_back ("-z shaped");
497 if (force16bit_button.get_active()) {
498 cmd.push_back ("-S");
501 if (soft_mode_button.get_active()) {
502 cmd.push_back ("-s");
505 } else if (using_coreaudio) {
508 // note: older versions of the CoreAudio JACK backend use -n instead of -d here
509 cmd.push_back ("-d");
510 cmd.push_back (get_device_name (driver, interface_combo.get_active_text()));
513 } else if (using_oss) {
515 } else if (using_netjack) {
521 EngineControl::engine_running ()
523 jack_status_t status;
524 jack_client_t* c = jack_client_open ("ardourprobe", JackNoStartServer, &status);
527 jack_client_close (c);
534 EngineControl::setup_engine ()
537 std::string cwd = "/tmp";
539 build_command_line (args);
541 Glib::ustring jackdrc_path = Glib::get_home_dir();
542 jackdrc_path += "/.jackdrc";
544 ofstream jackdrc (jackdrc_path.c_str());
546 error << string_compose (_("cannot open JACK rc file %1 to store parameters"), jackdrc_path) << endmsg;
550 for (vector<string>::iterator i = args.begin(); i != args.end(); ++i) {
551 jackdrc << (*i) << ' ';
562 EngineControl::realtime_changed ()
565 priority_spinner.set_sensitive (realtime_button.get_active());
570 EngineControl::enumerate_devices ()
572 /* note: case matters for the map keys */
575 devices["CoreAudio"] = enumerate_coreaudio_devices ();
577 devices["ALSA"] = enumerate_alsa_devices ();
578 devices["FFADO"] = enumerate_ffado_devices ();
579 devices["OSS"] = enumerate_oss_devices ();
580 devices["Dummy"] = enumerate_dummy_devices ();
581 devices["NetJACK"] = enumerate_netjack_devices ();
587 getDeviceUIDFromID( AudioDeviceID id, char *name, size_t nsize)
589 UInt32 size = sizeof(CFStringRef);
591 OSStatus res = AudioDeviceGetProperty(id, 0, false,
592 kAudioDevicePropertyDeviceUID, &size, &UI);
594 CFStringGetCString(UI,name,nsize,CFStringGetSystemEncoding());
600 EngineControl::enumerate_coreaudio_devices ()
604 // Find out how many Core Audio devices are there, if any...
605 // (code snippet gently "borrowed" from St?hane Letz jackdmp;)
608 size_t outSize = sizeof(isWritable);
610 backend_devs.clear ();
612 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
613 &outSize, &isWritable);
615 // Calculate the number of device available...
616 int numCoreDevices = outSize / sizeof(AudioDeviceID);
617 // Make space for the devices we are about to get...
618 AudioDeviceID *coreDeviceIDs = new AudioDeviceID [numCoreDevices];
619 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
620 &outSize, (void *) coreDeviceIDs);
622 // Look for the CoreAudio device name...
623 char coreDeviceName[256];
626 for (int i = 0; i < numCoreDevices; i++) {
628 nameSize = sizeof (coreDeviceName);
630 /* enforce duplex devices only */
632 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
633 0, true, kAudioDevicePropertyStreams,
634 &outSize, &isWritable);
636 if (err != noErr || outSize == 0) {
640 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
641 0, false, kAudioDevicePropertyStreams,
642 &outSize, &isWritable);
644 if (err != noErr || outSize == 0) {
648 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
649 0, true, kAudioDevicePropertyDeviceName,
650 &outSize, &isWritable);
652 err = AudioDeviceGetProperty(coreDeviceIDs[i],
653 0, true, kAudioDevicePropertyDeviceName,
654 &nameSize, (void *) coreDeviceName);
656 char drivername[128];
658 // this returns the unique id for the device
659 // that must be used on the commandline for jack
661 if (getDeviceUIDFromID(coreDeviceIDs[i], drivername, sizeof (drivername)) == noErr) {
662 devs.push_back (coreDeviceName);
663 backend_devs.push_back (drivername);
669 delete [] coreDeviceIDs;
672 if (devs.size() == 0) {
673 MessageDialog msg (_("\
674 You do not have any audio devices capable of\n\
675 simultaneous playback and recording.\n\n\
676 Please use Applications -> Utilities -> Audio MIDI Setup\n\
677 to create an \"aggregrate\" device, or install a suitable\n\
678 audio interface.\n\n\
679 Please send email to Apple and ask them why new Macs\n\
680 have no duplex audio device.\n\n\
681 Alternatively, if you really want just playback\n\
682 or recording but not both, start JACK before running\n\
683 Ardour and choose the relevant device then."
685 true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
686 msg.set_title (_("No suitable audio devices"));
687 msg.set_position (Gtk::WIN_POS_MOUSE);
696 EngineControl::enumerate_alsa_devices ()
701 snd_ctl_card_info_t *info;
702 snd_pcm_info_t *pcminfo;
703 snd_ctl_card_info_alloca(&info);
704 snd_pcm_info_alloca(&pcminfo);
709 backend_devs.clear ();
711 while (snd_card_next (&cardnum) >= 0 && cardnum >= 0) {
714 devname += to_string (cardnum, std::dec);
716 if (snd_ctl_open (&handle, devname.c_str(), 0) >= 0 && snd_ctl_card_info (handle, info) >= 0) {
718 while (snd_ctl_pcm_next_device (handle, &device) >= 0 && device >= 0) {
720 bool have_playback = false;
721 bool have_capture = false;
723 /* find duplex devices only */
725 snd_pcm_info_set_device (pcminfo, device);
726 snd_pcm_info_set_subdevice (pcminfo, 0);
727 snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_CAPTURE);
729 if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
733 snd_pcm_info_set_device (pcminfo, device);
734 snd_pcm_info_set_subdevice (pcminfo, 0);
735 snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_PLAYBACK);
737 if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
738 have_playback = true;
741 if (have_capture && have_playback) {
742 devs.push_back (snd_pcm_info_get_name (pcminfo));
744 devname += to_string (device, std::dec);
745 backend_devs.push_back (devname);
749 snd_ctl_close(handle);
757 EngineControl::enumerate_ffado_devices ()
763 EngineControl::enumerate_freebob_devices ()
769 EngineControl::enumerate_oss_devices ()
775 EngineControl::enumerate_dummy_devices ()
781 EngineControl::enumerate_netjack_devices ()
789 EngineControl::driver_changed ()
791 string driver = driver_combo.get_active_text();
792 vector<string>& strings = devices[driver];
793 string::size_type maxlen = 0;
797 for (vector<string>::iterator i = strings.begin(); i != strings.end(); ++i, ++n) {
798 if ((*i).length() > maxlen) {
799 maxlen = (*i).length();
804 set_popdown_strings (interface_combo, strings);
805 set_popdown_strings (input_device_combo, strings);
806 set_popdown_strings (output_device_combo, strings);
808 if (!strings.empty()) {
809 interface_combo.set_active_text (strings.front());
810 input_device_combo.set_active_text (strings.front());
811 output_device_combo.set_active_text (strings.front());
814 if (driver == "ALSA") {
815 soft_mode_button.set_sensitive (true);
816 force16bit_button.set_sensitive (true);
817 hw_monitor_button.set_sensitive (true);
818 hw_meter_button.set_sensitive (true);
819 monitor_button.set_sensitive (true);
821 soft_mode_button.set_sensitive (false);
822 force16bit_button.set_sensitive (false);
823 hw_monitor_button.set_sensitive (false);
824 hw_meter_button.set_sensitive (false);
825 monitor_button.set_sensitive (false);
830 EngineControl::get_rate ()
832 return atoi (sample_rate_combo.get_active_text ());
836 EngineControl::redisplay_latency ()
838 uint32_t rate = get_rate();
842 float periods = periods_adjustment.get_value();
844 float period_size = atof (period_size_combo.get_active_text());
847 snprintf (buf, sizeof(buf), "%.1fmsec", (periods * period_size) / (rate/1000.0));
849 latency_label.set_text (buf);
853 EngineControl::audio_mode_changed ()
855 Glib::ustring str = audio_mode_combo.get_active_text();
857 if (str == _("Playback/Recording on 1 Device")) {
858 input_device_combo.set_sensitive (false);
859 output_device_combo.set_sensitive (false);
860 } else if (str == _("Playback/Recording on 2 Devices")) {
861 input_device_combo.set_sensitive (true);
862 output_device_combo.set_sensitive (true);
863 } else if (str == _("Playback only")) {
864 output_device_combo.set_sensitive (true);
865 } else if (str == _("Recording only")) {
866 input_device_combo.set_sensitive (true);
870 static bool jack_server_filter(const string& str, void *arg)
872 return str == "jackd" || str == "jackdmp";
876 EngineControl::find_jack_servers (vector<string>& strings)
879 /* this magic lets us finds the path to the OSX bundle, and then
880 we infer JACK's location from there
883 char execpath[MAXPATHLEN+1];
884 uint32_t pathsz = sizeof (execpath);
886 _NSGetExecutablePath (execpath, &pathsz);
888 Glib::ustring path (Glib::path_get_dirname (execpath));
891 if (Glib::file_test (path, FILE_TEST_EXISTS)) {
892 strings.push_back (path);
895 if (getenv ("ARDOUR_WITH_JACK")) {
896 /* no other options - only use the JACK we supply */
897 if (strings.empty()) {
898 fatal << _("JACK appears to be missing from the Ardour bundle") << endmsg;
908 vector<string *> *jack_servers;
909 std::map<string,int> un;
911 path = getenv ("PATH");
913 jack_servers = scanner (path, jack_server_filter, 0, false, true);
915 vector<string *>::iterator iter;
917 for (iter = jack_servers->begin(); iter != jack_servers->end(); iter++) {
921 strings.push_back(p);
928 EngineControl::get_device_name (const string& driver, const string& human_readable)
930 vector<string>::iterator n;
931 vector<string>::iterator i;
933 if (backend_devs.empty()) {
934 return human_readable;
937 for (i = devices[driver].begin(), n = backend_devs.begin(); i != devices[driver].end(); ++i, ++n) {
938 if (human_readable == (*i)) {
943 if (i == devices[driver].end()) {
944 fatal << string_compose (_("programming error: %1"), "true hardware name for ID missing") << endmsg;
954 EngineControl::get_state ()
956 XMLNode* root = new XMLNode ("AudioSetup");
960 child = new XMLNode ("periods");
961 child->add_property ("val", to_string (periods_adjustment.get_value(), std::dec));
962 root->add_child_nocopy (*child);
964 child = new XMLNode ("priority");
965 child->add_property ("val", to_string (priority_adjustment.get_value(), std::dec));
966 root->add_child_nocopy (*child);
968 child = new XMLNode ("ports");
969 child->add_property ("val", to_string (ports_adjustment.get_value(), std::dec));
970 root->add_child_nocopy (*child);
972 child = new XMLNode ("inchannels");
973 child->add_property ("val", to_string (input_channels.get_value(), std::dec));
974 root->add_child_nocopy (*child);
976 child = new XMLNode ("outchannels");
977 child->add_property ("val", to_string (output_channels.get_value(), std::dec));
978 root->add_child_nocopy (*child);
980 child = new XMLNode ("inlatency");
981 child->add_property ("val", to_string (input_latency.get_value(), std::dec));
982 root->add_child_nocopy (*child);
984 child = new XMLNode ("outlatency");
985 child->add_property ("val", to_string (output_latency.get_value(), std::dec));
986 root->add_child_nocopy (*child);
988 child = new XMLNode ("realtime");
989 child->add_property ("val", to_string (realtime_button.get_active(), std::dec));
990 root->add_child_nocopy (*child);
992 child = new XMLNode ("nomemorylock");
993 child->add_property ("val", to_string (no_memory_lock_button.get_active(), std::dec));
994 root->add_child_nocopy (*child);
996 child = new XMLNode ("unlockmemory");
997 child->add_property ("val", to_string (unlock_memory_button.get_active(), std::dec));
998 root->add_child_nocopy (*child);
1000 child = new XMLNode ("softmode");
1001 child->add_property ("val", to_string (soft_mode_button.get_active(), std::dec));
1002 root->add_child_nocopy (*child);
1004 child = new XMLNode ("force16bit");
1005 child->add_property ("val", to_string (force16bit_button.get_active(), std::dec));
1006 root->add_child_nocopy (*child);
1008 child = new XMLNode ("hwmonitor");
1009 child->add_property ("val", to_string (hw_monitor_button.get_active(), std::dec));
1010 root->add_child_nocopy (*child);
1012 child = new XMLNode ("hwmeter");
1013 child->add_property ("val", to_string (hw_meter_button.get_active(), std::dec));
1014 root->add_child_nocopy (*child);
1016 child = new XMLNode ("verbose");
1017 child->add_property ("val", to_string (verbose_output_button.get_active(), std::dec));
1018 root->add_child_nocopy (*child);
1020 child = new XMLNode ("samplerate");
1021 child->add_property ("val", sample_rate_combo.get_active_text());
1022 root->add_child_nocopy (*child);
1024 child = new XMLNode ("periodsize");
1025 child->add_property ("val", period_size_combo.get_active_text());
1026 root->add_child_nocopy (*child);
1028 child = new XMLNode ("serverpath");
1029 child->add_property ("val", serverpath_combo.get_active_text());
1030 root->add_child_nocopy (*child);
1032 child = new XMLNode ("driver");
1033 child->add_property ("val", driver_combo.get_active_text());
1034 root->add_child_nocopy (*child);
1036 child = new XMLNode ("interface");
1037 child->add_property ("val", interface_combo.get_active_text());
1038 root->add_child_nocopy (*child);
1040 child = new XMLNode ("timeout");
1041 child->add_property ("val", timeout_combo.get_active_text());
1042 root->add_child_nocopy (*child);
1044 child = new XMLNode ("dither");
1045 child->add_property ("val", dither_mode_combo.get_active_text());
1046 root->add_child_nocopy (*child);
1048 child = new XMLNode ("audiomode");
1049 child->add_property ("val", audio_mode_combo.get_active_text());
1050 root->add_child_nocopy (*child);
1052 child = new XMLNode ("inputdevice");
1053 child->add_property ("val", input_device_combo.get_active_text());
1054 root->add_child_nocopy (*child);
1056 child = new XMLNode ("outputdevice");
1057 child->add_property ("val", output_device_combo.get_active_text());
1058 root->add_child_nocopy (*child);
1064 EngineControl::set_state (const XMLNode& root)
1067 XMLNodeConstIterator citer;
1071 bool using_dummy = false;
1076 if ( (child = root.child("driver"))){
1077 prop = child->property("val");
1078 if (prop && (prop->value() == "Dummy") ) {
1083 clist = root.children();
1085 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1089 prop = child->property ("val");
1091 if (!prop || prop->value().empty()) {
1092 if ( using_dummy && ( child->name() == "interface" || child->name() == "inputdevice" || child->name() == "outputdevice" ))
1094 error << string_compose (_("AudioSetup value for %1 is missing data"), child->name()) << endmsg;
1098 strval = prop->value();
1100 /* adjustments/spinners */
1102 if (child->name() == "periods") {
1103 val = atoi (strval);
1104 periods_adjustment.set_value(val);
1105 } else if (child->name() == "priority") {
1106 val = atoi (strval);
1107 priority_adjustment.set_value(val);
1108 } else if (child->name() == "ports") {
1109 val = atoi (strval);
1110 ports_adjustment.set_value(val);
1111 } else if (child->name() == "inchannels") {
1112 val = atoi (strval);
1113 input_channels.set_value(val);
1114 } else if (child->name() == "outchannels") {
1115 val = atoi (strval);
1116 output_channels.set_value(val);
1117 } else if (child->name() == "inlatency") {
1118 val = atoi (strval);
1119 input_latency.set_value(val);
1120 } else if (child->name() == "outlatency") {
1121 val = atoi (strval);
1122 output_latency.set_value(val);
1127 else if (child->name() == "realtime") {
1128 val = atoi (strval);
1129 realtime_button.set_active(val);
1130 } else if (child->name() == "nomemorylock") {
1131 val = atoi (strval);
1132 no_memory_lock_button.set_active(val);
1133 } else if (child->name() == "unlockmemory") {
1134 val = atoi (strval);
1135 unlock_memory_button.set_active(val);
1136 } else if (child->name() == "softmode") {
1137 val = atoi (strval);
1138 soft_mode_button.set_active(val);
1139 } else if (child->name() == "force16bit") {
1140 val = atoi (strval);
1141 force16bit_button.set_active(val);
1142 } else if (child->name() == "hwmonitor") {
1143 val = atoi (strval);
1144 hw_monitor_button.set_active(val);
1145 } else if (child->name() == "hwmeter") {
1146 val = atoi (strval);
1147 hw_meter_button.set_active(val);
1148 } else if (child->name() == "verbose") {
1149 val = atoi (strval);
1150 verbose_output_button.set_active(val);
1155 else if (child->name() == "samplerate") {
1156 sample_rate_combo.set_active_text(strval);
1157 } else if (child->name() == "periodsize") {
1158 period_size_combo.set_active_text(strval);
1159 } else if (child->name() == "serverpath") {
1160 /* do not allow us to use a server path that doesn't
1161 exist on this system. this handles cases where
1162 the user has an RC file listing a serverpath
1163 from some other machine.
1165 vector<string>::iterator x;
1166 for (x = server_strings.begin(); x != server_strings.end(); ++x) {
1171 if (x != server_strings.end()) {
1172 serverpath_combo.set_active_text (strval);
1174 warning << string_compose (_("configuration files contain a JACK server path that doesn't exist (%1)"),
1178 } else if (child->name() == "driver") {
1179 driver_combo.set_active_text(strval);
1180 } else if (child->name() == "interface") {
1181 interface_combo.set_active_text(strval);
1182 } else if (child->name() == "timeout") {
1183 timeout_combo.set_active_text(strval);
1184 } else if (child->name() == "dither") {
1185 dither_mode_combo.set_active_text(strval);
1186 } else if (child->name() == "audiomode") {
1187 audio_mode_combo.set_active_text(strval);
1188 } else if (child->name() == "inputdevice") {
1189 input_device_combo.set_active_text(strval);
1190 } else if (child->name() == "outputdevice") {
1191 output_device_combo.set_active_text(strval);