A parameter is defined by the defparameter item. The primitive can use a parameter to store data values, remembering them from one invocation to another.
Parameters differ from ordinary members of the primitive, which are defined using the public, protected or private items, in the way that they have a name and can be accessed from outside the primitive in systematic ways.
For instance, the MLDesigner permits the programmer to set any parameter with the A_SETTABLE attribute to some value prior to a run. The MLDesigner command interpreter provides similar functionality through the setparam command. The parameter attributes are set in the state item. A parameter may be modified by the primitive’s code during a run. The attribute A_NONCONSTANT is used as a pragma to mark a parameter as one that gets modified during a run. There is currently no mechanism for checking the properness of these attributes.
All parameters are derived from the base class State, defined in the MLDesigner kernel. The derived parameter classes currently defined in the kernel are FloatState, IntState, ComplexState, StringState, FixState, FloatArrayState, IntArrayState, ComplexArrayState, StringArrayState, FixArrayState, DataStructState and EnumState.
defparameter
{
name { myState }
type { float }
default { "1.0" }
desc { "Gain Parameter." }
}
This will define a member of class FloatState with default value 1.0. No attributes are defined, so A_CONSTANT and A_SETTABLE, the default attributes, are assumed. To use the value of a parameter, it should be cast to type double, either explicitly by the programmer or implicitly by the context. For example, the value of this parameter can be accessed in the go method as follows:
go
{
output%0 << (double)myState * (double)(input%0);
}
The references to input and output are explained above. The reference to myState has an explicit cast to double. This cast is defined in FloatState class. Similarly, a cast to int is available for IntState, to Complex from ComplexState, and to const char* for StringState. In principle, it is possible to rely on the compiler to automatically invoke this cast.
Some compilers (notably some versions of g++) may not choose the expected cast. In particular, g++ has been known to cast everything to Fix if the explicit cast is omitted in expressions similar to that above. The arithmetic is then performed using fixed-point point computations. This will be dramatically slower than double or integer arithmetic, and may yield unexpected results. It is best to explicitly cast parameters to the desired form.
An exception is with simple assignment statements, like
double stateValue = myName;
Even g++ gets this right. Explicit casting should be used whenever a parameter is used in an expression. For example, from the setup method of the SDFChop primitive, in which use_past_inputs is an integer parameter,
if (int(use_past_inputs))
input.setSDFParams(int(nread),int(nread)+int(offset)-1);
else
input.setSDFParams(int(nread),int(nread)-1);
Note that the type Complex is not a fundamental part of C++. We have implemented a subset of the Complex class as defined by several library vendors. Using the ComplexState class will automatically ensure the inclusion of the appropriate header files. A member of type Complex can be initialized and operated upon any number of ways. For details, see Complex Data Type. A parameter may be updated by an ordinary assignment in C++, as in the following lines
double t = expression;
myState = t;
This works because the assignment operator = has been overloaded by the FloatState class definition to set its value from a double. Similarly, an IntState can be set from an int and a StringState can be set from a char* or const char*.