[PD-cvs] externals/pdp/modules/generic Makefile, 1.2, 1.3 README, 1.2, 1.3 pdp_convert.c, 1.2, 1.3 pdp_del.c, 1.2, 1.3 pdp_description.c, 1.2, 1.3 pdp_inspect.c, 1.2, 1.3 pdp_loop.c, 1.2, 1.3 pdp_rawin.c, 1.2, 1.3 pdp_rawout.c, 1.2, 1.3 pdp_reg.c, 1.2, 1.3 pdp_route.c, 1.2, 1.3 pdp_snap.c, 1.2, 1.3 pdp_trigger.c, 1.2, 1.3 pdp_udp_receive.c, 1.2, 1.3 pdp_udp_send.c, 1.2, 1.3

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


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

Added Files:
	Makefile README pdp_convert.c pdp_del.c pdp_description.c 
	pdp_inspect.c pdp_loop.c pdp_rawin.c pdp_rawout.c pdp_reg.c 
	pdp_route.c pdp_snap.c pdp_trigger.c pdp_udp_receive.c 
	pdp_udp_send.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_convert.c ---
/*
 *   Pure Data Packet 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.
 *
 */



#include "pdp.h"


typedef struct pdp_convert_struct
{
    t_object x_obj;
    t_symbol *x_type_mask;
    t_outlet *x_outlet0;
    int x_packet0;

} t_pdp_convert;



static void pdp_convert_type_mask(t_pdp_convert *x, t_symbol *s)
{
    x->x_type_mask = s;
}

static void pdp_convert_input_0(t_pdp_convert *x, t_symbol *s, t_floatarg f)
{
    int p = (int)f;
    int passes, i;

    if (s== gensym("register_ro")){
	pdp_packet_mark_unused(x->x_packet0);
	if (x->x_type_mask->s_name[0])
	    x->x_packet0 = pdp_packet_convert_ro(p, pdp_gensym(x->x_type_mask->s_name));
	else
	    x->x_packet0 = pdp_packet_copy_ro(p);
    }


    if ((s == gensym("process")) && (-1 != x->x_packet0)){
	pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet0);
    }
}


t_class *pdp_convert_class;



void pdp_convert_free(t_pdp_convert *x)
{
    pdp_packet_mark_unused(x->x_packet0);
}

