9 #include <CoreAudio/CoreAudio.h>
10 #include <CoreFoundation/CFString.h>
11 #include <sys/param.h>
12 #include <mach-o/dyld.h>
14 #include <alsa/asoundlib.h>
17 #include <ardour/profile.h>
18 #include <jack/jack.h>
20 #include <gtkmm/stock.h>
21 #include <gtkmm2ext/utils.h>
23 #include <pbd/convert.h>
24 #include <pbd/error.h>
30 #include "engine_dialog.h"
35 using namespace Gtkmm2ext;
39 EngineControl::EngineControl ()
40 : periods_adjustment (2, 2, 16, 1, 2),
41 periods_spinner (periods_adjustment),
42 priority_adjustment (60, 10, 90, 1, 10),
43 priority_spinner (priority_adjustment),
44 ports_adjustment (128, 8, 1024, 1, 16),
45 ports_spinner (ports_adjustment),
46 realtime_button (_("Realtime")),
47 no_memory_lock_button (_("Do not lock memory")),
48 unlock_memory_button (_("Unlock memory")),
49 soft_mode_button (_("No zombies")),
50 monitor_button (_("Provide monitor ports")),
51 force16bit_button (_("Force 16 bit")),
52 hw_monitor_button (_("H/W monitoring")),
53 hw_meter_button (_("H/W metering")),
54 verbose_output_button (_("Verbose output")),
55 start_button (_("Start")),
56 stop_button (_("Stop")),
59 options_packer (4, 2),
63 options_packer (14, 2),
67 using namespace Notebook_Helpers;
69 vector<string> strings;
74 strings.push_back (_("8000Hz"));
75 strings.push_back (_("22050Hz"));
76 strings.push_back (_("44100Hz"));
77 strings.push_back (_("48000Hz"));
78 strings.push_back (_("88200Hz"));
79 strings.push_back (_("96000Hz"));
80 strings.push_back (_("192000Hz"));
81 set_popdown_strings (sample_rate_combo, strings);
82 sample_rate_combo.set_active_text ("48000Hz");
85 strings.push_back ("32");
86 strings.push_back ("64");
87 strings.push_back ("128");
88 strings.push_back ("256");
89 strings.push_back ("512");
90 strings.push_back ("1024");
91 strings.push_back ("2048");
92 strings.push_back ("4096");
93 strings.push_back ("8192");
94 set_popdown_strings (period_size_combo, strings);
95 period_size_combo.set_active_text ("1024");
98 strings.push_back (_("None"));
99 strings.push_back (_("Triangular"));
100 strings.push_back (_("Rectangular"));
101 strings.push_back (_("Shaped"));
102 set_popdown_strings (dither_mode_combo, strings);
103 dither_mode_combo.set_active_text (_("None"));
105 /* basic parameters */
107 basic_packer.set_spacings (6);
111 strings.push_back (X_("CoreAudio"));
113 strings.push_back (X_("ALSA"));
114 strings.push_back (X_("OSS"));
115 strings.push_back (X_("FFADO"));
117 strings.push_back (X_("NetJACK"));
118 strings.push_back (X_("Dummy"));
119 set_popdown_strings (driver_combo, strings);
120 driver_combo.set_active_text (strings.front());
122 /* figure out available devices and set up interface_combo */
124 enumerate_devices ();
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);
191 if (engine_running()) {
192 start_button.set_sensitive (false);
194 stop_button.set_sensitive (false);
197 start_button.signal_clicked().connect (mem_fun (*this, &EngineControl::start_engine));
198 stop_button.signal_clicked().connect (mem_fun (*this, &EngineControl::start_engine));
201 button_box.pack_start (start_button, false, false);
202 button_box.pack_start (stop_button, false, false);
204 // basic_packer.attach (button_box, 0, 2, 8, 9, FILL|EXPAND, (AttachOptions) 0);
208 options_packer.set_spacings (6);
211 options_packer.attach (realtime_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
213 label = manage (new Label (_("Realtime Priority")));
214 label->set_alignment (1.0, 0.5);
215 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
216 options_packer.attach (priority_spinner, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
218 priority_spinner.set_value (60);
220 realtime_button.signal_toggled().connect (mem_fun (*this, &EngineControl::realtime_changed));
224 options_packer.attach (no_memory_lock_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
226 options_packer.attach (unlock_memory_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
228 options_packer.attach (soft_mode_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
230 options_packer.attach (monitor_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
232 options_packer.attach (force16bit_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
234 options_packer.attach (hw_monitor_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
236 options_packer.attach (hw_meter_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
238 options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
241 options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
246 strings.push_back (_("Ignore"));
247 strings.push_back ("500 msec");
248 strings.push_back ("1 sec");
249 strings.push_back ("2 sec");
250 strings.push_back ("10 sec");
251 set_popdown_strings (timeout_combo, strings);
252 timeout_combo.set_active_text (strings.front ());
254 label = manage (new Label (_("Client timeout")));
255 label->set_alignment (1.0, 0.5);
256 options_packer.attach (timeout_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
257 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
260 label = manage (new Label (_("Number of ports")));
261 label->set_alignment (1.0, 0.5);
262 options_packer.attach (ports_spinner, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
263 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
267 label = manage (new Label (_("Dither")));
268 label->set_alignment (1.0, 0.5);
269 options_packer.attach (dither_mode_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
270 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
274 find_jack_servers (server_strings);
276 if (server_strings.empty()) {
277 fatal << _("No JACK server found anywhere on this system. Please install JACK and restart") << endmsg;
281 set_popdown_strings (serverpath_combo, server_strings);
282 serverpath_combo.set_active_text (server_strings.front());
284 if (server_strings.size() > 1) {
285 label = manage (new Label (_("Server:")));
286 options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
287 label->set_alignment (0.0, 0.5);
288 options_packer.attach (serverpath_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
292 /* device settings */
294 device_packer.set_spacings (6);
298 label = manage (new Label (_("Input device")));
299 label->set_alignment (1.0, 0.5);
300 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
301 device_packer.attach (input_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
303 label = manage (new Label (_("Output 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 (output_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
309 label = manage (new Label (_("Input channels")));
310 label->set_alignment (1.0, 0.5);
311 device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
312 device_packer.attach (input_channels, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
314 label = manage (new Label (_("Output 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 (output_channels, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
319 label = manage (new Label (_("Hardware input latency (samples)")));
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 (input_latency, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
324 label = manage (new Label (_("Hardware output 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 (output_latency, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
330 basic_hbox.pack_start (basic_packer, false, false);
331 options_hbox.pack_start (options_packer, false, false);
333 device_packer.set_border_width (12);
334 options_packer.set_border_width (12);
335 basic_packer.set_border_width (12);
337 notebook.pages().push_back (TabElem (basic_hbox, _("Device")));
338 notebook.pages().push_back (TabElem (options_hbox, _("Options")));
339 notebook.pages().push_back (TabElem (device_packer, _("Advanced")));
340 notebook.set_border_width (12);
342 set_border_width (12);
343 pack_start (notebook);
346 EngineControl::~EngineControl ()
352 EngineControl::build_command_line (vector<string>& cmd)
356 bool using_oss = false;
357 bool using_alsa = false;
358 bool using_coreaudio = false;
359 bool using_netjack = false;
360 bool using_ffado = false;
362 /* first, path to jackd */
364 cmd.push_back (serverpath_combo.get_active_text ());
366 /* now jackd arguments */
368 str = timeout_combo.get_active_text ();
369 if (str != _("Ignore")) {
373 msecs = (uint32_t) floor (secs * 1000.0);
374 cmd.push_back ("-t");
375 cmd.push_back (to_string (msecs, std::dec));
378 if (no_memory_lock_button.get_active()) {
379 cmd.push_back ("-m"); /* no munlock */
382 cmd.push_back ("-p"); /* port max */
383 cmd.push_back (to_string ((uint32_t) floor (ports_spinner.get_value()), std::dec));
385 if (realtime_button.get_active()) {
386 cmd.push_back ("-R");
387 cmd.push_back ("-P");
388 cmd.push_back (to_string ((uint32_t) floor (priority_spinner.get_value()), std::dec));
391 if (unlock_memory_button.get_active()) {
392 cmd.push_back ("-u");
395 if (verbose_output_button.get_active()) {
396 cmd.push_back ("-v");
399 /* now add fixed arguments (not user-selectable) */
401 cmd.push_back ("-T"); // temporary */
403 /* next the driver */
405 cmd.push_back ("-d");
407 driver = driver_combo.get_active_text ();
408 if (driver == X_("ALSA")) {
410 cmd.push_back ("alsa");
411 } else if (driver == X_("OSS")) {
413 cmd.push_back ("oss");
414 } else if (driver == X_("CoreAudio")) {
415 using_coreaudio = true;
416 cmd.push_back ("coreaudio");
417 } else if (driver == X_("NetJACK")) {
418 using_netjack = true;
419 cmd.push_back ("netjack");
420 } else if (driver == X_("FFADO")) {
422 cmd.push_back ("ffado");
425 /* driver arguments */
427 if (!using_coreaudio) {
428 str = audio_mode_combo.get_active_text();
430 if (str == _("Playback/Recording on 1 Device")) {
434 } else if (str == _("Playback/Recording on 2 Devices")) {
436 cmd.push_back ("-C");
437 cmd.push_back (get_device_name (driver, input_device_combo.get_active_text()));
438 cmd.push_back ("-P");
439 cmd.push_back (get_device_name (driver, output_device_combo.get_active_text()));
441 } else if (str == _("Playback only")) {
442 cmd.push_back ("-P");
443 } else if (str == _("Recording only")) {
444 cmd.push_back ("-C");
447 cmd.push_back ("-n");
448 cmd.push_back (to_string ((uint32_t) floor (periods_spinner.get_value()), std::dec));
451 cmd.push_back ("-r");
452 cmd.push_back (to_string (get_rate(), std::dec));
454 cmd.push_back ("-p");
455 cmd.push_back (period_size_combo.get_active_text());
459 if (audio_mode_combo.get_active_text() != _("Playback/Recording on 2 Devices")) {
460 cmd.push_back ("-d");
461 cmd.push_back (get_device_name (driver, interface_combo.get_active_text()));
464 if (hw_meter_button.get_active()) {
465 cmd.push_back ("-M");
468 if (hw_monitor_button.get_active()) {
469 cmd.push_back ("-H");
472 str = dither_mode_combo.get_active_text();
474 if (str == _("None")) {
475 } else if (str == _("Triangular")) {
476 cmd.push_back ("-z triangular");
477 } else if (str == _("Rectangular")) {
478 cmd.push_back ("-z rectangular");
479 } else if (str == _("Shaped")) {
480 cmd.push_back ("-z shaped");
483 if (force16bit_button.get_active()) {
484 cmd.push_back ("-S");
487 if (soft_mode_button.get_active()) {
488 cmd.push_back ("-s");
491 } else if (using_coreaudio) {
494 cmd.push_back ("-n");
495 cmd.push_back (get_device_name (driver, interface_combo.get_active_text()));
498 } else if (using_oss) {
500 } else if (using_netjack) {
506 EngineControl::engine_running ()
508 jack_status_t status;
509 jack_client_t* c = jack_client_open ("ardourprobe", JackNoStartServer, &status);
512 jack_client_close (c);
519 EngineControl::start_engine ()
522 std::string cwd = "/tmp";
525 build_command_line (args);
527 Glib::ustring jackdrc_path = Glib::get_home_dir();
528 jackdrc_path += "/.jackdrc";
530 ofstream jackdrc (jackdrc_path.c_str());
532 error << string_compose (_("cannot open JACK rc file %1 to store parameters"), jackdrc_path) << endmsg;
536 cerr << "will execute ...\n";
537 for (vector<string>::iterator i = args.begin(); i != args.end(); ++i) {
538 jackdrc << (*i) << ' ';
550 spawn_async_with_pipes (cwd, args, SpawnFlags (0), sigc::slot<void>(), &engine_pid, &engine_stdin, &engine_stdout, &engine_stderr);
553 catch (Glib::Exception& err) {
554 error << _("could not start JACK server: ") << err.what() << endmsg;
563 EngineControl::stop_engine ()
569 EngineControl::realtime_changed ()
571 priority_spinner.set_sensitive (realtime_button.get_active());
575 EngineControl::enumerate_devices ()
577 /* note: case matters for the map keys */
580 devices["CoreAudio"] = enumerate_coreaudio_devices ();
582 devices["ALSA"] = enumerate_alsa_devices ();
583 devices["FFADO"] = enumerate_ffado_devices ();
584 devices["OSS"] = enumerate_oss_devices ();
585 devices["Dummy"] = enumerate_dummy_devices ();
586 devices["NetJACK"] = enumerate_netjack_devices ();
592 getDeviceUIDFromID( AudioDeviceID id, char *name, size_t nsize)
594 UInt32 size = sizeof(CFStringRef);
596 OSStatus res = AudioDeviceGetProperty(id, 0, false,
597 kAudioDevicePropertyDeviceUID, &size, &UI);
599 CFStringGetCString(UI,name,nsize,CFStringGetSystemEncoding());
605 EngineControl::enumerate_coreaudio_devices ()
609 // Find out how many Core Audio devices are there, if any...
610 // (code snippet gently "borrowed" from St?hane Letz jackdmp;)
613 size_t outSize = sizeof(isWritable);
615 backend_devs.clear ();
617 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
618 &outSize, &isWritable);
620 // Calculate the number of device available...
621 int numCoreDevices = outSize / sizeof(AudioDeviceID);
622 // Make space for the devices we are about to get...
623 AudioDeviceID *coreDeviceIDs = new AudioDeviceID [numCoreDevices];
624 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
625 &outSize, (void *) coreDeviceIDs);
627 // Look for the CoreAudio device name...
628 char coreDeviceName[256];
629 size_t nameSize = sizeof (coreDeviceName);
630 for (int i = 0; i < numCoreDevices; i++) {
631 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
632 0, true, kAudioDevicePropertyDeviceName,
633 &outSize, &isWritable);
635 err = AudioDeviceGetProperty(coreDeviceIDs[i],
636 0, true, kAudioDevicePropertyDeviceName,
637 &nameSize, (void *) coreDeviceName);
640 char drivername[128];
642 // this returns the unique id for the device
643 // that must be used on the commandline for jack
645 if (getDeviceUIDFromID(coreDeviceIDs[i], drivername, sizeof (drivername)) == noErr) {
646 devs.push_back (coreDeviceName);
647 backend_devs.push_back (drivername);
653 delete [] coreDeviceIDs;
660 EngineControl::enumerate_alsa_devices ()
665 snd_ctl_card_info_t *info;
666 snd_pcm_info_t *pcminfo;
667 snd_ctl_card_info_alloca(&info);
668 snd_pcm_info_alloca(&pcminfo);
673 backend_devs.clear ();
675 while (snd_card_next (&cardnum) >= 0 && cardnum >= 0) {
678 devname += to_string (cardnum, std::dec);
680 if (snd_ctl_open (&handle, devname.c_str(), 0) >= 0 && snd_ctl_card_info (handle, info) >= 0) {
682 while (snd_ctl_pcm_next_device (handle, &device) >= 0 && device >= 0) {
684 bool have_playback = false;
685 bool have_capture = false;
687 /* find duplex devices only */
689 snd_pcm_info_set_device (pcminfo, device);
690 snd_pcm_info_set_subdevice (pcminfo, 0);
691 snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_CAPTURE);
693 if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
697 snd_pcm_info_set_device (pcminfo, device);
698 snd_pcm_info_set_subdevice (pcminfo, 0);
699 snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_PLAYBACK);
701 if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
702 have_playback = true;
705 if (have_capture && have_playback) {
706 devs.push_back (snd_pcm_info_get_name (pcminfo));
708 devname += to_string (device, std::dec);
709 backend_devs.push_back (devname);
713 snd_ctl_close(handle);
721 EngineControl::enumerate_ffado_devices ()
727 EngineControl::enumerate_oss_devices ()
733 EngineControl::enumerate_dummy_devices ()
739 EngineControl::enumerate_netjack_devices ()
747 EngineControl::driver_changed ()
749 string driver = driver_combo.get_active_text();
750 vector<string>& strings = devices[driver];
751 string::size_type maxlen = 0;
755 for (vector<string>::iterator i = strings.begin(); i != strings.end(); ++i, ++n) {
756 if ((*i).length() > maxlen) {
757 maxlen = (*i).length();
762 set_popdown_strings (interface_combo, strings);
763 set_popdown_strings (input_device_combo, strings);
764 set_popdown_strings (output_device_combo, strings);
766 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button interface_combo
767 set_size_request_to_display_given_text (interface_combo, strings[maxindex].c_str(), 5+FUDGE, 5);
768 set_size_request_to_display_given_text (input_device_combo, strings[maxindex].c_str(), 5+FUDGE, 5);
769 set_size_request_to_display_given_text (output_device_combo, strings[maxindex].c_str(), 5+FUDGE, 5);
771 if (!strings.empty()) {
772 interface_combo.set_active_text (strings.front());
773 input_device_combo.set_active_text (strings.front());
774 output_device_combo.set_active_text (strings.front());
777 if (driver == "ALSA") {
778 soft_mode_button.set_sensitive (true);
779 force16bit_button.set_sensitive (true);
780 hw_monitor_button.set_sensitive (true);
781 hw_meter_button.set_sensitive (true);
782 monitor_button.set_sensitive (true);
784 soft_mode_button.set_sensitive (false);
785 force16bit_button.set_sensitive (false);
786 hw_monitor_button.set_sensitive (false);
787 hw_meter_button.set_sensitive (false);
788 monitor_button.set_sensitive (false);
793 EngineControl::get_rate ()
795 return atoi (sample_rate_combo.get_active_text ());
799 EngineControl::redisplay_latency ()
801 uint32_t rate = get_rate();
805 float periods = periods_adjustment.get_value();
807 float period_size = atof (period_size_combo.get_active_text());
810 snprintf (buf, sizeof(buf), "%.1fmsec", (periods * period_size) / (rate/1000.0));
812 latency_label.set_text (buf);
816 EngineControl::audio_mode_changed ()
818 Glib::ustring str = audio_mode_combo.get_active_text();
820 if (str == _("Playback/Recording on 1 Device")) {
821 input_device_combo.set_sensitive (false);
822 output_device_combo.set_sensitive (false);
823 } else if (str == _("Playback/Recording on 2 Devices")) {
824 input_device_combo.set_sensitive (true);
825 output_device_combo.set_sensitive (true);
826 } else if (str == _("Playback only")) {
827 output_device_combo.set_sensitive (true);
828 } else if (str == _("Recording only")) {
829 input_device_combo.set_sensitive (true);
834 EngineControl::find_jack_servers (vector<string>& strings)
837 /* this magic lets us finds the path to the OSX bundle, and then
838 we infer JACK's location from there
841 char execpath[MAXPATHLEN+1];
842 uint32_t pathsz = sizeof (execpath);
844 _NSGetExecutablePath (execpath, &pathsz);
846 cerr << " execpath = " << execpath << endl;
848 Glib::ustring path (Glib::path_get_dirname (execpath));
851 if (Glib::file_test (path, FILE_TEST_EXISTS)) {
852 strings.push_back (path);
853 cerr << "Found jack in " << path << endl;
856 if (ARDOUR::Profile->get_single_package()) {
857 /* no other options - only use the JACK we supply */
858 if (strings.empty()) {
859 // cerr << "OOPS!\n";
860 // fatal << _("JACK appears to be missing from the Ardour bundle") << endmsg;
867 if (Glib::file_test ("/usr/bin/jackd", FILE_TEST_EXISTS)) {
868 strings.push_back ("/usr/bin/jackd");
870 if (Glib::file_test ("/usr/local/bin/jackd", FILE_TEST_EXISTS)) {
871 strings.push_back ("/usr/local/bin/jackd");
873 if (Glib::file_test ("/opt/bin/jackd", FILE_TEST_EXISTS)) {
874 strings.push_back ("/opt/bin/jackd");
876 if (Glib::file_test ("/usr/bin/jackdmp", FILE_TEST_EXISTS)) {
877 strings.push_back ("/usr/bin/jackd");
879 if (Glib::file_test ("/usr/local/bin/jackdmp", FILE_TEST_EXISTS)) {
880 strings.push_back ("/usr/local/bin/jackd");
882 if (Glib::file_test ("/opt/bin/jackdmp", FILE_TEST_EXISTS)) {
883 strings.push_back ("/opt/bin/jackd");
889 EngineControl::get_device_name (const string& driver, const string& human_readable)
891 vector<string>::iterator n;
892 vector<string>::iterator i;
894 if (backend_devs.empty()) {
895 return human_readable;
898 for (i = devices[driver].begin(), n = backend_devs.begin(); i != devices[driver].end(); ++i, ++n) {
899 if (human_readable == (*i)) {
904 if (i == devices[driver].end()) {
905 fatal << string_compose (_("programming error: %1"), "true hardware name for ID missing") << endmsg;
915 EngineControl::get_state ()
917 XMLNode* root = new XMLNode ("AudioSetup");
921 child = new XMLNode ("periods");
922 child->add_property ("val", to_string (periods_adjustment.get_value(), std::dec));
923 root->add_child_nocopy (*child);
925 child = new XMLNode ("priority");
926 child->add_property ("val", to_string (priority_adjustment.get_value(), std::dec));
927 root->add_child_nocopy (*child);
929 child = new XMLNode ("ports");
930 child->add_property ("val", to_string (ports_adjustment.get_value(), std::dec));
931 root->add_child_nocopy (*child);
933 child = new XMLNode ("inchannels");
934 child->add_property ("val", to_string (input_channels.get_value(), std::dec));
935 root->add_child_nocopy (*child);
937 child = new XMLNode ("outchannels");
938 child->add_property ("val", to_string (output_channels.get_value(), std::dec));
939 root->add_child_nocopy (*child);
941 child = new XMLNode ("inlatency");
942 child->add_property ("val", to_string (input_latency.get_value(), std::dec));
943 root->add_child_nocopy (*child);
945 child = new XMLNode ("outlatency");
946 child->add_property ("val", to_string (output_latency.get_value(), std::dec));
947 root->add_child_nocopy (*child);
949 child = new XMLNode ("realtime");
950 child->add_property ("val", to_string (realtime_button.get_active(), std::dec));
951 root->add_child_nocopy (*child);
953 child = new XMLNode ("nomemorylock");
954 child->add_property ("val", to_string (no_memory_lock_button.get_active(), std::dec));
955 root->add_child_nocopy (*child);
957 child = new XMLNode ("unlockmemory");
958 child->add_property ("val", to_string (unlock_memory_button.get_active(), std::dec));
959 root->add_child_nocopy (*child);
961 child = new XMLNode ("softmode");
962 child->add_property ("val", to_string (soft_mode_button.get_active(), std::dec));
963 root->add_child_nocopy (*child);
965 child = new XMLNode ("force16bit");
966 child->add_property ("val", to_string (force16bit_button.get_active(), std::dec));
967 root->add_child_nocopy (*child);
969 child = new XMLNode ("hwmonitor");
970 child->add_property ("val", to_string (hw_monitor_button.get_active(), std::dec));
971 root->add_child_nocopy (*child);
973 child = new XMLNode ("hwmeter");
974 child->add_property ("val", to_string (hw_meter_button.get_active(), std::dec));
975 root->add_child_nocopy (*child);
977 child = new XMLNode ("verbose");
978 child->add_property ("val", to_string (verbose_output_button.get_active(), std::dec));
979 root->add_child_nocopy (*child);
981 child = new XMLNode ("samplerate");
982 child->add_property ("val", sample_rate_combo.get_active_text());
983 root->add_child_nocopy (*child);
985 child = new XMLNode ("periodsize");
986 child->add_property ("val", period_size_combo.get_active_text());
987 root->add_child_nocopy (*child);
989 child = new XMLNode ("serverpath");
990 child->add_property ("val", serverpath_combo.get_active_text());
991 root->add_child_nocopy (*child);
993 child = new XMLNode ("driver");
994 child->add_property ("val", driver_combo.get_active_text());
995 root->add_child_nocopy (*child);
997 child = new XMLNode ("interface");
998 child->add_property ("val", interface_combo.get_active_text());
999 root->add_child_nocopy (*child);
1001 child = new XMLNode ("timeout");
1002 child->add_property ("val", timeout_combo.get_active_text());
1003 root->add_child_nocopy (*child);
1005 child = new XMLNode ("dither");
1006 child->add_property ("val", dither_mode_combo.get_active_text());
1007 root->add_child_nocopy (*child);
1009 child = new XMLNode ("audiomode");
1010 child->add_property ("val", audio_mode_combo.get_active_text());
1011 root->add_child_nocopy (*child);
1013 child = new XMLNode ("inputdevice");
1014 child->add_property ("val", input_device_combo.get_active_text());
1015 root->add_child_nocopy (*child);
1017 child = new XMLNode ("outputdevice");
1018 child->add_property ("val", output_device_combo.get_active_text());
1019 root->add_child_nocopy (*child);
1025 EngineControl::set_state (const XMLNode& root)
1028 XMLNodeConstIterator citer;
1035 clist = root.children();
1037 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1041 prop = child->property ("val");
1043 if (!prop || prop->value().empty()) {
1044 error << string_compose (_("AudioSetup value for %1 is missing data"), child->name()) << endmsg;
1048 strval = prop->value();
1050 /* adjustments/spinners */
1052 if (child->name() == "periods") {
1053 val = atoi (strval);
1054 periods_adjustment.set_value(val);
1055 } else if (child->name() == "priority") {
1056 val = atoi (strval);
1057 priority_adjustment.set_value(val);
1058 } else if (child->name() == "ports") {
1059 val = atoi (strval);
1060 ports_adjustment.set_value(val);
1061 } else if (child->name() == "inchannels") {
1062 val = atoi (strval);
1063 input_channels.set_value(val);
1064 } else if (child->name() == "outchannels") {
1065 val = atoi (strval);
1066 output_channels.set_value(val);
1067 } else if (child->name() == "inlatency") {
1068 val = atoi (strval);
1069 input_latency.set_value(val);
1070 } else if (child->name() == "outlatency") {
1071 val = atoi (strval);
1072 output_latency.set_value(val);
1077 else if (child->name() == "realtime") {
1078 val = atoi (strval);
1079 realtime_button.set_active(val);
1080 } else if (child->name() == "nomemorylock") {
1081 val = atoi (strval);
1082 no_memory_lock_button.set_active(val);
1083 } else if (child->name() == "unlockmemory") {
1084 val = atoi (strval);
1085 unlock_memory_button.set_active(val);
1086 } else if (child->name() == "softmode") {
1087 val = atoi (strval);
1088 soft_mode_button.set_active(val);
1089 } else if (child->name() == "force16bit") {
1090 val = atoi (strval);
1091 force16bit_button.set_active(val);
1092 } else if (child->name() == "hwmonitor") {
1093 val = atoi (strval);
1094 hw_monitor_button.set_active(val);
1095 } else if (child->name() == "hwmeter") {
1096 val = atoi (strval);
1097 hw_meter_button.set_active(val);
1098 } else if (child->name() == "verbose") {
1099 val = atoi (strval);
1100 verbose_output_button.set_active(val);
1105 else if (child->name() == "samplerate") {
1106 sample_rate_combo.set_active_text(strval);
1107 } else if (child->name() == "periodsize") {
1108 period_size_combo.set_active_text(strval);
1109 } else if (child->name() == "serverpath") {
1110 /* do not allow us to use a server path that doesn't
1111 exist on this system. this handles cases where
1112 the user has an RC file listing a serverpath
1113 from some other machine.
1115 vector<string>::iterator x;
1116 for (x = server_strings.begin(); x != server_strings.end(); ++x) {
1121 if (x != server_strings.end()) {
1122 serverpath_combo.set_active_text (strval);
1124 warning << string_compose (_("configuration files contain a JACK server path that doesn't exist (%1)"),
1128 } else if (child->name() == "driver") {
1129 driver_combo.set_active_text(strval);
1130 } else if (child->name() == "interface") {
1131 interface_combo.set_active_text(strval);
1132 } else if (child->name() == "timeout") {
1133 timeout_combo.set_active_text(strval);
1134 } else if (child->name() == "dither") {
1135 dither_mode_combo.set_active_text(strval);
1136 } else if (child->name() == "audiomode") {
1137 audio_mode_combo.set_active_text(strval);
1138 } else if (child->name() == "inputdevice") {
1139 input_device_combo.set_active_text(strval);
1140 } else if (child->name() == "outputdevice") {
1141 output_device_combo.set_active_text(strval);