, input_maxbuf (0)
, input_offset (0)
, input_buffers (0)
+ , input_map (0)
, frames_processed (0)
, audio_input_cnt (0)
, _parameter_listener (0)
, input_maxbuf (0)
, input_offset (0)
, input_buffers (0)
+ , input_map (0)
, frames_processed (0)
, _parameter_listener (0)
, _parameter_listener_arg (0)
const CAAUParameter* param = param_info.GetParamInfo (d.id);
const AudioUnitParameterInfo& info (param->ParamInfo());
- const int len = CFStringGetLength (param->GetName());;
+ const int len = CFStringGetLength (param->GetName());
char local_buffer[len*2];
- Boolean good = CFStringGetCString(param->GetName(),local_buffer,len*2,kCFStringEncodingMacRoman);
+ Boolean good = CFStringGetCString (param->GetName(), local_buffer ,len*2 , kCFStringEncodingUTF8);
if (!good) {
d.label = "???";
} else {
if (initialized) {
//if we are already running with the requested i/o config, bail out here
if ( (audio_in==input_channels) && (audio_out==output_channels) ) {
- return 0;
+ return true;
} else {
deactivate ();
}
streamFormat.mChannelsPerFrame = audio_in;
if (set_input_format (streamFormat) != 0) {
- return -1;
+ return false;
}
streamFormat.mChannelsPerFrame = audio_out;
if (set_output_format (streamFormat) != 0) {
- return -1;
+ return false;
}
/* reset plugin info to show currently configured state */
activate ();
}
- return 0;
+ return true;
}
ChanCount
}
bool
-AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out)
+AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out, ChanCount* imprecise)
{
- // Note: We never attempt to multiply-instantiate plugins to meet io configurations.
-
- int32_t audio_in = in.n_audio();
+ _output_configs.clear ();
+ const int32_t audio_in = in.n_audio();
int32_t audio_out;
- bool found = false;
AUPluginInfoPtr pinfo = boost::dynamic_pointer_cast<AUPluginInfo>(get_info());
/* lets check MIDI first */
- if (in.n_midi() > 0) {
- if (!_has_midi_input) {
- return false;
- }
+ if (in.n_midi() > 0 && !_has_midi_input && !imprecise) {
+ return false;
}
vector<pair<int,int> >& io_configs = pinfo->cache.io_configs;
DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("%1 has %2 IO configurations, looking for %3 in, %4 out\n",
name(), io_configs.size(), in, out));
- //Ardour expects the plugin to tell it the output
- //configuration but AU plugins can have multiple I/O
- //configurations in most cases. so first lets see
- //if there's a configuration that keeps out==in
-
- if (in.n_midi() > 0 && audio_in == 0) {
- audio_out = 2; // prefer stereo version if available.
- } else {
- audio_out = audio_in;
- }
+ // preferred setting (provided by plugin_insert)
+ const int preferred_out = out.n_audio ();
+ audio_out = out.n_audio ();
+ bool found = false;
+ bool exact_match = false;
/* kAudioUnitProperty_SupportedNumChannels
* https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html#//apple_ref/doc/uid/TP40003278-CH12-SW20
int32_t possible_in = i->first;
int32_t possible_out = i->second;
- if ((possible_in == audio_in) && (possible_out == audio_out)) {
+ if ((possible_in == audio_in) && (possible_out == preferred_out)) {
DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("\tCHOSEN: %1 in %2 out to match in %3 out %4\n",
- possible_in, possible_out,
- in, out));
-
- out.set (DataType::MIDI, 0);
- out.set (DataType::AUDIO, audio_out);
+ possible_in, possible_out,
+ in, out));
- return 1;
+ // exact match
+ _output_configs.insert (preferred_out);
+ exact_match = true;
+ found = true;
+ break;
}
}
/* now allow potentially "imprecise" matches */
+ int32_t audio_out = -1;
+ float penalty = 9999;
+ int used_possible_in = 0;
+
+#define FOUNDCFG(nch) { \
+ float p = fabsf ((float)(nch) - preferred_out); \
+ _output_configs.insert (nch); \
+ if ((nch) > preferred_out) { p *= 1.1; } \
+ if (p < penalty) { \
+ used_possible_in = possible_in; \
+ audio_out = (nch); \
+ penalty = p; \
+ found = true; \
+ } \
+}
+
+#define ANYTHINGGOES \
+ _output_configs.insert (0);
- audio_out = -1;
+#define UPTO(nch) { \
+ for (int n = 1; n < nch; ++n) { \
+ _output_configs.insert (n); \
+ } \
+}
for (vector<pair<int,int> >::iterator i = io_configs.begin(); i != io_configs.end(); ++i) {
}
if (possible_in == 0) {
-
- /* instrument plugin, always legal but throws away inputs ...
- */
-
+ /* no inputs, generators & instruments */
if (possible_out == -1) {
/* any configuration possible, provide stereo output */
- audio_out = 2;
- found = true;
+ FOUNDCFG (preferred_out);
+ ANYTHINGGOES;
} else if (possible_out == -2) {
- /* plugins shouldn't really use (0,-2) but might.
- any configuration possible, provide stereo output
- */
- audio_out = 2;
- found = true;
+ /* invalid, should be (0, -1) */
+ FOUNDCFG (preferred_out);
+ ANYTHINGGOES;
} else if (possible_out < -2) {
- /* explicitly variable number of outputs.
- *
- * We really need to ask the user in this case.
- * stereo will be correct in 99.9% of all cases.
- */
- audio_out = 2;
- found = true;
+ /* variable number of outputs up to -N, */
+ FOUNDCFG (min (-possible_out, preferred_out));
+ UPTO (-possible_out);
} else {
/* exact number of outputs */
- audio_out = possible_out;
- found = true;
+ FOUNDCFG (possible_out);
}
}
if (possible_in == -1) {
-
/* wildcard for input */
-
if (possible_out == -1) {
- /* out much match in */
- audio_out = audio_in;
- found = true;
+ /* out must match in */
+ FOUNDCFG (audio_in);
} else if (possible_out == -2) {
/* any configuration possible, pick matching */
- audio_out = audio_in;
- found = true;
+ FOUNDCFG (preferred_out);
+ ANYTHINGGOES;
} else if (possible_out < -2) {
/* explicitly variable number of outputs, pick maximum */
- audio_out = -possible_out;
- found = true;
+ FOUNDCFG (max (-possible_out, preferred_out));
+ /* and try min, too, in case the penalty is lower */
+ FOUNDCFG (min (-possible_out, preferred_out));
+ UPTO (-possible_out)
} else {
/* exact number of outputs */
- audio_out = possible_out;
- found = true;
+ FOUNDCFG (possible_out);
}
}
if (possible_in == -2) {
-
if (possible_out == -1) {
/* any configuration possible, pick matching */
- audio_out = audio_in;
- found = true;
+ FOUNDCFG (preferred_out);
+ ANYTHINGGOES;
} else if (possible_out == -2) {
- /* plugins shouldn't really use (-2,-2) but might.
- interpret as (-1,-1).
- */
- audio_out = audio_in;
- found = true;
+ /* invalid. interpret as (-1, -1) */
+ FOUNDCFG (preferred_out);
+ ANYTHINGGOES;
} else if (possible_out < -2) {
- /* explicitly variable number of outputs, pick maximum */
- audio_out = -possible_out;
- found = true;
+ /* invalid, interpret as (<-2, <-2)
+ * variable number of outputs up to -N, */
+ FOUNDCFG (min (-possible_out, preferred_out));
+ UPTO (-possible_out)
} else {
/* exact number of outputs */
- audio_out = possible_out;
- found = true;
+ FOUNDCFG (possible_out);
}
}
if (possible_in < -2) {
-
/* explicit variable number of inputs */
-
- if (audio_in > -possible_in) {
- /* request is too large */
+ if (audio_in > -possible_in && imprecise != NULL) {
+ // hide inputs ports
+ imprecise->set (DataType::AUDIO, -possible_in);
}
-
- if (possible_out == -1) {
- /* any output configuration possible, provide stereo out */
- audio_out = 2;
- found = true;
+ if (audio_in > -possible_in && imprecise == NULL) {
+ /* request is too large */
+ } else if (possible_out == -1) {
+ /* any output configuration possible */
+ FOUNDCFG (preferred_out);
+ ANYTHINGGOES;
} else if (possible_out == -2) {
- /* plugins shouldn't really use (<-2,-2) but might.
- interpret as (<-2,-1): any configuration possible, provide stereo output
- */
- audio_out = 2;
- found = true;
+ /* invalid. interpret as (<-2, -1) */
+ FOUNDCFG (preferred_out);
+ ANYTHINGGOES;
} else if (possible_out < -2) {
- /* explicitly variable number of outputs.
- *
- * We really need to ask the user in this case.
- * stereo will be correct in 99.9% of all cases.
- */
- audio_out = 2;
- found = true;
+ /* variable number of outputs up to -N, */
+ FOUNDCFG (min (-possible_out, preferred_out));
+ UPTO (-possible_out)
} else {
/* exact number of outputs */
- audio_out = possible_out;
- found = true;
+ FOUNDCFG (possible_out);
}
}
if (possible_in && (possible_in == audio_in)) {
-
/* exact number of inputs ... must match obviously */
-
if (possible_out == -1) {
- /* any output configuration possible, provide stereo output */
- audio_out = 2;
- found = true;
+ /* any output configuration possible */
+ FOUNDCFG (preferred_out);
+ ANYTHINGGOES;
} else if (possible_out == -2) {
- /* plugins shouldn't really use (>0,-2) but might.
- interpret as (>0,-1):
- any output configuration possible, provide stereo output
- */
- audio_out = 2;
- found = true;
+ /* plugins shouldn't really use (>0,-2), interpret as (>0,-1) */
+ FOUNDCFG (preferred_out);
+ ANYTHINGGOES;
} else if (possible_out < -2) {
- /* explicitly variable number of outputs, pick maximum */
- audio_out = -possible_out;
- found = true;
+ /* > 0, < -2 is not specified
+ * interpret as up to -N */
+ FOUNDCFG (min (-possible_out, preferred_out));
+ UPTO (-possible_out)
} else {
/* exact number of outputs */
- audio_out = possible_out;
- found = true;
+ FOUNDCFG (possible_out);
}
}
+ }
+
+ if (!found && imprecise) {
+ /* try harder */
+ for (vector<pair<int,int> >::iterator i = io_configs.begin(); i != io_configs.end(); ++i) {
+ int32_t possible_in = i->first;
+ int32_t possible_out = i->second;
+
+ assert (possible_in > 0); // all other cases will have been matched above
+ assert (possible_out !=0 || possible_in !=0); // already handled above
- if (found) {
- if (possible_in < -2 && audio_in == 0) {
- // input-port count cannot be zero, use as many ports
- // as outputs, but at most abs(possible_in)
- audio_input_cnt = max (1, min (audio_out, -possible_in));
+ imprecise->set (DataType::AUDIO, possible_in);
+ if (possible_out == -1 || possible_out == -2) {
+ FOUNDCFG (2);
+ } else if (possible_out < -2) {
+ /* explicitly variable number of outputs, pick maximum */
+ FOUNDCFG (min (-possible_out, preferred_out));
+ } else {
+ /* exact number of outputs */
+ FOUNDCFG (possible_out);
}
- break;
+ // ideally we'll also find the closest, best matching
+ // input configuration with minimal output penalty...
}
+ }
+ if (!found) {
+ DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("\tFAIL: no io configs match %1\n", in));
+ return false;
}
- if (found) {
+ if (exact_match) {
+ out.set (DataType::MIDI, 0); // currently always zero
+ out.set (DataType::AUDIO, preferred_out);
+ } else {
+ if (used_possible_in < -2 && audio_in == 0) {
+ // input-port count cannot be zero, use as many ports
+ // as outputs, but at most abs(possible_in)
+ audio_input_cnt = max (1, min (audio_out, -used_possible_in));
+ }
out.set (DataType::MIDI, 0); /// XXX
out.set (DataType::AUDIO, audio_out);
- DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("\tCHOSEN: in %1 out %2\n", in, out));
- } else {
- DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("\tFAIL: no io configs match %1\n", in));
- return false;
}
+ DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("\tCHOSEN: in %1 out %2\n", in, out));
return true;
}
// name(), inNumberFrames, ioData->mNumberBuffers));
if (input_maxbuf == 0) {
+ DEBUG_TRACE (DEBUG::AudioUnits, "AUPlugin: render callback called illegally!");
error << _("AUPlugin: render callback called illegally!") << endmsg;
return kAudioUnitErr_CannotDoInCurrentContext;
}
uint32_t limit = min ((uint32_t) ioData->mNumberBuffers, input_maxbuf);
+ ChanCount bufs_count (DataType::AUDIO, 1);
+ BufferSet& silent_bufs = _session.get_silent_buffers(bufs_count);
+
for (uint32_t i = 0; i < limit; ++i) {
ioData->mBuffers[i].mNumberChannels = 1;
ioData->mBuffers[i].mDataByteSize = sizeof (Sample) * inNumberFrames;
- /* we don't use the channel mapping because audiounits are
- * never replicated. one plugin instance uses all channels/buffers
- * passed to PluginInsert::connect_and_run()
- */
-
- ioData->mBuffers[i].mData = input_buffers->get_audio (i).data (cb_offset + input_offset);
+ bool valid = false;
+ uint32_t idx = input_map->get (DataType::AUDIO, i, &valid);
+ if (valid) {
+ ioData->mBuffers[i].mData = input_buffers->get_audio (idx).data (cb_offset + input_offset);
+ } else {
+ ioData->mBuffers[i].mData = silent_bufs.get_audio(0).data (cb_offset + input_offset);
+ }
}
cb_offset += inNumberFrames;
_last_nframes = nframes;
}
- DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("%1 in %2 out %3 MIDI %4 bufs %5 (available %6)\n",
+ /* test if we can run in-place; only compare audio buffers */
+ bool inplace = true;
+ ChanMapping::Mappings inmap (in_map.mappings ());
+ ChanMapping::Mappings outmap (out_map.mappings ());
+ assert (outmap[DataType::AUDIO].size () > 0);
+ if (inmap[DataType::AUDIO].size() > 0 && inmap != outmap) {
+ inplace = false;
+ }
+
+ DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("%1 in %2 out %3 MIDI %4 bufs %5 (available %6) Inplace: %7\n",
name(), input_channels, output_channels, _has_midi_input,
- bufs.count(), bufs.available()));
+ bufs.count(), bufs.available(), inplace));
/* the apparent number of buffers matches our input configuration, but we know that the bufferset
- has the capacity to handle our outputs.
- */
+ * has the capacity to handle our outputs.
+ */
assert (bufs.available() >= ChanCount (DataType::AUDIO, output_channels));
input_buffers = &bufs;
+ input_map = &in_map;
input_maxbuf = bufs.count().n_audio(); // number of input audio buffers
input_offset = offset;
cb_offset = 0;
buffers->mNumberBuffers = output_channels;
+ ChanCount bufs_count (DataType::AUDIO, 1);
+ BufferSet& scratch_bufs = _session.get_scratch_buffers(bufs_count);
+
for (int32_t i = 0; i < output_channels; ++i) {
buffers->mBuffers[i].mNumberChannels = 1;
buffers->mBuffers[i].mDataByteSize = nframes * sizeof (Sample);
* a non-null values tells the plugin to render into the buffer pointed
* at by the value.
*/
- buffers->mBuffers[i].mData = 0;
+ if (inplace) {
+ buffers->mBuffers[i].mData = 0;
+ } else {
+ bool valid = false;
+ uint32_t idx = out_map.get (DataType::AUDIO, i, &valid);
+ if (valid) {
+ buffers->mBuffers[i].mData = bufs.get_audio (idx).data (offset);
+ } else {
+ buffers->mBuffers[i].mData = scratch_bufs.get_audio(0).data(offset);
+ }
+ }
}
if (_has_midi_input) {
}
}
- /* does this really mean anything ?
- */
+ /* does this really mean anything ? */
ts.mSampleTime = frames_processed;
ts.mFlags = kAudioTimeStampSampleTimeValid;
int32_t i;
for (i = 0; i < limit; ++i) {
- Sample* expected_buffer_address= bufs.get_audio (i).data (offset);
+ bool valid = false;
+ uint32_t idx = out_map.get (DataType::AUDIO, i, &valid);
+ if (!valid) continue;
+ Sample* expected_buffer_address = bufs.get_audio (idx).data (offset);
if (expected_buffer_address != buffers->mBuffers[i].mData) {
/* plugin provided its own buffer for output so copy it back to where we want it
*/
*/
for (;i < output_channels; ++i) {
- memset (bufs.get_audio (i).data (offset), 0, nframes * sizeof (Sample));
+ bool valid = false;
+ uint32_t idx = out_map.get (DataType::AUDIO, i, &valid);
+ if (!valid) continue;
+ memset (bufs.get_audio (idx).data (offset), 0, nframes * sizeof (Sample));
}
return 0;
include "<manufacturer>/<plugin-name>" in their path.
*/
- Plugin* p = (Plugin *) arg;
- string match = p->maker();
+ AUPluginInfo* p = (AUPluginInfo *) arg;
+ string match = p->creator;
match += '/';
- match += p->name();
+ match += p->name;
ret = str.find (match) != string::npos;
if (ret == false) {
- string m = p->maker ();
- string n = p->name ();
+ string m = p->creator;
+ string n = p->name;
strip_whitespace_edges (m);
strip_whitespace_edges (n);
match = m;
user_preset_map.clear ();
- find_files_matching_filter (preset_files, preset_search_path, au_preset_filter, this, true, true, true);
+ PluginInfoPtr nfo = get_info();
+ find_files_matching_filter (preset_files, preset_search_path, au_preset_filter,
+ boost::dynamic_pointer_cast<AUPluginInfo> (nfo).get(),
+ true, true, true);
if (preset_files.empty()) {
DEBUG_TRACE (DEBUG::AudioUnits, "AU No Preset Files found for given plugin.\n");
}
}
+std::vector<Plugin::PresetRecord>
+AUPluginInfo::get_presets (bool user_only) const
+{
+ std::vector<Plugin::PresetRecord> p;
+ boost::shared_ptr<CAComponent> comp;
+#ifndef NO_PLUGIN_STATE
+ try {
+ comp = boost::shared_ptr<CAComponent>(new CAComponent(*descriptor));
+ if (!comp->IsValid()) {
+ throw failed_constructor();
+ }
+ } catch (failed_constructor& err) {
+ return p;
+ }
+
+ // user presets
+
+ if (!preset_search_path_initialized) {
+ Glib::ustring p = Glib::get_home_dir();
+ p += "/Library/Audio/Presets:";
+ 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));
+ }
+
+ vector<string> preset_files;
+ find_files_matching_filter (preset_files, preset_search_path, au_preset_filter, const_cast<AUPluginInfo*>(this), true, true, true);
+
+ for (vector<string>::iterator x = preset_files.begin(); x != preset_files.end(); ++x) {
+ string path = *x;
+ string preset_name;
+ preset_name = Glib::path_get_basename (path);
+ preset_name = preset_name.substr (0, preset_name.find_last_of ('.'));
+ if (check_and_get_preset_name (comp.get()->Comp(), path, preset_name)) {
+ p.push_back (Plugin::PresetRecord (path, preset_name));
+ }
+ }
+
+ if (user_only) {
+ return p;
+ }
+
+ // factory presets
+
+ CFArrayRef presets;
+ UInt32 dataSize;
+ Boolean isWritable;
+
+ boost::shared_ptr<CAAudioUnit> unit (new CAAudioUnit);
+ if (noErr != CAAudioUnit::Open (*(comp.get()), *unit)) {
+ return p;
+ }
+ if (noErr != unit->GetPropertyInfo (kAudioUnitProperty_FactoryPresets, kAudioUnitScope_Global, 0, &dataSize, &isWritable)) {
+ unit->Uninitialize ();
+ return p;
+ }
+ if (noErr != unit->GetProperty (kAudioUnitProperty_FactoryPresets, kAudioUnitScope_Global, 0, (void*) &presets, &dataSize)) {
+ unit->Uninitialize ();
+ return p;
+ }
+ if (!presets) {
+ unit->Uninitialize ();
+ return p;
+ }
+
+ CFIndex cnt = CFArrayGetCount (presets);
+ for (CFIndex i = 0; i < cnt; ++i) {
+ AUPreset* preset = (AUPreset*) CFArrayGetValueAtIndex (presets, i);
+ string const uri = string_compose ("%1", i);
+ string name = CFStringRefToStdString (preset->presetName);
+ p.push_back (Plugin::PresetRecord (uri, name, false));
+ }
+ CFRelease (presets);
+ unit->Uninitialize ();
+
+#endif // NO_PLUGIN_STATE
+ return p;
+}
+
Glib::ustring
AUPluginInfo::au_cache_path ()
{
continue;
}
+ bool has_midi_in = false;
+
AUPluginInfoPtr info (new AUPluginInfo
(boost::shared_ptr<CAComponentDescription> (new CAComponentDescription(temp))));
break;
case kAudioUnitType_MusicDevice:
info->category = _("AudioUnit Instruments");
+ has_midi_in = true;
break;
case kAudioUnitType_MusicEffect:
info->category = _("AudioUnit MusicEffects");
+ has_midi_in = true;
break;
case kAudioUnitType_Effect:
info->category = _("AudioUnit Effects");
info->n_inputs.set (DataType::AUDIO, 1);
}
+ info->n_inputs.set (DataType::MIDI, has_midi_in ? 1 : 0);
+
if (possible_out > 0) {
info->n_outputs.set (DataType::AUDIO, possible_out);
} else {
}
bool
-AUPluginInfo::needs_midi_input ()
+AUPluginInfo::needs_midi_input () const
{
return is_effect_with_midi_input () || is_instrument ();
}