void *pdp_convert_new(t_symbol *s)
{
    t_pdp_convert *x = (t_pdp_convert *)pd_new(pdp_convert_class);

    x->x_type_mask = s;
    x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); 
    x->x_packet0 = -1;

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_convert_setup(void)
{


    pdp_convert_class = class_new(gensym("pdp_convert"), (t_newmethod)pdp_convert_new,
    	(t_method)pdp_convert_free, sizeof(t_pdp_convert), 0, A_DEFSYMBOL, A_NULL);


    class_addmethod(pdp_convert_class, (t_method)pdp_convert_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addsymbol(pdp_convert_class, (t_method)pdp_convert_type_mask);

}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_udp_receive.c ---
/*
 *   Pure Data Packet 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 module sends receives an udp packet stream and converts to pdp packet */

#include "pdp_net.h"
#include "pdp.h"
#include "pdp_resample.h"

#define D if(0)

typedef struct pdp_udp_receive_struct
{

    t_object x_obj;
    t_float x_f;

    /* receiver object */
    t_pdp_udp_receiver *x_receiver;


    /* thread vars */
    pthread_attr_t x_attr;
    pthread_t x_thread;
    int x_exit_thread;

    /* packet queue */
    int x_index;
    int x_packet[2];    

    /* polling clock */
    t_clock *x_clock;
    /* outlet */
    t_outlet *x_outlet0;

} t_pdp_udp_receive;


static void clock_tick(t_pdp_udp_receive *x)
{
    /* poll for new packet */
  
    pdp_pass_if_valid(x->x_outlet0, &x->x_packet[!x->x_index]);
    clock_delay(x->x_clock, 1.0f);
}




static void *receive_thread(void *threaddata)
{
    t_pdp_udp_receive *x = (t_pdp_udp_receive *)threaddata;
    t_pdp *pdp_header = 0;
    void *pdp_data = 0;
    int tmp_packet = -1;
    char *type = 0;
    unsigned int size = 0;

    /* listen for packets */
    while (!x->x_exit_thread){
	

	switch(pdp_udp_receiver_receive(x->x_receiver, 100)){
	case -1:
	    /* error */
	    goto exit;
	case 0:
	    /* timeout */
	    continue;
	case 1:
	    /* data ready */
	    break;
	}

        /* create a new packet */
	type = pdp_udp_receiver_type(x->x_receiver);
        tmp_packet = pdp_factory_newpacket(pdp_gensym(type));
        pdp_header = pdp_packet_header(tmp_packet);
        pdp_data = pdp_packet_data(tmp_packet);

        /* check if we were able to create the pdp packet */
        if (!(pdp_header && pdp_data)){
            post("pdp_netreceive: can't create packet (type %s)", type);
	    pdp_udp_receiver_reset(x->x_receiver);
	    continue;
        }

	/* check size */
	size = pdp_udp_receiver_size(x->x_receiver);
	if ((pdp_header->size - PDP_HEADER_SIZE) != size){
	    pdp_packet_mark_unused(tmp_packet);
	    tmp_packet = -1;
            post("pdp_netreceive: invalid packet size %d (pdp packet size = %d)", 
		 size, pdp_header->size - PDP_HEADER_SIZE);
	    continue;
	}

	/* copy the data */
	memcpy(pdp_data, pdp_udp_receiver_data(x->x_receiver), size);

	/* copy the packet into queue */
	x->x_index ^= 1;
        pdp_packet_mark_unused(x->x_packet[x->x_index]);
	x->x_packet[x->x_index] = tmp_packet;
    

    }

 exit:
    post("thread exiting");
    return 0;
}


static void pdp_udp_receive_free(t_pdp_udp_receive *x)
{
    int i;
    void* retval;
    x->x_exit_thread = 1; // wait for thread to finish
    pthread_join(x->x_thread, &retval);
    
    pdp_udp_receiver_free(x->x_receiver);

    pdp_packet_mark_unused(x->x_packet[0]);
    pdp_packet_mark_unused(x->x_packet[1]);

}

t_class *pdp_udp_receive_class;



void *pdp_udp_receive_new(t_floatarg fport)
{
    int i;
    int port;
    struct hostent *hp;

    t_pdp_udp_receive *x = (t_pdp_udp_receive *)pd_new(pdp_udp_receive_class);

    x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); 

    x->x_packet[0] = -1;
    x->x_packet[1] = -1;
    x->x_index = 0;

    port = (fport == 0.0f) ? 7777 : fport;
    x->x_receiver = pdp_udp_receiver_new(port);

    /* setup thread stuff & create thread */
    x->x_exit_thread = 0;
    pthread_attr_init(&x->x_attr);
    pthread_attr_setschedpolicy(&x->x_attr, SCHED_OTHER); 
    pthread_create(&x->x_thread, &x->x_attr, receive_thread, x);


    /* setup the clock */
    x->x_clock = clock_new(x, (t_method)clock_tick);
    clock_delay(x->x_clock, 0);

    post("pdp_netreceive: WARNING: experimental object");

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_udp_receive_setup(void)
{


    pdp_udp_receive_class = class_new(gensym("pdp_netreceive"), (t_newmethod)pdp_udp_receive_new,
    	(t_method)pdp_udp_receive_free, sizeof(t_pdp_udp_receive), 0, A_DEFFLOAT, A_NULL);


}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_loop.c ---
/*
 *   Pure Data Packet 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.
 *
 */


/*

  pdp_loop: a looping packet delay line
  messages:
     record x: start recording at position x (default = 0)
     stop:     stop recording
     float:    output packet at position
     bang:     output next packet
     rewind:   rewind
     loop:     set looping mode

*/


#include "pdp.h"
#include "pdp_internals.h"


typedef struct pdp_loop_struct
{
    t_object x_obj;
    t_float x_f;
  
    t_outlet *x_outlet0;
    t_outlet *x_outlet1;

    int *x_packet;
    int x_order;       /* size of the packet loop */
    int x_play_head;   /* next position to play back */
    int x_record_head; /* next position to record to */

    int x_loop;
    int x_recording_frames;    /* nb frames left to record */
    //int x_recording_shot; /* single frame recording is on */
} t_pdp_loop;





static void pdp_loop_input_0(t_pdp_loop *x, t_symbol *s, t_floatarg f)
{
  int in;
  int out;
  int packet;

  
  /* if recording is off, ignore packet */
  if ((!x->x_recording_frames)) return;

  /* store a packet on register ro */
  if (s == gensym("register_ro")){

      /* delete old & store new */
      in = x->x_record_head; //% x->x_order;
      pdp_packet_mark_unused(x->x_packet[in]);
      packet = pdp_packet_copy_ro((int)f);
      x->x_packet[in] = packet;

      /* advance head & decrease record counter */
      x->x_recording_frames--;
      x->x_record_head++;

      /* turn off recording if we are at the end */
      if (x->x_record_head == x->x_order) x->x_recording_frames = 0;
  }
}


static void pdp_loop_bang(t_pdp_loop *x){
    int out;
    int packet;

    out = x->x_play_head;

    /* don't play if we're at the end of the sequence and looping is disabled */
    if ((!x->x_loop) && (out >= x->x_order)) return;

    /* wrap index */
    out %=  x->x_order;

    /* output the current packet */
    packet = x->x_packet[out];
    outlet_float(x->x_outlet1, (float)out); // output location
    if (-1 != packet) outlet_pdp(x->x_outlet0, packet); // output packet

    /* advance playback head */
    x->x_play_head++;

}






static void pdp_loop_reset(t_pdp_loop *x)
{
  int i;
  for (i=0; i<x->x_order; i++) {
      pdp_packet_mark_unused(x->x_packet[i]);
      x->x_packet[i] = -1;
  }
  x->x_play_head = 0;
  x->x_record_head = 0;

}

static void pdp_loop_record(t_pdp_loop *x, t_floatarg fstart, t_floatarg fdur)
{
    int istart = (int)fstart;
    int idur = (int)fdur;
    istart %= x->x_order;
    if (istart<0) istart+= x->x_order;
    if (idur <= 0) idur = x->x_order - istart;

    x->x_record_head = istart;
    x->x_recording_frames = idur;
}

static void pdp_loop_store(t_pdp_loop *x, t_floatarg f)
{
    int i = (int)f;
    i %= x->x_order;
    if (i<0) i+= x->x_order;

    x->x_record_head = i;
    x->x_recording_frames = 1;
}

static void pdp_loop_seek(t_pdp_loop *x, t_floatarg f)
{
    int i = (int)f;
    i %= x->x_order;
    if (i<0) i+= x->x_order;

    x->x_play_head = i;
}

static void pdp_loop_seek_hot(t_pdp_loop *x, t_floatarg f)
{
    pdp_loop_seek(x, f);
    pdp_loop_bang(x);
}


static void pdp_loop_stop(t_pdp_loop *x)
{
    x->x_recording_frames = 0;
}

static void pdp_loop_loop(t_pdp_loop *x, t_floatarg f)
{
    if (f == 0.0f) x->x_loop = 0;
    if (f == 1.0f) x->x_loop = 1;

}
static void pdp_loop_free(t_pdp_loop *x)
{
  pdp_loop_reset(x);
  pdp_dealloc (x->x_packet);
}

static int pdp_loop_realsize(float f)
{
    int order = (int)f;
    if (order <= 2) order = 2;
    return order;
}


static void pdp_loop_resize(t_pdp_loop *x, t_floatarg f)
{
    int i;
    int order = pdp_loop_realsize(f);
    int *newloop;

    /* if size didn't change, do nothing */
    if (x->x_order == order) return;

    /* create new array */
    newloop = (int *)pdp_alloc(sizeof(int) * order);


    /* extend it */
    if (x->x_order < order){

	/* copy old packets */
	for (i=0; i<x->x_order; i++) newloop[i] = x->x_packet[i];

	/* loop extend the rest */
	for (i=x->x_order; i<order; i++) newloop[i] = pdp_packet_copy_ro(x->x_packet[i % x->x_order]);

    }

    /* or shrink it */
    else {
	/* copy part of old packets */
	for (i=0; i<order; i++) newloop[i] = x->x_packet[i];

	/* delete the other part of old packets */
	for (i=order; i<x->x_order; i++) pdp_packet_mark_unused(x->x_packet[i]);

	/* adjust heads */
	x->x_play_head %= order;
	x->x_record_head %= order;

    }

    /* delete old line & store new */
    pdp_dealloc (x->x_packet);
    x->x_packet = newloop;
    x->x_order = order;
    

}


t_class *pdp_loop_class;



void *pdp_loop_new(t_floatarg f)
{
    int i;
    int order = pdp_loop_realsize(f);
    t_pdp_loop *x = (t_pdp_loop *)pd_new(pdp_loop_class);

    x->x_order = order;
    x->x_packet = (int *)pdp_alloc(sizeof(int)*order);
    for(i=0; i<order; i++) x->x_packet[i] = -1;

    x->x_play_head = 0;
    x->x_record_head = 0;
    x->x_recording_frames = 0;

    inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("seek"));
    x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); 
    x->x_outlet1 = outlet_new(&x->x_obj, &s_anything); 

    x->x_loop = 1;
    
    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_loop_setup(void)
{


    pdp_loop_class = class_new(gensym("pdp_loop"), (t_newmethod)pdp_loop_new,
			      (t_method)pdp_loop_free, sizeof(t_pdp_loop), 0, A_DEFFLOAT, A_NULL);
    
    class_addmethod(pdp_loop_class, (t_method)pdp_loop_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_loop_class, (t_method)pdp_loop_record, gensym("record"),  A_DEFFLOAT, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_loop_class, (t_method)pdp_loop_store, gensym("store"),  A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_loop_class, (t_method)pdp_loop_reset, gensym("reset"),  A_NULL);
    class_addmethod(pdp_loop_class, (t_method)pdp_loop_bang, gensym("bang"),  A_NULL);
    class_addmethod(pdp_loop_class, (t_method)pdp_loop_stop, gensym("stop"),  A_NULL);
    class_addmethod(pdp_loop_class, (t_method)pdp_loop_seek, gensym("seek"),  A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_loop_class, (t_method)pdp_loop_resize, gensym("size"),  A_FLOAT, A_NULL);
    class_addmethod(pdp_loop_class, (t_method)pdp_loop_loop, gensym("loop"),  A_FLOAT, A_NULL);
    class_addfloat(pdp_loop_class, (t_method)pdp_loop_seek_hot);

}

#ifdef __cplusplus
}
#endif

--- NEW FILE: Makefile ---
current: all_modules

include ../../Makefile.config

PDP_MOD = pdp_reg.o pdp_del.o pdp_snap.o pdp_trigger.o \
	pdp_route.o pdp_inspect.o pdp_loop.o pdp_description.o pdp_convert.o \
	pdp_udp_send.o pdp_udp_receive.o pdp_rawin.o pdp_rawout.o

