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

Subsections

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 up previous contents
Next: a complex external: counter Up: HOWTO write an External Previous: my first external: helloworld   Contents
IOhannes m zmoelnig 2001-09-13