Processing data
After input ports, output ports, and parameters have been set up in the macro’s constructor, we are ready to process data.
Overridables
The macro’s base class MacroBase
defines four virtual methods
which are called by Impresario during processing:
virtual Status onInit();
virtual Status onApply();
virtual Status onExit();
virtual void onParametersChanged(ParameterSet& parameters);
The methods onInit()
, onApply()
, and onExit()
return a Status
code which is defined
as follows:
enum Status {
Ok, // tell Impresario to continue processing normally
Stop, // tell Impresario to stop processing
Error // tell Impresario to abort processing abnormally
};
The base class implementations of onInit()
, onApply()
, and onExit()
just return Ok
,
onParametersChanged(ParameterSet& parameters)
does nothing.
onInit()
is called once for each macro in the process graph
before the first call to onApply()
. So this is the place to check whether all requirements are
met to start processing and to initialize internal data which is needed in subsequent processing.
onInit()
has to return Ok
to indicate that processing can continue. Returning Error
or Stop
will stopp processing immediately and onExit()
will be called for every macro in the process graph.
onApply()
is the only method which must be overridden to realize data processing, overriding the other methods
is optional. onApply()
is called by Impresario cyclically with new input data and must return Ok
to continue
processing, Stop
to stop processing, or Error
to abort processing.
onExit()
is called for each macro in the process graph in case onInit()
or onApply()
of any macro in the
process graph returns Stop
or Error
or the user stopped processing with the
command in Impresario’s GUI. You can override this method in case you have to do some cleanup after processing. Stop
Finally, onParametersChanged(ParameterSet& parameters)
is called by Impresario just before each call to onInit()
,
onApply()
, and onExit()
. ParameterSet
is defined as std::set<unsigned int>
and contains the indices of all
changed parameters. You can override this method to handle parameter changes separately, e.g. in case more complex computations
are required in case a parameter changes. There are two important aspects to mention here:
- When
onParametersChanged(ParameterSet& parameters)
is called just after processing was started and beforeonInit()
,ParameterSet
contains the indices of all defined paramters to make sure everything can be initialized correctly. - In subsequent calls before
onApply()
, andonExit()
,ParameterSet
only contains the indices of parameters which have been changed by the user since the last call. In case no paramters have been changed,onParametersChanged(ParameterSet& parameters)
is not called at all, i.e. you will never see an empty set.
When you override one or more of the above methods you need to access the input ports, output ports, and parameters within these methods. Therefore the API provides access methods.
Access methods
Within the overridable methods you can you the following access methods to access inputs, outputs, and parameters:
template<typename T>
const T* accessInput(std::size_t index);
template<typename T>
T& accessOutput(std::size_t index);
template<typename T>
const T& getParameterValue(std::size_t index);
All methods take an index
as parameter which is the zero based index of inputs, outputs, and parameters in the order they
are defined in the macro’s constructor. The template type provided must match the type used for the definition.
accessInput(std::size_t index)
returns a pointer to the input object instance which can be nullptr
in case the input port
is not connected in the corresponing process graph. This can be checked in onInit()
once before processing starts as it is
not possible to change the process graph while Impresario is processing it. The returned input object instance is also constant,
i.e. not modifyable. Only outputs can be manipulated.
Outputs are accessed with accessOutput(std::size_t index)
. This method returns a reference to the output object instance which
can be modified. Please note: Outputs must only be modified in onApply()
as Impresario expects modifications only here.
With getParameterValue(std::size_t index)
you can read the current parameters. Parameters are usually set by the user in
Impresario’s property window but the API provides a method to set parameter
values also in code:
template<typename T>
void setParameterValue(std::size_t index, const T& value);
Usually both access methods are called in the overridable onParametersChanged(ParameterSet& parameters)
but can also be used
in the other overridable methods.
Message output
There are two ways to provide text output to Impresario. First, in case you return Error
in onInit()
, onApply()
, or onExit()
you can set an error message with the following method:
void setErrorMsg(const std::wstring& strErrorMsg);
The text you provide to this method will be shown in Impresario’s
System Messages Window. Please note: This message is only shown
when you return Error
, otherwise a call to this message does not have any effect.
Second, you can use the standard streams std::cout
and std::cerr
. Impresario redirects these streams to it’s
Console output Window. This is sometimes helpful for debugging.
Example
The following shows the implementation of the overridables in our example. In this example we do not use onExit()
so that the
base class implementation is used.
MacroBase::Status LtiCannyEdge::onInit() {
// check whether the input port is connected
const lti::channel8* input = accessInput<lti::channel8>(0);
if (input == nullptr) {
// input port is not connected, so abort processing
// with an error message
setErrorMsg(L"Input is not connected.");
return Error;
}
return Ok;
}
MacroBase::Status LtiCannyEdge::onApply() {
// access input
const lti::channel8* input = accessInput<lti::channel8>(0);
// access output
lti::channel8& output = accessOutput<lti::channel8>(0);
// just let the LTI Lib 2 algorithm do the work
return (cannyFunctor.apply(*input,output)) ? Ok : Error;
}
void LtiCannyEdge::onParametersChanged(ParameterSet & paramSet) {
for(ParameterSet::iterator it = paramSet.begin();
it != paramSet.end(); ++it) {
switch (*it) {
case 0:
params.edgeValue = lti::ubyte(getParameterValue<int>(0));
break;
case 1:
params.noEdgeValue = lti::ubyte(getParameterValue<int>(1));
break;
}
}
cannyFunctor.setParameters(params);
}