# build generic modules
all_modules: $(PDP_MOD)

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


--- NEW FILE: pdp_udp_send.c ---
/*
 *   Pure Data Packet 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 module sends a pure packet out as an udp packet stream */

#include "pdp_net.h"
#include "pdp.h"
#include "pdp_resample.h"

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <netdb.h>

#define DD if(0)  // print DROP debug info
#define D if(0)  // print extra connection debug info
#define V if(0)  // be verbose (parameter setting feedback)

typedef struct pdp_udp_send_struct
{

    t_object x_obj;
    t_float x_f;

    /* sender object */
    t_pdp_udp_sender *x_sender;

    /* pthread vars */
    pthread_mutex_t x_mut;
    pthread_cond_t x_cond_data_ready;
    pthread_cond_t x_cond_send_done;
    pthread_t x_thread;
    int x_exit_thread;

    // drop info
    unsigned int x_drop;

    t_outlet *x_outlet0;

    // packet queue
    int x_nb_packets;
    int x_read_packet;
    int x_write_packet;
    int *x_packet;    


} t_pdp_udp_send;





/* some synchro code */

static int _wait_for_feeder(t_pdp_udp_send *x)
{

    /* only use locking when there is no data */
    if (x->x_packet[x->x_read_packet] == -1){

	/* signal sending is done */
	pthread_mutex_lock(&x->x_mut);
	pthread_cond_signal(&x->x_cond_send_done);

	/* wait until there is an item in the queue */
	while((x->x_packet[x->x_read_packet] == -1) && (!x->x_exit_thread)){
	    pthread_cond_wait(&x->x_cond_data_ready, &x->x_mut);
	}
	pthread_mutex_unlock(&x->x_mut);

	/* check if we need to stop the thread */
	if (x->x_exit_thread) return 0;

    }

    return !x->x_exit_thread;
}

static void _signal_sender(t_pdp_udp_send *x)
{

    pthread_mutex_lock(&x->x_mut);
    pthread_cond_signal(&x->x_cond_data_ready);
    pthread_mutex_unlock(&x->x_mut);
}

static void _wait_until_done(t_pdp_udp_send *x)
{
    pthread_mutex_lock(&x->x_mut);
    while (x->x_packet[x->x_read_packet] != -1){
	  pthread_cond_wait(&x->x_cond_send_done, &x->x_mut);
    }
    pthread_mutex_unlock(&x->x_mut);
}


static void _remove_packet_from_queue(t_pdp_udp_send *x)
{

}





static void *send_thread(void *threaddata)
{
    t_pdp_udp_send *x = (t_pdp_udp_send *)threaddata;

    /* main thread loop */

    /* get a pdp packet from queue */
    /* send header packet and make sure it has arrived */
    /* send a chunk burst */
    /* send done packet and get the resend list */
    /* repeat until send list is empty */

    while (_wait_for_feeder(x)){
	t_pdp *header;
	void *data;

	/* check if we have a valid pdp packet */
	if ((!(header = pdp_packet_header(x->x_packet[x->x_read_packet])))
	    ||(!(data = pdp_packet_data(x->x_packet[x->x_read_packet])))
	    ||(0 == header->desc)) goto remove; /* nothing to transmit  */

	/* send it */
	pdp_udp_sender_send(x->x_sender, 
			    header->desc->s_name,
			    header->size - PDP_HEADER_SIZE, data); 


      remove:
	/* remove packet from queue */
	pdp_packet_mark_unused(x->x_packet[x->x_read_packet]);
	x->x_packet[x->x_read_packet] = -1;
	x->x_read_packet++;
	x->x_read_packet %= x->x_nb_packets;
   
    }
    return 0;
}


static void pdp_udp_send_input_0(t_pdp_udp_send *x, t_symbol *s, t_floatarg f)
{

    int p = (int)f;
    int my_p;
    int transferred = 0;

    if (s== gensym("register_ro")){


	// check if packet can be stored in the queue
	// this is possible if the current write location does not contain a packet

	if (x->x_packet[x->x_write_packet] == -1){

	    // get the packet outside of the lock
	    my_p = pdp_packet_copy_ro(p); 


	    // add to queue (do we really need to lock here?>
	    //pthread_mutex_lock(&x->x_mut); // LOCK
	       x->x_packet[x->x_write_packet] = my_p;
	       x->x_write_packet++;
	       x->x_write_packet %= x->x_nb_packets;
	       transferred = 1;
	    //pthread_mutex_unlock(&x->x_mut); // UNLOCK
	}

	// signal sender if transfer succeded
	if (transferred) _signal_sender(x);

	// else send a float indicating the number of drops so far
	else{
	    x->x_drop++;
	    //outlet_float(x->x_outlet0, (float)x->x_drop);

	    DD post ("pdp_netsend: DROP: queue full");
	}
    }
}



/* some flow control hacks */

static void pdp_udp_send_timeout(t_pdp_udp_send *x, float f)
{
    if (f < 0.0f) f = 0.0f;
    pdp_udp_sender_timeout_us(x->x_sender, 1000.0f * f);
}


static void pdp_udp_send_sleepgrain(t_pdp_udp_send *x, float f)
{
    if (f < 0.0f) f = 0.0f;
    pdp_udp_sender_sleepgrain_us(x->x_sender, 1000.0f * f);
}

static void pdp_udp_send_sleepperiod(t_pdp_udp_send *x, float f)
{
    if (f < 0.0f) f = 0.0f;
    pdp_udp_sender_sleepperiod(x->x_sender, f);
}


static void pdp_udp_send_udpsize(t_pdp_udp_send *x, float f)
{
    if (f < 0.0f) f = 0.0f;
    pdp_udp_sender_udp_packet_size(x->x_sender, f);
}

static void pdp_udp_send_connect(t_pdp_udp_send *x, t_symbol *shost, t_float fport)
{
    unsigned int port;
    struct hostent *hp;

    /* suspend until sending thread is finished */
    _wait_until_done(x);

    /* set target address */
    port = (fport == 0.0f) ? 7777 : fport;
    if (shost == gensym("")) shost = gensym("127.0.0.1");

    /* connect */
    pdp_udp_sender_connect(x->x_sender, shost->s_name, port);

}


static void pdp_udp_send_free(t_pdp_udp_send *x)
{
    int i;
    void* retval;
    _wait_until_done(x);  // send all remaining packets
    x->x_exit_thread = 1; // .. and wait for thread to finish
    _signal_sender(x);
    pthread_join(x->x_thread, &retval);

    pdp_udp_sender_free(x->x_sender);

    
    for (i=0; i<x->x_nb_packets; i++) pdp_packet_mark_unused(x->x_packet[i]);
    pdp_dealloc(x->x_packet);

}

t_class *pdp_udp_send_class;



