/* * Pure Data Packet base class implementation. * Copyright (c) by Tom Schouten * * 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 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; ib_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; ib_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 (s == S_REGISTER_RO){ 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 (s == S_REGISTER_RW) { 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 ((s == S_PROCESS) && (-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 != S_REGISTER_RO) 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; ib_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; ib_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; ib_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; } }