Move to new FLParam model for passing parameters

This commit is contained in:
Alex Harker
2019-12-05 16:24:55 +00:00
parent 225cd5bb59
commit 4ac729638d
2 changed files with 187 additions and 251 deletions
+88 -99
View File
@@ -1,106 +1,96 @@
FLParam : UGen {
*ir { arg tag, a;
*ir { arg a;
^this.parseTag(tag, a);
var args = ['init'];
var i = 0;
while ( {(i + 1) < a.size} , {
var tag = a[i];
var b = [a[i + 1]];
i = i + 2;
while( { (i < a.size) && (a[i].isKindOf(Symbol) == false) }, {
b = b.add(a[i]);
i = i + 1;
});
args = args ++ this.parseTag(tag, b);
});
^this.new1( *args );
}
*parseTag { arg tag, val;
if (tag.isKindOf(Symbol))
{
var args1 = this.parseSymbol(tag);
var args2 = this.parseValue(val);
var detectSymbol = (val.size == 1) && val[0].isKindOf(Symbol);
var args1 = this.parseSymbol(tag);
var args2 = val;
var newArgs = ['init', val.isKindOf(Symbol).if(1, 0), args1.size].addAll(args1).add(args2.size).addAll(args2);
switch (detectSymbol,
true, { args2 = this.parseSymbol(val[0]); },
false, { args2 = val; });
^this.new1( *newArgs );
}
^[detectSymbol.if(1, 0), args1.size].addAll(args1).add(args2.size).addAll(args2);
}
*parseSymbol { arg str;
var ascii = str.ascii;
var loopmod = ascii.size % 3;
var args;
var args = Array.fill((ascii.size / 3).asInteger, { arg i;
ascii[i * 3] + (ascii[i * 3 + 1] * 256) + (ascii[i * 3 + 2] * 65536) });
args = Array.fill((ascii.size / 3).asInteger, { arg i; ascii[i * 3] + (ascii[i * 3 + 1] * 256) + (ascii[i * 3 + 2] * 65536) });
switch (loopmod,
switch (ascii.size % 3,
0, { ^args; },
1, { ^args.add(ascii[args.size * 3]); },
2, { ^args.add(ascii[args.size * 3] + (ascii[args.size * 3 + 1] * 256)); });
}
*parseValue { arg a;
switch(a.isKindOf(Symbol).asInt + (a.isKindOf(Array).asInt * 2),
0, { ^[a]; },
1, { ^this.parseSymbol(a); },
2, { ^a; });
}
}
FLObject : UGen {
classvar paramCount;
*initClass {
paramCount = 0;
}
*makeNewParams { arg paramString = '', inputString = " ";
var count = -1;
if (paramString.isKindOf(String), { if(paramString.size() > 0, {
count = paramCount;
Server.local.sendMsg("/cmd", "FLParameters", paramCount, paramString, inputString);
paramCount = paramCount + 1;
})})
^count;
}
}
FLInterval : FLObject {
*fr { arg paramString = '', params = 0.0;
^this.multiNew('audio', this.makeNewParams(paramString), params)
*fr { arg initParams = '', params = 0.0;
^this.multiNew('audio', FLParam.ir(initParams), params)
}
}
FLRead : FLObject {
*fr { arg in1 = 0.0, params = 0.0, initParams = "";
^this.multiNew('control', this.makeNewParams(initParams), in1, params)
^this.multiNew('control', FLParam.ir(initParams), in1, params)
}
}
FLMap : FLObject {
*fr { arg in1 = 0.0, params = 0.0, initParams = "";
^this.multiNew('control', this.makeNewParams(initParams), in1, params)
^this.multiNew('control', FLParam.ir(initParams), in1, params)
}
}
FLWindow : FLObject {
*fr { arg in = 0.0, params = 0.0, initParams = "";
^this.multiNew('control', this.makeNewParams(initParams), in, params)
^this.multiNew('control', FLParam.ir(initParams), in, params)
}
}
// IO
FLSource : FLObject {
*fr { arg in1 = 0.0, trigger = 0.0, params = 0.0;
^this.multiNew('audio', this.makeNewParams(""), in1, trigger, params)
*fr { arg in1 = 0.0, trigger = 0.0, params = 0.0, initParams = "";
^this.multiNew('audio', FLParam.ir(initParams), in1, trigger, params)
}
}
FLSink : FLObject {
*fr { arg in = 0.0, params = 0.0, initParams = "";
^this.multiNew('audio', this.makeNewParams(initParams), in, params)
^this.multiNew('audio', FLParam.ir(initParams), in, params)
}
}
FLTrace : FLObject {
*fr { arg in = 0.0, params = 0.0, initParams = "";
^this.multiNew('audio', this.makeNewParams(initParams), in, params)
^this.multiNew('audio', FLParam.ir(initParams), in, params)
}
}
@@ -108,19 +98,19 @@ FLTrace : FLObject {
FLRamp : FLObject {
*fr { arg in1 = 0.0, params = 0.0, initParams = "";
^this.multiNew('control', this.makeNewParams(initParams), in1, params)
^this.multiNew('control', FLParam.ir(initParams), in1, params)
}
}
FLRand : FLObject {
*fr { arg in1 = 0.0, params = 0.0, initParams = "";
^this.multiNew('control', this.makeNewParams(initParams), in1, params)
^this.multiNew('control', FLParam.ir(initParams), in1, params)
}
}
FLUniform : FLObject {
*fr { arg in1 = 0.0, params = 0.0, initParams = "";
^this.multiNew('control', this.makeNewParams(initParams), in1, params)
^this.multiNew('control', FLParam.ir(initParams), in1, params)
}
}
@@ -128,183 +118,182 @@ FLUniform : FLObject {
FLNot : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLAcos : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLAsin : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLAtan : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLAcosh : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLAsinh : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLAtanh : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLCos : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLSin : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLTan : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLCosh : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLSinh : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLTanh : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLLog : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLLog2 : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLLog10 : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLExp : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLExp2 : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLAbs : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLCeil : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLFloor : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLRound : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLTrunc : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLSqrt : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLCbrt : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLErf : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
FLErfc : FLObject {
*fr { arg in = 0.0;
^this.multiNew('control', -1, in)}
^this.multiNew('control', FLParam.ir(), in)}
}
// Binary
FLMul : FLObject {
*fr { arg in1 = 0.0, in2 = 0.0, params = "";
^this.multiNew('control', this.makeNewParams(params), in1, in2)}
*fr { arg in1 = 0.0, in2 = 0.0, initParams = "";
^this.multiNew('control', FLParam.ir(initParams), in1, in2)}
}
FLAdd : FLObject {
*fr { arg in1 = 0.0, in2 = 0.0, params = "";
^this.multiNew('control', this.makeNewParams(params), in1, in2)}
*fr { arg in1 = 0.0, in2 = 0.0, initParams = "";
^this.multiNew('control', FLParam.ir(initParams), in1, in2)}
}
FLSub : FLObject {
*fr { arg in1 = 0.0, in2 = 0.0, params = "";
^this.multiNew('control', this.makeNewParams(params), in1, in2)}
*fr { arg in1 = 0.0, in2 = 0.0, initParams = "";
^this.multiNew('control', FLParam.ir(initParams), in1, in2)}
}
FLDiv : FLObject {
*fr { arg in1 = 0.0, in2 = 0.0, params = "";
^this.multiNew('control', this.makeNewParams(params), in1, in2)}
*fr { arg in1 = 0.0, in2 = 0.0, initParams = "";
^this.multiNew('control', FLParam.ir(initParams), in1, in2)}
}
FLPow : FLObject {
*fr { arg in1 = 0.0, in2 = 0.0, params = "";
^this.multiNew('control', this.makeNewParams(params), in1, in2)}
*fr { arg in1 = 0.0, in2 = 0.0, initParams = "";
^this.multiNew('control', FLParam.ir(initParams), in1, in2)}
}
FLAtan2 : FLObject {
*fr { arg in1 = 0.0, in2 = 0.0, params = "";
^this.multiNew('control', this.makeNewParams(params), in1, in2)}
*fr { arg in1 = 0.0, in2 = 0.0, initParams = "";
^this.multiNew('control', FLParam.ir(initParams), in1, in2)}
}
FLHypot : FLObject {
*fr { arg in1 = 0.0, in2 = 0.0, params = "";
^this.multiNew('control', this.makeNewParams(params), in1, in2)}
*fr { arg in1 = 0.0, in2 = 0.0, initParams = "";
^this.multiNew('control', FLParam.ir(initParams), in1, in2)}
}
FLCopySign : FLObject {
*fr { arg in1 = 0.0, in2 = 0.0, params = "";
^this.multiNew('control', this.makeNewParams(params), in1, in2)}
*fr { arg in1 = 0.0, in2 = 0.0, initParams = "";
^this.multiNew('control', FLParam.ir(initParams), in1, in2)}
}
FLMin : FLObject {
*fr { arg in1 = 0.0, in2 = 0.0, params = "";
^this.multiNew('control', this.makeNewParams(params), in1, in2)}
*fr { arg in1 = 0.0, in2 = 0.0, initParams = "";
^this.multiNew('control', FLParam.ir(initParams), in1, in2)}
}
FLMax : FLObject {
*fr { arg in1 = 0.0, in2 = 0.0, params = "";
^this.multiNew('control', this.makeNewParams(params), in1, in2)}
*fr { arg in1 = 0.0, in2 = 0.0, initParams = "";
^this.multiNew('control', FLParam.ir(initParams), in1, in2)}
}
FLModulo : FLObject {
*fr { arg in1 = 0.0, in2 = 0.0, params = "";
^this.multiNew('control', this.makeNewParams(params), in1, in2)}
*fr { arg in1 = 0.0, in2 = 0.0, initParams = "";
^this.multiNew('control', FLParam.ir(initParams), in1, in2)}
}
+99 -152
View File
@@ -46,33 +46,6 @@ struct SC_FrameLib_Global
}
};
struct InitParameters
{
InitParameters() : mSerial(nullptr), mInputsSerial(nullptr) {}
~InitParameters()
{
delete mSerial;
delete mInputsSerial;
}
// Non-copyable
InitParameters(const InitParameters&) = delete;
InitParameters& operator=(const InitParameters&) = delete;
InitParameters(InitParameters&& rhs)
{
mSerial = rhs.mSerial;
mInputsSerial = rhs.mInputsSerial;
rhs.mSerial = nullptr;
rhs.mInputsSerial = nullptr;
}
FrameLib_Parameters::AutoSerial *mSerial;
FrameLib_Parameters::AutoSerial *mInputsSerial;
};
SC_FrameLib_Global() : mGlobal(nullptr)
{
FrameLib_Global::get(&mGlobal, &mNotifier);
@@ -89,86 +62,11 @@ struct SC_FrameLib_Global
}
UnitCalcFunc GetCalcFunc() const { return (UnitCalcFunc) CalcFunc; }
void ParseString(World *inWorld, FrameLib_Parameters::AutoSerial& serial, const char *str)
{
char *tempStr = (char *) RTAlloc(inWorld, strlen(str) + 1);
strcpy(tempStr, str);
double array[4096];
int arraySize;
for (char *strParse = strtok(tempStr, " "); strParse;)
{
char *tag = strParse;
strParse = strtok(nullptr, " ");
for (arraySize = 0; strParse; arraySize++)
{
char *endPtr;
double nextDouble = strtod(strParse, &endPtr);
if (endPtr[0])
break;
array[arraySize] = nextDouble;
strParse = strtok(nullptr, " ");
}
if (arraySize)
serial.write(tag, array, arraySize);
else
{
if (strParse)
{
serial.write(tag, strParse);
strParse = strtok(nullptr, " ");
}
}
}
RTFree(inWorld, tempStr);
}
void SetInitParameters(World *inWorld, int id, const char *params, const char *inputs)
{
if (id >= mInitParameters.size())
mInitParameters.resize(id + 1);
if (mInitParameters[id].mSerial)
mInitParameters[id].mSerial->clear();
else
mInitParameters[id].mSerial = new FrameLib_Parameters::AutoSerial;
ParseString(inWorld, *mInitParameters[id].mSerial, params);
if (mInitParameters[id].mInputsSerial)
mInitParameters[id].mInputsSerial->clear();
else
mInitParameters[id].mInputsSerial = new FrameLib_Parameters::AutoSerial;
ParseString(inWorld, *mInitParameters[id].mInputsSerial, inputs);
}
InitParameters *GetInitParameters(FrameLib_SC_UGen* unit)
{
if (unit->mNumInputs && unit->mInput[0]->mCalcRate == calc_ScalarRate)
{
int paramID = unit->mInput[0]->mScalarValue;
if (paramID >= 0 && paramID < mInitParameters.size())
return &mInitParameters[paramID];
}
return nullptr;
}
FrameLib_Global *getGlobal() { return mGlobal; }
FrameLib_Global *mGlobal;
Notifier mNotifier;
std::vector<InitParameters> mInitParameters;
};
static SC_FrameLib_Global sGlobal;
@@ -177,21 +75,16 @@ static SC_FrameLib_Global sGlobal;
struct FrameLib_Param_UGen : public Unit
{
SC_FrameLib_Global* mGlobal;
char *mTag;
char *mSymbol;
float *mVector;
size_t mVecLength;
SC_FrameLib_Global *mGlobal;
FrameLib_Parameters::Serial *mSerial;
};
size_t FLParam_String(FrameLib_Param_UGen* unit, char*& str, size_t i)
{
size_t length = 0;
Wire **it = unit->mInput + i;
Wire **end = unit->mInput + unit->mNumInputs;
length = (*it++)->mScalarValue;
str = (char *) ft->fRTAlloc(unit->mWorld, sizeof(char) * (length * 3 + 1));
size_t length = (*it++)->mScalarValue;
for (size_t j = 0; it != end && j < length; it++, j++)
{
@@ -207,51 +100,117 @@ size_t FLParam_String(FrameLib_Param_UGen* unit, char*& str, size_t i)
return unit->mNumInputs - (end - it);
}
void FLParam_Vector(FrameLib_Param_UGen* unit, float*& vec, size_t i)
size_t FLParam_Vector(FrameLib_Param_UGen* unit, double*& vec, size_t i, size_t& N)
{
size_t length = 0;
Wire **it = unit->mInput + i;
Wire **end = unit->mInput + unit->mNumInputs;
unit->mVecLength = length = (*it++)->mScalarValue;
vec = (float *) ft->fRTAlloc(unit->mWorld, sizeof(float) * (length + 1));
N = (*it++)->mScalarValue;
for (size_t j = 0; it != end && j < length; it++, j++)
for (size_t j = 0; it != end && j < N; it++, j++)
vec[j] = (*it)->mScalarValue;
return unit->mNumInputs - (end - it);
}
void FLParam_Release_Serial(FrameLib_Param_UGen* unit)
{
using Serial = FrameLib_Parameters::Serial;
if (unit->mSerial)
{
unit->mSerial->~Serial();
ft->fRTFree(unit->mWorld, unit->mSerial);
}
}
template <class T>
T *FLParam_Temporary(FrameLib_Param_UGen* unit, T *stack, size_t size, size_t defaultSize)
{
return size > defaultSize ? (T *) ft->fRTAlloc(unit->mWorld, sizeof(T) * size) : stack;
}
void FLParam_Ctor(FrameLib_Param_UGen* unit)
{
unit->mGlobal= &sGlobal;
unit->mTag = nullptr;
unit->mSymbol = nullptr;
unit->mVector = nullptr;
unit->mVecLength = 0;
using Serial = FrameLib_Parameters::Serial;
const size_t DEF_STR_SIZE = 1024;
const size_t DEF_VEC_SIZE = 1024;
bool string = unit->mInput[0]->mScalarValue;
char stack_str[DEF_STR_SIZE];
double stack_vec[DEF_VEC_SIZE];
size_t pos = FLParam_String(unit, unit->mTag, 1);
size_t N = 0, max_str = 0, max_vec = 0, size = 0, l1 = 0, l2 = 0;
if (string)
FLParam_String(unit, unit->mSymbol, pos);
else
FLParam_Vector(unit, unit->mVector, pos);
unit->mGlobal = &sGlobal;
unit->mSerial = nullptr;
// Loop to calculate sizes;
for (size_t i = 0; i < unit->mNumInputs; i += 3 + l1 + l2)
{
l1 = unit->mInput[i + 1]->mScalarValue;
l2 = unit->mInput[i + l1 + 2]->mScalarValue;
if (unit->mInput[i]->mScalarValue)
{
max_str = std::max(max_str, (l1 + l2) * 3 + 2);
size += Serial::calcString(l1 * 3, l2 * 3);
}
else
{
max_str = std::max(max_str, l1 * 3 + 1);
max_vec = std::max(max_vec, l2);
size += Serial::calcVector(l1 * 3, l2);
}
}
// Allocate if needed
if (size)
{
size_t allocationSize = Serial::inPlaceSize(size);
unit->mSerial = Serial::newInPlace(ft->fRTAlloc(unit->mWorld, allocationSize), size);
}
char *tag = FLParam_Temporary(unit, stack_str, max_str, DEF_STR_SIZE);
double *vec = FLParam_Temporary(unit, stack_vec, max_vec, DEF_VEC_SIZE);
// Loop to serialise parameters
for (size_t i = 0; i < unit->mNumInputs; )
{
if (unit->mInput[i]->mScalarValue)
{
char *str = tag + ((size_t) unit->mInput[i + 1]->mScalarValue) * 3 + 1;
i = FLParam_String(unit, tag, i + 1);
i = FLParam_String(unit, str, i);
unit->mSerial->write(tag, str);
}
else
{
i = FLParam_String(unit, tag, i + 1);
i = FLParam_Vector(unit, vec, i, N);
unit->mSerial->write(tag, vec, N);
}
}
// Free resources if needed
if (tag != stack_str)
ft->fRTFree(unit->mWorld, tag);
if (vec != stack_vec)
ft->fRTFree(unit->mWorld, vec);
unit->mCalcFunc = (UnitCalcFunc) &FLTest_CalcZero;
}
void FLParam_Dtor(FrameLib_Param_UGen* unit)
{
using std::vector;
// In case the parameters haven't been freed
if (unit->mTag)
ft->fRTFree(unit->mWorld, unit->mTag);
unit->mVector.~vector<float>();
if (unit->mSymbol)
ft->fRTFree(unit->mWorld, unit->mSymbol);
FLParam_Release_Serial(unit);
}
//////////////////////////////////////////////////////////////////
// Proxies
@@ -349,16 +308,16 @@ FrameLib_Proxy *GetProxy(FrameLib_SC_UGen *unit, FrameLib_Expand<FrameLib_Read>
template<class T>
void FLTest_Ctor(FrameLib_SC_UGen* unit)
{
SC_FrameLib_Global* global = &sGlobal;
FrameLib_Context context(global->getGlobal(), unit->mParent);
// FIX - number of streams / fixed inputs
FrameLib_Param_UGen *paramUGen = (FrameLib_Param_UGen *) unit->mInput[0]->mFromUnit;
SC_FrameLib_Global::InitParameters *params = global->GetInitParameters(unit);
SC_FrameLib_Global* global = paramUGen->mGlobal;
FrameLib_Context context(global->getGlobal(), unit->mParent);
unit->mProxy = GetProxy<T>(unit, static_cast<T *>(nullptr));
int nStreams = 1;
unit->mObject = new T(context, params ? params->mSerial : nullptr, unit->mProxy, nStreams);
unit->mObject = new T(context, paramUGen->mSerial, unit->mProxy, nStreams);
unit->mAudioBuffers = nullptr;
bool handlesAudio = T::handlesAudio();
@@ -372,7 +331,7 @@ void FLTest_Ctor(FrameLib_SC_UGen* unit)
{
Wire *wire = unit->mInput[i + numAudioIns + 1];
Unit *connect = wire->mFromUnit;
/*
if (params && params->mInputsSerial)
{
char tag[10];
@@ -387,7 +346,7 @@ void FLTest_Ctor(FrameLib_SC_UGen* unit)
unit->mObject->setFixedInput(i, array, arraySize);
continue;
}
}
}*/
if (global->CheckFrameLib(connect))
{
@@ -518,22 +477,10 @@ void DefineFrameLibExpUnit(const char *name)
(*ft->fDefineUnit)(name, sizeof(FrameLib_SC_UGen), (UnitCtorFunc)&FLTest_Ctor<FrameLib_Expand<T>>,(UnitDtorFunc)&FLTest_Dtor, 0);
}
void ParameterSetup(World *inWorld, void* inUserData, sc_msg_iter *args, void *replyAddr)
{
double count = args->getd();
const char *paramMessage = args->gets();
const char *inputMessage = args->gets();
SC_FrameLib_Global *global = (SC_FrameLib_Global *) inUserData;
global->SetInitParameters(inWorld, count, paramMessage, inputMessage);
}
PluginLoad(FrameLib)
{
ft = inTable; // store pointer to InterfaceTable
(*ft->fDefinePlugInCmd)("FLParameters", &ParameterSetup, nullptr);
// Define parameter UGen
(*ft->fDefineUnit)("FLParam", sizeof(FrameLib_Param_UGen), (UnitCtorFunc)&FLParam_Ctor,(UnitDtorFunc)&FLParam_Dtor, 0);