Vuo  0.4.4
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Modules

Description

To write a node class in C, you need to:

Read on for details.

Getting started

The easiest way to begin a new node class is with the Qt Creator wizard.

Stateless node classes

Stateless node classes are simpler, so let's start with them. A stateless node (for example, Add or Read from Console) can take in data and events through input ports. If it's an interface node, it can also see the world outside the composition (filesystem, network, devices). But when a stateless node executes, it can't look up information about previous executions. It has no way to store its state in memory.

Let's walk through a simple example: a simplified version of the Add node class. We'll call it Add Two Integers. This node class will output the sum of two integers.

The node class will be implemented in a file called example.addTwoIntegers.c. The file name determines the class's machine name (as opposed to its human-readable name, Add Two Integers). So the machine name is example.addTwoIntegers.

#include "node.h"

Every node class needs this line.

const char * moduleName = "Add Two Integers";
const char * moduleDescription = "Outputs the sum of the input integers.";
const unsigned int moduleVersion = 100;
const char * moduleKeywords[] = { "sum" };

This is metadata to help Vuo users know how to use your node class. For more information, see node.h.

const bool nodeIsInterface = false;

This is metadata to indicate how your node class interacts with the outside world. For more information, see node.h.

void nodeEvent(
VuoInputData(VuoInteger, {"default":0}) in0,
VuoInputData(VuoInteger, {"default":0}) in1,
) {
*sum = in0 + in1;
}

This function is called each time the node executes. The input and output ports are defined here, as parameters of this function. An Add Two Integers node has two input ports called in0 and in1 and an output port called sum. The function adds the two integers supplied by the input ports and sends their sum through the output port.

The second argument of the VuoInputData macro, {"default":0}, assigns the input port a default value of 0. In a running composition, the input port data keeps its default value until the port receives some other data through an incoming cable or unless the port has been assigned a constant value.

In addition to the port's default value, the second argument of the VuoInputData macro can specify other details about the port. These details can be used by data editor plugins in the Vuo Editor when the user is editing the constant value of the port. For example, VuoInputData(VuoInteger, {"default":0,"suggestedMin":0}) would cause the port's data editor to display a spin box widget whose buttons have a minimum value of 0 (but whose text box has no limit). Some data editors support suggestedMin, suggestedMax, and suggestedStep. suggestedMin and suggestedMax provide a hint about the typical range of values for this port (but don't actually limit the values that the port can receive). suggestedStep is the suggested step amount for spin box and slider widgets. Some data editors may support additional details about the port. The details must be JSON-formatted.

For more information on input and output ports, see node.h.

For more information on VuoInteger and other built-in port types, see Built-in Types.

Stateful node classes

A stateful node class (for example, Count or Recur) keeps track of its state, which is stored in node instance data. The node instance data can be of any data type. It's returned by nodeInstanceInit and passed as an argument to nodeInstanceEvent and nodeInstanceFini.

Let's walk through another example: a simplified version of the Count node class. We'll call it Count by One. A Count by One node will output a count, which will be incremented whenever the node executes.

The node class will be implemented in a file called example.countByOne.c, so its machine name will be example.countByOne.

#include "node.h"
const char * moduleName = "Count By One";
const char * moduleDescription = "Counts up by one when the refresh port receives an event.";
const unsigned int moduleVersion = 100;
const char * moduleKeywords[] = { "count", "increment" };
const bool nodeIsInterface = false;

This is the node class's metadata.

{
return 0;
}

This function is called once for each Count by One node when the composition starts running. Its return type determines the type of the node instance data (VuoInteger). It returns 0, so each Count by One node starts off with a count of 0.

) {
*countState = *countState + 1;
*count = *countState;
}

This function is called each time the node executes. The function updates the node instance data (countState) and sends the updated count to the output port (count).

} {
}

This function is called once for each Count by One node when the composition is stopped. The nodeInstanceFini function can clean up after nodeInstanceInit and nodeInstanceEvent if needed (for example, closing files and sockets). For the Count by One node class, like most node classes, no cleanup is needed.

Some node classes need to store heap-allocated data in their node instance data. For information on memory management, see

Naming node classes and ports

When naming node classes and ports, you're encouraged to follow these conventions:

Modules

 
 Node Instance Data
 Node instance data structure.
 
 Node Parameters
 Parameter decorations to be used by node classes.
 
 Node Methods: Stateless
 Event handler method to be implemented by node classes.
 
 Node Methods: Stateful
 Setup, event handler, and teardown methods to be implemented by stateful node classes.
 
 Node Debugging
 Macros to help with debugging.