AU support, plus changes in Plugin to make unique_id a string

git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@2754 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2007-12-10 21:29:51 +00:00
parent c467d75306
commit f3dd3e6b18
13 changed files with 709 additions and 144 deletions

View file

@ -30,6 +30,8 @@
#include <ardour/plugin.h>
#include <AudioUnit/AudioUnit.h>
#include <boost/shared_ptr.hpp>
class CAComponent;
@ -48,10 +50,10 @@ class AUPlugin : public ARDOUR::Plugin
AUPlugin (AudioEngine& engine, Session& session, CAComponent* comp);
virtual ~AUPlugin ();
uint32_t unique_id () const;
std::string unique_id () const;
const char * label () const;
const char * name () const { return _info->name.c_str(); }
const char * maker () const;
const char * maker () const { return _info->creator.c_str(); }
uint32_t parameter_count () const;
float default_value (uint32_t port);
nframes_t latency () const;
@ -84,34 +86,63 @@ class AUPlugin : public ARDOUR::Plugin
bool has_editor () const;
bool fixed_io() const { return false; }
int32_t can_support_input_configuration (int32_t in);
int32_t compute_output_streams (int32_t nplugins);
uint32_t output_streams() const;
uint32_t input_streams() const;
CAAudioUnit* get_au () { return unit; }
CAComponent* get_comp () { return comp; }
OSStatus render_callback(AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList* ioData);
private:
CAComponent* comp;
CAAudioUnit* unit;
AudioBufferList* in_list;
AudioBufferList* out_list;
CAAudioUnit* unit;
AudioStreamBasicDescription streamFormat;
bool initialized;
AudioBufferList* buffers;
UInt32 global_elements;
UInt32 output_elements;
UInt32 input_elements;
int set_output_format ();
int set_input_format ();
int set_stream_format (int scope, uint32_t cnt);
int _set_block_size (nframes_t nframes);
std::vector<std::pair<uint32_t, uint32_t> > parameter_map;
uint32_t current_maxbuf;
nframes_t current_offset;
nframes_t cb_offset;
vector<Sample*>* current_buffers;
nframes_t frames_processed;
};
typedef boost::shared_ptr<AUPlugin> AUPluginPtr;
class AUPluginInfo : public PluginInfo {
public:
AUPluginInfo () { };
AUPluginInfo (CAComponentDescription*);
~AUPluginInfo ();
CAComponentDescription* desc;
static PluginInfoList discover ();
PluginPtr load (Session& session);
static PluginInfoList discover ();
static void get_names (CAComponentDescription&, std::string& name, Glib::ustring& maker);
static std::string stringify_descriptor (const CAComponentDescription&);
private:
static std::string get_name (CAComponentDescription&);
void setup_nchannels (CAComponentDescription&);
CAComponentDescription* descriptor;
static void discover_music (PluginInfoList&);
static void discover_fx (PluginInfoList&);
static void discover_by_description (PluginInfoList&, CAComponentDescription&);
};
typedef boost::shared_ptr<AUPluginInfo> AUPluginInfoPtr;

View file

@ -52,7 +52,7 @@ class LadspaPlugin : public ARDOUR::Plugin
/* Plugin interface */
uint32_t unique_id() const { return descriptor->UniqueID; }
std::string unique_id() const;
const char * label() const { return descriptor->Label; }
const char * name() const { return descriptor->Name; }
const char * maker() const { return descriptor->Maker; }

View file

@ -67,11 +67,11 @@ class PluginInfo {
string category;
Glib::ustring creator;
Glib::ustring path;
uint32_t n_inputs;
uint32_t n_outputs;
int32_t n_inputs;
int32_t n_outputs;
ARDOUR::PluginType type;
long unique_id;
std::string unique_id;
virtual PluginPtr load (Session& session) = 0;
@ -108,7 +108,7 @@ class Plugin : public PBD::StatefulDestructible
bool max_unbound;
};
virtual uint32_t unique_id() const = 0;
virtual std::string unique_id() const = 0;
virtual const char * label() const = 0;
virtual const char * name() const = 0;
virtual const char * maker() const = 0;
@ -142,6 +142,12 @@ class Plugin : public PBD::StatefulDestructible
virtual bool has_editor() const = 0;
sigc::signal<void,uint32_t,float> ParameterChanged;
virtual bool fixed_io() const { return true; }
virtual int32_t can_support_input_configuration (int32_t in);
virtual int32_t compute_output_streams (int32_t nplugins);
virtual uint32_t output_streams() const;
virtual uint32_t input_streams() const;
PBD::Controllable *get_nth_control (uint32_t, bool do_not_create = false);
void make_nth_control (uint32_t, const XMLNode&);
@ -186,7 +192,7 @@ class Plugin : public PBD::StatefulDestructible
vector<PortControllable*> controls;
};
PluginPtr find_plugin(ARDOUR::Session&, string name, long unique_id, ARDOUR::PluginType);
PluginPtr find_plugin(ARDOUR::Session&, string unique_id, ARDOUR::PluginType);
} // namespace ARDOUR