void *pdp_udp_send_new(void)
{
    int i;
    pthread_attr_t attr;

    t_pdp_udp_send *x = (t_pdp_udp_send *)pd_new(pdp_udp_send_class);

    x->x_sender = pdp_udp_sender_new();
    
    //x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); 

    x->x_nb_packets = 4;
    x->x_packet = malloc(sizeof(int)*x->x_nb_packets);
    for (i=0; i<x->x_nb_packets; i++) x->x_packet[i] = -1;
    x->x_read_packet = 0;
    x->x_write_packet = 0;

    x->x_drop = 0;



    /* setup thread stuff & create thread */
    x->x_exit_thread = 0;
    pthread_mutex_init(&x->x_mut, NULL);
    pthread_cond_init(&x->x_cond_data_ready, NULL);
    pthread_cond_init(&x->x_cond_send_done, NULL);
    pthread_attr_init(&attr);
    //pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
    pthread_create(&x->x_thread, &attr, send_thread, x);
    post("pdp_netsend: WARNING: experimental object");


    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_udp_send_setup(void)
{

    pdp_udp_send_class = class_new(gensym("pdp_netsend"), (t_newmethod)pdp_udp_send_new,
    	(t_method)pdp_udp_send_free, sizeof(t_pdp_udp_send), 0, A_NULL);


    class_addmethod(pdp_udp_send_class, (t_method)pdp_udp_send_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_udp_send_class, (t_method)pdp_udp_send_sleepgrain, gensym("sleepgrain"), A_FLOAT, A_NULL);
    class_addmethod(pdp_udp_send_class, (t_method)pdp_udp_send_sleepperiod, gensym("sleepperiod"), A_FLOAT, A_NULL);
    class_addmethod(pdp_udp_send_class, (t_method)pdp_udp_send_udpsize, gensym("udpsize"), A_FLOAT, A_NULL);
    class_addmethod(pdp_udp_send_class, (t_method)pdp_udp_send_timeout, gensym("timeout"), A_FLOAT, A_NULL);
    class_addmethod(pdp_udp_send_class, (t_method)pdp_udp_send_connect, gensym("connect"), A_SYMBOL, A_FLOAT, A_NULL);

}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_rawin.c ---
/*
 *   Pure Data Packet module. packet forth console
 *   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 <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <fcntl.h>
#include "pdp_pd.h"
#include "pdp_debug.h"
#include "pdp_list.h"
#include "pdp_comm.h"
#include "pdp_post.h"
#include "pdp_packet.h"


#define PERIOD 1.0f
#define D if (1)




/* raw input from a unix pipe */

typedef struct rawin_struct
{
    /* pd */
    t_object x_obj;
    t_outlet *x_outlet;
    t_outlet *x_sync_outlet;
    t_clock *x_clock;

    /* comm */
    t_pdp_list *x_queue; // packet queue

    /* thread */
    pthread_mutex_t x_mut;
    pthread_attr_t x_attr;
    pthread_t x_thread;

    /* sync */
    int x_giveup;  // 1-> terminate reader thread
    int x_active;  // 1-> reader thread is launched
    int x_done;    // 1-> reader thread has exited

    /* config */
    t_symbol *x_pipe;
    t_pdp_symbol *x_type;

} t_rawin;


static inline void lock(t_rawin *x){pthread_mutex_lock(&x->x_mut);}
static inline void unlock(t_rawin *x){pthread_mutex_unlock(&x->x_mut);}

static void rawin_close(t_rawin *x);
static void tick(t_rawin *x)
{
    /* send all packets in queue to outlet */
    lock(x);
    while (x->x_queue->elements){
	outlet_pdp_atom(x->x_outlet, x->x_queue->first);
	pdp_list_pop(x->x_queue); // pop stale reference
    }
    unlock(x);
    clock_delay(x->x_clock, PERIOD);

    /* check if thread is done */
    if (x->x_done) rawin_close(x);

}

static void move_current_to_queue(t_rawin *x, int packet)
{
    lock(x);
    pdp_list_add_back(x->x_queue, a_packet, (t_pdp_word)packet);
    unlock(x);
}

static void *rawin_thread(void *y)
{
    int pipe;
    int packet = -1;
    t_rawin *x = (t_rawin *)y;
    int period_sec;
    int period_usec;


    //D pdp_post("pipe: %s", x->x_pipe->s_name);
    //D pdp_post("type: %s", x->x_type->s_name);

    /* open pipe */
    if (-1 == (pipe = open(x->x_pipe->s_name, O_RDONLY|O_NONBLOCK))){
	perror(x->x_pipe->s_name);
	goto exit;
    }

    /* main loop (packets) */
    while(1){
	void *data = 0;
	int left = -1;

	/* create packet */
	if (-1 != packet){
	    pdp_post("WARNING: deleting stale packet");
	    pdp_packet_mark_unused(packet);
	}
	packet = pdp_factory_newpacket(x->x_type);
	if (-1 == packet){
	    pdp_post("ERROR: can't create packet. type = %s", x->x_type->s_name);
	    goto exit;
	}
	
	/* fill packet */
	data = pdp_packet_data(packet);
	left = pdp_packet_data_size(packet);
	// D pdp_post("packet %d, data %x, size %d", packet, data, left);

	/* inner loop: pipe reads */
	while(left){

	    fd_set inset;
	    struct timeval tv = {0,10000};

	    /* check if we need to stop */
	    if (x->x_giveup){
		pdp_packet_mark_unused(packet);
		goto close;
	    }
	    /* select, with timeout */
	    FD_ZERO(&inset);
	    FD_SET(pipe, &inset);
	    if (-1 == select(pipe+1, &inset, NULL,NULL, &tv)){
		pdp_post("select error");
		goto close;
	    }

	    /* if ready, read, else retry */
	    if (FD_ISSET(pipe, &inset)){
		int bytes = read(pipe, data, left);
		if (!bytes){
		    /* if no bytes are read, pipe is closed */
		    goto close;
		}
		data += bytes;
		left -= bytes;
	    }
	}
		   
	/* move to queue */
	move_current_to_queue(x, packet);
	packet = -1;


    
    }

  close:
    /* close pipe */
    close(pipe);
	
	
  exit:
    x->x_done = 1;
    return 0;
}



static void rawin_type(t_rawin *x, t_symbol *type)
{
    x->x_type = pdp_gensym(type->s_name);
}

static void rawin_open(t_rawin *x, t_symbol *pipe)
{
    /* save pipe name if not empty */
    if (pipe->s_name[0]) {x->x_pipe = pipe;}

    if (x->x_active) {
	pdp_post("already open");
	return;
    }
    /* start thread */
    x->x_giveup = 0;
    x->x_done = 0;
    pthread_create(&x->x_thread, &x->x_attr, rawin_thread , x);
    x->x_active = 1;
}

static void rawin_close(t_rawin *x)
{

    if (!x->x_active) return;

    /* stop thread: set giveup + wait */
    x->x_giveup = 1;
    pthread_join(x->x_thread, NULL);
    x->x_active = 0;

    /* notify */
    outlet_bang(x->x_sync_outlet);
    pdp_post("connection to %s closed", x->x_pipe->s_name);

    


    
}

static void rawin_free(t_rawin *x)
{
    rawin_close(x);
    clock_free(x->x_clock);
    pdp_tree_strip_packets(x->x_queue);
    pdp_tree_free(x->x_queue);
}

t_class *rawin_class;


static void *rawin_new(t_symbol *pipe, t_symbol *type)
{
    t_rawin *x;

    pdp_post("%s %s", pipe->s_name, type->s_name);

    /* allocate & init */
    x = (t_rawin *)pd_new(rawin_class);
    x->x_outlet = outlet_new(&x->x_obj, &s_anything);
    x->x_sync_outlet = outlet_new(&x->x_obj, &s_anything);
    x->x_clock = clock_new(x, (t_method)tick);
    x->x_queue = pdp_list_new(0);
    x->x_active = 0;
    x->x_giveup = 0;
    x->x_done = 0;
    x->x_type = pdp_gensym("image/YCrCb/320x240"); //default
    x->x_pipe = gensym("/tmp/pdpraw"); // default
    pthread_attr_init(&x->x_attr);
    pthread_mutex_init(&x->x_mut, NULL);
    clock_delay(x->x_clock, PERIOD);

    /* args */
    rawin_type(x, type);
    if (pipe->s_name[0]) x->x_pipe = pipe; 

    return (void *)x;

}



#ifdef __cplusplus
extern "C"
{
#endif


void pdp_rawin_setup(void)
{
    int i;

    /* create a standard pd class: [pdp_rawin pipe type] */
    rawin_class = class_new(gensym("pdp_rawin"), (t_newmethod)rawin_new,
   	(t_method)rawin_free, sizeof(t_rawin), 0, A_DEFSYMBOL, A_DEFSYMBOL, A_NULL);

    /* add global message handler */
    class_addmethod(rawin_class, (t_method)rawin_type, gensym("type"), A_SYMBOL, A_NULL);
    class_addmethod(rawin_class, (t_method)rawin_open, gensym("open"), A_DEFSYMBOL, A_NULL);
    class_addmethod(rawin_class, (t_method)rawin_close, gensym("close"), A_NULL);


}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_del.c ---
/*
 *   Pure Data Packet 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.
 *
 */



#include "pdp.h"


typedef struct pdp_del_struct
{
    t_object x_obj;
    t_float x_f;
  
    t_outlet *x_outlet0;

    t_outlet **x_outlet;

    int *x_packet;
    int x_order;
    int x_head;
    int x_delay;
} t_pdp_del;





static void pdp_del_input_0(t_pdp_del *x, t_symbol *s, t_floatarg f)
{
  int in;
  int out;
  int packet;
  
    /* if this is a register_ro message or register_rw message, register with packet factory */
    /* if this is a process message, start the processing + propagate stuff to outputs */

    if (s == gensym("register_ro")){
      in = (x->x_head % x->x_order);
      //post("pdp_del: marking unused packed id=%d on loc %d", x->x_packet[0], in);
      pdp_packet_mark_unused(x->x_packet[in]);
      packet = pdp_packet_copy_ro((int)f);


      // TODO TODO TODO !!!!

      //pdp_packet_print_debug((int)f);

      


      x->x_packet[in] = packet;
      //post("pdp_del: writing packed id=%d on loc %d", packet, in);
    }
    else if (s == gensym("process")){
      out = (((x->x_head + x->x_delay)) % x->x_order);
      packet = x->x_packet[out];
      pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet[out]);

/*
      if (-1 != packet){
	//post("pdp_del: packet %d has id %d", out, packet);
	pdp_packet_mark_unused(packet);
	outlet_pdp(x->x_outlet0, packet);
	x->x_packet[out] = -1;
      }


      else {
	//post("pdp_del: packet %d is empty", out);
      }
*/

      x->x_head = (x->x_head + x->x_order - 1) % x->x_order;
    }


}





static void pdp_del_delay(t_pdp_del *x, t_floatarg fdel)
{
  int del = (int)fdel;
  if (del < 0) del = 0;
  if (del >= x->x_order) del = x->x_order - 1;

  x->x_delay = del;

}

static void pdp_del_reset(t_pdp_del *x)
{
  int i;
  for (i=0; i<x->x_order; i++) {
      pdp_packet_mark_unused(x->x_packet[i]);
      x->x_packet[i] = -1;
  }
  x->x_head = 0;

}

static void pdp_del_debug(t_pdp_del *x)
{
  int i;
  post ("order %d", x->x_order);
  post ("delay %d", x->x_delay);
  post ("head %d", x->x_head);
  for (i=0; i<x->x_order; i++) {
      post("%d ", x->x_packet[i]);
  }
}

static void pdp_del_free(t_pdp_del *x)
{
  pdp_del_reset(x);
  pdp_dealloc (x->x_packet);
}

t_class *pdp_del_class;



void *pdp_del_new(t_floatarg forder, t_floatarg fdel)
{
  int order = (int)forder;
  int del;
  int logorder;
  int i;
  t_pdp_del *x = (t_pdp_del *)pd_new(pdp_del_class);

  del = order;
  order++;

  if (del < 0) del = 0;
  if (order <= 2) order = 2;

  //post("pdp_del: order = %d", order);

  x->x_order = order;
  x->x_packet = (int *)pdp_alloc(sizeof(int)*order);
  for(i=0; i<order; i++) x->x_packet[i] = -1;
  x->x_delay = del;
  inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("delay"));
  x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); 


  return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_del_setup(void)
{


    pdp_del_class = class_new(gensym("pdp_del"), (t_newmethod)pdp_del_new,
			      (t_method)pdp_del_free, sizeof(t_pdp_del), 0, A_DEFFLOAT, A_NULL);
    
    class_addmethod(pdp_del_class, (t_method)pdp_del_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_del_class, (t_method)pdp_del_delay, gensym("delay"),  A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_del_class, (t_method)pdp_del_reset, gensym("reset"),  A_NULL);

    class_addmethod(pdp_del_class, (t_method)pdp_del_debug, gensym("_debug"),  A_NULL);

}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_description.c ---
/*
 *   Pure Data Packet 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.
 *
 */



