• ### send list to outlet in external

Hi,

I try to write an external, which sends a list to an outlet.

The following code is an example of calculating the maximum of a signal and send the maximum and it's index to the outlet.
But line 30 outlet_float(x->f_out, (max[0], max[1]) ); does only send one value to the outlet.
How can I achieve to send lists?

Xaver

``````#include "m_pd.h"

static t_class *maximum_tilde_class;

typedef struct _maximum_tilde {
t_object  x_obj;
t_sample d;

t_inlet*x_in1;
t_outlet*f_out;
} t_maximum_tilde;

t_int *maximum_tilde_perform(t_int *w)
{
t_maximum_tilde *x = (t_maximum_tilde *)(w[1]);
t_sample    *in1 = (t_sample *)(w[2]);
int            n = (int)(w[3]);

float max[] = { 0,-1 };
float abs_val =  0;

for (int i = 0; i < n; i++) {
abs_val = fabs(in1[i]);
if (abs_val > max[0]) {
max[0] = abs_val;
max[1] = i;
}
}

outlet_float(x->f_out, (max[0], max[1]) );
return (w + 4);
}

void maximum_tilde_dsp(t_maximum_tilde *x, t_signal **sp)
{
x,
sp[0]->s_vec, data forum

sp[0]->s_n);
}

void maximum_tilde_free(t_maximum_tilde *x)
{
inlet_free(x->x_in1);
}

void *maximum_tilde_new(t_floatarg f)
{
t_maximum_tilde *x = (t_maximum_tilde *)pd_new(maximum_tilde_class);
x->f_out = outlet_new(&x->x_obj, &s_list);
return (void *)x;
}

void init_maximum(void) {
maximum_tilde_class = class_new(gensym("max~"),
(t_newmethod)maximum_tilde_new,
0,//(t_method)maximum_tilde_free,
sizeof(t_maximum_tilde),
CLASS_DEFAULT,
A_DEFFLOAT, 0);

(t_method)maximum_tilde_dsp, gensym("dsp"), 0);
CLASS_MAINSIGNALIN(maximum_tilde_class, t_maximum_tilde, d);
}

void helloworld_setup(void) {
init_maximum();
}
``````
• Posts 8 | Views 6191
• You shout used outlet_list() instead of outlet_float().

``````outlet_list(x->x_out, &s_list, n, argv)
``````

where `x->x_out` is the pointer to the outlet, `n` is an integer representing the size of the list, and `argv` is an array of type t_atom containing the list elements.

If you look at Pd's source code, there is a file called x_list.c that contains the code for the list objects. It might help to look through that.

• You should use a clock to send the list with the other messages. Pd manages the messages by blocks between the signal blocks. Here you send a list inside a signal block, it shouldn't be very dangerous but it's better to use a clock with a zero delay that forces the synchronization with the next message block.

``````object_tick(t_object *x) {
av[2];
outlet_list(x->m_outlet, &s_list, 2, av);
}

perform(t_int *w) {
...
clock_set(x->m_clock, 0.f);
return (w+1);
}
``````

Here is an example.

Small tip:
You don't have to free the inlets (and the outlets).

@Maelstorm
I had a look at x_list.c and at sigmund~.c as sigmund sends out lists. I adapted code from sigmund and it works.

I inserted t_atom at[2]; in the struct and replaced line 30 outlet_float... with:

``````SETFLOAT(x->at, (t_float)max[0]);
SETFLOAT(x->at + 1, (t_float)max[1]);
outlet_list(x->f_out, 0, 2, x->at );
``````

Can you tell me, why your second argument is &s_list whereas in sigmund its just 0?

@Pierre
What is the advantage to send the message by a clock over doing it with an outlet?

And thanks for your tip. The HowTo says they should, but in the code, the method isn't used.
see HowTo
That was confusing me anyway.

• The clock methods are called just before the signal methods. So this approach ensures that the call of the outlet_list method will be done with the other message methods and not between two signal methods. As I said, in this case it's not a big deal because Pd has sequential approach but if one day Pd uses threads to parallelize the message and the dsp it can bring concurrency errors.

Yes, this part of the tutorial seems deprecated. All the inlets and outlets are linked, so Pd can free them at the destruction of the object. In fact it's necessary to free them only if you use your own inlets (for the proxy inlets like in [pack] for example).

