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")) {
432 /* do this until FFADO becomes the standard */
434 char* hack = getenv ("ARDOUR_FIREWIRE_DRIVER_NAME");
437 cmd.push_back (hack);
439 cmd.push_back ("freebob");
442 } else if ( driver == X_("Dummy")) {
444 cmd.push_back ("dummy");
447 /* driver arguments */
449 if (!using_coreaudio) {
450 str = audio_mode_combo.get_active_text();
452 if (str == _("Playback/Recording on 1 Device")) {
456 } else if (str == _("Playback/Recording on 2 Devices")) {
458 cmd.push_back ("-C");
459 cmd.push_back (get_device_name (driver, input_device_combo.get_active_text()));
460 cmd.push_back ("-P");
461 cmd.push_back (get_device_name (driver, output_device_combo.get_active_text()));
463 } else if (str == _("Playback only")) {
464 cmd.push_back ("-P");
465 } else if (str == _("Recording only")) {
466 cmd.push_back ("-C");
469 if (! using_dummy ) {
470 cmd.push_back ("-n");
471 cmd.push_back (to_string ((uint32_t) floor (periods_spinner.get_value()), std::dec));
475 cmd.push_back ("-r");
476 cmd.push_back (to_string (get_rate(), std::dec));
478 cmd.push_back ("-p");
479 cmd.push_back (period_size_combo.get_active_text());
483 if (audio_mode_combo.get_active_text() != _("Playback/Recording on 2 Devices")) {
484 cmd.push_back ("-d");
485 cmd.push_back (get_device_name (driver, interface_combo.get_active_text()));
488 if (hw_meter_button.get_active()) {
489 cmd.push_back ("-M");
492 if (hw_monitor_button.get_active()) {
493 cmd.push_back ("-H");
496 str = dither_mode_combo.get_active_text();
498 if (str == _("None")) {
499 } else if (str == _("Triangular")) {
500 cmd.push_back ("-z triangular");
501 } else if (str == _("Rectangular")) {
502 cmd.push_back ("-z rectangular");
503 } else if (str == _("Shaped")) {
504 cmd.push_back ("-z shaped");
507 if (force16bit_button.get_active()) {
508 cmd.push_back ("-S");
511 if (soft_mode_button.get_active()) {
512 cmd.push_back ("-s");
515 } else if (using_coreaudio) {
518 // note: older versions of the CoreAudio JACK backend use -n instead of -d here
519 cmd.push_back ("-d");
520 cmd.push_back (get_device_name (driver, interface_combo.get_active_text()));
523 } else if (using_oss) {
525 } else if (using_netjack) {
531 EngineControl::engine_running ()
533 jack_status_t status;
534 jack_client_t* c = jack_client_open ("ardourprobe", JackNoStartServer, &status);
537 jack_client_close (c);
544 EngineControl::setup_engine ()
547 std::string cwd = "/tmp";
549 build_command_line (args);
551 Glib::ustring jackdrc_path = Glib::get_home_dir();
552 jackdrc_path += "/.jackdrc";
554 ofstream jackdrc (jackdrc_path.c_str());
556 error << string_compose (_("cannot open JACK rc file %1 to store parameters"), jackdrc_path) << endmsg;
560 for (vector<string>::iterator i = args.begin(); i != args.end(); ++i) {
561 jackdrc << (*i) << ' ';
572 EngineControl::realtime_changed ()
575 priority_spinner.set_sensitive (realtime_button.get_active());
580 EngineControl::enumerate_devices ()
582 /* note: case matters for the map keys */
585 devices["CoreAudio"] = enumerate_coreaudio_devices ();
587 devices["ALSA"] = enumerate_alsa_devices ();
588 devices["FFADO"] = enumerate_ffado_devices ();
589 devices["OSS"] = enumerate_oss_devices ();
590 devices["Dummy"] = enumerate_dummy_devices ();
591 devices["NetJACK"] = enumerate_netjack_devices ();
597 getDeviceUIDFromID( AudioDeviceID id, char *name, size_t nsize)
599 UInt32 size = sizeof(CFStringRef);
601 OSStatus res = AudioDeviceGetProperty(id, 0, false,
602 kAudioDevicePropertyDeviceUID, &size, &UI);
604 CFStringGetCString(UI,name,nsize,CFStringGetSystemEncoding());
610 EngineControl::enumerate_coreaudio_devices ()
614 // Find out how many Core Audio devices are there, if any...
615 // (code snippet gently "borrowed" from St?hane Letz jackdmp;)
618 size_t outSize = sizeof(isWritable);
620 backend_devs.clear ();
622 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
623 &outSize, &isWritable);
625 // Calculate the number of device available...
626 int numCoreDevices = outSize / sizeof(AudioDeviceID);
627 // Make space for the devices we are about to get...
628 AudioDeviceID *coreDeviceIDs = new AudioDeviceID [numCoreDevices];
629 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
630 &outSize, (void *) coreDeviceIDs);
632 // Look for the CoreAudio device name...
633 char coreDeviceName[256];
636 for (int i = 0; i < numCoreDevices; i++) {
638 nameSize = sizeof (coreDeviceName);
640 /* enforce duplex devices only */
642 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
643 0, true, kAudioDevicePropertyStreams,
644 &outSize, &isWritable);
646 if (err != noErr || outSize == 0) {
650 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
651 0, false, kAudioDevicePropertyStreams,
652 &outSize, &isWritable);
654 if (err != noErr || outSize == 0) {
658 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
659 0, true, kAudioDevicePropertyDeviceName,
660 &outSize, &isWritable);
662 err = AudioDeviceGetProperty(coreDeviceIDs[i],
663 0, true, kAudioDevicePropertyDeviceName,
664 &nameSize, (void *) coreDeviceName);
666 char drivername[128];
668 // this returns the unique id for the device
669 // that must be used on the commandline for jack
671 if (getDeviceUIDFromID(coreDeviceIDs[i], drivername, sizeof (drivername)) == noErr) {
672 devs.push_back (coreDeviceName);
673 backend_devs.push_back (drivername);
679 delete [] coreDeviceIDs;
682 if (devs.size() == 0) {
683 MessageDialog msg (_("\
684 You do not have any audio devices capable of\n\
685 simultaneous playback and recording.\n\n\
686 Please use Applications -> Utilities -> Audio MIDI Setup\n\
687 to create an \"aggregrate\" device, or install a suitable\n\
688 audio interface.\n\n\
689 Please send email to Apple and ask them why new Macs\n\
690 have no duplex audio device.\n\n\
691 Alternatively, if you really want just playback\n\
692 or recording but not both, start JACK before running\n\
693 Ardour and choose the relevant device then."
695 true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
696 msg.set_title (_("No suitable audio devices"));
697 msg.set_position (Gtk::WIN_POS_MOUSE);
706 EngineControl::enumerate_alsa_devices ()
711 snd_ctl_card_info_t *info;
712 snd_pcm_info_t *pcminfo;
713 snd_ctl_card_info_alloca(&info);
714 snd_pcm_info_alloca(&pcminfo);
719 backend_devs.clear ();
721 while (snd_card_next (&cardnum) >= 0 && cardnum >= 0) {
724 devname += to_string (cardnum, std::dec);
726 if (snd_ctl_open (&handle, devname.c_str(), 0) >= 0 && snd_ctl_card_info (handle, info) >= 0) {
728 while (snd_ctl_pcm_next_device (handle, &device) >= 0 && device >= 0) {
730 bool have_playback = false;
731 bool have_capture = false;
733 /* find duplex devices only */
735 snd_pcm_info_set_device (pcminfo, device);
736 snd_pcm_info_set_subdevice (pcminfo, 0);
737 snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_CAPTURE);
739 if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
743 snd_pcm_info_set_device (pcminfo, device);
744 snd_pcm_info_set_subdevice (pcminfo, 0);
745 snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_PLAYBACK);
747 if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
748 have_playback = true;
751 if (have_capture && have_playback) {
752 devs.push_back (snd_pcm_info_get_name (pcminfo));
754 devname += to_string (device, std::dec);
755 backend_devs.push_back (devname);
759 snd_ctl_close(handle);
767 EngineControl::enumerate_ffado_devices ()
770 backend_devs.clear ();
774 EngineControl::enumerate_oss_devices ()
780 EngineControl::enumerate_dummy_devices ()
786 EngineControl::enumerate_netjack_devices ()
794 EngineControl::driver_changed ()
796 string driver = driver_combo.get_active_text();
797 vector<string>& strings = devices[driver];
798 string::size_type maxlen = 0;
802 for (vector<string>::iterator i = strings.begin(); i != strings.end(); ++i, ++n) {
803 if ((*i).length() > maxlen) {
804 maxlen = (*i).length();
809 set_popdown_strings (interface_combo, strings);
810 set_popdown_strings (input_device_combo, strings);
811 set_popdown_strings (output_device_combo, strings);
813 if (!strings.empty()) {
814 interface_combo.set_active_text (strings.front());
815 input_device_combo.set_active_text (strings.front());
816 output_device_combo.set_active_text (strings.front());
819 if (driver == "ALSA") {
820 soft_mode_button.set_sensitive (true);
821 force16bit_button.set_sensitive (true);
822 hw_monitor_button.set_sensitive (true);
823 hw_meter_button.set_sensitive (true);
824 monitor_button.set_sensitive (true);
826 soft_mode_button.set_sensitive (false);
827 force16bit_button.set_sensitive (false);
828 hw_monitor_button.set_sensitive (false);
829 hw_meter_button.set_sensitive (false);
830 monitor_button.set_sensitive (false);
835 EngineControl::get_rate ()
837 return atoi (sample_rate_combo.get_active_text ());
841 EngineControl::redisplay_latency ()
843 uint32_t rate = get_rate();
847 float periods = periods_adjustment.get_value();
849 float period_size = atof (period_size_combo.get_active_text());
852 snprintf (buf, sizeof(buf), "%.1fmsec", (periods * period_size) / (rate/1000.0));
854 latency_label.set_text (buf);
858 EngineControl::audio_mode_changed ()
860 Glib::ustring str = audio_mode_combo.get_active_text();
862 if (str == _("Playback/Recording on 1 Device")) {
863 input_device_combo.set_sensitive (false);
864 output_device_combo.set_sensitive (false);
865 } else if (str == _("Playback/Recording on 2 Devices")) {
866 input_device_combo.set_sensitive (true);
867 output_device_combo.set_sensitive (true);
868 } else if (str == _("Playback only")) {
869 output_device_combo.set_sensitive (true);
870 } else if (str == _("Recording only")) {
871 input_device_combo.set_sensitive (true);
875 static bool jack_server_filter(const string& str, void *arg)
877 return str == "jackd" || str == "jackdmp";
881 EngineControl::find_jack_servers (vector<string>& strings)
884 /* this magic lets us finds the path to the OSX bundle, and then
885 we infer JACK's location from there
888 char execpath[MAXPATHLEN+1];
889 uint32_t pathsz = sizeof (execpath);
891 _NSGetExecutablePath (execpath, &pathsz);
893 Glib::ustring path (Glib::path_get_dirname (execpath));
896 if (Glib::file_test (path, FILE_TEST_EXISTS)) {
897 strings.push_back (path);
900 if (getenv ("ARDOUR_WITH_JACK")) {
901 /* no other options - only use the JACK we supply */
902 if (strings.empty()) {
903 fatal << _("JACK appears to be missing from the Ardour bundle") << endmsg;
913 vector<string *> *jack_servers;
914 std::map<string,int> un;
916 path = getenv ("PATH");
918 jack_servers = scanner (path, jack_server_filter, 0, false, true);
920 vector<string *>::iterator iter;
922 for (iter = jack_servers->begin(); iter != jack_servers->end(); iter++) {
926 strings.push_back(p);
932 EngineControl::get_device_name (const string& driver, const string& human_readable)
934 vector<string>::iterator n;
935 vector<string>::iterator i;
937 if (backend_devs.empty()) {
938 return human_readable;
941 for (i = devices[driver].begin(), n = backend_devs.begin(); i != devices[driver].end(); ++i, ++n) {
942 if (human_readable == (*i)) {
947 if (i == devices[driver].end()) {
948 fatal << string_compose (_("programming error: %1"), "true hardware name for ID missing") << endmsg;
958 EngineControl::get_state ()
960 XMLNode* root = new XMLNode ("AudioSetup");
964 child = new XMLNode ("periods");
965 child->add_property ("val", to_string (periods_adjustment.get_value(), std::dec));
966 root->add_child_nocopy (*child);
968 child = new XMLNode ("priority");
969 child->add_property ("val", to_string (priority_adjustment.get_value(), std::dec));
970 root->add_child_nocopy (*child);
972 child = new XMLNode ("ports");
973 child->add_property ("val", to_string (ports_adjustment.get_value(), std::dec));
974 root->add_child_nocopy (*child);
976 child = new XMLNode ("inchannels");
977 child->add_property ("val", to_string (input_channels.get_value(), std::dec));
978 root->add_child_nocopy (*child);
980 child = new XMLNode ("outchannels");
981 child->add_property ("val", to_string (output_channels.get_value(), std::dec));
982 root->add_child_nocopy (*child);
984 child = new XMLNode ("inlatency");
985 child->add_property ("val", to_string (input_latency.get_value(), std::dec));
986 root->add_child_nocopy (*child);
988 child = new XMLNode ("outlatency");
989 child->add_property ("val", to_string (output_latency.get_value(), std::dec));
990 root->add_child_nocopy (*child);
992 child = new XMLNode ("realtime");
993 child->add_property ("val", to_string (realtime_button.get_active(), std::dec));
994 root->add_child_nocopy (*child);
996 child = new XMLNode ("nomemorylock");
997 child->add_property ("val", to_string (no_memory_lock_button.get_active(), std::dec));
998 root->add_child_nocopy (*child);
1000 child = new XMLNode ("unlockmemory");
1001 child->add_property ("val", to_string (unlock_memory_button.get_active(), std::dec));
1002 root->add_child_nocopy (*child);
1004 child = new XMLNode ("softmode");
1005 child->add_property ("val", to_string (soft_mode_button.get_active(), std::dec));
1006 root->add_child_nocopy (*child);
1008 child = new XMLNode ("force16bit");
1009 child->add_property ("val", to_string (force16bit_button.get_active(), std::dec));
1010 root->add_child_nocopy (*child);
1012 child = new XMLNode ("hwmonitor");
1013 child->add_property ("val", to_string (hw_monitor_button.get_active(), std::dec));
1014 root->add_child_nocopy (*child);
1016 child = new XMLNode ("hwmeter");
1017 child->add_property ("val", to_string (hw_meter_button.get_active(), std::dec));
1018 root->add_child_nocopy (*child);
1020 child = new XMLNode ("verbose");
1021 child->add_property ("val", to_string (verbose_output_button.get_active(), std::dec));
1022 root->add_child_nocopy (*child);
1024 child = new XMLNode ("samplerate");
1025 child->add_property ("val", sample_rate_combo.get_active_text());
1026 root->add_child_nocopy (*child);
1028 child = new XMLNode ("periodsize");
1029 child->add_property ("val", period_size_combo.get_active_text());
1030 root->add_child_nocopy (*child);
1032 child = new XMLNode ("serverpath");
1033 child->add_property ("val", serverpath_combo.get_active_text());
1034 root->add_child_nocopy (*child);
1036 child = new XMLNode ("driver");
1037 child->add_property ("val", driver_combo.get_active_text());
1038 root->add_child_nocopy (*child);
1040 child = new XMLNode ("interface");
1041 child->add_property ("val", interface_combo.get_active_text());
1042 root->add_child_nocopy (*child);
1044 child = new XMLNode ("timeout");
1045 child->add_property ("val", timeout_combo.get_active_text());
1046 root->add_child_nocopy (*child);
1048 child = new XMLNode ("dither");
1049 child->add_property ("val", dither_mode_combo.get_active_text());
1050 root->add_child_nocopy (*child);
1052 child = new XMLNode ("audiomode");
1053 child->add_property ("val", audio_mode_combo.get_active_text());
1054 root->add_child_nocopy (*child);
1056 child = new XMLNode ("inputdevice");
1057 child->add_property ("val", input_device_combo.get_active_text());
1058 root->add_child_nocopy (*child);
1060 child = new XMLNode ("outputdevice");
1061 child->add_property ("val", output_device_combo.get_active_text());
1062 root->add_child_nocopy (*child);
1068 EngineControl::set_state (const XMLNode& root)
1071 XMLNodeConstIterator citer;
1075 bool using_dummy = false;
1080 if ( (child = root.child("driver"))){
1081 prop = child->property("val");
1082 if (prop && (prop->value() == "Dummy") ) {
1087 clist = root.children();
1089 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1093 prop = child->property ("val");
1095 if (!prop || prop->value().empty()) {
1096 if ( using_dummy && ( child->name() == "interface" || child->name() == "inputdevice" || child->name() == "outputdevice" ))
1098 error << string_compose (_("AudioSetup value for %1 is missing data"), child->name()) << endmsg;
1102 strval = prop->value();
1104 /* adjustments/spinners */
1106 if (child->name() == "periods") {
1107 val = atoi (strval);
1108 periods_adjustment.set_value(val);
1109 } else if (child->name() == "priority") {
1110 val = atoi (strval);
1111 priority_adjustment.set_value(val);
1112 } else if (child->name() == "ports") {
1113 val = atoi (strval);
1114 ports_adjustment.set_value(val);
1115 } else if (child->name() == "inchannels") {
1116 val = atoi (strval);
1117 input_channels.set_value(val);
1118 } else if (child->name() == "outchannels") {
1119 val = atoi (strval);
1120 output_channels.set_value(val);
1121 } else if (child->name() == "inlatency") {
1122 val = atoi (strval);
1123 input_latency.set_value(val);
1124 } else if (child->name() == "outlatency") {
1125 val = atoi (strval);
1126 output_latency.set_value(val);
1131 else if (child->name() == "realtime") {
1132 val = atoi (strval);
1133 realtime_button.set_active(val);
1134 } else if (child->name() == "nomemorylock") {
1135 val = atoi (strval);
1136 no_memory_lock_button.set_active(val);
1137 } else if (child->name() == "unlockmemory") {
1138 val = atoi (strval);
1139 unlock_memory_button.set_active(val);
1140 } else if (child->name() == "softmode") {
1141 val = atoi (strval);
1142 soft_mode_button.set_active(val);
1143 } else if (child->name() == "force16bit") {
1144 val = atoi (strval);
1145 force16bit_button.set_active(val);
1146 } else if (child->name() == "hwmonitor") {
1147 val = atoi (strval);
1148 hw_monitor_button.set_active(val);
1149 } else if (child->name() == "hwmeter") {
1150 val = atoi (strval);
1151 hw_meter_button.set_active(val);
1152 } else if (child->name() == "verbose") {
1153 val = atoi (strval);
1154 verbose_output_button.set_active(val);
1159 else if (child->name() == "samplerate") {
1160 sample_rate_combo.set_active_text(strval);
1161 } else if (child->name() == "periodsize") {
1162 period_size_combo.set_active_text(strval);
1163 } else if (child->name() == "serverpath") {
1164 /* do not allow us to use a server path that doesn't
1165 exist on this system. this handles cases where
1166 the user has an RC file listing a serverpath
1167 from some other machine.
1169 vector<string>::iterator x;
1170 for (x = server_strings.begin(); x != server_strings.end(); ++x) {
1175 if (x != server_strings.end()) {
1176 serverpath_combo.set_active_text (strval);
1178 warning << string_compose (_("configuration files contain a JACK server path that doesn't exist (%1)"),
1182 } else if (child->name() == "driver") {
1183 driver_combo.set_active_text(strval);
1184 } else if (child->name() == "interface") {
1185 interface_combo.set_active_text(strval);
1186 } else if (child->name() == "timeout") {
1187 timeout_combo.set_active_text(strval);
1188 } else if (child->name() == "dither") {
1189 dither_mode_combo.set_active_text(strval);
1190 } else if (child->name() == "audiomode") {
1191 audio_mode_combo.set_active_text(strval);
1192 } else if (child->name() == "inputdevice") {
1193 input_device_combo.set_active_text(strval);
1194 } else if (child->name() == "outputdevice") {
1195 output_device_combo.set_active_text(strval);