#include "pdp.h"



typedef struct pdp_description_struct
{
    t_object x_obj;
    t_outlet *x_outlet;

} t_pdp_description;




static void pdp_description_input_pdp(t_pdp_description *x, t_symbol *s, t_floatarg f)
{
    int p = (int)f;
    t_symbol *rro = S_REGISTER_RO;

    if (rro == s){
	outlet_symbol(x->x_outlet, gensym(pdp_packet_get_description(p)->s_name));
    }
}

static void pdp_description_input_dpd(t_pdp_description *x, t_symbol *s, t_floatarg f)
{
    int p = (int)f;
    t_symbol *ins = S_INSPECT;

    if (ins == s){
	outlet_symbol(x->x_outlet, gensym(pdp_packet_get_description(p)->s_name));
    }
}


static void pdp_description_free(t_pdp_description *x)
{

}

t_class *pdp_description_class;



static void *pdp_description_new(t_symbol *s, int argc, t_atom *argv)
{
    t_pdp_description *x = (t_pdp_description *)pd_new(pdp_description_class);

    x->x_outlet = outlet_new(&x->x_obj, &s_symbol);

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_description_setup(void)
{


    pdp_description_class = class_new(gensym("pdp_description"), (t_newmethod)pdp_description_new,
    	(t_method)pdp_description_free, sizeof(t_pdp_description), 0, A_NULL);

    class_addmethod(pdp_description_class, (t_method)pdp_description_input_pdp, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_description_class, (t_method)pdp_description_input_dpd, gensym("dpd"),  A_SYMBOL, A_DEFFLOAT, A_NULL);


}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_snap.c ---
/*
 *   Pure Data Packet 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.
 *
 */



#include "pdp.h"
#include "pdp_internals.h"

typedef struct pdp_snap_struct
{
    t_object x_obj;
    t_float x_f;

    t_outlet *x_outlet0;

    int x_packet0;
    bool x_snapnext;

} t_pdp_snap;


static void pdp_snap_bang(t_pdp_snap *x)
{

  if (-1 != x->x_packet0)
    outlet_pdp(x->x_outlet0, x->x_packet0);

}




static void pdp_snap_input_1(t_pdp_snap *x, t_symbol *s, t_floatarg f)
{

    /* if this is a register_ro message or register_rw message, register with packet factory */

    /* if this is a process message, start the processing + propagate stuff to outputs */

    if (s == gensym("register_ro")){
      if(x->x_snapnext) {
	pdp_packet_mark_unused(x->x_packet0);
	x->x_packet0 = pdp_packet_copy_ro((int)f);
	x->x_snapnext = false;
      }
    }

}

static void pdp_snap_snap(t_pdp_snap *x)
{
  x->x_snapnext = true;
}

static void pdp_snap_free(t_pdp_snap *x)
{
    pdp_packet_mark_unused(x->x_packet0);

}

t_class *pdp_snap_class;



void *pdp_snap_new(void)
{
    t_pdp_snap *x = (t_pdp_snap *)pd_new(pdp_snap_class);

    inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));

    x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); 

    x->x_packet0 = -1;
    x->x_snapnext = false;

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_snap_setup(void)
{


    pdp_snap_class = class_new(gensym("pdp_snap"), (t_newmethod)pdp_snap_new,
    	(t_method)pdp_snap_free, sizeof(t_pdp_snap), 0, A_NULL);


    class_addmethod(pdp_snap_class, (t_method)pdp_snap_bang, gensym("bang"), A_NULL);
    class_addmethod(pdp_snap_class, (t_method)pdp_snap_snap, gensym("snap"), A_NULL);
    
    class_addmethod(pdp_snap_class, (t_method)pdp_snap_input_1, gensym("pdp1"),  A_SYMBOL, A_DEFFLOAT, A_NULL);

}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_trigger.c ---
/*
 *   Pure Data Packet 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.
 *
 */