• Thanks for your advise about the clock method. As this is quite important, this information should be given somewhere (In externs/dspobj~.c which comes with pd for example)

What are own inlets? Is a second inlet~ already an own inlet?
Can you point me to the source of [pack]? (Couldn't find a file "pack.c" or similar in pd's repository on github.)

Do I have to free memory I allocated myself with malloc?
(I just started with C (coming from Python), so I'm still unsure about how things work exactly.)

To leave a working example, here's my corrected code:

``````#include "m_pd.h"

static t_class *maximum_tilde_class;

typedef struct _maximum_tilde {
t_object    x_obj;
t_float     f;
t_clock*    m_clock;
t_inlet*    x_in1;
t_outlet*   f_out;
t_atom      at[2];
} t_maximum_tilde;

t_int maximum_tilde_tick(t_maximum_tilde *x) {
outlet_list(x->f_out, &s_list, 2, x->at);
}

t_int *maximum_tilde_perform(t_int *w)
{
t_maximum_tilde *x = (t_maximum_tilde *)(w[1]);
t_sample    *in1 = (t_sample *)(w[2]);
int            n = (int)(w[3]);

float max[] = { 0,-1 };
float abs_val =  0;

for (int i = 0; i < n; i++) {
abs_val = fabs(in1[i]);
if (abs_val > max[0]) {
max[0] = abs_val;
max[1] = i;
}
}

SETFLOAT(x->at, (t_float)max[0]);
SETFLOAT(x->at + 1, (t_float)max[1]);
clock_set(x->m_clock, 0.f);

return (w + 4);
}

void maximum_tilde_dsp(t_maximum_tilde *x, t_signal **sp)
{
x,
sp[0]->s_vec,
sp[0]->s_n);
}

void *maximum_tilde_new(t_floatarg f)
{
t_maximum_tilde *x = (t_maximum_tilde *)pd_new(maximum_tilde_class);

x->f_out = outlet_new(&x->x_obj, &s_list);
x->m_clock = clock_new(x, (t_method)maximum_tilde_tick);

return (void *)x;
}

void init_maximum(void) {
maximum_tilde_class = class_new(gensym("max~"),
(t_newmethod)maximum_tilde_new,
0,
sizeof(t_maximum_tilde),
CLASS_DEFAULT,
A_DEFFLOAT, 0);

(t_method)maximum_tilde_dsp, gensym("dsp"), 0);
CLASS_MAINSIGNALIN(maximum_tilde_class, t_maximum_tilde, f);
}

void helloworld_setup(void) {
init_maximum();
}
``````
• Thanks for your advise about the clock method. As this is quite important, this information should be given somewhere (In externs/dspobj~.c which comes with pd for example)

That's the difficulty with Pd, sometimes the information are scattered between this forum, puredata.info, the mailing list, facebook, etc. But you already have an example in d_misc.c with the object [bang~] (and it seems that I did a mistake, you should use clock_delay instead of clock_set. I don't know if it really matters, I'll investigate the code).

What are own inlets? Is a second inlet~ already an own inlet?
Can you point me to the source of [pack]? (Couldn't find a file "pack.c" or similar in pd's repository on github.)

No, in fact inlets' pointers are pretty useless that's why almost nobody use them in their objects. But the second arguments of the inlet_new methods can be necessary (pointerinlet_new, floatinlet_new, etc.). For example, when you create a floatinlet_new, you give the adress of the float value to set. If you need to allocate memory for this, you need to free it at the destruction of your object (see [pack] in x_connective.c). But you can also use another class as an intermediary between the "real" inlet and your object, I call this a "proxy" like in Max. In the function

``````EXTERN t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1,
t_symbol *s2);
``````

owner is your object, dest can be the proxy, s1 is the symbol expected by your object and s2 is the symbol that will be used for the proxy.
If you want an example, you can have a look at [clone] in g_clone.c or this example I made.

Do I have to free memory I allocated myself with malloc?
(I just started with C (coming from Python), so I'm still unsure about how things work exactly.)

Yes of course. And you can use t_getbytes and t_freebytes if you only want to include m_pd.h