diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2007-10-11 22:07:47 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2007-10-11 22:07:47 +0000 |
commit | f7f9d6fdc40248b190ec9c6e1a886261d55777ae (patch) | |
tree | 080723e9dc35a66013b37acbafc67a6afa929302 /gtk2_ardour/engine_dialog.cc | |
parent | aa1f736a651376534acaa2268b65d42a3786fff7 (diff) |
merge from 2.0-ongoing by hand, minus key binding editor
git-svn-id: svn://localhost/ardour2/trunk@2539 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'gtk2_ardour/engine_dialog.cc')
-rw-r--r-- | gtk2_ardour/engine_dialog.cc | 1126 |
1 files changed, 1126 insertions, 0 deletions
diff --git a/gtk2_ardour/engine_dialog.cc b/gtk2_ardour/engine_dialog.cc new file mode 100644 index 0000000000..5be28e9226 --- /dev/null +++ b/gtk2_ardour/engine_dialog.cc @@ -0,0 +1,1126 @@ +#include <vector> +#include <cmath> +#include <fstream> + +#include <glibmm.h> +#include <pbd/xml++.h> + +#ifdef __APPLE__ +#include <CoreAudio/CoreAudio.h> +#include <CoreFoundation/CFString.h> +#include <sys/param.h> +#include <mach-o/dyld.h> +#else +#include <alsa/asoundlib.h> +#endif + +#include <ardour/profile.h> +#include <jack/jack.h> + +#include <gtkmm/stock.h> +#include <gtkmm2ext/utils.h> + +#include <pbd/convert.h> +#include <pbd/error.h> + +#ifdef __APPLE +#include <CFBundle.h> +#endif + +#include "engine_dialog.h" +#include "i18n.h" + +using namespace std; +using namespace Gtk; +using namespace Gtkmm2ext; +using namespace PBD; +using namespace Glib; + +EngineControl::EngineControl () + : periods_adjustment (2, 2, 16, 1, 2), + periods_spinner (periods_adjustment), + priority_adjustment (60, 10, 90, 1, 10), + priority_spinner (priority_adjustment), + ports_adjustment (128, 8, 1024, 1, 16), + ports_spinner (ports_adjustment), + realtime_button (_("Realtime")), + no_memory_lock_button (_("Do not lock memory")), + unlock_memory_button (_("Unlock memory")), + soft_mode_button (_("No zombies")), + monitor_button (_("Provide monitor ports")), + force16bit_button (_("Force 16 bit")), + hw_monitor_button (_("H/W monitoring")), + hw_meter_button (_("H/W metering")), + verbose_output_button (_("Verbose output")), + start_button (_("Start")), + stop_button (_("Stop")), +#ifdef __APPLE__ + basic_packer (5, 2), + options_packer (4, 2), + device_packer (4, 2) +#else + basic_packer (8, 2), + options_packer (14, 2), + device_packer (6, 2) +#endif +{ + using namespace Notebook_Helpers; + Label* label; + vector<string> strings; + int row = 0; + + _used = false; + + strings.push_back (_("8000Hz")); + strings.push_back (_("22050Hz")); + strings.push_back (_("44100Hz")); + strings.push_back (_("48000Hz")); + strings.push_back (_("88200Hz")); + strings.push_back (_("96000Hz")); + strings.push_back (_("192000Hz")); + set_popdown_strings (sample_rate_combo, strings); + sample_rate_combo.set_active_text ("48000Hz"); + + strings.clear (); + strings.push_back ("32"); + strings.push_back ("64"); + strings.push_back ("128"); + strings.push_back ("256"); + strings.push_back ("512"); + strings.push_back ("1024"); + strings.push_back ("2048"); + strings.push_back ("4096"); + strings.push_back ("8192"); + set_popdown_strings (period_size_combo, strings); + period_size_combo.set_active_text ("1024"); + + strings.clear (); + strings.push_back (_("None")); + strings.push_back (_("Triangular")); + strings.push_back (_("Rectangular")); + strings.push_back (_("Shaped")); + set_popdown_strings (dither_mode_combo, strings); + dither_mode_combo.set_active_text (_("None")); + + /* basic parameters */ + + basic_packer.set_spacings (6); + + strings.clear (); +#ifdef __APPLE__ + strings.push_back (X_("CoreAudio")); +#else + strings.push_back (X_("ALSA")); + strings.push_back (X_("OSS")); + strings.push_back (X_("FFADO")); +#endif + strings.push_back (X_("NetJACK")); + strings.push_back (X_("Dummy")); + set_popdown_strings (driver_combo, strings); + driver_combo.set_active_text (strings.front()); + + /* figure out available devices and set up interface_combo */ + + enumerate_devices (); + driver_combo.signal_changed().connect (mem_fun (*this, &EngineControl::driver_changed)); + driver_changed (); + + strings.clear (); + strings.push_back (_("Playback/Recording on 1 Device")); + strings.push_back (_("Playback/Recording on 2 Devices")); + strings.push_back (_("Playback only")); + strings.push_back (_("Recording only")); + set_popdown_strings (audio_mode_combo, strings); + audio_mode_combo.set_active_text (strings.front()); + + audio_mode_combo.signal_changed().connect (mem_fun (*this, &EngineControl::audio_mode_changed)); + audio_mode_changed (); + + row = 0; + + label = manage (new Label (_("Driver"))); + basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + basic_packer.attach (driver_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + row++; + + label = manage (new Label (_("Interface"))); + basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + basic_packer.attach (interface_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + row++; + + label = manage (new Label (_("Sample Rate"))); + basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + row++; + + label = manage (new Label (_("Buffer size"))); + basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + basic_packer.attach (period_size_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + row++; + +#ifndef __APPLE__ + label = manage (new Label (_("Number of buffers"))); + basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + basic_packer.attach (periods_spinner, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + periods_spinner.set_value (2); + row++; +#endif + + label = manage (new Label (_("Approximate latency"))); + label->set_alignment (0.0, 0.5); + basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + basic_packer.attach (latency_label, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + row++; + + sample_rate_combo.signal_changed().connect (mem_fun (*this, &EngineControl::redisplay_latency)); + periods_adjustment.signal_value_changed().connect (mem_fun (*this, &EngineControl::redisplay_latency)); + period_size_combo.signal_changed().connect (mem_fun (*this, &EngineControl::redisplay_latency)); + redisplay_latency(); + row++; + /* no audio mode with CoreAudio, its duplex or nuthin' */ + +#ifndef __APPLE__ + label = manage (new Label (_("Audio Mode"))); + basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + basic_packer.attach (audio_mode_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + row++; +#endif + + interface_combo.set_size_request (125, -1); + input_device_combo.set_size_request (125, -1); + output_device_combo.set_size_request (125, -1); + + /* + + if (engine_running()) { + start_button.set_sensitive (false); + } else { + stop_button.set_sensitive (false); + } + + start_button.signal_clicked().connect (mem_fun (*this, &EngineControl::start_engine)); + stop_button.signal_clicked().connect (mem_fun (*this, &EngineControl::start_engine)); + */ + + button_box.pack_start (start_button, false, false); + button_box.pack_start (stop_button, false, false); + + // basic_packer.attach (button_box, 0, 2, 8, 9, FILL|EXPAND, (AttachOptions) 0); + + /* options */ + + options_packer.set_spacings (6); + row = 0; + + options_packer.attach (realtime_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + ++row; + + realtime_button.signal_toggled().connect (mem_fun (*this, &EngineControl::realtime_changed)); + realtime_changed (); + +#ifndef __APPLE__ + label = manage (new Label (_("Realtime Priority"))); + label->set_alignment (1.0, 0.5); + options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + options_packer.attach (priority_spinner, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + ++row; + priority_spinner.set_value (60); + + options_packer.attach (no_memory_lock_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + ++row; + options_packer.attach (unlock_memory_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + ++row; + options_packer.attach (soft_mode_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + ++row; + options_packer.attach (monitor_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + ++row; + options_packer.attach (force16bit_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + ++row; + options_packer.attach (hw_monitor_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + ++row; + options_packer.attach (hw_meter_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + ++row; + options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + ++row; +#else + options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + ++row; +#endif + + strings.clear (); + strings.push_back (_("Ignore")); + strings.push_back ("500 msec"); + strings.push_back ("1 sec"); + strings.push_back ("2 sec"); + strings.push_back ("10 sec"); + set_popdown_strings (timeout_combo, strings); + timeout_combo.set_active_text (strings.front ()); + + label = manage (new Label (_("Client timeout"))); + label->set_alignment (1.0, 0.5); + options_packer.attach (timeout_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0)); + options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + ++row; + + label = manage (new Label (_("Number of ports"))); + label->set_alignment (1.0, 0.5); + options_packer.attach (ports_spinner, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0)); + options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + ++row; + +#ifndef __APPLE__ + label = manage (new Label (_("Dither"))); + label->set_alignment (1.0, 0.5); + options_packer.attach (dither_mode_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0)); + options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + ++row; +#endif + + find_jack_servers (server_strings); + + if (server_strings.empty()) { + fatal << _("No JACK server found anywhere on this system. Please install JACK and restart") << endmsg; + /*NOTREACHED*/ + } + + set_popdown_strings (serverpath_combo, server_strings); + serverpath_combo.set_active_text (server_strings.front()); + + if (server_strings.size() > 1) { + label = manage (new Label (_("Server:"))); + options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + label->set_alignment (0.0, 0.5); + options_packer.attach (serverpath_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + ++row; + } + + /* device settings */ + + device_packer.set_spacings (6); + row = 0; + +#ifndef __APPLE__ + label = manage (new Label (_("Input device"))); + label->set_alignment (1.0, 0.5); + device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0); + device_packer.attach (input_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0); + ++row; + label = manage (new Label (_("Output device"))); + label->set_alignment (1.0, 0.5); + device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0); + device_packer.attach (output_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0); + ++row; +#endif + label = manage (new Label (_("Input channels"))); + label->set_alignment (1.0, 0.5); + device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0); + device_packer.attach (input_channels, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0); + ++row; + label = manage (new Label (_("Output channels"))); + label->set_alignment (1.0, 0.5); + device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0); + device_packer.attach (output_channels, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0); + ++row; + label = manage (new Label (_("Hardware input latency (samples)"))); + label->set_alignment (1.0, 0.5); + device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0); + device_packer.attach (input_latency, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0); + ++row; + label = manage (new Label (_("Hardware output latency (samples)"))); + label->set_alignment (1.0, 0.5); + device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0); + device_packer.attach (output_latency, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0); + ++row; + + basic_hbox.pack_start (basic_packer, false, false); + options_hbox.pack_start (options_packer, false, false); + + device_packer.set_border_width (12); + options_packer.set_border_width (12); + basic_packer.set_border_width (12); + + notebook.pages().push_back (TabElem (basic_hbox, _("Device"))); + notebook.pages().push_back (TabElem (options_hbox, _("Options"))); + notebook.pages().push_back (TabElem (device_packer, _("Advanced"))); + notebook.set_border_width (12); + + set_border_width (12); + pack_start (notebook); +} + +EngineControl::~EngineControl () +{ + +} + +void +EngineControl::build_command_line (vector<string>& cmd) +{ + string str; + string driver; + bool using_oss = false; + bool using_alsa = false; + bool using_coreaudio = false; + bool using_netjack = false; + bool using_ffado = false; + + /* first, path to jackd */ + + cmd.push_back (serverpath_combo.get_active_text ()); + + /* now jackd arguments */ + + str = timeout_combo.get_active_text (); + if (str != _("Ignore")) { + double secs; + uint32_t msecs; + atof (str); + msecs = (uint32_t) floor (secs * 1000.0); + cmd.push_back ("-t"); + cmd.push_back (to_string (msecs, std::dec)); + } + + if (no_memory_lock_button.get_active()) { + cmd.push_back ("-m"); /* no munlock */ + } + + cmd.push_back ("-p"); /* port max */ + cmd.push_back (to_string ((uint32_t) floor (ports_spinner.get_value()), std::dec)); + + if (realtime_button.get_active()) { + cmd.push_back ("-R"); + cmd.push_back ("-P"); + cmd.push_back (to_string ((uint32_t) floor (priority_spinner.get_value()), std::dec)); + } + + if (unlock_memory_button.get_active()) { + cmd.push_back ("-u"); + } + + if (verbose_output_button.get_active()) { + cmd.push_back ("-v"); + } + + /* now add fixed arguments (not user-selectable) */ + + cmd.push_back ("-T"); // temporary */ + + /* next the driver */ + + cmd.push_back ("-d"); + + driver = driver_combo.get_active_text (); + if (driver == X_("ALSA")) { + using_alsa = true; + cmd.push_back ("alsa"); + } else if (driver == X_("OSS")) { + using_oss = true; + cmd.push_back ("oss"); + } else if (driver == X_("CoreAudio")) { + using_coreaudio = true; + cmd.push_back ("coreaudio"); + } else if (driver == X_("NetJACK")) { + using_netjack = true; + cmd.push_back ("netjack"); + } else if (driver == X_("FFADO")) { + using_ffado = true; + cmd.push_back ("ffado"); + } + + /* driver arguments */ + + if (!using_coreaudio) { + str = audio_mode_combo.get_active_text(); + + if (str == _("Playback/Recording on 1 Device")) { + + /* relax */ + + } else if (str == _("Playback/Recording on 2 Devices")) { + + cmd.push_back ("-C"); + cmd.push_back (get_device_name (driver, input_device_combo.get_active_text())); + cmd.push_back ("-P"); + cmd.push_back (get_device_name (driver, output_device_combo.get_active_text())); + + } else if (str == _("Playback only")) { + cmd.push_back ("-P"); + } else if (str == _("Recording only")) { + cmd.push_back ("-C"); + } + + cmd.push_back ("-n"); + cmd.push_back (to_string ((uint32_t) floor (periods_spinner.get_value()), std::dec)); + } + + cmd.push_back ("-r"); + cmd.push_back (to_string (get_rate(), std::dec)); + + cmd.push_back ("-p"); + cmd.push_back (period_size_combo.get_active_text()); + + if (using_alsa) { + + if (audio_mode_combo.get_active_text() != _("Playback/Recording on 2 Devices")) { + cmd.push_back ("-d"); + cmd.push_back (get_device_name (driver, interface_combo.get_active_text())); + } + + if (hw_meter_button.get_active()) { + cmd.push_back ("-M"); + } + + if (hw_monitor_button.get_active()) { + cmd.push_back ("-H"); + } + + str = dither_mode_combo.get_active_text(); + + if (str == _("None")) { + } else if (str == _("Triangular")) { + cmd.push_back ("-z triangular"); + } else if (str == _("Rectangular")) { + cmd.push_back ("-z rectangular"); + } else if (str == _("Shaped")) { + cmd.push_back ("-z shaped"); + } + + if (force16bit_button.get_active()) { + cmd.push_back ("-S"); + } + + if (soft_mode_button.get_active()) { + cmd.push_back ("-s"); + } + + } else if (using_coreaudio) { + +#ifdef __APPLE__ + // note: older versions of the CoreAudio JACK backend use -n instead of -d here + cmd.push_back ("-d"); + cmd.push_back (get_device_name (driver, interface_combo.get_active_text())); +#endif + + } else if (using_oss) { + + } else if (using_netjack) { + + } +} + +bool +EngineControl::engine_running () +{ + jack_status_t status; + jack_client_t* c = jack_client_open ("ardourprobe", JackNoStartServer, &status); + + if (status == 0) { + jack_client_close (c); + return true; + } + return false; +} + +int +EngineControl::setup_engine () +{ + vector<string> args; + std::string cwd = "/tmp"; + + build_command_line (args); + + Glib::ustring jackdrc_path = Glib::get_home_dir(); + jackdrc_path += "/.jackdrc"; + + ofstream jackdrc (jackdrc_path.c_str()); + if (!jackdrc) { + error << string_compose (_("cannot open JACK rc file %1 to store parameters"), jackdrc_path) << endmsg; + return -1; + } + + for (vector<string>::iterator i = args.begin(); i != args.end(); ++i) { + jackdrc << (*i) << ' '; + } + jackdrc << endl; + jackdrc.close (); + + _used = true; + + return 0; +} + +void +EngineControl::realtime_changed () +{ +#ifndef __APPLE__ + priority_spinner.set_sensitive (realtime_button.get_active()); +#endif +} + +void +EngineControl::enumerate_devices () +{ + /* note: case matters for the map keys */ + +#ifdef __APPLE__ + devices["CoreAudio"] = enumerate_coreaudio_devices (); +#else + devices["ALSA"] = enumerate_alsa_devices (); + devices["FFADO"] = enumerate_ffado_devices (); + devices["OSS"] = enumerate_oss_devices (); + devices["Dummy"] = enumerate_dummy_devices (); + devices["NetJACK"] = enumerate_netjack_devices (); +#endif +} + +#ifdef __APPLE__ +static OSStatus +getDeviceUIDFromID( AudioDeviceID id, char *name, size_t nsize) +{ + UInt32 size = sizeof(CFStringRef); + CFStringRef UI; + OSStatus res = AudioDeviceGetProperty(id, 0, false, + kAudioDevicePropertyDeviceUID, &size, &UI); + if (res == noErr) + CFStringGetCString(UI,name,nsize,CFStringGetSystemEncoding()); + CFRelease(UI); + return res; +} + +vector<string> +EngineControl::enumerate_coreaudio_devices () +{ + vector<string> devs; + + // Find out how many Core Audio devices are there, if any... + // (code snippet gently "borrowed" from St?hane Letz jackdmp;) + OSStatus err; + Boolean isWritable; + size_t outSize = sizeof(isWritable); + + backend_devs.clear (); + + err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, + &outSize, &isWritable); + if (err == noErr) { + // Calculate the number of device available... + int numCoreDevices = outSize / sizeof(AudioDeviceID); + // Make space for the devices we are about to get... + AudioDeviceID *coreDeviceIDs = new AudioDeviceID [numCoreDevices]; + err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, + &outSize, (void *) coreDeviceIDs); + if (err == noErr) { + // Look for the CoreAudio device name... + char coreDeviceName[256]; + size_t nameSize; + for (int i = 0; i < numCoreDevices; i++) { + + nameSize = sizeof (coreDeviceName); + + err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i], + 0, true, kAudioDevicePropertyDeviceName, + &outSize, &isWritable); + if (err == noErr) { + err = AudioDeviceGetProperty(coreDeviceIDs[i], + 0, true, kAudioDevicePropertyDeviceName, + &nameSize, (void *) coreDeviceName); + if (err == noErr) { + char drivername[128]; + + // this returns the unique id for the device + // that must be used on the commandline for jack + + if (getDeviceUIDFromID(coreDeviceIDs[i], drivername, sizeof (drivername)) == noErr) { + devs.push_back (coreDeviceName); + backend_devs.push_back (drivername); + } + } + } + } + } + delete [] coreDeviceIDs; + } + + return devs; +} +#else +vector<string> +EngineControl::enumerate_alsa_devices () +{ + vector<string> devs; + + snd_ctl_t *handle; + snd_ctl_card_info_t *info; + snd_pcm_info_t *pcminfo; + snd_ctl_card_info_alloca(&info); + snd_pcm_info_alloca(&pcminfo); + string devname; + int cardnum = -1; + int device = -1; + + backend_devs.clear (); + + while (snd_card_next (&cardnum) >= 0 && cardnum >= 0) { + + devname = "hw:"; + devname += to_string (cardnum, std::dec); + + if (snd_ctl_open (&handle, devname.c_str(), 0) >= 0 && snd_ctl_card_info (handle, info) >= 0) { + + while (snd_ctl_pcm_next_device (handle, &device) >= 0 && device >= 0) { + + bool have_playback = false; + bool have_capture = false; + + /* find duplex devices only */ + + snd_pcm_info_set_device (pcminfo, device); + snd_pcm_info_set_subdevice (pcminfo, 0); + snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_CAPTURE); + + if (snd_ctl_pcm_info (handle, pcminfo) >= 0) { + have_capture = true; + } + + snd_pcm_info_set_device (pcminfo, device); + snd_pcm_info_set_subdevice (pcminfo, 0); + snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_PLAYBACK); + + if (snd_ctl_pcm_info (handle, pcminfo) >= 0) { + have_playback = true; + } + + if (have_capture && have_playback) { + devs.push_back (snd_pcm_info_get_name (pcminfo)); + devname += ','; + devname += to_string (device, std::dec); + backend_devs.push_back (devname); + } + } + + snd_ctl_close(handle); + } + } + + return devs; +} + +vector<string> +EngineControl::enumerate_ffado_devices () +{ + vector<string> devs; + return devs; +} +vector<string> +EngineControl::enumerate_oss_devices () +{ + vector<string> devs; + return devs; +} +vector<string> +EngineControl::enumerate_dummy_devices () +{ + vector<string> devs; + return devs; +} +vector<string> +EngineControl::enumerate_netjack_devices () +{ + vector<string> devs; + return devs; +} +#endif + +void +EngineControl::driver_changed () +{ + string driver = driver_combo.get_active_text(); + vector<string>& strings = devices[driver]; + string::size_type maxlen = 0; + int maxindex = -1; + int n = 0; + + for (vector<string>::iterator i = strings.begin(); i != strings.end(); ++i, ++n) { + if ((*i).length() > maxlen) { + maxlen = (*i).length(); + maxindex = n; + } + } + + set_popdown_strings (interface_combo, strings); + set_popdown_strings (input_device_combo, strings); + set_popdown_strings (output_device_combo, strings); + + if (!strings.empty()) { + interface_combo.set_active_text (strings.front()); + input_device_combo.set_active_text (strings.front()); + output_device_combo.set_active_text (strings.front()); + } + + if (driver == "ALSA") { + soft_mode_button.set_sensitive (true); + force16bit_button.set_sensitive (true); + hw_monitor_button.set_sensitive (true); + hw_meter_button.set_sensitive (true); + monitor_button.set_sensitive (true); + } else { + soft_mode_button.set_sensitive (false); + force16bit_button.set_sensitive (false); + hw_monitor_button.set_sensitive (false); + hw_meter_button.set_sensitive (false); + monitor_button.set_sensitive (false); + } +} + +uint32_t +EngineControl::get_rate () +{ + return atoi (sample_rate_combo.get_active_text ()); +} + +void +EngineControl::redisplay_latency () +{ + uint32_t rate = get_rate(); +#ifdef __APPLE_ + float periods = 2; +#else + float periods = periods_adjustment.get_value(); +#endif + float period_size = atof (period_size_combo.get_active_text()); + + char buf[32]; + snprintf (buf, sizeof(buf), "%.1fmsec", (periods * period_size) / (rate/1000.0)); + + latency_label.set_text (buf); +} + +void +EngineControl::audio_mode_changed () +{ + Glib::ustring str = audio_mode_combo.get_active_text(); + + if (str == _("Playback/Recording on 1 Device")) { + input_device_combo.set_sensitive (false); + output_device_combo.set_sensitive (false); + } else if (str == _("Playback/Recording on 2 Devices")) { + input_device_combo.set_sensitive (true); + output_device_combo.set_sensitive (true); + } else if (str == _("Playback only")) { + output_device_combo.set_sensitive (true); + } else if (str == _("Recording only")) { + input_device_combo.set_sensitive (true); + } +} + +void +EngineControl::find_jack_servers (vector<string>& strings) +{ +#ifdef __APPLE__ + /* this magic lets us finds the path to the OSX bundle, and then + we infer JACK's location from there + */ + + char execpath[MAXPATHLEN+1]; + uint32_t pathsz = sizeof (execpath); + + _NSGetExecutablePath (execpath, &pathsz); + + cerr << " execpath = " << execpath << endl; + + Glib::ustring path (Glib::path_get_dirname (execpath)); + path += "/jackd"; + + if (Glib::file_test (path, FILE_TEST_EXISTS)) { + strings.push_back (path); + cerr << "Found jack in " << path << endl; + } + + if (getenv ("ARDOUR_WITH_JACK")) { + /* no other options - only use the JACK we supply */ + if (strings.empty()) { + fatal << _("JACK appears to be missing from the Ardour bundle") << endmsg; + /*NOTREACHED*/ + } + return; + } +#endif + + if (Glib::file_test ("/usr/bin/jackd", FILE_TEST_EXISTS)) { + strings.push_back ("/usr/bin/jackd"); + } + if (Glib::file_test ("/usr/local/bin/jackd", FILE_TEST_EXISTS)) { + strings.push_back ("/usr/local/bin/jackd"); + } + if (Glib::file_test ("/opt/bin/jackd", FILE_TEST_EXISTS)) { + strings.push_back ("/opt/bin/jackd"); + } + if (Glib::file_test ("/usr/bin/jackdmp", FILE_TEST_EXISTS)) { + strings.push_back ("/usr/bin/jackd"); + } + if (Glib::file_test ("/usr/local/bin/jackdmp", FILE_TEST_EXISTS)) { + strings.push_back ("/usr/local/bin/jackd"); + } + if (Glib::file_test ("/opt/bin/jackdmp", FILE_TEST_EXISTS)) { + strings.push_back ("/opt/bin/jackd"); + } + +} + +string +EngineControl::get_device_name (const string& driver, const string& human_readable) +{ + vector<string>::iterator n; + vector<string>::iterator i; + + if (backend_devs.empty()) { + return human_readable; + } + + for (i = devices[driver].begin(), n = backend_devs.begin(); i != devices[driver].end(); ++i, ++n) { + if (human_readable == (*i)) { + return (*n); + } + } + + if (i == devices[driver].end()) { + fatal << string_compose (_("programming error: %1"), "true hardware name for ID missing") << endmsg; + /*NOTREACHED*/ + } + + /* keep gcc happy */ + + return string(); +} + +XMLNode& +EngineControl::get_state () +{ + XMLNode* root = new XMLNode ("AudioSetup"); + XMLNode* child; + Glib::ustring path; + + child = new XMLNode ("periods"); + child->add_property ("val", to_string (periods_adjustment.get_value(), std::dec)); + root->add_child_nocopy (*child); + + child = new XMLNode ("priority"); + child->add_property ("val", to_string (priority_adjustment.get_value(), std::dec)); + root->add_child_nocopy (*child); + + child = new XMLNode ("ports"); + child->add_property ("val", to_string (ports_adjustment.get_value(), std::dec)); + root->add_child_nocopy (*child); + + child = new XMLNode ("inchannels"); + child->add_property ("val", to_string (input_channels.get_value(), std::dec)); + root->add_child_nocopy (*child); + + child = new XMLNode ("outchannels"); + child->add_property ("val", to_string (output_channels.get_value(), std::dec)); + root->add_child_nocopy (*child); + + child = new XMLNode ("inlatency"); + child->add_property ("val", to_string (input_latency.get_value(), std::dec)); + root->add_child_nocopy (*child); + + child = new XMLNode ("outlatency"); + child->add_property ("val", to_string (output_latency.get_value(), std::dec)); + root->add_child_nocopy (*child); + + child = new XMLNode ("realtime"); + child->add_property ("val", to_string (realtime_button.get_active(), std::dec)); + root->add_child_nocopy (*child); + + child = new XMLNode ("nomemorylock"); + child->add_property ("val", to_string (no_memory_lock_button.get_active(), std::dec)); + root->add_child_nocopy (*child); + + child = new XMLNode ("unlockmemory"); + child->add_property ("val", to_string (unlock_memory_button.get_active(), std::dec)); + root->add_child_nocopy (*child); + + child = new XMLNode ("softmode"); + child->add_property ("val", to_string (soft_mode_button.get_active(), std::dec)); + root->add_child_nocopy (*child); + + child = new XMLNode ("force16bit"); + child->add_property ("val", to_string (force16bit_button.get_active(), std::dec)); + root->add_child_nocopy (*child); + + child = new XMLNode ("hwmonitor"); + child->add_property ("val", to_string (hw_monitor_button.get_active(), std::dec)); + root->add_child_nocopy (*child); + + child = new XMLNode ("hwmeter"); + child->add_property ("val", to_string (hw_meter_button.get_active(), std::dec)); + root->add_child_nocopy (*child); + + child = new XMLNode ("verbose"); + child->add_property ("val", to_string (verbose_output_button.get_active(), std::dec)); + root->add_child_nocopy (*child); + + child = new XMLNode ("samplerate"); + child->add_property ("val", sample_rate_combo.get_active_text()); + root->add_child_nocopy (*child); + + child = new XMLNode ("periodsize"); + child->add_property ("val", period_size_combo.get_active_text()); + root->add_child_nocopy (*child); + + child = new XMLNode ("serverpath"); + child->add_property ("val", serverpath_combo.get_active_text()); + root->add_child_nocopy (*child); + + child = new XMLNode ("driver"); + child->add_property ("val", driver_combo.get_active_text()); + root->add_child_nocopy (*child); + + child = new XMLNode ("interface"); + child->add_property ("val", interface_combo.get_active_text()); + root->add_child_nocopy (*child); + + child = new XMLNode ("timeout"); + child->add_property ("val", timeout_combo.get_active_text()); + root->add_child_nocopy (*child); + + child = new XMLNode ("dither"); + child->add_property ("val", dither_mode_combo.get_active_text()); + root->add_child_nocopy (*child); + + child = new XMLNode ("audiomode"); + child->add_property ("val", audio_mode_combo.get_active_text()); + root->add_child_nocopy (*child); + + child = new XMLNode ("inputdevice"); + child->add_property ("val", input_device_combo.get_active_text()); + root->add_child_nocopy (*child); + + child = new XMLNode ("outputdevice"); + child->add_property ("val", output_device_combo.get_active_text()); + root->add_child_nocopy (*child); + + return *root; +} + +void +EngineControl::set_state (const XMLNode& root) +{ + XMLNodeList clist; + XMLNodeConstIterator citer; + XMLNode* child; + XMLProperty* prop; + + int val; + string strval; + + clist = root.children(); + + for (citer = clist.begin(); citer != clist.end(); ++citer) { + + child = *citer; + + prop = child->property ("val"); + + if (!prop || prop->value().empty()) { + error << string_compose (_("AudioSetup value for %1 is missing data"), child->name()) << endmsg; + continue; + } + + strval = prop->value(); + + /* adjustments/spinners */ + + if (child->name() == "periods") { + val = atoi (strval); + periods_adjustment.set_value(val); + } else if (child->name() == "priority") { + val = atoi (strval); + priority_adjustment.set_value(val); + } else if (child->name() == "ports") { + val = atoi (strval); + ports_adjustment.set_value(val); + } else if (child->name() == "inchannels") { + val = atoi (strval); + input_channels.set_value(val); + } else if (child->name() == "outchannels") { + val = atoi (strval); + output_channels.set_value(val); + } else if (child->name() == "inlatency") { + val = atoi (strval); + input_latency.set_value(val); + } else if (child->name() == "outlatency") { + val = atoi (strval); + output_latency.set_value(val); + } + + /* buttons */ + + else if (child->name() == "realtime") { + val = atoi (strval); + realtime_button.set_active(val); + } else if (child->name() == "nomemorylock") { + val = atoi (strval); + no_memory_lock_button.set_active(val); + } else if (child->name() == "unlockmemory") { + val = atoi (strval); + unlock_memory_button.set_active(val); + } else if (child->name() == "softmode") { + val = atoi (strval); + soft_mode_button.set_active(val); + } else if (child->name() == "force16bit") { + val = atoi (strval); + force16bit_button.set_active(val); + } else if (child->name() == "hwmonitor") { + val = atoi (strval); + hw_monitor_button.set_active(val); + } else if (child->name() == "hwmeter") { + val = atoi (strval); + hw_meter_button.set_active(val); + } else if (child->name() == "verbose") { + val = atoi (strval); + verbose_output_button.set_active(val); + } + + /* combos */ + + else if (child->name() == "samplerate") { + sample_rate_combo.set_active_text(strval); + } else if (child->name() == "periodsize") { + period_size_combo.set_active_text(strval); + } else if (child->name() == "serverpath") { + /* do not allow us to use a server path that doesn't + exist on this system. this handles cases where + the user has an RC file listing a serverpath + from some other machine. + */ + vector<string>::iterator x; + for (x = server_strings.begin(); x != server_strings.end(); ++x) { + if (*x == strval) { + break; + } + } + if (x != server_strings.end()) { + serverpath_combo.set_active_text (strval); + } else { + warning << string_compose (_("configuration files contain a JACK server path that doesn't exist (%1)"), + strval) + << endmsg; + } + } else if (child->name() == "driver") { + driver_combo.set_active_text(strval); + } else if (child->name() == "interface") { + interface_combo.set_active_text(strval); + } else if (child->name() == "timeout") { + timeout_combo.set_active_text(strval); + } else if (child->name() == "dither") { + dither_mode_combo.set_active_text(strval); + } else if (child->name() == "audiomode") { + audio_mode_combo.set_active_text(strval); + } else if (child->name() == "inputdevice") { + input_device_combo.set_active_text(strval); + } else if (child->name() == "outputdevice") { + output_device_combo.set_active_text(strval); + } + } +} |