next up previous contents
Next: Compiling and Installing Up: Overflow User's Manual Previous: Software Architecture   Contents

Subsections

Extending Overflow

Overflow is designed to be extendible in many areas, so that it is possible to create new: node types, operators and data types.

Writing New Nodes

Most of the new nodes will derive from either the Node abstract class or the BufferedNode abstract class. You should use public inheritance when deriving your new class. In all cases, you will need to define a constructor for your new node class. The parameters for this constructors are: (string nodeName, const ParameterSet &params), which are used to initialize the base class, e.g.

class MyNode : public BufferedNode { 

public: 

   MyNode(nodeName, params) : BufferedNode(nodeName, params) 

   ... 

};

Also, if you derive from BufferedNode, you need to define the virtual void calculate(int output_id, int count, Buffer &out) method. The arguments are the ID of the input requested (output_id), the iteration ID (count) and the output buffer for the requested output (out). The calculate method is expected to assign an object to out[count].

If you derive directly from the Node class, you will need to override the ObjectRef getOutput(int output_id, int count) method. The meaning of output_id and count is the same as for the BufferedNode equivalent, and the result should be returned as an ObjectRef.

Here are some other methods you might want to define too:

In some rare cases, you will want to define the following method:

At last for a new node to be visible in vflow, a special header must be present. An example of this is:

class  MyNode;

DECLARE_NODE( MyNode)

/*Node

 *

 * @name  MyNode

 * @category  MyCategory:MySubCategory

 * @description  Some description of what MyNode does

 * 

 * @input_name  SOME_INPUT_NAME

 * @input_type  this_input_type

 * @input_description  Description of this input

 * 

 * @input_name  SOME_OTHER_INPUT

 * @input_type  that_input_type

 * @input_description  Description of that output

 * 

 * @output_name  SOME_OUTPUT

 * @output_type  this_output_type

 * @output_description  Description of the output

 * 

 * @parameter_name  SOME_PARAMETER

 * @parameter_type  this_parameter_type

 * @parameter_description  The description of the parameter

 * END*/

Although this header is only a C++ comment, it is parsed by a PERL script to produce an XML description of each toolbox. The DECLARE_NODE(MyNode) macro is used to register the node in a dictionary when the toolbox is dynamically loaded.

Example: VAdd.cc

Most nodes must include BufferedNode.h. Also, since this node deals with vectors, we need Vector.h

#include "BufferedNode.h" 

#include "Vector.h"

forward declaration of class VAdd for use with the DECLARE_NODE macro

class VAdd;
Declaration of the node. This definition is transformed into XML data for the GUI, as well as documentation for the node

DECLARE_NODE(VAdd) 

/*Node  

*  

* @name VAdd  

* @category DSP:Base  

* @description Adds two vectors of same length  

*  

* @input_name INPUT1  

* @input_type Vector<float>  

* @input_description First vector  

*  

* @input_name INPUT2  

* @input_type Vector<float>  

* @input_description Second vector  

*  

* @output_name OUTPUT  

* @output_type Vector<float>  

* @output_description Result vector  

END*/

Class definition/implementation. Note that because we won't need to derive from this class, we don't need a header file (.h) and we can put everything in the .cc. Our node, like most other nodes, derives from BufferedNode.

class VAdd : public BufferedNode {

   int input1ID;

   int input2ID;

   int outputID;

public:

   VAdd(string nodeName, ParameterSet params)

   : BufferedNode(nodeName, params)

   {

In the constructor, we create both the inputs and outputs.

      input1ID = addInput("INPUT1");

      input2ID = addInput("INPUT2");

      outputID = addOutput("OUTPUT");

   }

This is the main method for the node, it is called from the BufferedNode class each time a result needs to be calculated.

   void calculate(int output_id, int count, Buffer &out)

   {

Get input data from previous node(s).

      ObjectRef input1Value = getInput(input1ID, count);

      ObjectRef input2Value = getInput(input2ID, count);

We cast the generic objects (received through ObjectRefs) into a reference to a Vector<float>. If the cast fails, an exception will automatically be thrown.

      

      const Vector<float> &in1 = object_cast<Vector<float> > (input1Value);

      const Vector<float> &in2 = object_cast<Vector<float> > (input2Value);

Check that the size of the two vectors match. Otherwise, throw an exception. Here __FILE__ and __LINE__ are pre-processor macros that will print the file and line where this exception was thrown.

      if (in1.size() != in2.size())

          throw new NodeException(this, 

                                  "Input vectors must be of same length",

                                   __FILE__, __LINE__);

      int inputLength = in1.size();

Allocate a new Vector<float> from the pool of free vectors (that's why we don't use new).

      Vector<float> = &output =

                      *Vector<float>::alloc(inputLength);

Put the new Vector<float> in the return buffer.

      out[count] = &output;
Compute the result of the sum.

      for (int i=0;i<inputLength;i++)

         output[i]=in1[i]+in2[i];

   }

}; 

Creating New Operators

Double Dispatched Operators

It is possible to define binary operators that can act on different kinds of input. One example is the "add" operator, which can be used to add two ints, two floats, two vectors, or an int and a float, ... See data-flow/include/operators.h

Adding New Data Type

It is possible to define new types in Overflow. In order to be used in new nodes, new types must derive from the Object base class. That the only absolute requirement. However, if you want the new type to integrate more closely with Overflow, there are several things you can do:

There is a certain format which all Object must respect. The object should start with "<MyType" and end with ">" (without the quotes). Usually, every field will be inside < and > signs.


next up previous contents
Next: Compiling and Installing Up: Overflow User's Manual Previous: Software Architecture   Contents
Jean-Marc Valin 2002-06-17