View file

@ -40,6 +40,7 @@ class PluginManager {
ARDOUR::PluginInfoList &vst_plugin_info () { return _vst_plugin_info; }
ARDOUR::PluginInfoList &ladspa_plugin_info () { return _ladspa_plugin_info; }
ARDOUR::PluginInfoList &au_plugin_info () { return _au_plugin_info; }
void refresh ();
@ -51,6 +52,8 @@ class PluginManager {
private:
ARDOUR::PluginInfoList _vst_plugin_info;
ARDOUR::PluginInfoList _ladspa_plugin_info;
ARDOUR::PluginInfoList _au_plugin_info;
std::map<uint32_t, std::string> rdf_type;
std::string ladspa_path;
@ -64,6 +67,9 @@ class PluginManager {
void add_vst_presets ();
void add_presets (std::string domain);
int au_discover ();
void au_refresh ();
int vst_discover_from_path (std::string path);
int vst_discover (std::string path);

View file

@ -56,7 +56,7 @@ class VSTPlugin : public ARDOUR::Plugin
/* Plugin interface */
uint32_t unique_id() const;
std::string unique_id() const;
const char * label() const;
const char * name() const;
const char * maker() const;

View file

@ -18,10 +18,16 @@
*/
#include <sstream>
#include <pbd/transmitter.h>
#include <pbd/xml++.h>
#include <pbd/whitespace.h>
#include <glibmm/thread.h>
#include <ardour/audioengine.h>
#include <ardour/io.h>
#include <ardour/audio_unit.h>
#include <ardour/session.h>
#include <ardour/utils.h>
@ -37,13 +43,31 @@ using namespace std;
using namespace PBD;
using namespace ARDOUR;
static OSStatus
_render_callback(void *userData,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList* ioData)
{
return ((AUPlugin*)userData)->render_callback (ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
}
AUPlugin::AUPlugin (AudioEngine& engine, Session& session, CAComponent* _comp)
:
Plugin (engine, session),
comp (_comp),
unit (new CAAudioUnit)
unit (new CAAudioUnit),
initialized (false),
buffers (0),
current_maxbuf (0),
current_offset (0),
current_buffers (0),
frames_processed (0)
{
OSErr err = CAAudioUnit::Open (*comp, *unit);
if (err != noErr) {
error << _("AudioUnit: Could not convert CAComponent to CAAudioUnit") << endmsg;
delete unit;
@ -51,7 +75,42 @@ AUPlugin::AUPlugin (AudioEngine& engine, Session& session, CAComponent* _comp)
throw failed_constructor ();
}
unit->Initialize ();
AURenderCallbackStruct renderCallbackInfo;
renderCallbackInfo.inputProc = _render_callback;
renderCallbackInfo.inputProcRefCon = this;
if ((err = unit->SetProperty (kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input,
0, (void*) &renderCallbackInfo, sizeof(renderCallbackInfo))) != 0) {
cerr << "cannot install render callback (err = " << err << ')' << endl;
delete unit;
delete comp;
throw failed_constructor();
}
unit->GetElementCount (kAudioUnitScope_Input, input_elements);
unit->GetElementCount (kAudioUnitScope_Output, output_elements);
// set up the basic stream format. these fields do not change
streamFormat.mSampleRate = session.frame_rate();
streamFormat.mFormatID = kAudioFormatLinearPCM;
streamFormat.mFormatFlags = kAudioFormatFlagIsFloat|kAudioFormatFlagIsPacked|kAudioFormatFlagIsNonInterleaved;
streamFormat.mBitsPerChannel = 32;
streamFormat.mFramesPerPacket = 1;
// subject to later modification as we discover channel counts
streamFormat.mBytesPerPacket = 4;
streamFormat.mBytesPerFrame = 4;
streamFormat.mChannelsPerFrame = 1;
if (_set_block_size (_session.get_block_size())) {
error << _("AUPlugin: cannot set processing block size") << endmsg;
delete unit;
delete comp;
throw failed_constructor();
}
}
AUPlugin::~AUPlugin ()
@ -60,43 +119,26 @@ AUPlugin::~AUPlugin ()
unit->Uninitialize ();
delete unit;
}
if (buffers) {
free (buffers);
}
if (comp) {
delete comp;
}
if (in_list) {
delete in_list;
}
if (out_list) {
delete out_list;
}
}
AUPluginInfo::~AUPluginInfo ()
{
if (desc) {
delete desc;
}
}
uint32_t
string
AUPlugin::unique_id () const
{
return 0;
return AUPluginInfo::stringify_descriptor (comp->Desc());
}
const char *
AUPlugin::label () const
{
return "AUPlugin label";
}
const char *
AUPlugin::maker () const
{
return "AUplugin maker";
return _info->name.c_str();
}
uint32_t
@ -121,7 +163,7 @@ AUPlugin::latency () const
void
AUPlugin::set_parameter (uint32_t which, float val)
{
unit->SetParameter (parameter_map[which].first, parameter_map[which].second, 0, val);
// unit->SetParameter (parameter_map[which].first, parameter_map[which].second, 0, val);
}
float
@ -129,7 +171,7 @@ AUPlugin::get_parameter (uint32_t which) const
{
float outValue = 0.0;
unit->GetParameter(parameter_map[which].first, parameter_map[which].second, 0, outValue);
// unit->GetParameter(parameter_map[which].first, parameter_map[which].second, 0, outValue);
return outValue;
}
@ -149,19 +191,168 @@ AUPlugin::nth_parameter (uint32_t which, bool& ok) const
void
AUPlugin::activate ()
{
unit->GlobalReset ();
if (!initialized) {
OSErr err;
if ((err = unit->Initialize()) != noErr) {
error << string_compose (_("AUPlugin: cannot initialize plugin (err = %1)"), err) << endmsg;
} else {
frames_processed = 0;
initialized = true;
}
}
}
void
AUPlugin::deactivate ()
{
// not needed. GlobalReset () takes care of it.
unit->GlobalReset ();
}
void
AUPlugin::set_block_size (nframes_t nframes)
{
_set_block_size (nframes);
}
int
AUPlugin::_set_block_size (nframes_t nframes)
{
bool was_initialized = initialized;
UInt32 numFrames = nframes;
OSErr err;
if (initialized) {
unit->Uninitialize ();
}
set_input_format ();
set_output_format ();
if ((err = unit->SetProperty (kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global,
0, &numFrames, sizeof (numFrames))) != noErr) {
cerr << "cannot set max frames (err = " << err << ')' << endl;
return -1;
}
if (was_initialized) {
activate ();
}
return 0;
}
int32_t
AUPlugin::can_support_input_configuration (int32_t in)
{
streamFormat.mBytesPerPacket = 4 * in;
streamFormat.mBytesPerFrame = 4 * in;
streamFormat.mChannelsPerFrame = in;
if (set_input_format () == 0) {
return 1;
} else {
return -1;
}
}
int
AUPlugin::set_input_format ()
{
return set_stream_format (kAudioUnitScope_Input, input_elements);
}
int
AUPlugin::set_output_format ()
{
return set_stream_format (kAudioUnitScope_Output, output_elements);
}
int
AUPlugin::set_stream_format (int scope, uint32_t cnt)
{
OSErr result;
for (uint32_t i = 0; i < cnt; ++i) {
if ((result = unit->SetFormat (scope, i, streamFormat)) != 0) {
error << string_compose (_("AUPlugin: could not set stream format for %1/%2"),
(scope == kAudioUnitScope_Input ? "input" : "output"), i) << endmsg;
return -1;
}
}
return 0;
}
int32_t
AUPlugin::compute_output_streams (int32_t nplugins)
{
/* we will never replicate AU plugins - either they can do the I/O we need
or not. thus, we can ignore nplugins entirely.
*/
if (set_output_format() == 0) {
if (buffers) {
free (buffers);
buffers = 0;
}
buffers = (AudioBufferList *) malloc (offsetof(AudioBufferList, mBuffers) +
streamFormat.mChannelsPerFrame * sizeof(AudioBuffer));
Glib::Mutex::Lock em (_session.engine().process_lock());
IO::MoreOutputs (streamFormat.mChannelsPerFrame);
return streamFormat.mChannelsPerFrame;
} else {
return -1;
}
}
uint32_t
AUPlugin::output_streams() const
{
if (!initialized) {
warning << _("AUPlugin: output_streams() called without calling Initialize!") << endmsg;
return 1;
}
return streamFormat.mChannelsPerFrame;
}
uint32_t
AUPlugin::input_streams() const
{
if (!initialized) {
warning << _("AUPlugin: input_streams() called without calling Initialize!") << endmsg;
return 1;
}
return streamFormat.mChannelsPerFrame;
}
OSStatus
AUPlugin::render_callback(AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList* ioData)
{
/* not much to do - the data is already in the buffers given to us in connect_and_run() */
if (current_maxbuf == 0) {
error << _("AUPlugin: render callback called illegally!") << endmsg;
return kAudioUnitErr_CannotDoInCurrentContext;
}
for (uint32_t i = 0; i < current_maxbuf; ++i) {
ioData->mBuffers[i].mNumberChannels = 1;
ioData->mBuffers[i].mDataByteSize = sizeof (Sample) * inNumberFrames;
ioData->mBuffers[i].mData = (*current_buffers)[i] + cb_offset + current_offset;
}
cb_offset += inNumberFrames;
return noErr;
}
int
@ -169,17 +360,37 @@ AUPlugin::connect_and_run (vector<Sample*>& bufs, uint32_t maxbuf, int32_t& in,
{
AudioUnitRenderActionFlags flags = 0;
AudioTimeStamp ts;
AudioBufferList abl;
abl.mNumberBuffers = 1;
abl.mBuffers[0].mNumberChannels = 1;
abl.mBuffers[0].mDataByteSize = nframes * sizeof(Sample);
abl.mBuffers[0].mData = &bufs[0];
unit->Render (&flags, &ts, 0, 0, &abl);
return 0;
current_buffers = &bufs;
current_maxbuf = maxbuf;
current_offset = offset;
cb_offset = 0;
buffers->mNumberBuffers = maxbuf;
for (uint32_t i = 0; i < maxbuf; ++i) {
buffers->mBuffers[i].mNumberChannels = 1;
buffers->mBuffers[i].mDataByteSize = nframes * sizeof (Sample);
buffers->mBuffers[i].mData = 0;
}
ts.mSampleTime = frames_processed;
ts.mFlags = kAudioTimeStampSampleTimeValid;
if (unit->Render (&flags, &ts, 0, nframes, buffers) == noErr) {
current_maxbuf = 0;
frames_processed += nframes;
for (uint32_t i = 0; i < maxbuf; ++i) {
if (bufs[i] + offset != buffers->mBuffers[i].mData) {
memcpy (bufs[i]+offset, buffers->mBuffers[i].mData, nframes * sizeof (Sample));
}
}
return 0;
}
return -1;
}
set<uint32_t>
@ -229,8 +440,8 @@ AUPlugin::parameter_is_output (uint32_t) const
XMLNode&
AUPlugin::get_state()
{
XMLNode* root = new XMLNode (state_node_name());
XMLNode *root = new XMLNode (state_node_name());
LocaleGuard lg (X_("POSIX"));
return *root;
}
@ -263,7 +474,22 @@ AUPlugin::get_presets ()
bool
AUPlugin::has_editor () const
{
return false;
// even if the plugin doesn't have its own editor, the AU API can be used
// to create one that looks native.
return true;
}
AUPluginInfo::AUPluginInfo (CAComponentDescription* d)
: descriptor (d)
{
}
AUPluginInfo::~AUPluginInfo ()
{
if (descriptor) {
delete descriptor;
}
}
PluginPtr
@ -272,7 +498,7 @@ AUPluginInfo::load (Session& session)
try {
PluginPtr plugin;
CAComponent* comp = new CAComponent(*desc);
CAComponent* comp = new CAComponent(*descriptor);
if (!comp->IsValid()) {
error << ("AudioUnit: not a valid Component") << endmsg;
@ -294,6 +520,28 @@ AUPluginInfo::discover ()
{
PluginInfoList plugs;
discover_fx (plugs);
discover_music (plugs);
return plugs;
}
void
AUPluginInfo::discover_music (PluginInfoList& plugs)
{
CAComponentDescription desc;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
desc.componentSubType = 0;
desc.componentManufacturer = 0;
desc.componentType = kAudioUnitType_MusicEffect;
discover_by_description (plugs, desc);
}
void
AUPluginInfo::discover_fx (PluginInfoList& plugs)
{
CAComponentDescription desc;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
@ -301,35 +549,145 @@ AUPluginInfo::discover ()
desc.componentManufacturer = 0;
desc.componentType = kAudioUnitType_Effect;
discover_by_description (plugs, desc);
}
void
AUPluginInfo::discover_by_description (PluginInfoList& plugs, CAComponentDescription& desc)
{
Component comp = 0;
comp = FindNextComponent (NULL, &desc);
while (comp != NULL) {
CAComponentDescription temp;
GetComponentInfo (comp, &temp, NULL, NULL, NULL);
AUPluginInfoPtr plug(new AUPluginInfo);
plug->name = AUPluginInfo::get_name (temp);
plug->type = ARDOUR::AudioUnit;
plug->n_inputs = 0;
plug->n_outputs = 0;
// plug->setup_nchannels (temp);
plug->category = "AudioUnit";
plug->desc = new CAComponentDescription(temp);
plugs.push_back(plug);
AUPluginInfoPtr info (new AUPluginInfo (new CAComponentDescription(temp)));
/* no panners, format converters or i/o AU's for our purposes
*/
switch (info->descriptor->Type()) {
case kAudioUnitType_Panner:
case kAudioUnitType_OfflineEffect:
case kAudioUnitType_FormatConverter:
continue;
default:
break;
}
switch (info->descriptor->SubType()) {
case kAudioUnitSubType_DefaultOutput:
case kAudioUnitSubType_SystemOutput:
case kAudioUnitSubType_GenericOutput:
case kAudioUnitSubType_AUConverter:
continue;
break;
case kAudioUnitSubType_DLSSynth:
info->category = "DLSSynth";
break;
case kAudioUnitType_MusicEffect:
info->category = "MusicEffect";
break;
case kAudioUnitSubType_Varispeed:
info->category = "Varispeed";
break;
case kAudioUnitSubType_Delay:
info->category = "Delay";
break;
case kAudioUnitSubType_LowPassFilter:
info->category = "LowPassFilter";
break;
case kAudioUnitSubType_HighPassFilter:
info->category = "HighPassFilter";
break;
case kAudioUnitSubType_BandPassFilter:
info->category = "BandPassFilter";
break;
case kAudioUnitSubType_HighShelfFilter:
info->category = "HighShelfFilter";
break;
case kAudioUnitSubType_LowShelfFilter:
info->category = "LowShelfFilter";
break;
case kAudioUnitSubType_ParametricEQ:
info->category = "ParametricEQ";
break;
case kAudioUnitSubType_GraphicEQ:
info->category = "GraphicEQ";
break;
case kAudioUnitSubType_PeakLimiter:
info->category = "PeakLimiter";
break;
case kAudioUnitSubType_DynamicsProcessor:
info->category = "DynamicsProcessor";
break;
case kAudioUnitSubType_MultiBandCompressor:
info->category = "MultiBandCompressor";
break;
case kAudioUnitSubType_MatrixReverb:
info->category = "MatrixReverb";
break;
case kAudioUnitType_Mixer:
info->category = "Mixer";
break;
case kAudioUnitSubType_StereoMixer:
info->category = "StereoMixer";
break;
case kAudioUnitSubType_3DMixer:
info->category = "3DMixer";
break;
case kAudioUnitSubType_MatrixMixer:
info->category = "MatrixMixer";
break;
default:
info->category = "";
}
AUPluginInfo::get_names (temp, info->name, info->creator);
info->type = ARDOUR::AudioUnit;
info->unique_id = stringify_descriptor (*info->descriptor);
/* mark the plugin as having flexible i/o */
info->n_inputs = -1;
info->n_outputs = -1;
plugs.push_back (info);
comp = FindNextComponent (comp, &desc);
}
return plugs;
}
string
AUPluginInfo::get_name (CAComponentDescription& comp_desc)
void
AUPluginInfo::get_names (CAComponentDescription& comp_desc, std::string& name, Glib::ustring& maker)
{
CFStringRef itemName = NULL;
// Marc Poirier -style item name
// Marc Poirier-style item name
CAComponent auComponent (comp_desc);
if (auComponent.IsValid()) {
CAComponentDescription dummydesc;
@ -363,23 +721,36 @@ AUPluginInfo::get_name (CAComponentDescription& comp_desc)
CFRelease(compManufacturerString);
}
return CFStringRefToStdString(itemName);
}
string str = CFStringRefToStdString(itemName);
string::size_type colon = str.find (':');
void
AUPluginInfo::setup_nchannels (CAComponentDescription& comp_desc)
{
CAAudioUnit unit;
CAAudioUnit::Open (comp_desc, unit);
if (unit.SupportsNumChannels()) {
n_inputs = n_outputs = 0;
if (colon) {
name = str.substr (colon+1);
maker = str.substr (0, colon);
// strip_whitespace_edges (maker);
// strip_whitespace_edges (name);
} else {
AUChannelInfo cinfo;
size_t info_size = sizeof(cinfo);
OSStatus err = AudioUnitGetProperty (unit.AU(), kAudioUnitProperty_SupportedNumChannels, kAudioUnitScope_Global,
0, &cinfo, &info_size);
name = str;
maker = "unknown";
}
}
// from CAComponentDescription.cpp (in libs/appleutility in ardour source)
extern char *StringForOSType (OSType t, char *writeLocation);
std::string
AUPluginInfo::stringify_descriptor (const CAComponentDescription& desc)
{
char str[24];
stringstream s;
s << StringForOSType (desc.Type(), str);
s << " - ";
s << StringForOSType (desc.SubType(), str);
s << " - ";
s << StringForOSType (desc.Manu(), str);
return s.str();
}

View file

@ -20,6 +20,7 @@
#include <unistd.h>
#include <cerrno>
#include <vector>
#include <sstream>
#include <glibmm/timer.h>
#include <pbd/pthread_utils.h>

View file

@ -75,7 +75,7 @@ PluginInsert::PluginInsert (Session& s, boost::shared_ptr<Plugin> plug, Placemen
init ();
{
if (_plugins[0]->fixed_io()) {
Glib::Mutex::Lock em (_session.engine().process_lock());
IO::MoreOutputs (output_streams ());
}
@ -94,7 +94,7 @@ PluginInsert::PluginInsert (Session& s, const XMLNode& node)
_plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed));
{
if (_plugins[0]->fixed_io()) {
Glib::Mutex::Lock em (_session.engine().process_lock());
IO::MoreOutputs (output_streams());
}
@ -182,13 +182,24 @@ PluginInsert::auto_state_changed (uint32_t which)
uint32_t
PluginInsert::output_streams() const
{
return _plugins[0]->get_info()->n_outputs * _plugins.size();
int32_t out = _plugins[0]->get_info()->n_outputs;
if (out < 0) {
return _plugins[0]->output_streams ();
} else {
return out * _plugins.size();
}
}
uint32_t
PluginInsert::input_streams() const
{
return _plugins[0]->get_info()->n_inputs * _plugins.size();
int32_t in = _plugins[0]->get_info()->n_inputs;
if (in < 0) {
return _plugins[0]->input_streams ();
} else {
return in * _plugins.size();
}
}
uint32_t
@ -366,12 +377,17 @@ PluginInsert::run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nf
uint32_t in = _plugins[0]->get_info()->n_inputs;
uint32_t out = _plugins[0]->get_info()->n_outputs;
if (out > in) {
/* not active, but something has make up for any channel count increase */
if (in < 0 || out < 0) {
for (uint32_t n = out - in; n < out; ++n) {
memcpy (bufs[n], bufs[in - 1], sizeof (Sample) * nframes);
} else {
if (out > in) {
/* not active, but something has make up for any channel count increase */
for (uint32_t n = out - in; n < out; ++n) {
memcpy (bufs[n], bufs[in - 1], sizeof (Sample) * nframes);
}
}
}
}
@ -528,7 +544,14 @@ PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
int32_t
PluginInsert::compute_output_streams (int32_t cnt) const
{
return _plugins[0]->get_info()->n_outputs * cnt;
int32_t outputs;
if ((outputs = _plugins[0]->get_info()->n_outputs) < 0) {
// have to ask the plugin itself, because it has flexible I/O
return _plugins[0]->compute_output_streams (cnt);
}
return outputs * cnt;
}
int32_t
@ -543,6 +566,12 @@ PluginInsert::can_support_input_configuration (int32_t in) const
int32_t outputs = _plugins[0]->get_info()->n_outputs;
int32_t inputs = _plugins[0]->get_info()->n_inputs;
if (outputs < 0 || inputs < 0) {
/* have to ask the plugin because its got reconfigurable I/O
*/
return _plugins[0]->can_support_input_configuration (in);
}
if (inputs == 0) {
/* instrument plugin, always legal, but it throws
@ -591,13 +620,7 @@ PluginInsert::state (bool full)
node->add_child_nocopy (Redirect::state (full));
node->add_property ("type", _plugins[0]->state_node_name());
snprintf(buf, sizeof(buf), "%s", _plugins[0]->name());
node->add_property("id", string(buf));
if (_plugins[0]->state_node_name() == "ladspa") {
char buf[32];
snprintf (buf, sizeof (buf), "%ld", _plugins[0]->get_info()->unique_id);
node->add_property("unique-id", string(buf));
}
node->add_property("unique-id", _plugins[0]->unique_id());
node->add_property("count", string_compose("%1", _plugins.size()));
node->add_child_nocopy (_plugins[0]->get_state());
@ -641,7 +664,6 @@ PluginInsert::set_state(const XMLNode& node)
XMLNodeIterator niter;
XMLPropertyList plist;
const XMLProperty *prop;
long unique = 0;
ARDOUR::PluginType type;
if ((prop = node.property ("type")) == 0) {
@ -653,6 +675,8 @@ PluginInsert::set_state(const XMLNode& node)
type = ARDOUR::LADSPA;
} else if (prop->value() == X_("vst")) {
type = ARDOUR::VST;
} else if (prop->value() == X_("audiounit")) {
type = ARDOUR::AudioUnit;
} else {
error << string_compose (_("unknown plugin type %1 in plugin insert state"),
prop->value())
@ -661,22 +685,27 @@ PluginInsert::set_state(const XMLNode& node)
}
prop = node.property ("unique-id");
if (prop != 0) {
unique = atol(prop->value().c_str());
}
if (prop == 0) {
#ifdef VST_SUPPORT
/* older sessions contain VST plugins with only an "id" field.
*/
if (type == ARDOUR::VST) {
if (prop = node.property ("id")) {
}
}
#endif
/* recheck */
if ((prop = node.property ("id")) == 0) {
error << _("XML node describing insert is missing the `id' field") << endmsg;
return -1;
if (prop == 0) {
error << _("Plugin has no unique ID field") << endmsg;
return -1;
}
}
boost::shared_ptr<Plugin> plugin;
if (unique != 0) {
plugin = find_plugin (_session, "", unique, type);
} else {
plugin = find_plugin (_session, prop->value(), 0, type);
}
plugin = find_plugin (_session, prop->value(), type);
if (plugin == 0) {
error << string_compose(_("Found a reference to a plugin (\"%1\") that is unknown.\n"

View file

@ -157,6 +157,15 @@ LadspaPlugin::~LadspaPlugin ()
}
}
string
LadspaPlugin::unique_id() const
{
char buf[32];
snprintf (buf, sizeof (buf), "%u", descriptor->UniqueID);
return string (buf);
}
float
LadspaPlugin::default_value (uint32_t port)
{

View file

@ -42,6 +42,10 @@
#include <ardour/ladspa_plugin.h>
#include <ardour/plugin_manager.h>
#ifdef HAVE_AUDIOUNITS
#include <ardour/audio_unit.h>
#endif
#include <pbd/stl_delete.h>
#include "i18n.h"
@ -192,7 +196,21 @@ vector<string>
Plugin::get_presets()
{
vector<string> labels;
lrdf_uris* set_uris = lrdf_get_setting_uris(unique_id());
uint32_t id;
std::string unique (unique_id());
/* XXX problem: AU plugins don't have numeric ID's.
Solution: they have a different method of providing presets.
XXX sub-problem: implement it.
*/
if (!isdigit (unique[0])) {
return labels;
}
id = atol (unique.c_str());
lrdf_uris* set_uris = lrdf_get_setting_uris(id);
if (set_uris) {
for (uint32_t i = 0; i < (uint32_t) set_uris->count; ++i) {
@ -234,6 +252,20 @@ Plugin::save_preset (string name, string domain)
{
lrdf_portvalue portvalues[parameter_count()];
lrdf_defaults defaults;
uint32_t id;
std::string unique (unique_id());
/* XXX problem: AU plugins don't have numeric ID's.
Solution: they have a different method of providing/saving presets.
XXX sub-problem: implement it.
*/
if (!isdigit (unique[0])) {
return false;
}
id = atol (unique.c_str());
defaults.count = parameter_count();
defaults.items = portvalues;
@ -252,7 +284,7 @@ Plugin::save_preset (string name, string domain)
string source(string_compose("file:%1/.%2/rdf/ardour-presets.n3", envvar, domain));
free(lrdf_add_preset(source.c_str(), name.c_str(), unique_id(), &defaults));
free(lrdf_add_preset(source.c_str(), name.c_str(), id, &defaults));
string path = string_compose("%1/.%2", envvar, domain);
if (g_mkdir_with_parents (path.c_str(), 0775)) {
@ -275,7 +307,7 @@ Plugin::save_preset (string name, string domain)
}
PluginPtr
ARDOUR::find_plugin(Session& session, string name, long unique_id, PluginType type)
ARDOUR::find_plugin(Session& session, string identifier, PluginType type)
{
PluginManager *mgr = PluginManager::the_manager();
PluginInfoList plugs;
@ -288,14 +320,12 @@ ARDOUR::find_plugin(Session& session, string name, long unique_id, PluginType ty
#ifdef VST_SUPPORT
case ARDOUR::VST:
plugs = mgr->vst_plugin_info();
unique_id = 0; // VST plugins don't have a unique id.
break;
#endif
#ifdef HAVE_AUDIOUNITS
case ARDOUR::AudioUnit:
plugs = AUPluginInfo::discover ();
unique_id = 0; // Neither do AU.
plugs = mgr->au_plugin_info();
break;
#endif
@ -304,13 +334,49 @@ ARDOUR::find_plugin(Session& session, string name, long unique_id, PluginType ty
}
PluginInfoList::iterator i;
for (i = plugs.begin(); i != plugs.end(); ++i) {
if ((name == "" || (*i)->name == name) &&
(unique_id == 0 || (*i)->unique_id == unique_id)) {
return (*i)->load (session);
if (identifier == (*i)->unique_id){
return (*i)->load (session);
}
}
return PluginPtr ((Plugin*) 0);
}
int32_t
Plugin::can_support_input_configuration (int32_t in)
{
/* LADSPA & VST should not get here because they do not
return negative i/o counts.
*/
return -1;
}
int32_t
Plugin::compute_output_streams (int32_t nplugins)
{
/* LADSPA & VST should not get here because they do not
return negative i/o counts.
*/
return -1;
}
uint32_t
Plugin::output_streams () const
{
/* LADSPA & VST should not get here because they do not
return negative i/o counts.
*/
return 0;
}
uint32_t
Plugin::input_streams () const
{
/* LADSPA & VST should not get here because they do not
return negative i/o counts.
*/
return 0;
}

View file

@ -40,6 +40,10 @@
#include <ardour/vst_plugin.h>
#endif
#ifdef HAVE_AUDIOUNITS
#include <ardour/audio_unit.h>
#endif
#include <pbd/error.h>
#include <pbd/stl_delete.h>
@ -109,6 +113,9 @@ PluginManager::refresh ()
vst_refresh ();
}
#endif // VST_SUPPORT
#ifdef HAVE_AUDIOUNITS
au_refresh ();
#endif
}
void
@ -123,6 +130,7 @@ PluginManager::ladspa_refresh ()
ladspa_discover_from_path (ladspa_path);
}
int
PluginManager::add_ladspa_directory (string path)
{
@ -273,7 +281,10 @@ PluginManager::ladspa_discover (string path)
info->n_inputs = 0;
info->n_outputs = 0;
info->type = ARDOUR::LADSPA;
info->unique_id = descriptor->UniqueID;
char buf[32];
snprintf (buf, sizeof (buf), "%u", descriptor->UniqueID);
info->unique_id = buf;
for (uint32_t n=0; n < descriptor->PortCount; ++n) {
if ( LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[n]) ) {
@ -310,7 +321,7 @@ PluginManager::get_ladspa_category (uint32_t plugin_id)
lrdf_statement* matches1 = lrdf_matches (&pattern);
if (!matches1) {
return _("Unknown");
return _("");
}
pattern.subject = matches1->object;
@ -322,7 +333,7 @@ PluginManager::get_ladspa_category (uint32_t plugin_id)
lrdf_free_statements(matches1);
if (!matches2) {
return _("Unknown");
return _("");
}
string label = matches2->object;
@ -331,6 +342,22 @@ PluginManager::get_ladspa_category (uint32_t plugin_id)
return label;
}
#ifdef HAVE_AUDIOUNITS
void
PluginManager::au_refresh ()
{
au_discover();
}
int
PluginManager::au_discover ()
{
_au_plugin_info = AUPluginInfo::discover();
return 0;
}
#endif
#ifdef VST_SUPPORT
void
@ -389,6 +416,7 @@ int
PluginManager::vst_discover (string path)
{
FSTInfo* finfo;
char buf[32];
if ((finfo = fst_get_info (const_cast<char *> (path.c_str()))) == 0) {
warning << "Cannot get VST information from " << path << endmsg;
@ -411,6 +439,9 @@ PluginManager::vst_discover (string path)
info->name = finfo->name;
}
snprintf (buf, sizeof (buf), "%d", finfo->uniqueID);
info->uniqueID = buf;
info->category = "VST";
info->path = path;
// need to set info->creator but FST doesn't provide it

View file

@ -1263,7 +1263,13 @@ Route::check_some_plugin_counts (list<InsertCount>& iclist, int32_t required_inp
}
(*i).in = required_inputs;
(*i).out = (*i).insert->compute_output_streams ((*i).cnt);
if (((*i).out = (*i).insert->compute_output_streams ((*i).cnt)) < 0) {
if (err_streams) {
*err_streams = required_inputs;
}
return -1;
}
required_inputs = (*i).out;
}
@ -1560,22 +1566,29 @@ Route::add_redirect_from_xml (const XMLNode& node)
if ((prop = node.property ("type")) != 0) {
boost::shared_ptr<Insert> insert;
bool have_insert = false;
if (prop->value() == "ladspa" || prop->value() == "Ladspa" || prop->value() == "vst") {
if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
prop->value() == "vst" ||
prop->value() == "audiounit") {
insert.reset (new PluginInsert(_session, node));
have_insert = true;
} else if (prop->value() == "port") {
insert.reset (new PortInsert (_session, node));
have_insert = true;
} else {
error << string_compose(_("unknown Insert type \"%1\"; ignored"), prop->value()) << endmsg;
}
add_redirect (insert, this);
if (have_insert) {
add_redirect (insert, this);
}
} else {
error << _("Insert XML node has no type property") << endmsg;

View file

@ -141,7 +141,7 @@ VSTPlugin::get_state()
{
XMLNode *root = new XMLNode (state_node_name());
LocaleGuard lg (X_("POSIX"));
if (_plugin->flags & effFlagsProgramChunks) {
/* fetch the current chunk */
@ -408,10 +408,12 @@ VSTPlugin::activate ()
_plugin->dispatcher (_plugin, effMainsChanged, 0, 1, NULL, 0.0f);
}
uint32_t
string
VSTPlugin::unique_id() const
{
return _plugin->uniqueID;
char buf[32];
snprintf (buf, sizeof (buf), "%d", _plugin->uniqueID);
return string (buf);
}