#include "pdp.h"
#include "pdp_internals.h"

/* adapted from the pd trigger object */

#define TR_BANG 0
#define TR_FLOAT 1
#define TR_SYMBOL 2
#define TR_POINTER 3
#define TR_LIST 4
#define TR_ANYTHING 5
#define TR_PDP 6

/*

$$$TODO: emplement so that it behaves like the standard trigger object

i.e. [trigger bang pdp pdp bang pdp]

register_ro and register_rw messages pass right trough,
since they're not action events, only configure events.
a bang is made equivalent to a process event.

*/

typedef struct triggerout
{
    int u_type;         /* outlet type from above */
    t_outlet *u_outlet;
} t_triggerout;


typedef struct pdp_trigger_struct
{
    t_object x_obj;
    t_float x_f;

    int x_n;
    t_triggerout *x_vec;

} t_pdp_trigger;




static void pdp_trigger_input_pdp(t_pdp_trigger *x, t_symbol *s, t_floatarg f)
{
    t_atom atom[2];
    t_symbol *pdp = S_PDP;
    t_symbol *prc = S_PROCESS;
    t_triggerout *u;
    int i;

    for (i = x->x_n, u = x->x_vec + i; u--, i--;){
	/* trigger bang outlet only when a process event is recieved */
	if ((u->u_type == TR_BANG) && (s == prc)){
	    outlet_bang(u->u_outlet);
	}
	/* just pass the message if it is a pdp outlet */
	if ((u->u_type) == TR_PDP){
	    SETSYMBOL(atom+0, s);
	    SETFLOAT(atom+1, f);
	    if (s == prc) outlet_anything(u->u_outlet, pdp, 1, atom);
	    else outlet_anything(u->u_outlet, pdp, 2, atom);
	    
	}
    }
    
}

static void pdp_trigger_input_dpd(t_pdp_trigger *x, t_symbol *s, t_floatarg f)
{
    t_atom atom[2];
    t_symbol *dpd = S_DPD;
    t_symbol *acc = S_ACCUMULATE;
    t_triggerout *u;
    int i;
    int p = (int)f;

    for (i = x->x_n, u = x->x_vec + i; u--, i--;){
	/* trigger outlet only when an accumulate event is recieved */
	if (s == acc){

	    /* output bang */
	    if (u->u_type == TR_BANG) outlet_bang(u->u_outlet);

	    /* output a complete dpd message if it is a pdp outlet */
	    if ((u->u_type) == TR_PDP){
		outlet_dpd(u->u_outlet, p);
	    }
	}
    }
    
}


static void pdp_trigger_free(t_pdp_trigger *x)
{
    pdp_dealloc(x->x_vec);
}

t_class *pdp_trigger_class;



