[PD-cvs] externals/pdp/puredata CONTENTS, 1.2, 1.3 Makefile, 1.2, 1.3 pdp_base.c, 1.2, 1.3 pdp_comm.c, 1.2, 1.3 pdp_compat.c, 1.2, 1.3 pdp_control.c, 1.2, 1.3 pdp_dpd_base.c, 1.2, 1.3 pdp_imagebase.c, 1.2, 1.3 pdp_queue.c, 1.2, 1.3 pdp_ut.c, 1.2, 1.3

Hans-Christoph Steiner eighthave at users.sourceforge.net
Fri Dec 16 02:05:38 CET 2005


Update of /cvsroot/pure-data/externals/pdp/puredata
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6756/puredata

Added Files:
	CONTENTS Makefile pdp_base.c pdp_comm.c pdp_compat.c 
	pdp_control.c pdp_dpd_base.c pdp_imagebase.c pdp_queue.c 
	pdp_ut.c 
Log Message:
checking in pdp 0.12.4 from http://zwizwa.fartit.com/pd/pdp/pdp-0.12.4.tar.gz

--- NEW FILE: pdp_imagebase.c ---
/*
 *   Pure Data Packet image processor base class implementation.
 *   Copyright (c) by Tom Schouten <pdp at 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;
}


--- NEW FILE: pdp_dpd_base.c ---
/*
 *   Pure Data Packet module. DPD base class implementation.
 *   Copyright (c) by Tom Schouten <pdp at 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 (s == S_INSPECT){

	/* 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 (s == S_ACCUMULATE){

	/* 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

--- NEW FILE: Makefile ---

OBJECTS = pdp_base.o pdp_imagebase.o pdp_dpd_base.o  pdp_ut.o  pdp_queue.o pdp_comm.o \
	pdp_control.o pdp_compat.o $(PDP_PDMOD)


include ../Makefile.config

all: $(OBJECTS)

clean:
	rm -f *~
	rm -f *.o

--- NEW FILE: pdp_comm.c ---
/*
 *   Pure Data Packet system implementation.
 *   Copyright (c) by Tom Schouten <pdp at 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 misc communication (packet) methods for pd */


#include <stdio.h>
#include "pdp_pd.h"
#include "pdp_internals.h"
#include "pdp_packet.h"
#include "pdp_comm.h"
#include "pdp_type.h"
#include "pdp_control.h"
#include "pdp_mem.h"
#include "pdp_queue.h" // for notify drop: fix this (should be from pdp_control.h)
#include "pdp_debug.h"

