aboutsummaryrefslogtreecommitdiff
path: root/system/pdbase
diff options
context:
space:
mode:
Diffstat (limited to 'system/pdbase')
-rw-r--r--system/pdbase/Makefile11
-rw-r--r--system/pdbase/pdp_base.c415
-rw-r--r--system/pdbase/pdp_dpd_base.c270
-rw-r--r--system/pdbase/pdp_imagebase.c79
4 files changed, 775 insertions, 0 deletions
diff --git a/system/pdbase/Makefile b/system/pdbase/Makefile
new file mode 100644
index 0000000..58efa41
--- /dev/null
+++ b/system/pdbase/Makefile
@@ -0,0 +1,11 @@
+
+OBJECTS = pdp_base.o pdp_imagebase.o pdp_dpd_base.o
+
+
+include ../../Makefile.config
+
+all: $(OBJECTS)
+
+clean:
+ rm -f *~
+ rm -f *.o
diff --git a/system/pdbase/pdp_base.c b/system/pdbase/pdp_base.c
new file mode 100644
index 0000000..4d5593f
--- /dev/null
+++ b/system/pdbase/pdp_base.c
@@ -0,0 +1,415 @@
+/*
+ * Pure Data Packet base class implementation.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/*
+
+ This file contains the pdp base class object.
+ This is really nothing more than an attempt to stay away from c++
+ as far as possible, while having some kind of base class functionality
+ for pdp (tucking away the communication & thread protocol).
+
+*/
+
+#include "pdp_base.h"
+#include <stdarg.h>
+
+
+static void pdp_base_debug(t_pdp_base *b, t_floatarg f)
+{
+ int i;
+ post("debug");
+ post("inlets: %d", b->b_inlets);
+ post("\tpacket\tnext_packet");
+ for (i=0; i<b->b_inlets; i++)
+ post("\t%d\t%d", b->b_packet[i], b->b_packet_next[i]);
+ //post("outlets: %d", b->b_inlets);
+}
+
+static void pdp_base_thread(t_pdp_base *b, t_floatarg f)
+{
+ int i = (int)f;
+ if ((i == 0) || (i == 1)) b->b_thread_enabled = i;
+}
+
+static void pdp_base_process(t_pdp_base *b)
+{
+
+ if (b->b_process_method)
+ (*b->b_process_method)(b);
+}
+
+/* this method is called after the thread has finished processing */
+static void pdp_base_postprocess(t_pdp_base *b)
+{
+ /* call the derived class postproc callback if there is any */
+ if (b->b_postproc_method)
+ (*b->b_postproc_method)(b);
+
+ /* unregister (mark unused) packet and propagate if packet is valid */
+ if (b->b_outlet[0])
+ pdp_pass_if_valid(b->b_outlet[0], &b->b_packet[0]);
+}
+
+
+/* move the passive packets in place */
+void pdp_base_movepassive(void *x)
+{
+ t_pdp_base *b = (t_pdp_base *)x;
+ int i;
+
+ /* if a cold packet was received in the meantime
+ swap it in, else keep the old one */
+ for (i=1; i<b->b_inlets; i++){
+ pdp_replace_if_valid(&b->b_packet[i], &b->b_packet_next[i]);
+ }
+
+
+}
+
+/* the standard bang method */
+void pdp_base_bang(void *x)
+{
+ t_pdp_base *b = (t_pdp_base *)x;
+ int i;
+
+ /* if pdp thread is still processing, do nothing */
+ if (-1 != b->b_queue_id) return;
+
+ /* move packets in place */
+ pdp_base_movepassive(x);
+
+
+ /* if there is a preproc method defined, call it inside
+ the pd thread. (mainly for allocations) */
+ if (b->b_preproc_method)
+ (*b->b_preproc_method)(b);
+
+ /* check if we need to use pdp queue */
+ if (b->b_thread_enabled){
+
+ /* add the process method and callback to the process queue */
+ pdp_procqueue_add(b->b_q, b, pdp_base_process, pdp_base_postprocess, &b->b_queue_id);
+ }
+ else{
+ /* call both methods directly */
+ pdp_base_process(b);
+ pdp_base_postprocess(b);
+ }
+}
+
+/* hot packet input handler */
+void pdp_base_input_hot(t_pdp_base *b, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+
+ /* dont register if active inlet is disabled */
+ if (!b->b_active_inlet_enabled) return;
+
+ /* register the packet (readonly or read/write)
+ or drop it if we have an active packet
+ if type template is not null, packet will be converted */
+
+
+ if (b->b_active_inlet_readonly){
+ if (pdp_sym_rro() == s){
+ if (b->b_type_template[0]){
+ pdp_packet_convert_ro_or_drop(&b->b_packet[0], p, b->b_type_template[0]);
+ }
+ else{
+ pdp_packet_copy_ro_or_drop(&b->b_packet[0], p);
+ }
+ }
+ }
+ else{
+ if (pdp_sym_rrw() == s) {
+ if (b->b_type_template[0]){
+ pdp_packet_convert_rw_or_drop(&b->b_packet[0], p, b->b_type_template[0]);
+ }
+ else{
+ pdp_packet_copy_rw_or_drop(&b->b_packet[0], p);
+ }
+ }
+ }
+
+ /* start processing if there is an active packet to process
+ and the processing method is not active */
+
+ if ((pdp_sym_prc() == s) && (-1 != b->b_packet[0]) && (-1 == b->b_queue_id)){
+ pdp_base_bang(b);
+ }
+ //if ((pdp_sym_prc() == s) && (-1 != b->b_packet[0]) && (!b->b_dropped)) pdp_base_bang(b);
+
+}
+
+/* cold packet input handlers */
+void pdp_base_input_cold(t_pdp_base *b, t_symbol *s, int ac, t_atom *av)
+{
+
+ int p;
+ int i;
+ char msg[] = "pdp1";
+ char *c;
+
+ int inlet;
+
+ //post("pdp_base_input_cold: got packet");
+
+ /* do cheap tests first */
+ if (ac != 2) return;
+ if (av[0].a_type != A_SYMBOL) return;
+ if (av[0].a_w.w_symbol != pdp_sym_rro()) return;
+ if (av[1].a_type != A_FLOAT) return;
+ p = (int)av[1].a_w.w_float;
+
+
+ /* check if it's a pdp message
+ and determine inlet */
+ for (i=1; i<MAX_NB_PDP_BASE_INLETS; i++){
+ if (s == gensym(msg)){
+ inlet = i;
+ goto found;
+ }
+ else{
+ msg[3]++;
+ }
+ }
+ return;
+
+
+ found:
+
+ /* store the packet and trow away
+ the old one, if there is any */
+
+ pdp_packet_copy_ro_or_drop(&b->b_packet_next[inlet], p);
+}
+
+
+void pdp_base_set_process_method(void *x, t_pdp_method m)
+{
+ t_pdp_base *b = (t_pdp_base *)x;
+ b->b_process_method = m;
+}
+
+void pdp_base_set_preproc_method(void *x, t_pdp_method m)
+{
+ t_pdp_base *b = (t_pdp_base *)x;
+ b->b_preproc_method = m;
+}
+
+
+void pdp_base_set_postproc_method(void *x, t_pdp_method m)
+{
+ t_pdp_base *b = (t_pdp_base *)x;
+ b->b_postproc_method = m;
+}
+
+
+void pdp_base_queue_wait(void *x)
+{
+ t_pdp_base *b = (t_pdp_base *)x;
+ pdp_procqueue_wait(b->b_q);
+}
+
+void pdp_base_set_queue(void *x, t_pdp_procqueue *q)
+{
+ t_pdp_base *b = (t_pdp_base *)x;
+ pdp_base_queue_wait(x);
+ b->b_q = q;
+}
+
+t_pdp_procqueue *pdp_base_get_queue(void *x)
+{
+ t_pdp_base *b = (t_pdp_base *)x;
+ return b->b_q;
+}
+
+void pdp_base_setup(t_class *c)
+{
+
+ /* add pdp base class methods */
+ class_addmethod(c, (t_method)pdp_base_thread, gensym("thread"), A_FLOAT, A_NULL);
+ class_addmethod(c, (t_method)pdp_base_debug, gensym("debug"), A_NULL);
+
+ /* hot packet handler */
+ class_addmethod(c, (t_method)pdp_base_input_hot, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+ /* cold packet handler */
+ class_addanything(c, (t_method)pdp_base_input_cold);
+}
+
+/* pdp base instance constructor */
+void pdp_base_init(void *x)
+{
+ int i;
+ t_pdp_base *b = (t_pdp_base *)x;
+
+ b->b_channel_mask = -1;
+
+ for(i=0; i<MAX_NB_PDP_BASE_INLETS; i++){
+ b->b_packet[i] = -1;
+ b->b_packet_next[i] = -1;
+ b->b_type_template[i] = 0;
+ }
+
+ b->b_queue_id = -1;
+ //b->b_dropped = 0;
+ b->b_process_method = 0;
+ b->b_preproc_method = 0;
+ b->b_inlets = 1;
+ b->b_outlets = 0;
+ b->b_active_inlet_enabled = 1;
+ b->b_active_inlet_readonly = 0;
+ b->b_thread_enabled = 1;
+
+ // default queue is pdp queue
+ b->b_q = pdp_queue_get_queue();
+
+}
+
+/* base instance destructor */
+void pdp_base_free(void *x)
+{
+ int i;
+ t_pdp_base *b = (t_pdp_base *)x;
+ /* remove process method from queue before deleting data */
+ pdp_procqueue_finish(b->b_q, b->b_queue_id);
+
+ /* delete stuff */
+ for(i=0; i<MAX_NB_PDP_BASE_INLETS; i++){
+ pdp_packet_mark_unused(b->b_packet[i]);
+ pdp_packet_mark_unused(b->b_packet_next[i]);
+ }
+
+}
+
+void pdp_base_readonly_active_inlet(void *x)
+{
+ t_pdp_base *b = (t_pdp_base *)x;
+ b->b_active_inlet_readonly = 1;
+}
+
+void pdp_base_disable_active_inlet(void *x)
+{
+ t_pdp_base *b = (t_pdp_base *)x;
+ b->b_active_inlet_enabled = 0;
+}
+
+
+/* add an inlet */
+void pdp_base_add_pdp_inlet(void *x)
+{
+ t_pdp_base *b = (t_pdp_base *)x;
+ char s[] = "pdp0";
+ s[3] += b->b_inlets;
+
+ if (b->b_inlets < MAX_NB_PDP_BASE_INLETS){
+ inlet_new(&b->x_obj, &b->x_obj.ob_pd, gensym("pdp"), gensym(s));
+ b->b_inlets++;
+ }
+ else {
+ post("pdp_base_add_pdp_inlet: only %d pdp inlets allowed. ignoring.", MAX_NB_PDP_BASE_INLETS);
+ }
+}
+
+
+/* add an outlet: only one allowed */
+t_outlet *pdp_base_add_pdp_outlet(void *x)
+{
+ t_pdp_base *b = (t_pdp_base *)x;
+ t_outlet *outlet = outlet_new(&b->x_obj, &s_anything);
+
+
+ if (b->b_outlets < MAX_NB_PDP_BASE_OUTLETS){
+ b->b_outlet[b->b_outlets] = outlet;
+ b->b_outlets++;
+ }
+
+ return outlet;
+
+}
+
+void pdp_base_set_packet(void *x, int inlet, int packet)
+{
+ t_pdp_base *b = (t_pdp_base *)x;
+
+ if (inlet < b->b_inlets){
+ //post("%d %d", b->b_packet[inlet], b->b_packet_next[inlet]);
+ pdp_packet_mark_unused(b->b_packet[inlet]);
+ b->b_packet[inlet] = packet;
+ }
+}
+
+
+int pdp_base_get_packet(void *x, int inlet)
+{
+ t_pdp_base *b = (t_pdp_base *)x;
+
+ if (inlet < b->b_inlets){
+ //post("%d %d", b->b_packet[inlet], b->b_packet_next[inlet]);
+ return (b->b_packet[inlet]);
+ }
+
+ return -1;
+}
+
+int pdp_base_move_packet(void *x, int inlet)
+{
+ t_pdp_base *b = (t_pdp_base *)x;
+ int p;
+
+ if (inlet < b->b_inlets){
+ p = b->b_packet[inlet];
+ b->b_packet[inlet] = -1;
+ return (p);
+ }
+
+ return -1;
+}
+
+
+
+t_object *pdp_base_get_object(void *x)
+{
+ return (t_object *)x;
+}
+
+void pdp_base_add_gen_inlet(void *x, t_symbol *from, t_symbol *to)
+{
+ t_object *o = (t_object *)x;
+ inlet_new(o, &o->ob_pd, from, to);
+}
+
+void pdp_base_disable_thread(void *x)
+{
+
+ t_pdp_base *b = (t_pdp_base *)x;
+ b->b_thread_enabled = 0;
+}
+
+void pdp_base_set_type_template(void *x, int inlet, t_pdp_symbol *type_template)
+{
+ t_pdp_base *b = (t_pdp_base *)x;
+ if (inlet < b->b_inlets){
+ b->b_type_template[inlet] = type_template;
+ }
+}
diff --git a/system/pdbase/pdp_dpd_base.c b/system/pdbase/pdp_dpd_base.c
new file mode 100644
index 0000000..162368d
--- /dev/null
+++ b/system/pdbase/pdp_dpd_base.c
@@ -0,0 +1,270 @@
+/*
+ * Pure Data Packet module. DPD base class implementation.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include "pdp_dpd_base.h"
+#include "pdp_internals.h"
+
+
+#define THIS(b) t_pdp_dpd_base *b = (t_pdp_dpd_base *)x
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+/* PRIVATE METHODS */
+
+
+
+
+/* dpd packet context input handler */
+static void _pdp_dpd_base_context_input(t_pdp_dpd_base *b, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+ int i;
+
+ //post ("pdp_dpd_base_context_input: got %s %d", s->s_name, p);
+
+ /* sources/sinks have active inlet disabled */
+ if (b->b_dpd_active_inlet_disabled) return;
+
+ /* handle inspect message */
+ if (pdp_sym_ins() == s){
+
+ /* store packet for inspector */
+ b->b_context_packet = p;
+
+ /* add inspector to pdp queue
+ this is special: it doesn't use a command object */
+ pdp_dpd_base_queue_command(b, b, b->b_inspector_method, b->b_inspector_callback, 0);
+ }
+
+ /* handle accumulate message */
+ if (pdp_sym_acc() == s){
+
+ /* store context for accumulator methods */
+ b->b_context_packet = p;
+
+ /* call bang */
+ pdp_dpd_base_bang(b);
+
+
+ }
+
+}
+
+/* default command object (returns self) */
+void *_pdp_dpd_base_get_command_object(void *x){return x;}
+
+/* PUBLIC METHODS */
+
+
+void pdp_dpd_base_queue_command(void *x, void *c, t_pdp_method process,
+ t_pdp_method callback, int *id)
+{
+ THIS(b);
+ t_pdp_procqueue *q = pdp_base_get_queue(x);
+ pdp_procqueue_add(q, c, process, callback, id);
+
+}
+
+/* bang method (propagate context to outlet) : it is not registered as a pd message by default ! */
+void pdp_dpd_base_bang(void *x)
+{
+ THIS(b);
+ int i, id;
+ void *cobj;
+
+ /* move passive pdp packets in place */
+ pdp_base_movepassive(x);
+
+ /* get command object (or use self) */
+ cobj = b->b_command_factory_method ? (b->b_command_factory_method)(b) : b;
+ //post(" command object is %x. object is %x", cobj, b);
+
+
+ /* queue acc method & propagate for all outlets */
+ for (i=b->b_nb_context_outlets; i--;){
+
+
+ /* propagate the context packet to the outlet */
+ if (b->b_outlet_enable[i]){
+ pdp_dpd_base_queue_command(x, cobj, b->b_accum_method[i], b->b_accum_callback[i], 0);
+ outlet_dpd(b->b_context_outlet[i], b->b_context_packet);
+ }
+ else{
+ //post("outlet %d disabled", i);
+ }
+ }
+
+ /* queue cleanup method */
+ if (b->b_cleanup_method)
+ //pdp_procqueue_add(b->b_q, b, b->b_cleanup_method, 0, &b->b_cleanup_queue_id);
+ pdp_dpd_base_queue_command(x, cobj, b->b_cleanup_method, b->b_cleanup_callback, 0);
+
+ /* send communication complete notify */
+ if (b->b_complete_notify)
+ (b->b_complete_notify)(x);
+
+}
+
+/* get/set context packet */
+int pdp_dpd_base_get_context_packet(void *x){
+ THIS(b);
+ return b->b_context_packet;
+}
+int pdp_dpd_base_move_context_packet(void *x){
+ THIS(b);
+ int p = b->b_context_packet;
+ b->b_context_packet = -1;
+ return p;
+}
+
+void pdp_dpd_base_set_context_packet(void *x, int p){
+ THIS(b);
+ pdp_packet_mark_unused(b->b_context_packet);
+ b->b_context_packet = p;
+}
+
+/* add a cleanup callback (called after all propagation is finished) for sources/sinks */
+void pdp_dpd_base_add_cleanup(void *x, t_pdp_method cleanup_method, t_pdp_method cleanup_callback)
+{
+ THIS(b);
+ b->b_cleanup_method = cleanup_method;
+ b->b_cleanup_callback = cleanup_callback;
+ //b->b_cleanup_queue_id = -1;
+}
+
+/* add a inspector callback */
+void pdp_dpd_base_add_inspector(void *x, t_pdp_method inspector_method)
+{
+ THIS(b);
+ b->b_inspector_method = inspector_method;
+ //b->b_inspector_queue_id = -1;
+}
+
+/* add a context outlet */
+t_outlet *pdp_dpd_base_add_outlet(void *x, t_pdp_method accum_method, t_pdp_method accum_callback)
+{
+ THIS(b);
+ int i = b->b_nb_context_outlets;
+ if (i < PDP_DPD_MAX_CONTEXT_OUTLETS){
+ b->b_context_outlet[i] = outlet_new((t_object *)b, &s_anything);
+ b->b_outlet_enable[i] = 1;
+ b->b_accum_method[i] = accum_method;
+ b->b_accum_callback[i] = accum_callback;
+ //b->b_accum_queue_id[i] = -1;
+ b->b_nb_context_outlets++;
+ return b->b_context_outlet[i];
+ }
+ else{
+ post("pdp_dpd_base_add_outlet: no more free outlet slots");
+ return 0;
+ }
+
+}
+
+
+/* destructor */
+void pdp_dpd_base_free(void *x)
+{
+ THIS(b);
+
+ /* free base */
+ pdp_base_free(b);
+}
+
+
+void pdp_dpd_base_disable_active_inlet(void *x)
+{
+ THIS(b);
+ b->b_dpd_active_inlet_disabled = 1;
+}
+
+
+
+void pdp_dpd_base_enable_outlet(void *x, int outlet, int toggle)
+{
+ THIS(b);
+ if (outlet >=0 && outlet < PDP_DPD_MAX_CONTEXT_OUTLETS){
+ b->b_outlet_enable[outlet] = toggle;
+ }
+
+}
+
+
+void pdp_dpd_base_register_complete_notify(void *x, t_pdp_method method)
+{
+ THIS(b);
+ b->b_complete_notify = method;
+}
+
+void pdp_dpd_base_register_command_factory_method(void *x, t_pdp_newmethod command_factory_method)
+{
+ THIS(b);
+ b->b_command_factory_method = command_factory_method;
+}
+
+
+/* init method */
+void pdp_dpd_base_init(void *x)
+{
+ THIS(b);
+
+ /* super init */
+ pdp_base_init(b);
+
+ /* disable pdp messages on active inlet (dpd messages are used as sync) */
+ pdp_base_disable_active_inlet(b);
+
+ /* init data */
+ b->b_nb_context_outlets = 0;
+ b->b_context_packet = -1;
+ b->b_cleanup_method = 0;
+ //b->b_cleanup_queue_id = -1;
+ b->b_inspector_method = 0;
+ //b->b_inspector_queue_id = -1;
+ b->b_dpd_active_inlet_disabled = 0;
+
+ // default notify == none
+ b->b_complete_notify = 0;
+
+ // default command object getter
+ b->b_command_factory_method = 0;
+
+}
+
+
+void pdp_dpd_base_setup(t_class *class)
+{
+
+ pdp_base_setup(class);
+ class_addmethod(class, (t_method)_pdp_dpd_base_context_input, gensym("dpd"), A_SYMBOL, A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/system/pdbase/pdp_imagebase.c b/system/pdbase/pdp_imagebase.c
new file mode 100644
index 0000000..f9634e1
--- /dev/null
+++ b/system/pdbase/pdp_imagebase.c
@@ -0,0 +1,79 @@
+/*
+ * Pure Data Packet image processor base class implementation.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/*
+
+ This file contains the pdp image base class object.
+*/
+
+#include "pdp_imagebase.h"
+#include <stdarg.h>
+
+
+static void pdp_imagebase_chanmask(t_pdp_base *b, t_floatarg f)
+{
+ int i = (int)f;
+ if (i < 0) i = -1;
+ b->b_channel_mask = i;
+}
+
+void pdp_imagebase_setup(t_class *c)
+{
+ /* parent class setup */
+ pdp_base_setup(c);
+
+ /* add pdp base class methods */
+ class_addmethod(c, (t_method)pdp_imagebase_chanmask, gensym("chanmask"), A_FLOAT, A_NULL);
+
+}
+
+/* pdp base instance constructor */
+void pdp_imagebase_init(void *x)
+{
+ int i;
+ t_pdp_imagebase *b = (t_pdp_imagebase *)x;
+
+ /* init super */
+ pdp_base_init(x);
+
+ /* convert all active incoming packet types to image */
+ pdp_base_set_type_template(x, 0, pdp_gensym("image/*/*"));
+
+ /* default chanmask == all */
+ b->b_channel_mask = -1;
+
+}
+
+/* base instance destructor */
+void pdp_imagebase_free(void *x)
+{
+ /* free super */
+ pdp_base_free(x);
+
+}
+
+/* chanmask getter */
+u32 pdp_imagebase_get_chanmask(void *x)
+{
+ t_pdp_base *b = (t_pdp_base *)x;
+ return b->b_channel_mask;
+}
+