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 ("firewire");
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 ()
760 backend_devs.clear ();
764 EngineControl::enumerate_oss_devices ()
770 EngineControl::enumerate_dummy_devices ()
776 EngineControl::enumerate_netjack_devices ()
784 EngineControl::driver_changed ()
786 string driver = driver_combo.get_active_text();
787 vector<string>& strings = devices[driver];
788 string::size_type maxlen = 0;
792 for (vector<string>::iterator i = strings.begin(); i != strings.end(); ++i, ++n) {
793 if ((*i).length() > maxlen) {
794 maxlen = (*i).length();
799 set_popdown_strings (interface_combo, strings);
800 set_popdown_strings (input_device_combo, strings);
801 set_popdown_strings (output_device_combo, strings);
803 if (!strings.empty()) {
804 interface_combo.set_active_text (strings.front());
805 input_device_combo.set_active_text (strings.front());
806 output_device_combo.set_active_text (strings.front());
809 if (driver == "ALSA") {
810 soft_mode_button.set_sensitive (true);
811 force16bit_button.set_sensitive (true);
812 hw_monitor_button.set_sensitive (true);
813 hw_meter_button.set_sensitive (true);
814 monitor_button.set_sensitive (true);
816 soft_mode_button.set_sensitive (false);
817 force16bit_button.set_sensitive (false);
818 hw_monitor_button.set_sensitive (false);
819 hw_meter_button.set_sensitive (false);
820 monitor_button.set_sensitive (false);
825 EngineControl::get_rate ()
827 return atoi (sample_rate_combo.get_active_text ());
831 EngineControl::redisplay_latency ()
833 uint32_t rate = get_rate();
837 float periods = periods_adjustment.get_value();
839 float period_size = atof (period_size_combo.get_active_text());
842 snprintf (buf, sizeof(buf), "%.1fmsec", (periods * period_size) / (rate/1000.0));
844 latency_label.set_text (buf);
848 EngineControl::audio_mode_changed ()
850 Glib::ustring str = audio_mode_combo.get_active_text();
852 if (str == _("Playback/Recording on 1 Device")) {
853 input_device_combo.set_sensitive (false);
854 output_device_combo.set_sensitive (false);
855 } else if (str == _("Playback/Recording on 2 Devices")) {
856 input_device_combo.set_sensitive (true);
857 output_device_combo.set_sensitive (true);
858 } else if (str == _("Playback only")) {
859 output_device_combo.set_sensitive (true);
860 } else if (str == _("Recording only")) {
861 input_device_combo.set_sensitive (true);
865 static bool jack_server_filter(const string& str, void *arg)
867 return str == "jackd" || str == "jackdmp";
871 EngineControl::find_jack_servers (vector<string>& strings)
874 /* this magic lets us finds the path to the OSX bundle, and then
875 we infer JACK's location from there
878 char execpath[MAXPATHLEN+1];
879 uint32_t pathsz = sizeof (execpath);
881 _NSGetExecutablePath (execpath, &pathsz);
883 Glib::ustring path (Glib::path_get_dirname (execpath));
886 if (Glib::file_test (path, FILE_TEST_EXISTS)) {
887 strings.push_back (path);
890 if (getenv ("ARDOUR_WITH_JACK")) {
891 /* no other options - only use the JACK we supply */
892 if (strings.empty()) {
893 fatal << _("JACK appears to be missing from the Ardour bundle") << endmsg;
903 vector<string *> *jack_servers;
904 std::map<string,int> un;
906 path = getenv ("PATH");
908 jack_servers = scanner (path, jack_server_filter, 0, false, true);
910 vector<string *>::iterator iter;
912 for (iter = jack_servers->begin(); iter != jack_servers->end(); iter++) {
916 strings.push_back(p);
922 EngineControl::get_device_name (const string& driver, const string& human_readable)
924 vector<string>::iterator n;
925 vector<string>::iterator i;
927 if (backend_devs.empty()) {
928 return human_readable;
931 for (i = devices[driver].begin(), n = backend_devs.begin(); i != devices[driver].end(); ++i, ++n) {
932 if (human_readable == (*i)) {
937 if (i == devices[driver].end()) {
938 fatal << string_compose (_("programming error: %1"), "true hardware name for ID missing") << endmsg;
948 EngineControl::get_state ()
950 XMLNode* root = new XMLNode ("AudioSetup");
954 child = new XMLNode ("periods");
955 child->add_property ("val", to_string (periods_adjustment.get_value(), std::dec));
956 root->add_child_nocopy (*child);
958 child = new XMLNode ("priority");
959 child->add_property ("val", to_string (priority_adjustment.get_value(), std::dec));
960 root->add_child_nocopy (*child);
962 child = new XMLNode ("ports");
963 child->add_property ("val", to_string (ports_adjustment.get_value(), std::dec));
964 root->add_child_nocopy (*child);
966 child = new XMLNode ("inchannels");
967 child->add_property ("val", to_string (input_channels.get_value(), std::dec));
968 root->add_child_nocopy (*child);
970 child = new XMLNode ("outchannels");
971 child->add_property ("val", to_string (output_channels.get_value(), std::dec));
972 root->add_child_nocopy (*child);
974 child = new XMLNode ("inlatency");
975 child->add_property ("val", to_string (input_latency.get_value(), std::dec));
976 root->add_child_nocopy (*child);
978 child = new XMLNode ("outlatency");
979 child->add_property ("val", to_string (output_latency.get_value(), std::dec));
980 root->add_child_nocopy (*child);
982 child = new XMLNode ("realtime");
983 child->add_property ("val", to_string (realtime_button.get_active(), std::dec));
984 root->add_child_nocopy (*child);
986 child = new XMLNode ("nomemorylock");
987 child->add_property ("val", to_string (no_memory_lock_button.get_active(), std::dec));
988 root->add_child_nocopy (*child);
990 child = new XMLNode ("unlockmemory");
991 child->add_property ("val", to_string (unlock_memory_button.get_active(), std::dec));
992 root->add_child_nocopy (*child);
994 child = new XMLNode ("softmode");
995 child->add_property ("val", to_string (soft_mode_button.get_active(), std::dec));
996 root->add_child_nocopy (*child);
998 child = new XMLNode ("force16bit");
999 child->add_property ("val", to_string (force16bit_button.get_active(), std::dec));
1000 root->add_child_nocopy (*child);
1002 child = new XMLNode ("hwmonitor");
1003 child->add_property ("val", to_string (hw_monitor_button.get_active(), std::dec));
1004 root->add_child_nocopy (*child);
1006 child = new XMLNode ("hwmeter");
1007 child->add_property ("val", to_string (hw_meter_button.get_active(), std::dec));
1008 root->add_child_nocopy (*child);
1010 child = new XMLNode ("verbose");
1011 child->add_property ("val", to_string (verbose_output_button.get_active(), std::dec));
1012 root->add_child_nocopy (*child);
1014 child = new XMLNode ("samplerate");
1015 child->add_property ("val", sample_rate_combo.get_active_text());
1016 root->add_child_nocopy (*child);
1018 child = new XMLNode ("periodsize");
1019 child->add_property ("val", period_size_combo.get_active_text());
1020 root->add_child_nocopy (*child);
1022 child = new XMLNode ("serverpath");
1023 child->add_property ("val", serverpath_combo.get_active_text());
1024 root->add_child_nocopy (*child);
1026 child = new XMLNode ("driver");
1027 child->add_property ("val", driver_combo.get_active_text());
1028 root->add_child_nocopy (*child);
1030 child = new XMLNode ("interface");
1031 child->add_property ("val", interface_combo.get_active_text());
1032 root->add_child_nocopy (*child);
1034 child = new XMLNode ("timeout");
1035 child->add_property ("val", timeout_combo.get_active_text());
1036 root->add_child_nocopy (*child);
1038 child = new XMLNode ("dither");
1039 child->add_property ("val", dither_mode_combo.get_active_text());
1040 root->add_child_nocopy (*child);
1042 child = new XMLNode ("audiomode");
1043 child->add_property ("val", audio_mode_combo.get_active_text());
1044 root->add_child_nocopy (*child);
1046 child = new XMLNode ("inputdevice");
1047 child->add_property ("val", input_device_combo.get_active_text());
1048 root->add_child_nocopy (*child);
1050 child = new XMLNode ("outputdevice");
1051 child->add_property ("val", output_device_combo.get_active_text());
1052 root->add_child_nocopy (*child);
1058 EngineControl::set_state (const XMLNode& root)
1061 XMLNodeConstIterator citer;
1065 bool using_dummy = false;
1070 if ( (child = root.child("driver"))){
1071 prop = child->property("val");
1072 if (prop && (prop->value() == "Dummy") ) {
1077 clist = root.children();
1079 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1083 prop = child->property ("val");
1085 if (!prop || prop->value().empty()) {
1086 if ( using_dummy && ( child->name() == "interface" || child->name() == "inputdevice" || child->name() == "outputdevice" ))
1088 error << string_compose (_("AudioSetup value for %1 is missing data"), child->name()) << endmsg;
1092 strval = prop->value();
1094 /* adjustments/spinners */
1096 if (child->name() == "periods") {
1097 val = atoi (strval);
1098 periods_adjustment.set_value(val);
1099 } else if (child->name() == "priority") {
1100 val = atoi (strval);
1101 priority_adjustment.set_value(val);
1102 } else if (child->name() == "ports") {
1103 val = atoi (strval);
1104 ports_adjustment.set_value(val);
1105 } else if (child->name() == "inchannels") {
1106 val = atoi (strval);
1107 input_channels.set_value(val);
1108 } else if (child->name() == "outchannels") {
1109 val = atoi (strval);
1110 output_channels.set_value(val);
1111 } else if (child->name() == "inlatency") {
1112 val = atoi (strval);
1113 input_latency.set_value(val);
1114 } else if (child->name() == "outlatency") {
1115 val = atoi (strval);
1116 output_latency.set_value(val);
1121 else if (child->name() == "realtime") {
1122 val = atoi (strval);
1123 realtime_button.set_active(val);
1124 } else if (child->name() == "nomemorylock") {
1125 val = atoi (strval);
1126 no_memory_lock_button.set_active(val);
1127 } else if (child->name() == "unlockmemory") {
1128 val = atoi (strval);
1129 unlock_memory_button.set_active(val);
1130 } else if (child->name() == "softmode") {
1131 val = atoi (strval);
1132 soft_mode_button.set_active(val);
1133 } else if (child->name() == "force16bit") {
1134 val = atoi (strval);
1135 force16bit_button.set_active(val);
1136 } else if (child->name() == "hwmonitor") {
1137 val = atoi (strval);
1138 hw_monitor_button.set_active(val);
1139 } else if (child->name() == "hwmeter") {
1140 val = atoi (strval);
1141 hw_meter_button.set_active(val);
1142 } else if (child->name() == "verbose") {
1143 val = atoi (strval);
1144 verbose_output_button.set_active(val);
1149 else if (child->name() == "samplerate") {
1150 sample_rate_combo.set_active_text(strval);
1151 } else if (child->name() == "periodsize") {
1152 period_size_combo.set_active_text(strval);
1153 } else if (child->name() == "serverpath") {
1154 /* do not allow us to use a server path that doesn't
1155 exist on this system. this handles cases where
1156 the user has an RC file listing a serverpath
1157 from some other machine.
1159 vector<string>::iterator x;
1160 for (x = server_strings.begin(); x != server_strings.end(); ++x) {
1165 if (x != server_strings.end()) {
1166 serverpath_combo.set_active_text (strval);
1168 warning << string_compose (_("configuration files contain a JACK server path that doesn't exist (%1)"),
1172 } else if (child->name() == "driver") {
1173 driver_combo.set_active_text(strval);
1174 } else if (child->name() == "interface") {
1175 interface_combo.set_active_text(strval);
1176 } else if (child->name() == "timeout") {
1177 timeout_combo.set_active_text(strval);
1178 } else if (child->name() == "dither") {
1179 dither_mode_combo.set_active_text(strval);
1180 } else if (child->name() == "audiomode") {
1181 audio_mode_combo.set_active_text(strval);
1182 } else if (child->name() == "inputdevice") {
1183 input_device_combo.set_active_text(strval);
1184 } else if (child->name() == "outputdevice") {
1185 output_device_combo.set_active_text(strval);