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;
557 for (vector<string>::iterator i = args.begin(); i != args.end(); ++i) {
558 jackdrc << (*i) << ' ';
569 EngineControl::realtime_changed ()
572 priority_spinner.set_sensitive (realtime_button.get_active());
577 EngineControl::enumerate_devices (const string& driver)
579 /* note: case matters for the map keys */
581 if (driver == "CoreAudio") {
583 devices[driver] = enumerate_coreaudio_devices ();
587 } else if (driver == "ALSA") {
588 devices[driver] = enumerate_alsa_devices ();
589 } else if (driver == "FFADO") {
590 devices[driver] = enumerate_ffado_devices ();
591 } else if (driver == "OSS") {
592 devices[driver] = enumerate_oss_devices ();
593 } else if (driver == "Dummy") {
594 devices[driver] = enumerate_dummy_devices ();
595 } else if (driver == "NetJACK") {
596 devices[driver] = enumerate_netjack_devices ();
605 getDeviceUIDFromID( AudioDeviceID id, char *name, size_t nsize)
607 UInt32 size = sizeof(CFStringRef);
609 OSStatus res = AudioDeviceGetProperty(id, 0, false,
610 kAudioDevicePropertyDeviceUID, &size, &UI);
612 CFStringGetCString(UI,name,nsize,CFStringGetSystemEncoding());
618 EngineControl::enumerate_coreaudio_devices ()
622 // Find out how many Core Audio devices are there, if any...
623 // (code snippet gently "borrowed" from St?hane Letz jackdmp;)
626 size_t outSize = sizeof(isWritable);
628 backend_devs.clear ();
630 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
631 &outSize, &isWritable);
633 // Calculate the number of device available...
634 int numCoreDevices = outSize / sizeof(AudioDeviceID);
635 // Make space for the devices we are about to get...
636 AudioDeviceID *coreDeviceIDs = new AudioDeviceID [numCoreDevices];
637 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
638 &outSize, (void *) coreDeviceIDs);
640 // Look for the CoreAudio device name...
641 char coreDeviceName[256];
644 for (int i = 0; i < numCoreDevices; i++) {
646 nameSize = sizeof (coreDeviceName);
648 /* enforce duplex devices only */
650 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
651 0, true, kAudioDevicePropertyStreams,
652 &outSize, &isWritable);
654 if (err != noErr || outSize == 0) {
658 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
659 0, false, kAudioDevicePropertyStreams,
660 &outSize, &isWritable);
662 if (err != noErr || outSize == 0) {
666 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
667 0, true, kAudioDevicePropertyDeviceName,
668 &outSize, &isWritable);
670 err = AudioDeviceGetProperty(coreDeviceIDs[i],
671 0, true, kAudioDevicePropertyDeviceName,
672 &nameSize, (void *) coreDeviceName);
674 char drivername[128];
676 // this returns the unique id for the device
677 // that must be used on the commandline for jack
679 if (getDeviceUIDFromID(coreDeviceIDs[i], drivername, sizeof (drivername)) == noErr) {
680 devs.push_back (coreDeviceName);
681 backend_devs.push_back (drivername);
687 delete [] coreDeviceIDs;
691 if (devs.size() == 0) {
692 MessageDialog msg (_("\
693 You do not have any audio devices capable of\n\
694 simultaneous playback and recording.\n\n\
695 Please use Applications -> Utilities -> Audio MIDI Setup\n\
696 to create an \"aggregrate\" device, or install a suitable\n\
697 audio interface.\n\n\
698 Please send email to Apple and ask them why new Macs\n\
699 have no duplex audio device.\n\n\
700 Alternatively, if you really want just playback\n\
701 or recording but not both, start JACK before running\n\
702 Ardour and choose the relevant device then."
704 true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
705 msg.set_title (_("No suitable audio devices"));
706 msg.set_position (Gtk::WIN_POS_MOUSE);
716 EngineControl::enumerate_alsa_devices ()
721 snd_ctl_card_info_t *info;
722 snd_pcm_info_t *pcminfo;
723 snd_ctl_card_info_alloca(&info);
724 snd_pcm_info_alloca(&pcminfo);
729 backend_devs.clear ();
731 while (snd_card_next (&cardnum) >= 0 && cardnum >= 0) {
734 devname += to_string (cardnum, std::dec);
736 if (snd_ctl_open (&handle, devname.c_str(), 0) >= 0 && snd_ctl_card_info (handle, info) >= 0) {
738 while (snd_ctl_pcm_next_device (handle, &device) >= 0 && device >= 0) {
740 bool have_playback = false;
741 bool have_capture = false;
743 /* find duplex devices only */
745 snd_pcm_info_set_device (pcminfo, device);
746 snd_pcm_info_set_subdevice (pcminfo, 0);
747 snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_CAPTURE);
749 if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
753 snd_pcm_info_set_device (pcminfo, device);
754 snd_pcm_info_set_subdevice (pcminfo, 0);
755 snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_PLAYBACK);
757 if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
758 have_playback = true;
761 if (have_capture && have_playback) {
762 devs.push_back (snd_pcm_info_get_name (pcminfo));
764 devname += to_string (device, std::dec);
765 backend_devs.push_back (devname);
769 snd_ctl_close(handle);
777 EngineControl::enumerate_ffado_devices ()
780 backend_devs.clear ();
785 EngineControl::enumerate_oss_devices ()
791 EngineControl::enumerate_dummy_devices ()
797 EngineControl::enumerate_netjack_devices ()
805 EngineControl::driver_changed ()
807 string driver = driver_combo.get_active_text();
808 string::size_type maxlen = 0;
812 enumerate_devices (driver);
814 vector<string>& strings = devices[driver];
816 if (strings.empty()) {
817 error << string_compose (_("No devices found for driver \"%1\""), driver) << endmsg;
821 for (vector<string>::iterator i = strings.begin(); i != strings.end(); ++i, ++n) {
822 if ((*i).length() > maxlen) {
823 maxlen = (*i).length();
828 set_popdown_strings (interface_combo, strings);
829 set_popdown_strings (input_device_combo, strings);
830 set_popdown_strings (output_device_combo, strings);
832 if (!strings.empty()) {
833 interface_combo.set_active_text (strings.front());
834 input_device_combo.set_active_text (strings.front());
835 output_device_combo.set_active_text (strings.front());
838 if (driver == "ALSA") {
839 soft_mode_button.set_sensitive (true);
840 force16bit_button.set_sensitive (true);
841 hw_monitor_button.set_sensitive (true);
842 hw_meter_button.set_sensitive (true);
843 monitor_button.set_sensitive (true);
845 soft_mode_button.set_sensitive (false);
846 force16bit_button.set_sensitive (false);
847 hw_monitor_button.set_sensitive (false);
848 hw_meter_button.set_sensitive (false);
849 monitor_button.set_sensitive (false);
854 EngineControl::get_rate ()
856 return atoi (sample_rate_combo.get_active_text ());
860 EngineControl::redisplay_latency ()
862 uint32_t rate = get_rate();
866 float periods = periods_adjustment.get_value();
868 float period_size = atof (period_size_combo.get_active_text());
871 snprintf (buf, sizeof(buf), "%.1fmsec", (periods * period_size) / (rate/1000.0));
873 latency_label.set_text (buf);
877 EngineControl::audio_mode_changed ()
879 Glib::ustring str = audio_mode_combo.get_active_text();
881 if (str == _("Playback/Recording on 1 Device")) {
882 input_device_combo.set_sensitive (false);
883 output_device_combo.set_sensitive (false);
884 } else if (str == _("Playback/Recording on 2 Devices")) {
885 input_device_combo.set_sensitive (true);
886 output_device_combo.set_sensitive (true);
887 } else if (str == _("Playback only")) {
888 output_device_combo.set_sensitive (true);
889 } else if (str == _("Recording only")) {
890 input_device_combo.set_sensitive (true);
894 static bool jack_server_filter(const string& str, void *arg)
896 return str == "jackd" || str == "jackdmp";
900 EngineControl::find_jack_servers (vector<string>& strings)
903 /* this magic lets us finds the path to the OSX bundle, and then
904 we infer JACK's location from there
907 char execpath[MAXPATHLEN+1];
908 uint32_t pathsz = sizeof (execpath);
910 _NSGetExecutablePath (execpath, &pathsz);
912 Glib::ustring path (Glib::path_get_dirname (execpath));
915 if (Glib::file_test (path, FILE_TEST_EXISTS)) {
916 strings.push_back (path);
919 if (getenv ("ARDOUR_WITH_JACK")) {
920 /* no other options - only use the JACK we supply */
921 if (strings.empty()) {
922 fatal << _("JACK appears to be missing from the Ardour bundle") << endmsg;
932 vector<string *> *jack_servers;
933 std::map<string,int> un;
935 path = getenv ("PATH");
937 jack_servers = scanner (path, jack_server_filter, 0, false, true);
939 vector<string *>::iterator iter;
941 for (iter = jack_servers->begin(); iter != jack_servers->end(); iter++) {
945 strings.push_back(p);
951 EngineControl::get_device_name (const string& driver, const string& human_readable)
953 vector<string>::iterator n;
954 vector<string>::iterator i;
956 if (backend_devs.empty()) {
957 return human_readable;
960 for (i = devices[driver].begin(), n = backend_devs.begin(); i != devices[driver].end(); ++i, ++n) {
961 if (human_readable == (*i)) {
966 if (i == devices[driver].end()) {
967 fatal << string_compose (_("programming error: %1"), "true hardware name for ID missing") << endmsg;
977 EngineControl::get_state ()
979 XMLNode* root = new XMLNode ("AudioSetup");
983 child = new XMLNode ("periods");
984 child->add_property ("val", to_string (periods_adjustment.get_value(), std::dec));
985 root->add_child_nocopy (*child);
987 child = new XMLNode ("priority");
988 child->add_property ("val", to_string (priority_adjustment.get_value(), std::dec));
989 root->add_child_nocopy (*child);
991 child = new XMLNode ("ports");
992 child->add_property ("val", to_string (ports_adjustment.get_value(), std::dec));
993 root->add_child_nocopy (*child);
995 child = new XMLNode ("inchannels");
996 child->add_property ("val", to_string (input_channels.get_value(), std::dec));
997 root->add_child_nocopy (*child);
999 child = new XMLNode ("outchannels");
1000 child->add_property ("val", to_string (output_channels.get_value(), std::dec));
1001 root->add_child_nocopy (*child);
1003 child = new XMLNode ("inlatency");
1004 child->add_property ("val", to_string (input_latency.get_value(), std::dec));
1005 root->add_child_nocopy (*child);
1007 child = new XMLNode ("outlatency");
1008 child->add_property ("val", to_string (output_latency.get_value(), std::dec));
1009 root->add_child_nocopy (*child);
1011 child = new XMLNode ("realtime");
1012 child->add_property ("val", to_string (realtime_button.get_active(), std::dec));
1013 root->add_child_nocopy (*child);
1015 child = new XMLNode ("nomemorylock");
1016 child->add_property ("val", to_string (no_memory_lock_button.get_active(), std::dec));
1017 root->add_child_nocopy (*child);
1019 child = new XMLNode ("unlockmemory");
1020 child->add_property ("val", to_string (unlock_memory_button.get_active(), std::dec));
1021 root->add_child_nocopy (*child);
1023 child = new XMLNode ("softmode");
1024 child->add_property ("val", to_string (soft_mode_button.get_active(), std::dec));
1025 root->add_child_nocopy (*child);
1027 child = new XMLNode ("force16bit");
1028 child->add_property ("val", to_string (force16bit_button.get_active(), std::dec));
1029 root->add_child_nocopy (*child);
1031 child = new XMLNode ("hwmonitor");
1032 child->add_property ("val", to_string (hw_monitor_button.get_active(), std::dec));
1033 root->add_child_nocopy (*child);
1035 child = new XMLNode ("hwmeter");
1036 child->add_property ("val", to_string (hw_meter_button.get_active(), std::dec));
1037 root->add_child_nocopy (*child);
1039 child = new XMLNode ("verbose");
1040 child->add_property ("val", to_string (verbose_output_button.get_active(), std::dec));
1041 root->add_child_nocopy (*child);
1043 child = new XMLNode ("samplerate");
1044 child->add_property ("val", sample_rate_combo.get_active_text());
1045 root->add_child_nocopy (*child);
1047 child = new XMLNode ("periodsize");
1048 child->add_property ("val", period_size_combo.get_active_text());
1049 root->add_child_nocopy (*child);
1051 child = new XMLNode ("serverpath");
1052 child->add_property ("val", serverpath_combo.get_active_text());
1053 root->add_child_nocopy (*child);
1055 child = new XMLNode ("driver");
1056 child->add_property ("val", driver_combo.get_active_text());
1057 root->add_child_nocopy (*child);
1059 child = new XMLNode ("interface");
1060 child->add_property ("val", interface_combo.get_active_text());
1061 root->add_child_nocopy (*child);
1063 child = new XMLNode ("timeout");
1064 child->add_property ("val", timeout_combo.get_active_text());
1065 root->add_child_nocopy (*child);
1067 child = new XMLNode ("dither");
1068 child->add_property ("val", dither_mode_combo.get_active_text());
1069 root->add_child_nocopy (*child);
1071 child = new XMLNode ("audiomode");
1072 child->add_property ("val", audio_mode_combo.get_active_text());
1073 root->add_child_nocopy (*child);
1075 child = new XMLNode ("inputdevice");
1076 child->add_property ("val", input_device_combo.get_active_text());
1077 root->add_child_nocopy (*child);
1079 child = new XMLNode ("outputdevice");
1080 child->add_property ("val", output_device_combo.get_active_text());
1081 root->add_child_nocopy (*child);
1087 EngineControl::set_state (const XMLNode& root)
1090 XMLNodeConstIterator citer;
1093 bool using_dummy = false;
1098 if ( (child = root.child ("driver"))){
1099 prop = child->property("val");
1100 if (prop && (prop->value() == "Dummy") ) {
1105 clist = root.children();
1107 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1111 prop = child->property ("val");
1113 if (!prop || prop->value().empty()) {
1115 if ( using_dummy && ( child->name() == "interface" || child->name() == "inputdevice" || child->name() == "outputdevice" ))
1117 error << string_compose (_("AudioSetup value for %1 is missing data"), child->name()) << endmsg;
1121 strval = prop->value();
1123 /* adjustments/spinners */
1125 if (child->name() == "periods") {
1126 val = atoi (strval);
1127 periods_adjustment.set_value(val);
1128 } else if (child->name() == "priority") {
1129 val = atoi (strval);
1130 priority_adjustment.set_value(val);
1131 } else if (child->name() == "ports") {
1132 val = atoi (strval);
1133 ports_adjustment.set_value(val);
1134 } else if (child->name() == "inchannels") {
1135 val = atoi (strval);
1136 input_channels.set_value(val);
1137 } else if (child->name() == "outchannels") {
1138 val = atoi (strval);
1139 output_channels.set_value(val);
1140 } else if (child->name() == "inlatency") {
1141 val = atoi (strval);
1142 input_latency.set_value(val);
1143 } else if (child->name() == "outlatency") {
1144 val = atoi (strval);
1145 output_latency.set_value(val);
1150 else if (child->name() == "realtime") {
1151 val = atoi (strval);
1152 realtime_button.set_active(val);
1153 } else if (child->name() == "nomemorylock") {
1154 val = atoi (strval);
1155 no_memory_lock_button.set_active(val);
1156 } else if (child->name() == "unlockmemory") {
1157 val = atoi (strval);
1158 unlock_memory_button.set_active(val);
1159 } else if (child->name() == "softmode") {
1160 val = atoi (strval);
1161 soft_mode_button.set_active(val);
1162 } else if (child->name() == "force16bit") {
1163 val = atoi (strval);
1164 force16bit_button.set_active(val);
1165 } else if (child->name() == "hwmonitor") {
1166 val = atoi (strval);
1167 hw_monitor_button.set_active(val);
1168 } else if (child->name() == "hwmeter") {
1169 val = atoi (strval);
1170 hw_meter_button.set_active(val);
1171 } else if (child->name() == "verbose") {
1172 val = atoi (strval);
1173 verbose_output_button.set_active(val);
1178 else if (child->name() == "samplerate") {
1179 sample_rate_combo.set_active_text(strval);
1180 } else if (child->name() == "periodsize") {
1181 period_size_combo.set_active_text(strval);
1182 } else if (child->name() == "serverpath") {
1183 /* do not allow us to use a server path that doesn't
1184 exist on this system. this handles cases where
1185 the user has an RC file listing a serverpath
1186 from some other machine.
1188 vector<string>::iterator x;
1189 for (x = server_strings.begin(); x != server_strings.end(); ++x) {
1194 if (x != server_strings.end()) {
1195 serverpath_combo.set_active_text (strval);
1197 warning << string_compose (_("configuration files contain a JACK server path that doesn't exist (%1)"),
1201 } else if (child->name() == "driver") {
1202 driver_combo.set_active_text(strval);
1203 } else if (child->name() == "interface") {
1204 interface_combo.set_active_text(strval);
1205 } else if (child->name() == "timeout") {
1206 timeout_combo.set_active_text(strval);
1207 } else if (child->name() == "dither") {
1208 dither_mode_combo.set_active_text(strval);
1209 } else if (child->name() == "audiomode") {
1210 audio_mode_combo.set_active_text(strval);
1211 } else if (child->name() == "inputdevice") {
1212 input_device_combo.set_active_text(strval);
1213 } else if (child->name() == "outputdevice") {
1214 output_device_combo.set_active_text(strval);