static void *pdp_trigger_new(t_symbol *s, int argc, t_atom *argv)
{
    t_pdp_trigger *x = (t_pdp_trigger *)pd_new(pdp_trigger_class);
    t_atom defarg[2], *ap;
    t_triggerout *u;
    int i;


    if (!argc)
    {
        argv = defarg;
        argc = 2;
        SETSYMBOL(&defarg[0], gensym("pdp"));
        SETSYMBOL(&defarg[1], gensym("bang"));
    }

    x->x_n = argc;
    x->x_vec = pdp_alloc(argc * sizeof(*x->x_vec));

    for (i = 0, ap = argv, u = x->x_vec; i < argc; u++, ap++, i++)
    {
        t_atomtype thistype = ap->a_type;
        char c;
        if (thistype == TR_SYMBOL) c = ap->a_w.w_symbol->s_name[0];
        else c = 0;
        if (c == 'p')
            u->u_type = TR_PDP,
                u->u_outlet = outlet_new(&x->x_obj, &s_anything);
        else if (c == 'b')
            u->u_type = TR_BANG, u->u_outlet = outlet_new(&x->x_obj, &s_bang);
        else
        {
            pd_error(x, "pdp_trigger: %s: bad type", ap->a_w.w_symbol->s_name);
            u->u_type = TR_BANG, u->u_outlet = outlet_new(&x->x_obj, &s_bang);
        }
    }

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_trigger_setup(void)
{


    pdp_trigger_class = class_new(gensym("pdp_trigger"), (t_newmethod)pdp_trigger_new,
    	(t_method)pdp_trigger_free, sizeof(t_pdp_trigger), 0, A_GIMME, A_NULL);

    class_addcreator((t_newmethod)pdp_trigger_new, gensym("pdp_t"), A_GIMME, 0);
    
    class_addmethod(pdp_trigger_class, (t_method)pdp_trigger_input_pdp, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_trigger_class, (t_method)pdp_trigger_input_dpd, gensym("dpd"),  A_SYMBOL, A_DEFFLOAT, A_NULL);


}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_inspect.c ---
/*
 *   Pure Data Packet 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.
 *
 */



#include "pdp.h"

/* adapted from the pd trigger object */

#define TR_BANG 0
#define TR_FLOAT 1
#define TR_SYMBOL 2
#define TR_POINTER 3
#define TR_LIST 4
#define TR_ANYTHING 5
#define TR_PDP 6

/*

$$$TODO: emplement so that it behaves like the standard trigger object

i.e. [trigger bang pdp pdp bang pdp]

register_ro and register_rw messages pass right trough,
since they're not action events, only configure events.
a bang is made equivalent to a process event.

*/

typedef struct pdp_inspect_struct
{
    t_object x_obj;
    t_float x_f;

    t_outlet *x_outlet;

} t_pdp_inspect;




static void pdp_inspect_input_0(t_pdp_inspect *x, t_symbol *s, t_floatarg f)
{
    t_atom atom[2];
    t_symbol *pdp = gensym("pdp");
    t_symbol *prc = gensym("process");
    t_symbol *rro = gensym("register_ro");
    int i;


    /* if there is a reg_ro, shortcut the right outlet */
    if (s == rro){
	SETSYMBOL(atom+0, s);
	SETFLOAT(atom+1, f);
	outlet_anything(x->x_outlet, pdp, 2, atom);
	SETSYMBOL(atom+0, prc);
	outlet_anything(x->x_outlet, pdp, 1, atom);
    }

    
}



static void pdp_inspect_free(t_pdp_inspect *x)
{

}

t_class *pdp_inspect_class;



static void *pdp_inspect_new(void)
{
    t_pdp_inspect *x = (t_pdp_inspect *)pd_new(pdp_inspect_class);

    
    x->x_outlet = outlet_new(&x->x_obj, &s_anything);

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_inspect_setup(void)
{


    pdp_inspect_class = class_new(gensym("pdp_inspect_ro"), (t_newmethod)pdp_inspect_new,
    	(t_method)pdp_inspect_free, sizeof(t_pdp_inspect), 0, A_GIMME, A_NULL);

    class_addcreator((t_newmethod)pdp_inspect_new, gensym("pdp_t"), A_GIMME, 0);
    
    class_addmethod(pdp_inspect_class, (t_method)pdp_inspect_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);


}

#ifdef __cplusplus
}
#endif

--- NEW FILE: README ---
This directory contains generic packet processors (i.e. containers).
Should work with any packet type.

--- NEW FILE: pdp_rawout.c ---
/*
 *   Pure Data Packet module. packet forth console
 *   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 <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include "pdp_pd.h"
#include "pdp_debug.h"
#include "pdp_list.h"
#include "pdp_comm.h"
#include "pdp_post.h"
#include "pdp_packet.h"


#define D if (1)
#define MAX_QUEUESIZE 4
#define PIPE_BLOCKSIZE 4096




/* raw input from a unix pipe */

typedef struct rawout_struct
{
    /* pd */
    t_object x_obj;
    //t_outlet *x_outlet;
    t_outlet *x_sync_outlet;

    /* comm */
    t_pdp_list *x_queue; // packet queue

    /* thread */
    pthread_mutex_t x_mut;
    pthread_attr_t x_attr;
    pthread_t x_thread;

    /* sync */
    int x_giveup;  // 1-> terminate writer thread
    int x_active;  // 1-> writer thread is launched
    int x_done;    // 1-> writer thread has exited

    /* config */
    t_symbol *x_pipe;
    t_pdp_symbol *x_type;

} t_rawout;


static inline void lock(t_rawout *x){pthread_mutex_lock(&x->x_mut);}
static inline void unlock(t_rawout *x){pthread_mutex_unlock(&x->x_mut);}

static void rawout_close(t_rawout *x);
static void pdp_in(t_rawout *x, t_symbol *s, t_float f)
{
    /* save packet to pdp queue, if size is smaller than maxsize */
    if (s == S_REGISTER_RO){
	if (x->x_queue->elements < MAX_QUEUESIZE){
	    int p = (int)f;
	    p = pdp_packet_copy_ro(p);
	    if (p != -1){
		lock(x);
		pdp_list_add_back(x->x_queue, a_packet, (t_pdp_word)p);
		unlock(x);
	    }
	}
	else {
	    pdp_post("pdp_rawout: dropping packet: (queue full)", MAX_QUEUESIZE);
	}
	    
    }

    /* check if thread is done */
    if (x->x_done) rawout_close(x);

}



static void *rawout_thread(void *y)
{
    int pipe;
    int packet = -1;
    t_rawout *x = (t_rawout *)y;
    int period_sec;
    int period_usec;
    sigset_t sigvec; /* signal handling  */

    /* ignore pipe signal */
    sigemptyset(&sigvec);
    sigaddset(&sigvec,SIGPIPE);
    pthread_sigmask(SIG_BLOCK, &sigvec, 0);

    //D pdp_post("pipe: %s", x->x_pipe->s_name);
    //D pdp_post("type: %s", x->x_type->s_name);

    /* open pipe */
    if (-1 == (pipe = open(x->x_pipe->s_name, O_WRONLY|O_NONBLOCK))){
	perror(x->x_pipe->s_name);
	goto exit;
    }

    /* main loop (packets) */
    while(1){
	void *data = 0;
	int left = -1;

	/* try again if queue is empty */
	if (!x->x_queue->elements){
	    /* check if we need to stop */
	    if (x->x_giveup){
		goto close;
	    }
	    else {
		usleep(1000.0f); // sleep before polling again
		continue;
	    }
	}
	/* get packet from queue */
	lock(x);
	packet = pdp_list_pop(x->x_queue).w_packet;
	unlock(x);
	
	/* send packet */
	data = pdp_packet_data(packet);
	left = pdp_packet_data_size(packet);

	/* inner loop: pipe reads */
	while(left){

	    fd_set outset;
	    struct timeval tv = {0,10000};

	    /* check if we need to stop */
	    if (x->x_giveup){
		pdp_packet_mark_unused(packet);
		goto close;
	    }

	    /* select, with timeout */
	    FD_ZERO(&outset);
	    FD_SET(pipe, &outset);
	    if (-1 == select(pipe+1, NULL, &outset, NULL, &tv)){
		pdp_post("select error");
		goto close;
	    }

	    /* if ready, read, else retry */
	    if (FD_ISSET(pipe, &outset)){
		int bytes = write(pipe, data, left);
		/* handle errors */
		if (bytes <= 0){
		    perror(x->x_pipe->s_name);
		    if (bytes != EAGAIN) goto close;
		}
		/* or update pointers */
		else{
		    data += bytes;
		    left -= bytes;
		    //pdp_post("left %d", left);
		}
	    }
	    else {
		//pdp_post("retrying write");
	    }
	}
		   
	/* discard packet */
	pdp_packet_mark_unused(packet);

    
    }

  close:
    /* close pipe */
    close(pipe);
	
	
  exit:
    x->x_done = 1;
    return 0;
}



static void rawout_type(t_rawout *x, t_symbol *type)
{
    x->x_type = pdp_gensym(type->s_name);
}

static void rawout_open(t_rawout *x, t_symbol *pipe)
{
    /* save pipe name if not empty */
    if (pipe->s_name[0]) {x->x_pipe = pipe;}

    if (x->x_active) {
	pdp_post("already open");
	return;
    }
    /* start thread */
    x->x_giveup = 0;
    x->x_done = 0;
    pthread_create(&x->x_thread, &x->x_attr, rawout_thread , x);
    x->x_active = 1;
}

static void rawout_close(t_rawout *x)
{

    if (!x->x_active) return;

    /* stop thread: set giveup + wait */
    x->x_giveup = 1;
    pthread_join(x->x_thread, NULL);
    x->x_active = 0;

    /* notify */
    outlet_bang(x->x_sync_outlet);
    pdp_post("connection to %s closed", x->x_pipe->s_name);

    


    
}

static void rawout_free(t_rawout *x)
{
    rawout_close(x);
    pdp_tree_strip_packets(x->x_queue);
    pdp_tree_free(x->x_queue);
}

t_class *rawout_class;


static void *rawout_new(t_symbol *pipe, t_symbol *type)
{
    t_rawout *x;

    pdp_post("%s %s", pipe->s_name, type->s_name);

    /* allocate & init */
    x = (t_rawout *)pd_new(rawout_class);
    //x->x_outlet = outlet_new(&x->x_obj, &s_anything);
    x->x_sync_outlet = outlet_new(&x->x_obj, &s_anything);
    x->x_queue = pdp_list_new(0);
    x->x_active = 0;
    x->x_giveup = 0;
    x->x_done = 0;
    x->x_type = pdp_gensym("image/YCrCb/320x240"); //default
    x->x_pipe = gensym("/tmp/pdpraw"); // default
    pthread_attr_init(&x->x_attr);
    pthread_mutex_init(&x->x_mut, NULL);

    /* args */
    rawout_type(x, type);
    if (pipe->s_name[0]) x->x_pipe = pipe; 

    return (void *)x;

}



#ifdef __cplusplus
extern "C"
{
#endif


void pdp_rawout_setup(void)
{
    int i;

    /* create a standard pd class: [pdp_rawout pipe type] */
    rawout_class = class_new(gensym("pdp_rawout"), (t_newmethod)rawout_new,
   	(t_method)rawout_free, sizeof(t_rawout), 0, A_DEFSYMBOL, A_DEFSYMBOL, A_NULL);

    /* add global message handler */
    class_addmethod(rawout_class, (t_method)pdp_in, 
		    gensym("pdp"), A_SYMBOL, A_FLOAT, A_NULL);

    class_addmethod(rawout_class, (t_method)rawout_type, gensym("type"), A_SYMBOL, A_NULL);
    class_addmethod(rawout_class, (t_method)rawout_open, gensym("open"), A_DEFSYMBOL, A_NULL);
    class_addmethod(rawout_class, (t_method)rawout_close, gensym("close"), A_NULL);


}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_route.c ---
/*
 *   Pure Data Packet 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.
 *
 */



#include "pdp.h"
#include "pdp_internals.h"

// dynamic ????
#define PDP_ROUTE_MAX_NB_OUTLETS 100

typedef struct pdp_route_struct
{
    t_object x_obj;
    t_float x_f;

    t_outlet *x_outlet[PDP_ROUTE_MAX_NB_OUTLETS];

    int x_nb_outlets;
    int x_route;
    int x_route_next;


} t_pdp_route;


static void pdp_route_input_0(t_pdp_route *x, t_symbol *s, t_floatarg f)
{
    t_atom atom[2];
    t_symbol *pdp = gensym("pdp");


    /* trigger on register_ro */
    if (s == gensym("register_ro")){
	x->x_route = x->x_route_next;
    }

    /* propagate the pdp message */
    SETSYMBOL(atom+0, s);
    SETFLOAT(atom+1, f);
    outlet_anything(x->x_outlet[x->x_route], pdp, 2, atom);

}

static void pdp_route_input_0_dpd(t_pdp_route *x, t_symbol *s, t_floatarg f)
{

    /* trigger on accumulate */
    if (s == gensym("accumulate")){
	x->x_route = x->x_route_next;
    }

    /* propagate the dpd message */
    outlet_dpd(x->x_outlet[x->x_route], (int)f);

}



static void pdp_route_route(t_pdp_route *x, t_floatarg f)
{
    int route = (int)f;

    if (route < 0) route = 0;
    if (route >= x->x_nb_outlets) route = x->x_nb_outlets - 1;
    
    x->x_route_next = route;

}



static void pdp_route_free(t_pdp_route *x)
{
    
}

t_class *pdp_route_class;



void *pdp_route_new(t_floatarg f)
{
    int nboutlets = (int)f;
    int i;

    t_pdp_route *x = (t_pdp_route *)pd_new(pdp_route_class);


    if (nboutlets < 2) nboutlets = 2;
    if (nboutlets >= PDP_ROUTE_MAX_NB_OUTLETS) nboutlets = PDP_ROUTE_MAX_NB_OUTLETS - 1;


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

    x->x_nb_outlets = nboutlets;
    x->x_route = 0;
    x->x_route_next = 0;

    for (i=0; i<nboutlets; i++) 
	x->x_outlet[i] = outlet_new(&x->x_obj, &s_anything);

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_route_setup(void)
{


    pdp_route_class = class_new(gensym("pdp_route"), (t_newmethod)pdp_route_new,
    	(t_method)pdp_route_free, sizeof(t_pdp_route), 0, A_DEFFLOAT, A_NULL);


    class_addmethod(pdp_route_class, (t_method)pdp_route_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_route_class, (t_method)pdp_route_input_0_dpd, gensym("dpd"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_route_class, (t_method)pdp_route_route, gensym("route"),  A_DEFFLOAT, A_NULL);

}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_reg.c ---
/*
 *   Pure Data Packet 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.
 *
 */



#include "pdp.h"
#include "pdp_png.h"
#include "pdp_internals.h"


typedef struct pdp_reg_struct
{
    t_object x_obj;
    t_float x_f;

    t_outlet *x_outlet0;

    int x_packet0;

} t_pdp_reg;


static void pdp_reg_load_png(t_pdp_reg *x, t_symbol *s)
{
    int packet;
    //post("sym: %s", s->s_name);
    packet = pdp_packet_bitmap_from_png_file(s->s_name);
    if (-1 == packet){
	post("pdp_reg: error loading png file %s", s->s_name);
    }
    else{
	pdp_packet_mark_unused(x->x_packet0);
	x->x_packet0 = packet;
    }

}

static void pdp_reg_save_png(t_pdp_reg *x, t_symbol *s)
{
    int newpacket = pdp_packet_convert_ro(x->x_packet0, pdp_gensym("bitmap/*/*"));

    if (-1 == newpacket){
	post("pdp_reg: nothing to save");
	return;
    }

    if (!(pdp_packet_bitmap_save_png_file(newpacket, s->s_name))){
	post("pdp_reg: error saving png file %s", s->s_name);
    }

    pdp_packet_mark_unused(newpacket);
					  
}


static void pdp_reg_bang(t_pdp_reg *x)
{

    if (-1 != x->x_packet0) outlet_pdp(x->x_outlet0, x->x_packet0);

}



static void pdp_reg_input_0(t_pdp_reg *x, t_symbol *s, t_floatarg f)
{

    /* if this is a register_ro message or register_rw message, register with packet factory */

    /* if this is a process message, start the processing + propagate stuff to outputs */

    if (s == gensym("register_ro")){
	pdp_packet_mark_unused(x->x_packet0);
	x->x_packet0 = pdp_packet_copy_ro((int)f);
	//post("in0ro: requested %d, got %d", (int)f, x->x_packet0);
    }
    else if (s == gensym("process")){
	pdp_reg_bang(x);

    }


}


static void pdp_reg_input_1(t_pdp_reg *x, t_symbol *s, t_floatarg f)
{

    /* if this is a register_ro message or register_rw message, register with packet factory */

    /* if this is a process message, start the processing + propagate stuff to outputs */

    if (s == gensym("register_ro")){
	pdp_packet_mark_unused(x->x_packet0);
	x->x_packet0 = pdp_packet_copy_ro((int)f);
	//post("in0ro: requested %d, got %d", (int)f, x->x_packet0);
    }

}



static void pdp_reg_free(t_pdp_reg *x)
{
    pdp_packet_mark_unused(x->x_packet0);

}

t_class *pdp_reg_class;



void *pdp_reg_new(void)
{
    t_pdp_reg *x = (t_pdp_reg *)pd_new(pdp_reg_class);

    inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));

    x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); 

    x->x_packet0 = -1;

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_reg_setup(void)
{


    pdp_reg_class = class_new(gensym("pdp_reg"), (t_newmethod)pdp_reg_new,
    	(t_method)pdp_reg_free, sizeof(t_pdp_reg), 0, A_NULL);


    class_addmethod(pdp_reg_class, (t_method)pdp_reg_bang, gensym("bang"), A_NULL);
    
    class_addmethod(pdp_reg_class, (t_method)pdp_reg_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_reg_class, (t_method)pdp_reg_input_1, gensym("pdp1"),  A_SYMBOL, A_DEFFLOAT, A_NULL);

    class_addmethod(pdp_reg_class, (t_method)pdp_reg_save_png, gensym("save_png"), A_SYMBOL, A_NULL);
    class_addmethod(pdp_reg_class, (t_method)pdp_reg_load_png, gensym("load_png"), A_SYMBOL, A_NULL);

}

#ifdef __cplusplus
}
#endif





More information about the Pd-cvs mailing list