next up previous contents
Next: a simple external: counter Up: HOWTO write an External Previous: definitions and prerequisites   Contents

Subsections

my first external: helloworld

Usually the first attempt learning a programming-language is a ``hello world''-application.

In our case, an objectclass should be created, that prints the line ``hello world!!'' to the standarderror everytime it is triggered witha ``bang''-message.

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"

a class and its dataspace

First a new class has to be prepared and the dataspace 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 dataspace of the class.

An absolutely necessary element of the dataspace 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.

methodspace

Apart from the dataspace, 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 messagesystem of pd. On principal they have no return argument and are therefore are 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 dataspace.

Since we only want to output ``Hello world!'' (and, by the way, our dataspace is quite sparse), we renounce a manipulation.

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

generation of a new class

To generate a new class, information of the dataspace and the methodspace 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 functionn 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.

Das erste Argument ist der symbolische Name der Klasse.

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

Whenever a classobject is created in a pd-patch, the class-constructor (t_newmethod)helloworld_new instantiates the object and initializes the dataspace.

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 dataspace 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 dataspace, the size of the datastructure has to be passed as the fourth argument.

The fifth argument has influence on the graphical representaion of the classobjects. 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 atomtypes 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 methodspace 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.

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-argument constructor-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 dataspace, initializes the variables that are internal to the object and returns a pointer to the dataspace.

The type-cast to the dataspace is necessary.

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

The constructor has to return a pointer to the instantiated dataspace.

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);
}


next up previous contents
Next: a simple external: counter Up: HOWTO write an External Previous: definitions and prerequisites   Contents
IOhannes m zmoelnig 2001-09-13