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.
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.
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''.
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.
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.
#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); }