static bool preset_search_path_initialized = false;
FILE * AUPluginInfo::_crashlog_fd = NULL;
+
+static void au_blacklist (std::string id)
+{
+ string fn = Glib::build_filename (ARDOUR::user_cache_directory(), "au_blacklist.txt");
+ FILE * blacklist_fd = NULL;
+ if (! (blacklist_fd = fopen(fn.c_str(), "a"))) {
+ PBD::error << "Cannot append to AU blacklist for '"<< id <<"'\n";
+ return;
+ }
+ assert(id.find("\n") == string::npos);
+ fprintf(blacklist_fd, "%s\n", id.c_str());
+ ::fclose(blacklist_fd);
+}
+
+static void au_unblacklist (std::string id)
+{
+ string fn = Glib::build_filename (ARDOUR::user_cache_directory(), "au_blacklist.txt");
+ if (!Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
+ PBD::warning << "Expected Blacklist file does not exist.\n";
+ return;
+ }
+
+ std::string bl;
+ std::ifstream ifs(fn.c_str());
+ bl.assign ((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
+ ::g_unlink(fn.c_str());
+
+ assert(id.find("\n") == string::npos);
+
+ id += "\n"; // add separator
+ const size_t rpl = bl.find(id);
+ if (rpl != string::npos) {
+ bl.replace(rpl, id.size(), "");
+ }
+ if (bl.empty()) {
+ return;
+ }
+
+ FILE * blacklist_fd = NULL;
+ if (! (blacklist_fd = fopen(fn.c_str(), "w"))) {
+ PBD::error << "Cannot open AU blacklist.\n";
+ return;
+ }
+ fprintf(blacklist_fd, "%s", bl.c_str());
+ ::fclose(blacklist_fd);
+}
+
+static bool is_blacklisted (std::string id)
+{
+ string fn = Glib::build_filename (ARDOUR::user_cache_directory(), "au_blacklist.txt");
+ if (!Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
+ return false;
+ }
+ std::string bl;
+ std::ifstream ifs(fn.c_str());
+ bl.assign ((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
+
+ assert(id.find("\n") == string::npos);
+
+ id += "\n"; // add separator
+ const size_t rpl = bl.find(id);
+ if (rpl != string::npos) {
+ return true;
+ }
+ return false;
+}
+
+
+
static OSStatus
_render_callback(void *userData,
AudioUnitRenderActionFlags *ioActionFlags,
p += preset_search_path;
preset_search_path = p;
preset_search_path_initialized = true;
+ DEBUG_TRACE (DEBUG::AudioUnits, string_compose("AU Preset Path: %1\n", preset_search_path));
}
init ();
string name = CFStringRefToStdString (preset->presetName);
factory_preset_map[name] = preset->presetNumber;
+ DEBUG_TRACE (DEBUG::AudioUnits, string_compose("AU Factory Preset: %1 > %2\n", name, preset->presetNumber));
}
CFRelease (presets);
AUPlugin::init ()
{
OSErr err;
+ CFStringRef itemName;
/* these keep track of *configured* channel set up,
not potential set ups.
input_channels = -1;
output_channels = -1;
+ {
+ CAComponentDescription temp;
+ GetComponentInfo (comp.get()->Comp(), &temp, NULL, NULL, NULL);
+ CFStringRef compTypeString = UTCreateStringForOSType(temp.componentType);
+ CFStringRef compSubTypeString = UTCreateStringForOSType(temp.componentSubType);
+ CFStringRef compManufacturerString = UTCreateStringForOSType(temp.componentManufacturer);
+ itemName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ - %@ - %@"),
+ compTypeString, compManufacturerString, compSubTypeString);
+ if (compTypeString != NULL) CFRelease(compTypeString);
+ if (compSubTypeString != NULL) CFRelease(compSubTypeString);
+ if (compManufacturerString != NULL) CFRelease(compManufacturerString);
+ }
+
+ au_blacklist(CFStringRefToStdString(itemName));
try {
DEBUG_TRACE (DEBUG::AudioUnits, "opening AudioUnit\n");
discover_factory_presets ();
// Plugin::setup_controls ();
+
+ au_unblacklist(CFStringRefToStdString(itemName));
+ if (itemName != NULL) CFRelease(itemName);
}
void
for (uint32_t i = 0; i < sizeof (scopes) / sizeof (scopes[0]); ++i) {
- AUParamInfo param_info (unit->AU(), false, false, scopes[i]);
+ AUParamInfo param_info (unit->AU(), false, /* include read only */ true, scopes[i]);
for (uint32_t i = 0; i < param_info.NumParams(); ++i) {
d.toggled = (info.unit == kAudioUnitParameterUnit_Boolean) ||
(d.integer_step && ((d.upper - d.lower) == 1.0));
d.sr_dependent = (info.unit == kAudioUnitParameterUnit_SampleFrames);
- d.automatable = !d.toggled &&
+ d.automatable = /* !d.toggled && -- ardour can automate toggles, can AU ? */
!(info.flags & kAudioUnitParameterFlag_NonRealTime) &&
(info.flags & kAudioUnitParameterFlag_IsWritable);
{
ChanCount c;
- c.set (DataType::AUDIO, 1);
- c.set (DataType::MIDI, 0);
if (input_channels < 0) {
- warning << string_compose (_("AUPlugin: %1 input_streams() called without any format set!"), name()) << endmsg;
+ // force PluginIoReConfigure -- see also commit msg e38eb06
+ c.set (DataType::AUDIO, 0);
+ c.set (DataType::MIDI, 0);
} else {
c.set (DataType::AUDIO, input_channels);
c.set (DataType::MIDI, _has_midi_input ? 1 : 0);
{
ChanCount c;
- c.set (DataType::AUDIO, 1);
- c.set (DataType::MIDI, 0);
-
if (output_channels < 0) {
- warning << string_compose (_("AUPlugin: %1 output_streams() called without any format set!"), name()) << endmsg;
+ // force PluginIoReConfigure - see also commit msg e38eb06
+ c.set (DataType::AUDIO, 0);
+ c.set (DataType::MIDI, 0);
} else {
c.set (DataType::AUDIO, output_channels);
c.set (DataType::MIDI, _has_midi_output ? 1 : 0);
//configurations in most cases. so first lets see
//if there's a configuration that keeps out==in
- audio_out = audio_in;
+ if (in.n_midi() > 0 && audio_in == 0) {
+ audio_out = 2; // prefer stereo version if available.
+ } else {
+ audio_out = audio_in;
+ }
for (vector<pair<int,int> >::iterator i = io_configs.begin(); i != io_configs.end(); ++i) {
}
bool
-AUPlugin::parameter_is_control (uint32_t) const
+AUPlugin::parameter_is_control (uint32_t param) const
{
- return true;
+ assert(param < descriptors.size());
+ if (descriptors[param].automatable) {
+ /* corrently ardour expects all controls to be automatable
+ * IOW ardour GUI elements mandate an Evoral::Parameter
+ * for all input+control ports.
+ */
+ return true;
+ }
+ return false;
}
bool
-AUPlugin::parameter_is_input (uint32_t) const
+AUPlugin::parameter_is_input (uint32_t param) const
{
- return false;
+ /* AU params that are both readable and writeable,
+ * are listed in kAudioUnitScope_Global
+ */
+ return (descriptors[param].scope == kAudioUnitScope_Input || descriptors[param].scope == kAudioUnitScope_Global);
}
bool
-AUPlugin::parameter_is_output (uint32_t) const
+AUPlugin::parameter_is_output (uint32_t param) const
{
- return false;
+ assert(param < descriptors.size());
+ // TODO check if ardour properly handles ports
+ // that report is_input + is_output == true
+ // -> add || descriptors[param].scope == kAudioUnitScope_Global
+ return (descriptors[param].scope == kAudioUnitScope_Output);
}
void
CFRelease(propertyList);
+ user_preset_map[preset_name] = user_preset_path;;
+
+ DEBUG_TRACE (DEBUG::AudioUnits, string_compose("AU Saving Preset to %1\n", user_preset_path));
+
return string ("file:///") + user_preset_path;
}
find_files_matching_filter (preset_files, preset_search_path, au_preset_filter, this, true, true, true);
if (preset_files.empty()) {
+ DEBUG_TRACE (DEBUG::AudioUnits, "AU No Preset Files found for given plugin.\n");
return;
}
if (check_and_get_preset_name (get_comp()->Comp(), path, preset_name)) {
user_preset_map[preset_name] = path;
+ DEBUG_TRACE (DEBUG::AudioUnits, string_compose("AU Preset File: %1 > %2\n", preset_name, path));
+ } else {
+ DEBUG_TRACE (DEBUG::AudioUnits, string_compose("AU INVALID Preset: %1 > %2\n", preset_name, path));
}
}
for (UserPresetMap::iterator i = user_preset_map.begin(); i != user_preset_map.end(); ++i) {
_presets.insert (make_pair (i->second, Plugin::PresetRecord (i->second, i->first)));
+ DEBUG_TRACE (DEBUG::AudioUnits, string_compose("AU Adding User Preset: %1 > %2\n", i->first, i->second));
}
/* add factory presets */
/* XXX: dubious */
string const uri = string_compose ("%1", _presets.size ());
_presets.insert (make_pair (uri, Plugin::PresetRecord (uri, i->first, i->second)));
+ DEBUG_TRACE (DEBUG::AudioUnits, string_compose("AU Adding Factory Preset: %1 > %2\n", i->first, i->second));
}
}
while (comp != NULL) {
CAComponentDescription temp;
GetComponentInfo (comp, &temp, NULL, NULL, NULL);
+ CFStringRef itemName = NULL;
{
+ if (itemName != NULL) CFRelease(itemName);
CFStringRef compTypeString = UTCreateStringForOSType(temp.componentType);
CFStringRef compSubTypeString = UTCreateStringForOSType(temp.componentSubType);
CFStringRef compManufacturerString = UTCreateStringForOSType(temp.componentManufacturer);
- CFStringRef itemName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ - %@ - %@"),
+ itemName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ - %@ - %@"),
compTypeString, compManufacturerString, compSubTypeString);
au_crashlog(string_compose("Scanning ID: %1", CFStringRefToStdString(itemName)));
if (compTypeString != NULL)
CFRelease(compManufacturerString);
}
+ if (is_blacklisted(CFStringRefToStdString(itemName))) {
+ info << string_compose (_("Skipped blacklisted AU plugin %1 "), CFStringRefToStdString(itemName)) << endmsg;
+ comp = FindNextComponent (comp, &desc);
+ continue;
+ }
+
AUPluginInfoPtr info (new AUPluginInfo
(boost::shared_ptr<CAComponentDescription> (new CAComponentDescription(temp))));
case kAudioUnitType_Panner:
case kAudioUnitType_OfflineEffect:
case kAudioUnitType_FormatConverter:
+ comp = FindNextComponent (comp, &desc);
continue;
case kAudioUnitType_Output:
break;
}
+ au_blacklist(CFStringRefToStdString(itemName));
AUPluginInfo::get_names (temp, info->name, info->creator);
ARDOUR::PluginScanMessage(_("AU"), info->name, false);
au_crashlog(string_compose("Plugin: %1", info->name));
error << string_compose (_("Cannot get I/O configuration info for AU %1"), info->name) << endmsg;
}
+ au_unblacklist(CFStringRefToStdString(itemName));
au_crashlog("Success.");
comp = FindNextComponent (comp, &desc);
+ if (itemName != NULL) CFRelease(itemName); itemName = NULL;
}
au_crashlog(string_compose("End AU discovery for Type: %1", (int)desc.componentType));
}