2 my first external: helloworld

Usually the first attempt learning a programming-language is a “hello world”-application.

In our case, an object class should be created, that prints the line “hello world!!” to the standard error every time it is triggered with a “bang”-message.

2.1 the interface to Pd

To write a Pd-external a well-defined interface is needed. This is provided in the header-file “m_pd.h”.

#include "m_pd.h"

2.2 a class and its data space

First a new class has to be prepared and the data space for this class has to be defined.

static t_class *helloworld_class;  
 
typedef struct _helloworld {  
  t_object  x_obj;  
} t_helloworld;

hello_worldclass is going to be a pointer to the new class.

The structure t_helloworld (of the type _helloworld) is the data space of the class.

An absolutely necessary element of the data space is a variable of the type t_object, which is used to store internal object-properties like the graphical presentation of the object or data about inlets and outlets.

t_object has to be the first entry in the structure !

Because a simple “hello world”-application needs no variables, the structure is empty apart from the t_object.

2.3 method space

Apart from the data space, a class needs a set of manipulators (methods) to manipulate the data with.

If a message is sent to an instance of our class, a method is called. These methods are the interfaces to the message system of Pd. On principal they have no return argument and are therefore of the type void.

void helloworld_bang(t_helloworld *x)  
{  
  post("Hello world !!");  
}

This method has an argument of the type t_helloworld, which would enable us to manipulate the data space.

Since we only want to output “Hello world!” (and, by the way, our data space is quite sparse), we renounce a manipulation.

The command post(char *c,...) sends a string to the standard error. A carriage return is added automatically. Apart from this, the post-command works like the C-command printf().

2.4 generation of a new class

To generate a new class, information of the data space and the method space of this class, have to be passed to Pd when a library is loaded.

On loading a new library “my_lib”, Pd tries to call a function “my_lib_setup()”. This function (or functions called by it) declares the new classes and their properties. It is only called once, when the library is loaded. If the function-call fails (e.g., because no function of the specified name is present) no external of the library will be loaded.

void helloworld_setup(void)  
{  
  helloworld_class = class_new(gensym("helloworld"),  
        (t_newmethod)helloworld_new,  
        0, sizeof(t_helloworld),  
        CLASS_DEFAULT, 0);  
 
  class_addbang(helloworld_class, helloworld_bang);  
}

class_new The function class_new creates a new class and returns a pointer to this prototype.

The first argument is the symbolic name of the class.

The next two arguments define the constructor and destructor of the class.

Whenever a class object is created in a Pd-patch, the class-constructor (t_newmethod)helloworld_new instantiates the object and initialises the data space.

Whenever an object is destroyed (either by closing the containing patch or by deleting the object from the patch) the destructor frees the dynamically reserved memory. The allocated memory for the static data space is automatically reserved and freed.

Therefore we do not have to provide a destructor in this example, the argument is set to “0”.

To enable Pd to reserve and free enough memory for the static data space, the size of the data structure has to be passed as the fourth argument.

The fifth argument has influence on the graphical representation of the class objects. The default-value is CLASS_DEFAULT or simply “0”.

The remaining arguments define the arguments of an object and its type.

Up to six numeric and symbolic object-arguments can be defined via A_DEFFLOAT and A_DEFSYMBOL. If more arguments are to be passed to the object or if the order of atom types should by more flexible, A_GIMME can be used for passing an arbitrary list of atoms.

The list of object-arguments is terminated by “0”. In this example we have no object-arguments at all for the class.

class_addbang We still have to add a method space to the class.

class_addbang adds a method for a “bang”-message to the class that is defined in the first argument. The added method is defined in the second argument.

2.5 constructor: instantiation of an object

Each time, an object is created in a Pd-patch, the constructor that is defined with the class_new-command, generates a new instance of the class.

The constructor has to be of type void *.

void *helloworld_new(void)  
{  
  t_helloworld *x = (t_helloworld *)pd_new(helloworld_class);  
 
  return (void *)x;  
}

The arguments of the constructor-method depend on the object-arguments defined with class_new.

class_new-argumentconstructor-argument


A_DEFFLOAT t_floatarg f
A_DEFSYMBOL t_symbol *s
A_GIMME t_symbol *s, int argc, t_atom *argv

Because there are no object-arguments for our “hello world”-class, the constructor has anon too.

The function pd_new reserves memory for the data space, initialises the variables that are internal to the object and returns a pointer to the data space.

The type-cast to the data space is necessary.

Normally, the constructor would initialise the object-variables. However, since we have none, this is not necessary.

The constructor has to return a pointer to the instantiated data space.

2.6 the code: helloworld

#include "m_pd.h"  
 
static t_class *helloworld_class;  
 
typedef struct _helloworld {  
  t_object  x_obj;  
} t_helloworld;  
 
void helloworld_bang(t_helloworld *x)  
{  
  post("Hello world !!");  
}  
 
void *helloworld_new(void)  
{  
  t_helloworld *x = (t_helloworld *)pd_new(helloworld_class);  
 
  return (void *)x;  
}  
 
void helloworld_setup(void) {  
  helloworld_class = class_new(gensym("helloworld"),  
        (t_newmethod)helloworld_new,  
        0, sizeof(t_helloworld),  
        CLASS_DEFAULT, 0);  
  class_addbang(helloworld_class, helloworld_bang);  
}