/* all symbols are C style */
#ifdef __cplusplus
extern "C"
{
#endif


/* interface to pd system:
   pdp/dpd communication protocol in pd
   pd <-> pdp atom and list conversion */
   
    /* NOTE: when using the outlet_pdp methods, the packet
       is no longer read/write, but can be readonly */


    /* NOTE: since 0.13 the passing packet is no more.
       in order to limit copying. processors should always register ro,
       and replace with writable when packet needs to be written in the process method */


/* send a packet to an outlet */
void outlet_pdp_register(t_outlet *out, int packetid)
{
    t_atom atom[2];

    SETFLOAT(atom+1, (float)packetid);

    /* during the following phase, 
       objects can register a ro copy */

    SETSYMBOL(atom+0, S_REGISTER_RO);         
    outlet_anything(out, S_PDP, 2, atom);

    /* DEPRECIATED: objects can register a rw copy
       but this will always copy the packet. it is better
       to perform a pdp_packet_replace_with_writable operation during the process step */

    SETSYMBOL(atom+0, S_REGISTER_RW);         
    outlet_anything(out, S_PDP, 2, atom);    

}
/* send a packet to an outlet */
void outlet_pdp_process(t_outlet *out)
{
    t_atom atom[2];

    /* set a dummy invalid packet.
       this is for uniform pdp messages in pd, for ease of routing. */
    SETFLOAT(atom+1, (float)-1);

    /* during the process phase, objects can perform pdp_packet_replace_with_writable
       and process the packet data */
    SETSYMBOL(atom+0, S_PROCESS);
    outlet_anything(out, S_PDP, 2, atom);

}

/* for compat */
void outlet_pdp(t_outlet *out, int packetid)
{
    outlet_pdp_register(out, packetid);
    outlet_pdp_process(out);
}

/* send an accumulation packet to an outlet */
void outlet_dpd(t_outlet *out, int packetid)
{
    t_atom atom[2];

    SETFLOAT(atom+1, (float)packetid);

    SETSYMBOL(atom+0, S_INSPECT);
    outlet_anything(out, S_DPD, 2, atom);

    SETSYMBOL(atom+0, S_ACCUMULATE);
    outlet_anything(out, S_DPD, 2, atom);

}

/* unregister a packet and send it to an outlet */
void

pdp_packet_pass_if_valid(t_outlet *outlet, int *packet_ptr)
{
    t_pdp *header = pdp_packet_header(*packet_ptr);
    if (header){

	/* send register phase */
	outlet_pdp_register(outlet, *packet_ptr);

	/* unregister */
	pdp_packet_mark_unused(*packet_ptr);
	*packet_ptr = -1;

	/* send process phase */
	outlet_pdp_process(outlet);

    }
}

void
pdp_packet_replace_if_valid(int *dpacket, int *spacket)
{
    if (-1 != *spacket){
	pdp_packet_mark_unused(*dpacket);
	*dpacket = *spacket;
	*spacket = -1;
    }
    
}


int
pdp_packet_copy_ro_or_drop(int *dpacket, int spacket)
{
    int drop = 0;
    if (*dpacket == -1) *dpacket = pdp_packet_copy_ro(spacket);
    else {
	/* send a notification there is a dropped packet */
	pdp_control_notify_drop(spacket);
	drop = 1;
    }
    return drop;
}


int
pdp_packet_copy_rw_or_drop(int *dpacket, int spacket)
{
    int drop = 0;
    if (*dpacket == -1) *dpacket = pdp_packet_copy_rw(spacket);
    else {
	/* send a notification there is a dropped packet */
	pdp_control_notify_drop(spacket);
	drop = 1;
    }
    return drop;
}

int
pdp_packet_convert_ro_or_drop(int *dpacket, int spacket, t_pdp_symbol *template)
{
    int drop = 0;

    if (!template) return pdp_packet_copy_ro_or_drop(dpacket, spacket);

    if (*dpacket == -1) *dpacket = pdp_packet_convert_ro(spacket, template);
    else {
	/* send a notification there is a dropped packet */
	pdp_control_notify_drop(spacket);
	drop = 1;
    }
    return drop;
}


int
pdp_packet_convert_rw_or_drop(int *dpacket, int spacket, t_pdp_symbol *template)
{
    int drop = 0;

    if (!template) return pdp_packet_copy_rw_or_drop(dpacket, spacket);

    if (*dpacket == -1) *dpacket = pdp_packet_convert_rw(spacket, template);
    else {
	/* send a notification there is a dropped packet */
	pdp_control_notify_drop(spacket);
	drop = 1;
    }
    return drop;
}


/* send a pdp list to a pd outlet. packets are not copied but passed! */
void outlet_pdp_atom(t_outlet *out, t_pdp_atom *a)
{
    int packet = -1;
    if (!a) return;
    switch(a->t){
    case a_float:
	outlet_float(out, a->w.w_float);
	return;
    case a_int:
	outlet_float(out, (float)a->w.w_int);
	return;
    case a_symbol:
	outlet_symbol(out, gensym(a->w.w_symbol->s_name));
	return;
    case a_list:
	outlet_pdp_list(out, a->w.w_list);
	return;
    case a_packet:
	pdp_packet_pass_if_valid(out, &a->w.w_packet);
	return;
    default:
	return;
    }
}

void outlet_pdp_list(t_outlet *out, struct _pdp_list *l)
{
    int elements;
    t_atom *atomlist;
    t_pdp_atom *pdp_a;
    t_atom *pd_a;
    t_symbol *pd_selector;
    
    if (!l) return;
    switch(l->elements){
    case 0: /* bang */
	outlet_bang(out);
	return;
    case 1: /* atom */
	outlet_pdp_atom(out, l->first);
	return;
    default: /* proper list*/
	elements = l->elements;

	/* allocate list */
	atomlist = pdp_alloc(sizeof (t_atom) * l->elements);
	pd_a = atomlist;
	pdp_a = l->first;

	/* setup selector */
	if (pdp_a->t != a_symbol){
	    pd_selector = gensym("list");
	}
	else {
	    pd_selector = gensym(pdp_a->w.w_symbol->s_name);
	    elements--;
	    pdp_a = pdp_a->next;
	}

	/* setup atoms */
	while (pdp_a){
	    switch(pdp_a->t){
	    case a_float:
		SETFLOAT(pd_a, pdp_a->w.w_float);
		break;
	    case a_int:
		SETFLOAT(pd_a, (float)pdp_a->w.w_int);
		break;
	    case a_symbol:
		SETSYMBOL(pd_a, gensym(pdp_a->w.w_symbol->s_name));
		break;
	    default:
		SETSYMBOL(pd_a, gensym("invalid"));
		break;
	    }
			  
	    pdp_a = pdp_a->next;
	    pd_a++;
	}

	/* send out */
	outlet_anything(out, pd_selector, elements, atomlist);
	    


	/* clean up */
	pdp_dealloc(atomlist);
	
    }	
	
		
}


void pd_atom_to_pdp_atom(t_atom *pdatom, t_pdp_atom *pdpatom)
{
    switch (pdatom->a_type){
    case A_FLOAT:
	pdpatom->t = a_float;
	pdpatom->w.w_float = pdatom->a_w.w_float;
	break;
    case A_SYMBOL:
	pdpatom->t = a_symbol;
	pdpatom->w.w_symbol = pdp_gensym(pdatom->a_w.w_symbol->s_name);
	break;
    default:
	pdpatom->t = a_undef;
	break;
    }
}



/* some "accelerated" pd symbols */
t_symbol s_pdp         = {"pdp", 0, 0};
t_symbol s_register_ro = {"register_ro", 0, 0};
t_symbol s_register_rw = {"register_rw", 0, 0};
t_symbol s_process     = {"process", 0, 0};
t_symbol s_dpd         = {"dpd", 0, 0};
t_symbol s_inspect     = {"inspect", 0, 0};
t_symbol s_accumulate  = {"accumulate", 0, 0};
t_symbol s_chanmask    = {"chanmask", 0, 0};

// internal pd method
t_symbol *dogensym(char *s, t_symbol *oldsym);
static void _addsym(t_symbol *s)
{

    /* don't kill me for this one..
       if the symbol is already defined and used, .. well, that's a problem
       but right now it seems a reasonable hack */

    t_symbol *sret = dogensym(s->s_name, s);
    if (s != sret){
	post("PDP INIT ERROR: pd symbol clash adding symbol %s: new=%08x old=%08x", s->s_name, s, sret);
	post("try loading pdp before other libraries");
    }
}

void
pdp_pdsym_setup(void)
{

    _addsym(&s_pdp);
    _addsym(&s_register_ro);
    _addsym(&s_register_rw);
    _addsym(&s_process);
    _addsym(&s_dpd);
    _addsym(&s_inspect);
    _addsym(&s_accumulate);
    _addsym(&s_chanmask);

}



#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_compat.c ---
/*
 *   Pure Data Packet system implementation. Compatibility routines.
 *   Copyright (c) by Tom Schouten <pdp at 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 misc communication methods */

#include <stdio.h>

#include "pdp_pd.h"
#include "pdp_comm.h"
#include "pdp_internals.h"

/* all symbols are C style */
#ifdef __cplusplus
extern "C"
{
#endif



void
pdp_pass_if_valid(t_outlet *outlet, int *packet)
{
    pdp_packet_pass_if_valid(outlet, packet);
}

void
pdp_replace_if_valid(int *dpacket, int *spacket)
{
    pdp_packet_replace_if_valid(dpacket, spacket);
    
}






#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_control.c ---
/*
 *   Pure Data Packet system implementation: control object
 *   Copyright (c) by Tom Schouten <pdp at 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 is an actual pd class that is used for communication with the
   pdp framework */

#include "pdp_internals.h"
#include "pdp_control.h"
#include "pdp_packet.h"
#include <stdio.h>

/* all symbols are C style */
#ifdef __cplusplus
extern "C"
{
#endif



static long dropped_packets;

static t_class* pdp_control_class;


/* pdp control instance data */

struct _pdp_control;
typedef struct _pdp_control
{
    t_object x_obj;
    t_outlet *x_outlet0;
    struct _pdp_control *x_next;

} t_pdp_control;



static t_pdp_control *pdp_control_list;

static void pdp_control_info(t_pdp_control *x)
{
}

static void pdp_control_collectgarbage(t_pdp_control *x)
{
    int nb_packets_freed =  pdp_pool_collect_garbage();
    post("pdp_control: freed %d packets", nb_packets_freed);
    
}

static void pdp_control_set_mem_limit(t_pdp_control *x, t_floatarg f)
{
    int limit = (int)f;
    if (limit < 0) limit = 0;
    pdp_pool_set_max_mem_usage(limit);
    if (limit) post("pdp_control: set memory limit to %d bytes", limit);
    else post("pdp_control: disabled memory limit");
    
}

static void pdp_control_thread(t_pdp_control *x, t_floatarg f)
{
    int t = (int)f;

    if (t){
	post("pdp_control: pdp is now using its own processing thread");
	pdp_queue_use_thread(1);
    }
    else {
	post("pdp_control: pdp is now using the main pd thread");
	pdp_queue_use_thread(0);
    }
}


static void pdp_control_send_drop_message(t_pdp_control *x)
{
    t_atom atom[1];
    t_symbol *s = gensym("pdp_drop");

    SETFLOAT(atom+0, (float)dropped_packets);
    outlet_anything(x->x_outlet0, s, 1, atom);
}


static void pdp_control_free(t_pdp_control *x)
{
    /* remove from linked list */
    t_pdp_control *curr = pdp_control_list;
    if (pdp_control_list == x) pdp_control_list = x->x_next;
    else while (curr){
	if (curr->x_next == x) {
	    curr->x_next = x->x_next;
	    break;
	}
	else {
	    curr = curr->x_next;
	}
	
    }
}


static void *pdp_control_new(void)
{
    t_pdp_control *x = (t_pdp_control *)pd_new(pdp_control_class);
    x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);

    /* add to list */
    x->x_next = pdp_control_list;
    pdp_control_list = x;
    return x;
}

/************************* class methods ***************************************/


void pdp_control_addmethod(t_method m, t_symbol *s)
{
    class_addmethod(pdp_control_class, m, s, A_GIMME, A_NULL);
}

void pdp_control_setup(void)
{

    pdp_control_list = 0;
    dropped_packets = 0;

    /* setup pd class data */
    pdp_control_class = class_new(gensym("pdp_control"), (t_newmethod)pdp_control_new,
    	(t_method)pdp_control_free, sizeof(t_pdp_control), 0, A_NULL);


    class_addmethod(pdp_control_class, (t_method)pdp_control_info, gensym("info"), A_NULL);   
    class_addmethod(pdp_control_class, (t_method)pdp_control_thread, gensym("thread"),  A_DEFFLOAT, A_NULL);   
    class_addmethod(pdp_control_class, (t_method)pdp_control_collectgarbage, gensym("collectgarbage"),  A_NULL);   
    class_addmethod(pdp_control_class, (t_method)pdp_control_set_mem_limit, gensym("memlimit"),  A_FLOAT, A_NULL);   
}



void pdp_control_notify_broadcast(t_pdp_control_method_notify *notify)
{
    t_pdp_control *curr = pdp_control_list;
    while (curr){
	(*notify)(curr);
	curr = curr->x_next;
    }
}



/************************* notify class methods  *************************/

void pdp_control_notify_drop(int packet)
{
    dropped_packets++;

    /* send drop notify to controller class instances */
    pdp_control_notify_broadcast(pdp_control_send_drop_message);
    //post("dropped packet");
}



#ifdef __cplusplus
}
#endif

--- NEW FILE: CONTENTS ---
base			pdp base pd object
image_base		image processing base pd object
dpd_base		bucket base pd object
comm			pdp communication protocol in pd
compat			legacy pdp stuff
control			control pdp from within pd
fp			object interface to the forth system
forthconsole		console interface to the forth system
queue			processing queue and synchro stuff
ut			some utility pd objects

--- NEW FILE: pdp_ut.c ---
/*
 *   Pure Data Packet - Utility toolkit objects.
 *   Copyright (c) by Tom Schouten <pdp at 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 some small utility pd objects that make working with 
   pdp objects a lot easier. Mainly as glue to be used in the abstractions 
   in the distro. */


#include "pdp_pd.h"
#include <math.h>

/* this object does an add, scale, clip operation */

t_class *pdp_ut_addscaleclip_class;

typedef struct pdp_ut_addscaleclip_struct
{
    t_object x_obj;
    t_outlet *x_outlet0;
    t_float x_min;
    t_float x_max;
    t_float x_offset;
    t_float x_scale;
} t_pdp_ut_addscaleclip;


static void pdp_ut_addscaleclip_float(t_pdp_ut_addscaleclip *x, t_floatarg f)
{
    f += x->x_offset;
    f *= x->x_scale;
    f = (f < x->x_min) ? x->x_min : f;
    f = (f > x->x_max) ? x->x_max : f;
    outlet_float(x->x_outlet0, f);
}

static void pdp_ut_addscaleclip_free(t_pdp_ut_addscaleclip *x){}

void *pdp_ut_addscaleclip_new(t_floatarg offset, t_floatarg scale, t_floatarg min, t_floatarg max)
{
    t_pdp_ut_addscaleclip *x = (t_pdp_ut_addscaleclip *)pd_new(pdp_ut_addscaleclip_class);
    x->x_outlet0 = outlet_new(&x->x_obj, &s_float); 
    x->x_offset = offset;
    x->x_scale = scale;
    x->x_min = min;
    x->x_max = max;
    return (void *)x;
}

void pdp_ut_addscaleclip_setup(void)
{
    pdp_ut_addscaleclip_class = class_new(gensym("pdp_ut_addscaleclip"), (t_newmethod)pdp_ut_addscaleclip_new,
			      (t_method)pdp_ut_addscaleclip_free, sizeof(t_pdp_ut_addscaleclip), 0, 
					 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
    class_addfloat(pdp_ut_addscaleclip_class,  pdp_ut_addscaleclip_float);
}


/* pdp_ut_logmap does a logarithmic parameter mapping [0->1] x -> min(max/min)^x max an add, scale, clip operation */
/* pdp_ut_logmap_comp does x -> min(max/min)^(1-x) */
/* pdp_ut_linmap dos x -> min + (max - min * x */

t_class *pdp_ut_linmap_class;
t_class *pdp_ut_logmap_class;
t_class *pdp_ut_logmap_comp_class;

typedef struct pdp_ut_map_struct
{
    t_object x_obj;
    t_outlet *x_outlet0;
    t_float x_min;
    t_float x_max;
} t_pdp_ut_map;


static void pdp_ut_logmap_float(t_pdp_ut_map *x, t_floatarg f)
{
    f = (f < 0.0f) ? 0.0f : f;
    f = (f > 1.0f) ? 1.0f : f;

    f = x->x_min * pow((x->x_max / x->x_min), f);

    outlet_float(x->x_outlet0, f);
}

static void pdp_ut_linmap_float(t_pdp_ut_map *x, t_floatarg f)
{
    f = (f < 0.0f) ? 0.0f : f;
    f = (f > 1.0f) ? 1.0f : f;

    f = x->x_min + ((x->x_max - x->x_min) * f);

    outlet_float(x->x_outlet0, f);
}

static void pdp_ut_logmap_comp_float(t_pdp_ut_map *x, t_floatarg f)
{
    f = (f < 0.0f) ? 0.0f : f;
    f = (f > 1.0f) ? 1.0f : f;

    f = x->x_min * pow((x->x_max / x->x_min), (1.0f - f));

    outlet_float(x->x_outlet0, f);
}

static void pdp_ut_map_free(t_pdp_ut_map *x){}


void pdp_ut_map_init(t_pdp_ut_map *x, t_floatarg min, t_floatarg max)
{
    x->x_outlet0 = outlet_new(&x->x_obj, &s_float); 
    x->x_min = min;
    x->x_max = max;
}

void *pdp_ut_logmap_new(t_floatarg min, t_floatarg max)
{
    t_pdp_ut_map *x = (t_pdp_ut_map *)pd_new(pdp_ut_logmap_class);
    pdp_ut_map_init(x, min, max);
    return (void *)x;
}

void *pdp_ut_linmap_new(t_floatarg min, t_floatarg max)
{
    t_pdp_ut_map *x = (t_pdp_ut_map *)pd_new(pdp_ut_linmap_class);
    pdp_ut_map_init(x, min, max);
    return (void *)x;
}

void *pdp_ut_logmap_comp_new(t_floatarg min, t_floatarg max)
{
    t_pdp_ut_map *x = (t_pdp_ut_map *)pd_new(pdp_ut_logmap_comp_class);
    pdp_ut_map_init(x, min, max);
    return (void *)x;
}

void pdp_ut_logmap_setup(void)
{
    pdp_ut_logmap_class = class_new(gensym("pdp_ut_logmap"), (t_newmethod)pdp_ut_logmap_new,
			      (t_method)pdp_ut_map_free, sizeof(t_pdp_ut_map), 0, 
					 A_FLOAT, A_FLOAT, A_NULL);
    class_addfloat(pdp_ut_logmap_class,  pdp_ut_logmap_float);
}

void pdp_ut_logmap_comp_setup(void)
{
    pdp_ut_logmap_comp_class = class_new(gensym("pdp_ut_logmap_comp"), (t_newmethod)pdp_ut_logmap_comp_new,
			      (t_method)pdp_ut_map_free, sizeof(t_pdp_ut_map), 0, 
					 A_FLOAT, A_FLOAT, A_NULL);
    class_addfloat(pdp_ut_logmap_comp_class,  pdp_ut_logmap_comp_float);
}

void pdp_ut_linmap_setup(void)
{
    pdp_ut_linmap_class = class_new(gensym("pdp_ut_linmap"), (t_newmethod)pdp_ut_linmap_new,
			      (t_method)pdp_ut_map_free, sizeof(t_pdp_ut_map), 0, 
					 A_FLOAT, A_FLOAT, A_NULL);
    class_addfloat(pdp_ut_linmap_class,  pdp_ut_linmap_float);
}



t_class *pdp_ut_rgb2ycrcb_class;

typedef struct pdp_ut_rgb2ycrcb
{
    t_object x_obj;
    t_outlet *x_outlet_luma;
    t_outlet *x_outlet_chroma_red;
    t_outlet *x_outlet_chroma_blue;

    t_float x_red, x_green, x_blue;

} t_pdp_ut_rgb2ycrcb;


static void pdp_ut_rgb2ycrcb_bang  (t_pdp_ut_rgb2ycrcb* x)
{

    float luma = 0.299f * x->x_red + 0.587f * x->x_green + 0.114f * x->x_blue;
    float chroma_red  = (x->x_red - luma) * 0.713f;
    float chroma_blue = (x->x_blue - luma) * 0.565f;

    outlet_float(x->x_outlet_chroma_blue, chroma_blue);
    outlet_float(x->x_outlet_chroma_red, chroma_red);
    outlet_float(x->x_outlet_luma, luma);

}


static void pdp_ut_rgb2ycrcb_red   (t_pdp_ut_rgb2ycrcb* x, t_floatarg f)   {x->x_red = f;   pdp_ut_rgb2ycrcb_bang(x);}
static void pdp_ut_rgb2ycrcb_green (t_pdp_ut_rgb2ycrcb* x, t_floatarg f)   {x->x_green = f; pdp_ut_rgb2ycrcb_bang(x);}
static void pdp_ut_rgb2ycrcb_blue  (t_pdp_ut_rgb2ycrcb* x, t_floatarg f)   {x->x_blue = f;  pdp_ut_rgb2ycrcb_bang(x);}



static void pdp_ut_rgb2ycrcb_free  (t_pdp_ut_rgb2ycrcb* x)  {}
static void* pdp_ut_rgb2ycrcb_new(void)
{
    t_pdp_ut_rgb2ycrcb *x = (t_pdp_ut_rgb2ycrcb *)pd_new(pdp_ut_rgb2ycrcb_class);


    inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("green"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("blue"));

    x->x_outlet_luma        = outlet_new(&x->x_obj, &s_float); 
    x->x_outlet_chroma_red  = outlet_new(&x->x_obj, &s_float); 
    x->x_outlet_chroma_blue = outlet_new(&x->x_obj, &s_float); 

    x->x_red = 0.0f;
    x->x_green = 0.0f;
    x->x_blue = 0.0f;


    return (void *)x;
}

void pdp_ut_rgb2ycrcb_setup(void)
{
    pdp_ut_rgb2ycrcb_class = class_new(gensym("pdp_ut_rgb2ycrcb"), (t_newmethod)pdp_ut_rgb2ycrcb_new,
			      (t_method)pdp_ut_rgb2ycrcb_free, sizeof(t_pdp_ut_rgb2ycrcb), 0, A_NULL);
    class_addfloat(pdp_ut_rgb2ycrcb_class,  pdp_ut_rgb2ycrcb_red);
    class_addmethod(pdp_ut_rgb2ycrcb_class,  (t_method)pdp_ut_rgb2ycrcb_green, gensym("green"), A_FLOAT, A_NULL);
    class_addmethod(pdp_ut_rgb2ycrcb_class,  (t_method)pdp_ut_rgb2ycrcb_blue, gensym("blue"), A_FLOAT, A_NULL);
}


#ifdef __cplusplus
extern "C"
{
#endif

void pdp_ut_setup(void)
{
    pdp_ut_addscaleclip_setup();
    pdp_ut_logmap_setup();
    pdp_ut_logmap_comp_setup();
    pdp_ut_linmap_setup();
    pdp_ut_rgb2ycrcb_setup();
}


#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_queue.c ---
/*
 *   Pure Data Packet - processor queue module.
 *   Copyright (c) by Tom Schouten <pdp at 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 is a the processor queue pdp system module 
   it receives tasks from objects that are schedules to 
   be computed in another thread. the object is signalled back
   when the task is completed, using a polling mechanism
   based on a pd clock.

   the queue object can be reused. the pdp system however only
   has one instance (one pdp queue. pdp remains a serial program, though
   it can run in a separate thread)

 */


#include <string.h>

#include "pdp_queue.h"
#include "pdp_mem.h"


#define D if (0)

#ifdef __cplusplus
extern "C"
{
#endif

#define PDP_QUEUE_LOGSIZE 10
#define PDP_QUEUE_DELTIME 10.0f


/* there are 3 synchro methods, which can be used i.e. to ensure
   all processing is done before shared resources are freed.

   all 3 wait for the processing thread to finish, and

   _wait:   leaves callback queue untouched
   _finish: clears the queue_id item in the callback queue
   _flush:  waits for thread and calls callbacks
            and loops until callback list is empty

*/
   


/********************* general purpose pd process queue class *********************/

void pdp_procqueue_wait(t_pdp_procqueue *q)
{
    D post("pdp_procqueue_wait(%x): waiting for pdp_queue_thread to finish processing", q);
    pthread_mutex_lock(&q->mut);
    while(((q->curr - q->head) & q->mask) != 0){

	  pthread_cond_wait(&q->cond_processingdone, &q->mut);
    }
    pthread_mutex_unlock(&q->mut);
    D post("pdp_procqueue_wait(%x): pdp_procqueue_thread has finished processing", q);

}
void pdp_procqueue_finish(t_pdp_procqueue *q, int index)
{

  if (-1 == index) {
      //post("pdp_pq_remove: index == -1");
      return;
  }
  /* wait for processing thread to finish*/
  pdp_procqueue_wait(q);

  /* invalidate callback at index */
  q->q[index & q->mask].x_callback = 0;
  q->q[index & q->mask].x_queue_id = 0;

}

static void pdp_procqueue_callback (t_pdp_procqueue *q);

void pdp_procqueue_flush(t_pdp_procqueue *q)
{
    /* wait once */
    pdp_procqueue_wait(q);

    do {

	/* process callbacks and wait again
	   in case the callbacks introduced new tasks */
	pdp_procqueue_callback(q);
	pdp_procqueue_wait(q);
	
    }
    /* repeat if callback list is not empty */
    while ((q->curr - q->head) & q->mask);

    D post("pdp_procqueue_flush: done");
}

static void pdp_procqueue_signal_processor(t_pdp_procqueue *q)
{

    //NOTE: uncommenting these post statements causes a libc crash
    //in mutex lock in putc
    //D post("pdp_procqueue_signal_processor(%x): signalling process thread", q);
    pthread_mutex_lock(&q->mut);
    pthread_cond_signal(&q->cond_dataready);
    pthread_mutex_unlock(&q->mut);
    //D post("pdp_procqueue_signal_processor(%x): signalling done", q);


}

static void pdp_procqueue_wait_for_feeder(t_pdp_procqueue *q)
{


    /* only use locking when there is no data */
    if(((q->curr - q->head) & q->mask) == 0){

	/* signal processing done */
	D post("pdp_procqueue_wait_for_feeder(%x): signalling processing is done", q);
	pthread_mutex_lock(&q->mut);
	pthread_cond_signal(&q->cond_processingdone);

	/* wait until there is an item in the queue */
	while(((q->curr - q->head) & q->mask) == 0){
	    pthread_cond_wait(&q->cond_dataready, &q->mut);
	}

	pthread_mutex_unlock(&q->mut);
	D post("pdp_procqueue_wait_for_feeder(%x): waiting done", q);

    }
}


int pdp_procqueue_full(t_pdp_procqueue *q)
{
    return (1 == ((q->tail - q->head) & q->mask));
}


void pdp_procqueue_add(t_pdp_procqueue *q, void *owner, void *process, void *callback, int *queue_id)
{
    int i;

    /* if processing is in not in thread, just call the funcs */
    if (!q->use_thread){
	D post("pdp_procqueue_add(%q): calling processing routine directly", q);
	if (queue_id) *queue_id = -1;
	if (process)  ((t_pdpmethod) process)(owner);
	if (callback) ((t_pdpmethod) callback)(owner);
	return;
    }
	

    /* if queue is full, print an error message and return */
    if (pdp_procqueue_full(q)) {
	post("pdp_procqueue_add: WARNING: processing queue (%x) is full.\n", q);
	post("pdp_procqueue_add: WARNING: tail %08x, head %08x (%08x), mask %08x.\n", q->tail, q->head, q->head & q->mask, q->mask);
	post("pdp_procqueue_add: WARNING: skipping process method, calling callback directly.\n");
	if (queue_id) *queue_id = -1;
	if (callback) ((t_pdpmethod) callback)(owner);
	return;
	//exit(1);
    }

    /* schedule method in thread queue */
    i = q->head & q->mask;
    q->q[i].x_owner = owner;
    q->q[i].x_process = process;
    q->q[i].x_callback = callback;
    q->q[i].x_queue_id = queue_id;
    if (queue_id) *queue_id = i;
    //post("pdp_queue_add: added method to queue, index %d", i);

      
    // increase the packet count
    q->packets++;
  
    // move head forward
    q->head++;

    pdp_procqueue_signal_processor(q);

}


/* processing thread */
static void *pdp_procqueue_thread(void *vq)
{
    t_pdp_procqueue *q = (t_pdp_procqueue *)vq;

    D post("pdp_procqueue_thread(%x): thread started", q);

    while(1){
	t_process_queue_item *p;


	D post("pdp_procqueue_thread(%x): waiting for feeder", q);

	/* wait until there is data available */
	pdp_procqueue_wait_for_feeder(q);      


	D post("pdp_procqueue_thread(%x): processing %d", q, q->curr & q->mask);

	
	/* call the process routine */
	p = &q->q[q->curr & q->mask];
	if (p->x_process) 
	    (p->x_process)(p->x_owner);

	/* advance */
	q->curr++;


    }
    return 0;
}


/* call back all the callbacks */
static void pdp_procqueue_callback (t_pdp_procqueue *q)
{

  /* call callbacks for finished packets */
  while(0 != ((q->curr - q->tail) & q->mask))
    {
      int i = q->tail & q->mask;
      /* invalidate queue id */
      if(q->q[i].x_queue_id) *q->q[i].x_queue_id = -1;
      /* call callback */
      if(q->q[i].x_callback) (q->q[i].x_callback)(q->q[i].x_owner);
      //else post("pdp_pq_tick: callback %d is disabled",i );
      q->tail++;
    }

}

/* the clock method */
static void pdp_procqueue_tick (t_pdp_procqueue *q)
{
  /* do work */
  //if (!(ticks % 1000)) post("pdp tick %d", ticks);

  if (!q->use_thread) return;

  /* call callbacks */
  pdp_procqueue_callback(q);

  /* increase counter */
  q->ticks++;

  /* set clock for next update */
  clock_delay(q->pdp_clock, q->deltime);
}



void pdp_procqueue_use_thread(t_pdp_procqueue* q, int t)
{
    /* if thread usage is being disabled, 
       wait for thread to finish processing first */
    if (t == 0) {
	pdp_procqueue_wait(q);
	q->use_thread = 0;
	pdp_procqueue_callback(q);
	clock_unset(q->pdp_clock);
    }
    else {
	clock_unset(q->pdp_clock);
	clock_delay(q->pdp_clock, q->deltime);
	q->use_thread = 1;
    }

}

void pdp_procqueue_init(t_pdp_procqueue *q, double milliseconds, int logsize)
{
    pthread_attr_t attr;
    int size = 1 << logsize;

    /* setup pdp queue processor object */
    q->ticks = 0;
    q->deltime = milliseconds;

    /* setup queue data */
    q->mask = size - 1;
    q->head = 0;
    q->tail = 0;
    q->curr = 0;
    q->q = pdp_alloc(size * sizeof(t_process_queue_item));
    memset(q->q, 0, size * sizeof(t_process_queue_item));

    /* enable threads */
    q->use_thread = 1;

    /* setup synchro stuff */
    pthread_mutex_init(&q->mut, NULL);
    pthread_cond_init(&q->cond_dataready, NULL);
    pthread_cond_init(&q->cond_processingdone, NULL);

 
    /* allocate the clock */
    q->pdp_clock = clock_new(q, (t_method)pdp_procqueue_tick);

    /* set the clock */
    clock_delay(q->pdp_clock, 0);

    /* start processing thread */

    /* glibc doc says SCHED_OTHER is default,
       but it seems not to be when initiated from a RT thread
       so we explicitly set it here */
    pthread_attr_init (&attr);
    //pthread_attr_setschedpolicy(&attr, SCHED_FIFO); 
    pthread_attr_setschedpolicy(&attr, SCHED_OTHER); 

    D post("pdp_procqueue_init(%x): starting thread", q);
    pthread_create(&q->thread_id, &attr, pdp_procqueue_thread, (void *)q);
    D post("pdp_procqueue_init(%x): back in pd thread", q);

    /* wait for processing thread to finish */
    //pdp_procqueue_wait(q);

    /* set default disable/enable thread here */
    //post("pdp_queue: THREAD PROCESSING ON BY DEFAULT!!");
    pdp_procqueue_use_thread(q,0);

}




/* the (static) pdp queue object */
static t_pdp_procqueue pdp_queue;


/* get the default queue */
t_pdp_procqueue *pdp_queue_get_queue(void){return &pdp_queue;}


#if 1
/* default pdp queue shortcut methods */
void pdp_queue_wait() {pdp_procqueue_wait(&pdp_queue);}
void pdp_queue_finish(int index) { pdp_procqueue_finish(&pdp_queue, index);}
void pdp_queue_add(void *owner, void *process, void *callback, int *queue_id) {
    pdp_procqueue_add(&pdp_queue, owner, process, callback, queue_id);
}
void pdp_queue_use_thread(int t) {pdp_procqueue_use_thread(&pdp_queue, t);}
void pdp_queue_setup(void){
    pdp_procqueue_init(&pdp_queue, PDP_QUEUE_DELTIME, PDP_QUEUE_LOGSIZE);
    pdp_procqueue_use_thread(&pdp_queue,0);
}
#endif







#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_base.c ---
/*
 *   Pure Data Packet base class implementation.
 *   Copyright (c) by Tom Schouten <pdp at 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 (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; 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;
    }
}





More information about the Pd-cvs mailing list