Next: a complex external: counter Up: HOWTO write an External Previous: my first external: helloworld Contents
Subsections

- object-variables
- object-arguments
- constructor
- the countermethod
- the code: `counter`

# a simple external: `counter`

Now we want to realize a simple counter as an external. A ``bang''-trigger outputs the counter-value on the outlet and afterwards increases the counter-value by 1.

This class is similar to the previous one, but the dataspace is extended by a variable ``counter'' and the result is written as a message to an outlet instead of a string to the standarderror.

## object-variables

Of course, a counter needs a state-variable to store the actual counter-value.

State-variables that belong to classinstances belong to the dataspace.

    typedef struct _counter {
      t_object  x_obj;
      t_int i_count;
    } t_counter;

The integer variable `i_count` stores the counter-value.

## object-arguments

It is quite usefull for a counter, if a initial value can be defined by the user. Therefore this initial value should be passed to the object at creation-time.

    void counter_setup(void) {
      counter_class = class_new(gensym("counter"),
            (t_newmethod)counter_new,
            0, sizeof(t_counter),
            CLASS_DEFAULT,
            A_DEFFLOAT, 0);

      class_addbang(counter_class, counter_bang);
    }

So we have an additional argument in the function `class_new`: `A_DEFFLOAT` tells pd, that the object needs one argument of the type `t_floatarg`. If no argument is passed, this will default to ``0''.

## constructor

The constructor has some new tasks. On the one hand, a variable value has to be initialized, on the other hand, an outlet for the object has to be created.

    void *counter_new(t_floatarg f)
    {
      t_counter *x = (t_counter *)pd_new(counter_class);

      x->i_count=f;
      outlet_new(&x->x_obj, &s_float);

      return (void *)x;
    }

The constructor-method has one argument of type `t_floatarg` as declared in the setup-routine by `class_new`. This argument is used to initialize the counter.

A new outlet is created with the function `outlet_new`. The first argument is a pointer to the interna of the object the new outlet is created for.

The second argument is a symbolic description of the outlet-type. Since out counter should output numeric values it is of type ``float''.

`outlet_new` returns a pointer to the new outlet and saves this very pointer in the `t_object`-variable `x_obj.ob_outlet`. If only one outlet is used, the pointer need not additionally be stored in the dataspace. If more than one outlets are used, the pointers have to be stored in the dataspace, because the `t_object`-variable can only hold one outletpointer.

## the countermethod

When triggered, the countervalue should be sent to the outlet and afterwards be incremented by 1.

    void counter_bang(t_counter *x)
    {
      t_float f=x->i_count;
      x->i_count++;
      outlet_float(x->x_obj.ob_outlet, f);
    }

The function `outlet_float` sends a floating-point-value (second argument) to the outlet that is specified by the first argument.

We first store the counter in a floatingpoint-buffer. Afterwards the counter is incremented and not before that the buffervariable is sent to the outlet.

What appears to be unnecessary on the first glance, makes sense after further inspection: The buffervariable has been realized as `t_float`, since `outlet_float` expects a floatingpoint-value and a typecast is inevitable.

If the countervalue was sent to the outlet before being incremented, this could result in an unwanted (though welldefined) behaviour: If the counter-outlet directly triggered its own inlet, the counter-method would be called although the countervalue was not yet incremented. Normally this is not what we want.

The same (correct) result could of course be obtained with a single line, but this would obscure the reentrant-problem.

## the code: `counter`

    #include "m_pd.h"

    static t_class *counter_class;

    typedef struct _counter {
      t_object  x_obj;
      t_int i_count;
    } t_counter;

    void counter_bang(t_counter *x)
    {
      t_float f=x->i_count;
      x->i_count++;
      outlet_float(x->x_obj.ob_outlet, f);
    }

    void *counter_new(t_floatarg f)
    {
      t_counter *x = (t_counter *)pd_new(counter_class);

      x->i_count=f;
      outlet_new(&x->x_obj, &s_float);

      return (void *)x;
    }

    void counter_setup(void) {
      counter_class = class_new(gensym("counter"),
            (t_newmethod)counter_new,
            0, sizeof(t_counter),
            CLASS_DEFAULT,
            A_DEFFLOAT, 0);

      class_addbang(counter_class, counter_bang);
    }

Next: a complex external: counter Up: HOWTO write an External Previous: my first external: helloworld Contents