Next: a simple external: counter Up: HOWTO write an External Previous: definitions and prerequisites Contents
Subsections

- the interface to pd
- a class and its dataspace
- methodspace
- generation of a new class
  - class_new
  - class_addbang
- constructor: instantiation of an object
- the code: `helloworld`

# 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: a simple external: counter Up: HOWTO write an External Previous: definitions and prerequisites Contents