[PD-cvs] externals/pidip/modules pdp_background.c,NONE,1.1 pdp_binary.c,NONE,1.1 pdp_cropper.c,NONE,1.1 pdp_dilate.c,NONE,1.1 pdp_disintegration.c,NONE,1.1 pdp_distance.c,NONE,1.1 pdp_erode.c,NONE,1.1 pdp_hitandmiss.c,NONE,1.1 pdp_theorin~.c,NONE,1.1 pdp_theorout~.c,NONE,1.1

Yves Degoyon sevyves at users.sourceforge.net
Mon Nov 15 00:01:01 CET 2004


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

Added Files:
	pdp_background.c pdp_binary.c pdp_cropper.c pdp_dilate.c 
	pdp_disintegration.c pdp_distance.c pdp_erode.c 
	pdp_hitandmiss.c pdp_theorin~.c pdp_theorout~.c 
Log Message:
PiDiP 0.12.17

--- NEW FILE: pdp_disintegration.c ---
/*
 *   PiDiP module
 *   Copyright (c) by Yves Degoyon ( ydegoyon at free.fr )
 *
 *   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 object is a piksels sum-up operator
 */

#include "pdp.h"
#include "yuv.h"
#include <math.h>
#include <stdio.h>

static char   *pdp_disintegration_version = "pdp_disintegration: piksels sum-up version 0.1 written by Yves Degoyon (ydegoyon at free.fr)";

typedef struct pdp_disintegration_struct
{
    t_object x_obj;

    t_int x_packet0;
    t_int x_packet1;
    t_int x_queue_id;
    t_int x_dropped;

    t_int x_vwidth;
    t_int x_vheight;
    t_int x_vsize;
    t_int x_nbpasses;  // number of passes
    t_int x_reductor; // fraction reductor
    short int *x_frame;  // keep a copy of current frame for transformations

    t_outlet *x_pdp_output; // output packets

} t_pdp_disintegration;

static void pdp_disintegration_nbpasses(t_pdp_disintegration *x,  t_floatarg fpasses )
{
   if ( fpasses>=1.) 
   {
      x->x_nbpasses = (t_int)fpasses;
   }
}

static void pdp_disintegration_reductor(t_pdp_disintegration *x,  t_floatarg freductor )
{
   if ( freductor>=1.) 
   {
      x->x_reductor = (t_int)freductor;
   }
}

static void pdp_disintegration_allocate(t_pdp_disintegration *x)
{
    x->x_frame = (short int *) getbytes ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );

    if ( !x->x_frame )
    {
       post( "pdp_disintegration : severe error : cannot allocate buffer !!! ");
       return;
    }
}

static void pdp_disintegration_free_ressources(t_pdp_disintegration *x)
{
    if ( x->x_frame ) freebytes ( x->x_frame, ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );
}

static void pdp_disintegration_process_yv12(t_pdp_disintegration *x)
{
    t_pdp     *header = pdp_packet_header(x->x_packet0);
    short int *data   = (short int *)pdp_packet_data(x->x_packet0);
    t_pdp     *newheader = pdp_packet_header(x->x_packet1);
    short int *newdata = (short int *)pdp_packet_data(x->x_packet1);
    t_int     i;
    t_int     px=0, py=0; 
    short int *pfY, *pfU, *pfV;
    t_int     ppx, ppy, ix, iy, pn;
    t_int     nvalue;

    // allocate all ressources
    if ( ( (int)header->info.image.width != x->x_vwidth ) ||
         ( (int)header->info.image.height != x->x_vheight ) )
    {
        pdp_disintegration_free_ressources( x );
        x->x_vwidth = header->info.image.width;
        x->x_vheight = header->info.image.height;
        x->x_vsize = x->x_vwidth*x->x_vheight;
        pdp_disintegration_allocate( x );
        post( "pdp_disintegration : reallocated buffers" );
    }

    // post( "pdp_disintegration : newheader:%x", newheader );

    newheader->info.image.encoding = header->info.image.encoding;
    newheader->info.image.width = x->x_vwidth;
    newheader->info.image.height = x->x_vheight;

    memcpy( newdata, data, x->x_vsize+(x->x_vsize>>1)<<1 );
    memcpy( x->x_frame, data, x->x_vsize+(x->x_vsize>>1)<<1 );

    pfY = x->x_frame;
    pfV = x->x_frame+x->x_vsize;
    pfU = x->x_frame+x->x_vsize+(x->x_vsize>>2);
    
    // foreground piksels are now 1
    for ( py=0; py<x->x_vheight; py++ )
    {
      for ( px=0; px<x->x_vwidth; px++ )
      {
         if ( *(pfY+py*x->x_vwidth+px) == ((255)<<7) )
         {
           *(pfY+py*x->x_vwidth+px) = ((1)<<7); 
         }
      }
    }

    for ( pn=0; pn<x->x_nbpasses; pn++ )
    {
      memcpy( x->x_frame, newdata, x->x_vsize+(x->x_vsize>>1)<<1 );
      for ( py=0; py<x->x_vheight; py++ )
      {
        for ( px=0; px<x->x_vwidth; px++ )
        {
          nvalue = 0;
          for (ix=-1; ix<=1; ix++)
          {
            ppx=px+ix;
            if ( (ppx>=0) && (ppx<x->x_vwidth) )
            {
              for (iy=-1; iy<=1; iy++)
              {
                ppy=py+iy;
                if ( (ppy>=0) && (ppy<x->x_vheight) )
                {
                   nvalue += *(pfY+ppy*x->x_vwidth+ppx);
                }
              }
            }
          }
          if ( nvalue > ((255)<<7)*9 )
          {
            *(newdata+py*x->x_vwidth+px) = ((255)<<7);
          }
          else
          {
            *(newdata+py*x->x_vwidth+px) = nvalue/x->x_reductor;
          }
        }
      }
    }

    return;
}

static void pdp_disintegration_sendpacket(t_pdp_disintegration *x)
{
    /* release the packet */
    pdp_packet_mark_unused(x->x_packet0);
    x->x_packet0 = -1;

    /* unregister and propagate if valid dest packet */
    pdp_packet_pass_if_valid(x->x_pdp_output, &x->x_packet1);
}

static void pdp_disintegration_process(t_pdp_disintegration *x)
{
   int encoding;
   t_pdp *header = 0;

   /* check if image data packets are compatible */
   if ( (header = pdp_packet_header(x->x_packet0))
	&& (PDP_IMAGE == header->type)){
    
	/* pdp_disintegration_process inputs and write into active inlet */
	switch(pdp_packet_header(x->x_packet0)->info.image.encoding)
        {

	case PDP_IMAGE_YV12:
            x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
            pdp_queue_add(x, pdp_disintegration_process_yv12, pdp_disintegration_sendpacket, &x->x_queue_id);
	    break;

	case PDP_IMAGE_GREY:
            // should write something to handle these one day
            // but i don't use this mode                      
	    break;

	default:
	    /* don't know the type, so dont pdp_disintegration_process */
	    break;
	    
	}
    }

}

static void pdp_disintegration_input_0(t_pdp_disintegration *x, t_symbol *s, t_floatarg f)
{
    /* if this is a register_ro message or register_rw message, register with packet factory */

    if (s== gensym("register_rw"))
    {
       x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("image/YCrCb/*") );
    }

    if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped))
    {
        pdp_disintegration_process(x);
    }
}

static void pdp_disintegration_free(t_pdp_disintegration *x)
{
  int i;

    pdp_packet_mark_unused(x->x_packet0);
    pdp_disintegration_free_ressources( x );
}

t_class *pdp_disintegration_class;

void *pdp_disintegration_new(void)
{
    int i;

    t_pdp_disintegration *x = (t_pdp_disintegration *)pd_new(pdp_disintegration_class);
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("nbpasses"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("reductor"));

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

    x->x_packet0 = -1;
    x->x_packet1 = -1;
    x->x_vwidth = -1;
    x->x_vheight = -1;
    x->x_vsize = -1;
    x->x_frame = NULL;
    x->x_nbpasses = 3;
    x->x_reductor = 5;

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_disintegration_setup(void)
{
    // post( pdp_disintegration_version );
    pdp_disintegration_class = class_new(gensym("pdp_disintegration"), (t_newmethod)pdp_disintegration_new,
    	(t_method)pdp_disintegration_free, sizeof(t_pdp_disintegration), 0, A_NULL);

    class_addmethod(pdp_disintegration_class, (t_method)pdp_disintegration_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_disintegration_class, (t_method)pdp_disintegration_nbpasses, gensym("nbpasses"), A_FLOAT, A_NULL);
    class_addmethod(pdp_disintegration_class, (t_method)pdp_disintegration_reductor, gensym("reductor"), A_FLOAT, A_NULL);
    class_sethelpsymbol( pdp_disintegration_class, gensym("pdp_disintegration.pd") );
}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_cropper.c ---
/*
 *   PiDiP module.
 *   Copyright (c) by Yves Degoyon (ydegoyon at free.fr)
 *
 *   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 object is a video cropper
 *  Written by Yves Degoyon                                 
 */



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

static char   *pdp_cropper_version = "pdp_cropper: a video cropper, version 0.1, written by Yves Degoyon (ydegoyon at free.fr)";

typedef struct pdp_cropper_struct
{
    t_object x_obj;
    t_float x_f;

    t_outlet *x_outlet0;
    t_int x_packet0;
    t_int x_packet1;
    t_int x_dropped;
    t_int x_queue_id;

    t_int x_vwidth;
    t_int x_vheight;
    t_int x_vsize;
    t_int x_csizex;
    t_int x_csizey;
    t_int x_csizev;
    unsigned int x_encoding;

    int       x_cropx1;
    int       x_cropx2;
    int       x_cropy1;
    int       x_cropy2;

} t_pdp_cropper;

static void pdp_cropper_cropx1(t_pdp_cropper *x, t_floatarg fcropx1 )
{
    if ( ( fcropx1>=0 ) && ( fcropx1<x->x_vwidth ) )
    {
       x->x_cropx1 = (t_int)fcropx1;
    }
}

static void pdp_cropper_cropx2(t_pdp_cropper *x, t_floatarg fcropx2 )
{
    if ( ( fcropx2>=0 ) && ( fcropx2<x->x_vwidth ) )
    {
       x->x_cropx2 = (t_int)fcropx2;
    }
}

static void pdp_cropper_cropy1(t_pdp_cropper *x, t_floatarg fcropy1 )
{
    if ( ( fcropy1>=0 ) && ( fcropy1<x->x_vheight ) )
    {
       x->x_cropy1 = (t_int)fcropy1;
    }
}

static void pdp_cropper_cropy2(t_pdp_cropper *x, t_floatarg fcropy2 )
{
    if ( ( fcropy2>=0 ) && ( fcropy2<x->x_vheight ) )
    {
       x->x_cropy2 = (t_int)fcropy2;
    }
}

static void pdp_cropper_process_yv12(t_pdp_cropper *x)
{
    t_pdp     *header = pdp_packet_header(x->x_packet0);
    short int *data   = (short int *)pdp_packet_data(x->x_packet0);
    t_pdp     *newheader = NULL;
    short int *newdata = NULL;
    int       i;

    int px, py;
    short int *pY, *pU, *pV;
    short int *pnY, *pnU, *pnV;
    int minx, maxx;
    int miny, maxy;

    /* allocate all ressources */
    if ( ( (t_int)header->info.image.width != x->x_vwidth ) ||
         ( (t_int)header->info.image.height != x->x_vheight ) ) 
    {
       x->x_vwidth = header->info.image.width;
       x->x_vheight = header->info.image.height;
       x->x_vsize = x->x_vwidth*x->x_vheight;
       if ( ( x->x_cropx1 <0 ) || ( x->x_cropx1 >= x->x_vwidth ) ) x->x_cropx1 = 0;
       if ( ( x->x_cropx2 <0 ) || ( x->x_cropx2 >= x->x_vwidth ) ) x->x_cropx2 = x->x_vwidth-1;
       if ( ( x->x_cropy1 <0 ) || ( x->x_cropy1 >= x->x_vheight ) ) x->x_cropy1 = 0;
       if ( ( x->x_cropy2 <0 ) || ( x->x_cropy2 >= x->x_vheight ) ) x->x_cropy2 = x->x_vheight-1;
    }

    x->x_csizex = abs ( x->x_cropx2 - x->x_cropx1 );
    if ( x->x_csizex%8 != 0 ) x->x_csizex = x->x_csizex + (8-(x->x_csizex%8)); // align on 8
    x->x_csizey = abs ( x->x_cropy2 - x->x_cropy1 );
    if ( x->x_csizey%8 != 0 ) x->x_csizey = x->x_csizey + (8-(x->x_csizey%8)); // align on 8
    if ( x->x_csizex == 0 ) x->x_csizex = 8;
    if ( x->x_csizey == 0 ) x->x_csizey = 8;
    // post( "pdp_cropper : new image %dx%d", x->x_csizex, x->x_csizey );

    x->x_csizev = x->x_csizex*x->x_csizey;
    x->x_packet1 = pdp_packet_new_image_YCrCb( x->x_csizex, x->x_csizey );
    newheader = pdp_packet_header(x->x_packet1);
    newdata = (short int *)pdp_packet_data(x->x_packet1);

    newheader->info.image.encoding = header->info.image.encoding;
    newheader->info.image.width = x->x_csizex;
    newheader->info.image.height = x->x_csizey;

    pY = data;
    pU = (data+x->x_vsize);
    pV = (data+x->x_vsize+(x->x_vsize>>2));
    pnY = newdata;
    pnU = (newdata+x->x_csizev);
    pnV = (newdata+x->x_csizev+(x->x_csizev>>2));

    if ( x->x_cropx1<x->x_cropx2 ) 
    {
       minx = x->x_cropx1;
       maxx = x->x_cropx2;
    }
    else
    {
       minx = x->x_cropx2;
       maxx = x->x_cropx1;
    }

    if ( x->x_cropy1<x->x_cropy2 ) 
    {
       miny = x->x_cropy1;
       maxy = x->x_cropy2;
    }
    else
    {
       miny = x->x_cropy2;
       maxy = x->x_cropy1;
    }

    for(py=miny; py<maxy; py++) 
    {
      for(px=minx; px<maxx; px++) 
      {
         *(pnY+(py-miny)*x->x_csizex+(px-minx)) = *(pY+py*x->x_vwidth+px);
         if ( (py%2==0) && (px%2==0) )
         {
           *(pnU+((py-miny)>>1)*(x->x_csizex>>1)+((px-minx)>>1)) = *(pU+(py>>1)*(x->x_vwidth>>1)+(px>>1));
           *(pnV+((py-miny)>>1)*(x->x_csizex>>1)+((px-minx)>>1)) = *(pV+(py>>1)*(x->x_vwidth>>1)+(px>>1));
         }
      }
    }

    return;
}

static void pdp_cropper_sendpacket(t_pdp_cropper *x)
{
    /* release the packet */
    pdp_packet_mark_unused(x->x_packet0);
    x->x_packet0 = -1;

    /* unregister and propagate if valid dest packet */
    pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet1);
}

static void pdp_cropper_process(t_pdp_cropper *x)
{
   int encoding;
   t_pdp *header = 0;

   /* check if image data packets are compatible */
   if ( (header = pdp_packet_header(x->x_packet0))
	&& (PDP_IMAGE == header->type)){
    
	/* pdp_cropper_process inputs and write into active inlet */
	switch(pdp_packet_header(x->x_packet0)->info.image.encoding){

	case PDP_IMAGE_YV12:
            pdp_queue_add(x, pdp_cropper_process_yv12, pdp_cropper_sendpacket, &x->x_queue_id);
	    break;

	case PDP_IMAGE_GREY:
	    // pdp_cropper_process_packet(x);
	    break;

	default:
	    /* don't know the type, so dont pdp_cropper_process */
	    break;
	    
	}
    }
}

static void pdp_cropper_input_0(t_pdp_cropper *x, t_symbol *s, t_floatarg f)
{
    /* if this is a register_ro message or register_rw message, register with packet factory */

    if (s== gensym("register_rw"))
    {
       x->x_dropped = 
          pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("image/YCrCb/*") );
    }

    if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped))
    {
       /* add the process method and callback to the process queue */
       pdp_cropper_process(x);
    }
}

static void pdp_cropper_free(t_pdp_cropper *x)
{
  int i;

    pdp_queue_finish(x->x_queue_id);
    pdp_packet_mark_unused(x->x_packet0);
}

t_class *pdp_cropper_class;

void *pdp_cropper_new(void)
{
    int i;

    t_pdp_cropper *x = (t_pdp_cropper *)pd_new(pdp_cropper_class);
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("x1"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("x2"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("y1"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("y2"));

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

    x->x_packet0 = -1;
    x->x_packet1 = -1;
    x->x_queue_id = -1;

    x->x_cropx1=-1;
    x->x_cropx2=-1;
    x->x_cropy1=-1;
    x->x_cropy2=-1;

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_cropper_setup(void)
{
//    post( pdp_cropper_version );
    pdp_cropper_class = class_new(gensym("pdp_cropper"), (t_newmethod)pdp_cropper_new,
    	(t_method)pdp_cropper_free, sizeof(t_pdp_cropper), 0, A_NULL);

    class_addmethod(pdp_cropper_class, (t_method)pdp_cropper_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_cropper_class, (t_method)pdp_cropper_cropx1, gensym("x1"),  A_FLOAT, A_NULL);
    class_addmethod(pdp_cropper_class, (t_method)pdp_cropper_cropx2, gensym("x2"),  A_FLOAT, A_NULL);
    class_addmethod(pdp_cropper_class, (t_method)pdp_cropper_cropy1, gensym("y1"),  A_FLOAT, A_NULL);
    class_addmethod(pdp_cropper_class, (t_method)pdp_cropper_cropy2, gensym("y2"),  A_FLOAT, A_NULL);
    class_sethelpsymbol( pdp_cropper_class, gensym("pdp_cropper.pd") );
}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_theorout~.c ---
/*
 *   PiDiP module.
 *   Copyright (c) by Yves Degoyon <ydegoyon at free.fr>
 *
 *   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 object is a theora file encoder object
 *  It uses libtheora and some of it code samples ( copyright xiph.org )
 *  Copyleft by Yves Degoyon ( ydegoyon at free.fr )
 *
 */


#include "pdp.h"
#include <math.h>
#include <time.h>
#include <sys/time.h>
#include <theora/theora.h>
#include <vorbis/codec.h>
#include <vorbis/vorbisenc.h>

#define DEFAULT_FRAME_RATE 25
#define MIN_VIDEO_QUALITY 0
#define MAX_VIDEO_QUALITY 63
#define DEFAULT_VIDEO_QUALITY 16
#define MIN_VIDEO_BITRATE 45
#define MAX_VIDEO_BITRATE 2000
#define DEFAULT_VIDEO_BITRATE 96
#define MIN_AUDIO_QUALITY -0.1
#define MAX_AUDIO_QUALITY 1.0
#define DEFAULT_AUDIO_QUALITY 0.5
#define MIN_AUDIO_BITRATE 8
#define MAX_AUDIO_BITRATE 2000
#define DEFAULT_AUDIO_BITRATE 32

#define DEFAULT_CHANNELS 2
#define DEFAULT_BITS 8
#define MAX_AUDIO_PACKET_SIZE (128 * 1024)
// streams hard-coded serial numbers
#define STREAMV_SNO 0x987654
#define STREAMA_SNO 0x456789

#ifndef _REENTRANT
# define _REENTRANT
#endif

static char   *pdp_theorout_version = "pdp_theorout~: version 0.1, a theora video/audio recording object, written by ydegoyon at free.fr";

typedef struct pdp_theorout_struct
{
    t_object x_obj;
    t_float x_f;

    t_outlet *x_outlet0;
    t_int x_packet0;
    t_int x_packet1;
    t_int x_dropped;
    t_int x_queue_id;

    t_int x_vwidth;
    t_int x_tvwidth;       /* theora 16 pixels aligned width value */
    t_int x_vheight;
    t_int x_tvheight;      /* theora 16 pixels aligned height value */
    t_int x_vsize;

    FILE  *x_tfile;
    t_int x_framerate;
    t_int x_newfile;
    t_int x_einit;
    t_int x_recflag;
    t_int x_enduprec;;
    t_int x_frameswritten;
    t_int x_frames;
    struct timeval x_tstart;
    struct timeval x_tzero;
    struct timeval x_tcurrent;
    struct timeval x_tlastrec;

     /* vorbis/theora structures */
    ogg_page         x_ogg_page;       // ogg page
    ogg_packet       x_ogg_packet;     // ogg packet
    ogg_stream_state x_statev;         // vorbis stream state
    ogg_stream_state x_statet;         // theora stream state
    theora_info      x_theora_info;    // theora info
    theora_comment   x_theora_comment; // theora comment
    theora_state     x_theora_state;   // theora state
    vorbis_info      x_vorbis_info;    // vorbis info
    vorbis_dsp_state x_dsp_state;      // vorbis dsp state
    vorbis_block     x_vorbis_block;   // vorbis block
    vorbis_comment   x_vorbis_comment; // vorbis comment
    yuv_buffer       x_yuvbuffer;      // yuv buffer

    t_int            x_akbps;          // audio bit rate
    t_int            x_vkbps;          // video bit rate
    t_float          x_aquality;       // audio quality
    t_int            x_vquality;       // video quality
    t_int            x_abytesout;      // audio bytes written
    t_int            x_vbytesout;      // video bytes written

     /* audio structures */
    t_float **x_audio_buf; /* buffer for incoming audio */
    t_int x_audioin_position; // writing position for incoming audio
    t_int x_channels;      // audio channels 
    t_int x_samplerate;    // audio sample rate 
    t_int x_bits;          // audio bits

} t_pdp_theorout;

    /* allocate internal ressources */
static void pdp_theorout_allocate(t_pdp_theorout *x)
{
  int ret;

    x->x_yuvbuffer.y_width=x->x_vwidth;
    x->x_yuvbuffer.y_height=x->x_vheight;
    x->x_yuvbuffer.y_stride=x->x_vwidth;

    x->x_yuvbuffer.uv_width=x->x_vwidth>>1;
    x->x_yuvbuffer.uv_height=x->x_vheight>>1;
    x->x_yuvbuffer.uv_stride=x->x_vwidth>>1;

    x->x_yuvbuffer.y = (char *)malloc( x->x_yuvbuffer.y_width * x->x_yuvbuffer.y_height );
    x->x_yuvbuffer.u = (char *)malloc( x->x_yuvbuffer.uv_width * x->x_yuvbuffer.uv_height );
    x->x_yuvbuffer.v = (char *)malloc( x->x_yuvbuffer.uv_width * x->x_yuvbuffer.uv_height );
}

    /* free internal ressources */
static void pdp_theorout_free_ressources(t_pdp_theorout *x)
{
    if ( x->x_yuvbuffer.y ) free( x->x_yuvbuffer.y );
    if ( x->x_yuvbuffer.u ) free( x->x_yuvbuffer.u );
    if ( x->x_yuvbuffer.v ) free( x->x_yuvbuffer.v );
}

    /* initialize the encoder */
static void pdp_theorout_init_encoder(t_pdp_theorout *x)
{
  t_int ret;

    x->x_einit=0;

    // init streams
    ogg_stream_init(&x->x_statet, STREAMA_SNO);
    ogg_stream_init(&x->x_statev, STREAMV_SNO);

    theora_info_init(&x->x_theora_info);
    x->x_theora_info.width=x->x_tvwidth;
    x->x_theora_info.height=x->x_tvheight;
    x->x_theora_info.frame_width=x->x_vwidth;
    x->x_theora_info.frame_height=x->x_vheight;
    x->x_theora_info.offset_x=(x->x_tvwidth-x->x_vwidth)>>1;
    x->x_theora_info.offset_y=(x->x_tvheight-x->x_vheight)>>1;
    x->x_theora_info.fps_numerator=x->x_framerate;
    x->x_theora_info.fps_denominator=1;
    x->x_theora_info.aspect_numerator=x->x_vwidth;
    x->x_theora_info.aspect_denominator=x->x_vheight;
    x->x_theora_info.colorspace=OC_CS_UNSPECIFIED;
    x->x_theora_info.target_bitrate=x->x_vkbps;
    x->x_theora_info.quality=x->x_vquality;

    x->x_theora_info.dropframes_p=0;
    x->x_theora_info.quick_p=1;
    x->x_theora_info.keyframe_auto_p=1;
    x->x_theora_info.keyframe_frequency=64;
    x->x_theora_info.keyframe_frequency_force=64;
    x->x_theora_info.keyframe_data_target_bitrate=x->x_vkbps*1.5;
    x->x_theora_info.keyframe_auto_threshold=80;
    x->x_theora_info.keyframe_mindistance=8;
    x->x_theora_info.noise_sensitivity=1; 

    theora_encode_init(&x->x_theora_state,&x->x_theora_info);

    vorbis_info_init(&x->x_vorbis_info);

    if(x->x_aquality > -0.1)
    {
      ret = vorbis_encode_init_vbr(&x->x_vorbis_info, x->x_channels, x->x_samplerate, x->x_aquality);
    }
    else
    {
      ret = vorbis_encode_init(&x->x_vorbis_info, x->x_channels, x->x_samplerate, -1, x->x_akbps, -1);
    }

    if (ret)
    {
      post( "pdp_theorout~ : could not initialize vorbis encoder" );
      x->x_einit=0;
      return;
    }

    vorbis_comment_init(&x->x_vorbis_comment);
    vorbis_analysis_init(&x->x_dsp_state,&x->x_vorbis_info);
    vorbis_block_init(&x->x_dsp_state,&x->x_vorbis_block);
    
    post( "pdp_theorout~ : encoder initialized." );
    x->x_einit=1;

}

static void pdp_theorout_write_headers(t_pdp_theorout *x)
{
  t_int ret;
  ogg_packet aheader, aheadercomm, aheadercode;

    if ( !x->x_einit )
    {
      post( "pdp_theorout~ : trying to write headers but encoder is not initialized." );
      return;
    }

    if ( x->x_tfile == NULL )
    {
      post( "pdp_theorout~ : trying to write headers but no file is opened." );
      return;
    }

    theora_encode_header(&x->x_theora_state, &x->x_ogg_packet);
    ogg_stream_packetin(&x->x_statet, &x->x_ogg_packet);
    if(ogg_stream_pageout(&x->x_statet, &x->x_ogg_page)!=1)
    {
      post( "pdp_theorout~ : ogg encoding error." );
      return;
    }
    if ( ( ret = fwrite(x->x_ogg_page.header, 1, x->x_ogg_page.header_len, x->x_tfile) ) <= 0 )
    {
      post( "pdp_theorout~ : could not write headers (ret=%d).", ret );
      perror( "fwrite" );
      return;
    }
    if ( ( ret = fwrite(x->x_ogg_page.body, 1, x->x_ogg_page.body_len, x->x_tfile) ) <= 0 )
    {
      post( "pdp_theorout~ : could not write headers (ret=%d).", ret );
      perror( "fwrite" );
      return;
    }

    theora_comment_init(&x->x_theora_comment);
    theora_encode_comment(&x->x_theora_comment, &x->x_ogg_packet);
    ogg_stream_packetin(&x->x_statet, &x->x_ogg_packet);
    theora_encode_tables(&x->x_theora_state, &x->x_ogg_packet);
    ogg_stream_packetin(&x->x_statet, &x->x_ogg_packet);

    vorbis_analysis_headerout(&x->x_dsp_state, &x->x_vorbis_comment, 
                              &aheader,&aheadercomm,&aheadercode);
    ogg_stream_packetin(&x->x_statev,&aheader); 

    if(ogg_stream_pageout(&x->x_statev, &x->x_ogg_page)!=1)
    {
      post( "pdp_theorout~ : ogg encoding error." );
      return;
    }
    if ( ( ret = fwrite(x->x_ogg_page.header, 1, x->x_ogg_page.header_len, x->x_tfile) ) <= 0 )
    {
      post( "pdp_theorout~ : could not write headers (ret=%d).", ret );
      perror( "fwrite" );
      return;
    }
    if ( ( ret = fwrite(x->x_ogg_page.body, 1, x->x_ogg_page.body_len, x->x_tfile) ) <= 0 )
    {
      post( "pdp_theorout~ : could not write headers (ret=%d).", ret );
      perror( "fwrite" );
      return;
    }

    // remaining vorbis header packets 
    ogg_stream_packetin(&x->x_statev, &aheadercomm);
    ogg_stream_packetin(&x->x_statev, &aheadercode);

    // flush all the headers
    while(1)
    {
      ret = ogg_stream_flush(&x->x_statet, &x->x_ogg_page);
      if(ret<0){
        post( "pdp_theorout~ : ogg encoding error." );
        return;
      }
      if(ret==0)break;
      if ( ( ret = fwrite(x->x_ogg_page.header, 1, x->x_ogg_page.header_len, x->x_tfile) ) <= 0 )
      {
        post( "pdp_theorout~ : could not write headers (ret=%d).", ret );
        perror( "fwrite" );
        return;
      }
      if ( ( ret = fwrite(x->x_ogg_page.body, 1, x->x_ogg_page.body_len, x->x_tfile) ) <= 0 )
      {
        post( "pdp_theorout~ : could not write headers (ret=%d).", ret );
        perror( "fwrite" );
        return;
      }
    }

    while(1)
    {
      ret = ogg_stream_flush(&x->x_statev, &x->x_ogg_page);
      if(ret<0){
        post( "pdp_theorout~ : ogg encoding error." );
        return;
      }
      if(ret==0)break;
      if ( ( ret = fwrite(x->x_ogg_page.header, 1, x->x_ogg_page.header_len, x->x_tfile) ) <= 0 )
      {
        post( "pdp_theorout~ : could not write headers (ret=%d).", ret );
        perror( "fwrite" );
        return;
      }
      if ( ( ret = fwrite(x->x_ogg_page.body, 1, x->x_ogg_page.body_len, x->x_tfile) ) <= 0 )
      {
        post( "pdp_theorout~ : could not write headers (ret=%d).", ret );
        perror( "fwrite" );
        return;
      }
    }
}

    /* terminate the encoding process */
static void pdp_theorout_shutdown_encoder(t_pdp_theorout *x)
{
    ogg_stream_clear(&x->x_statev);
    vorbis_block_clear(&x->x_vorbis_block);
    vorbis_dsp_clear(&x->x_dsp_state);
    vorbis_comment_clear(&x->x_vorbis_comment);
    vorbis_info_clear(&x->x_vorbis_info);
    ogg_stream_clear(&x->x_statet);
    theora_clear(&x->x_theora_state);
}


    /* close a video file */
static void pdp_theorout_close(t_pdp_theorout *x)
{
  int ret;

    if ( x->x_tfile ) 
    {
       if ( fclose( x->x_tfile ) < 0 )
       {
          post( "pdp_theorout~ : could not close output file" );
          perror( "fclose" );
       }
       x->x_tfile = NULL;   
    }
}

    /* open a new video file */
static void pdp_theorout_open(t_pdp_theorout *x, t_symbol *sfile)
{
  t_int ret=0;

    // close previous video file if existing
    pdp_theorout_close(x);

    if ( x->x_recflag ) {
      x->x_recflag = 0;
    }
    x->x_frameswritten = 0;

    if ( ( x->x_tfile = fopen( sfile->s_name, "w+" ) ) == NULL )
    {
      post( "pdp_theorout~ : could not open output file" );
      perror( "fopen" );
      return;
    }
    else
    {
      post( "pdp_theorout~ : opened >%s<", sfile->s_name);
    }
    x->x_newfile = 1;

}

   /* start recording */
static void pdp_theorout_start(t_pdp_theorout *x)
{
    if ( !x->x_tfile ) 
    {
       post("pdp_theorout~ : start received but no file has been opened ... ignored.");
       return;
    }

    if ( x->x_recflag == 1 ) 
    {
       post("pdp_theorout~ : start received but recording is started ... ignored.");
       return;
    }

    if ( gettimeofday(&x->x_tstart, NULL) == -1)
    {
       post("pdp_theorout~ : could not set start time" );
    }

    x->x_recflag = 1;
    pdp_theorout_init_encoder( x );
    pdp_theorout_write_headers( x );
    post("pdp_theorout~ : start recording at %d frames/second", x->x_framerate);
}

   /* stop recording */
static void pdp_theorout_stop(t_pdp_theorout *x)
{
    if ( !x->x_tfile ) 
    {
       post("pdp_theorout~ : stop received but no file has been opened ... ignored.");
       return;
    }

    if ( x->x_recflag == 0 ) 
    {
       post("pdp_theorout~ : stop received but recording is stopped ... ignored.");
       return;
    }

    x->x_recflag = 0;

    // record last packet
    x->x_enduprec = 1;

}

   /* set video bitrate */
static void pdp_theorout_vbitrate(t_pdp_theorout *x, t_floatarg vbitrate )
{
  if ( ( (t_int) vbitrate < MIN_VIDEO_BITRATE ) || ( (t_int) vbitrate > MAX_VIDEO_BITRATE ) )
  {
     post( "pdp_theorout~ : wrong video bitrate %d : should be in [%d,%d] kbps", 
                            (t_int) vbitrate, MIN_VIDEO_BITRATE, MAX_VIDEO_BITRATE );
     return;
  }
  x->x_vkbps = (t_int) vbitrate;
}

   /* set audio bitrate */
static void pdp_theorout_abitrate(t_pdp_theorout *x, t_floatarg abitrate )
{
  if ( ( (t_int) abitrate < MIN_AUDIO_BITRATE ) || ( (t_int) abitrate > MAX_AUDIO_BITRATE ) )
  {
     post( "pdp_theorout~ : wrong audio bitrate %d : should be in [%d,%d] kbps", 
                            (t_int) abitrate, MIN_AUDIO_BITRATE, MAX_AUDIO_BITRATE );
     return;
  }
  x->x_akbps = (t_int) abitrate;
}

   /* set video quality */
static void pdp_theorout_vquality(t_pdp_theorout *x, t_floatarg vquality )
{
  if ( ( (t_int) vquality < MIN_VIDEO_QUALITY ) || ( (t_int) vquality > MAX_VIDEO_QUALITY ) )
  {
     post( "pdp_theorout~ : wrong video quality %d : should be in [%d,%d]", 
                            (t_int) vquality, MIN_VIDEO_QUALITY, MAX_VIDEO_QUALITY );
     return;
  }
  x->x_vquality = (t_int) vquality;
}

   /* set audio quality */
static void pdp_theorout_aquality(t_pdp_theorout *x, t_floatarg aquality )
{
  if ( ( (t_int) aquality < MIN_AUDIO_QUALITY ) || ( (t_int) aquality > MAX_AUDIO_QUALITY ) )
  {
     post( "pdp_theorout~ : wrong audio quality %d : should be in [%d,%d]", 
                            (t_int) aquality, MIN_AUDIO_QUALITY, MAX_AUDIO_QUALITY );
     return;
  }
  x->x_aquality = (t_int) aquality;
}

    /* store audio data in PCM format in a buffer for now */
static t_int *pdp_theorout_perform(t_int *w)
{
  t_float *in1   = (t_float *)(w[1]);       // left audio inlet
  t_float *in2   = (t_float *)(w[2]);       // right audio inlet
  t_pdp_theorout *x = (t_pdp_theorout *)(w[3]);
  int n = (int)(w[4]);                      // number of samples
  t_float fsample;
  t_int   isample, i;

   if ( x->x_recflag ) 
   {
    // just fills the buffer
    while (n--)
    {
       fsample=*(in1++);
       if (fsample > 1.0) { fsample = 1.0; }
       if (fsample < -1.0) { fsample = -1.0; }
       x->x_audio_buf[0][x->x_audioin_position]=fsample;
       fsample=*(in2++);
       if (fsample > 1.0) { fsample = 1.0; }
       if (fsample < -1.0) { fsample = -1.0; }
       x->x_audio_buf[1][x->x_audioin_position]=fsample;
       x->x_audioin_position=(x->x_audioin_position+1)%(MAX_AUDIO_PACKET_SIZE);
       if ( x->x_audioin_position == MAX_AUDIO_PACKET_SIZE-1 )
       {
          post( "pdp_theorout~ : reaching end of audio buffer" );
       }
    }
  }

  return (w+5);
}

static void pdp_theorout_dsp(t_pdp_theorout *x, t_signal **sp)
{
    dsp_add(pdp_theorout_perform, 4, sp[0]->s_vec, sp[1]->s_vec, x, sp[0]->s_n);
}

static void pdp_theorout_process_yv12(t_pdp_theorout *x)
{
  t_pdp     *header = pdp_packet_header(x->x_packet0);
  unsigned char *data   = (unsigned char *)pdp_packet_data(x->x_packet0);
  t_int     i, ret;
  t_int     px, py;
  char      *pY, *pU, *pV;
  struct timeval trec;
  t_int     nbaudiosamples, nbusecs, nbrecorded;
  t_float   fframerate=0.0;
  t_int     precflag;
  ogg_page  apage;
  ogg_page  vpage;
  t_float   **vbuffer;
  double    videotime, audiotime;

    if ( ( (int)(header->info.image.width) != x->x_vwidth ) || 
         ( (int)(header->info.image.height) != x->x_vheight ) || 
         ( x->x_newfile ) )
    {
       precflag = x->x_recflag;
       x->x_recflag = 0;
       pdp_theorout_free_ressources( x );
       pdp_theorout_shutdown_encoder( x );
       x->x_vwidth = header->info.image.width;
       x->x_vheight = header->info.image.height;
       x->x_vsize = x->x_vwidth*x->x_vheight;
       x->x_tvwidth=((x->x_vwidth + 15) >>4)<<4;
       x->x_tvheight=((x->x_vheight + 15) >>4)<<4;
       pdp_theorout_allocate( x );
       if ( x->x_tzero.tv_sec != 0 )
       {
         pdp_theorout_init_encoder( x );
         pdp_theorout_write_headers( x );
       }
       x->x_recflag = precflag;
       x->x_newfile = 0;
    }

    if ( x->x_tzero.tv_sec == 0 )
    {
      if ( gettimeofday(&x->x_tzero, NULL) == -1)
      {
         post("pdp_theorout~ : could get initial time" );
      }
    }
 
    x->x_frames++;

    // calculate current framerate
    if ( gettimeofday(&x->x_tcurrent, NULL) == -1)
    {
       post("pdp_theorout~ : could get current time" );
    }

    // calculate frame rate if it hasn't been set
    if ( ( x->x_tcurrent.tv_sec - x->x_tzero.tv_sec ) > 0 )
    {
      x->x_framerate = x->x_frames / ( x->x_tcurrent.tv_sec - x->x_tzero.tv_sec );
    }
    else
    {
      x->x_framerate = DEFAULT_FRAME_RATE;
    }

    if ( x->x_frameswritten == 0 )
    {
      if ( gettimeofday(&x->x_tlastrec, NULL) == -1)
      {
         post("pdp_theorout~ : could set start time" );
      }
    }

    pY = x->x_yuvbuffer.y;
    memcpy( (void*)pY, (void*)&data[0], x->x_vsize );
    pV = x->x_yuvbuffer.v;
    memcpy( (void*)pV, (void*)&data[x->x_vsize], (x->x_vsize>>2) );
    pU = x->x_yuvbuffer.u;
    memcpy( (void*)pU, (void*)&data[x->x_vsize+(x->x_vsize>>2)], (x->x_vsize>>2) );
      
    if ( x->x_tfile && x->x_recflag && !x->x_enduprec)
    {

      if ( ( ret = theora_encode_YUVin( &x->x_theora_state, &x->x_yuvbuffer ) ) != 0 )
      {
         post( "pdp_theorout~ : could not encode yuv image (ret=%d).", ret );
      }  
      else
      {
         // stream one packet
         theora_encode_packetout(&x->x_theora_state, 0, &x->x_ogg_packet);
         ogg_stream_packetin(&x->x_statet, &x->x_ogg_packet);
         // post( "pdp_theorout~ : new (theora) ogg packet : bytes:%ld, bos:%ld, eos:%ld, no:%lld",
         //                        x->x_ogg_packet.bytes, x->x_ogg_packet.b_o_s, 
         //                        x->x_ogg_packet.e_o_s, x->x_ogg_packet.packetno );

         while( ( ret = ogg_stream_pageout(&x->x_statet, &vpage) ) >0 )
         {
           videotime = theora_granule_time(&x->x_theora_state, ogg_page_granulepos(&vpage));
           x->x_vbytesout+=fwrite(vpage.header, 1, vpage.header_len, x->x_tfile );
           x->x_vbytesout+=fwrite(vpage.body, 1, vpage.body_len, x->x_tfile );
         }
      }

      // calculate the number of audio samples to output
      if ( gettimeofday(&trec, NULL) == -1)
      {
         post("pdp_theorout~ : could set stop time" );
      }
      // calculate time diff in micro seconds
      nbusecs = ( trec.tv_usec - x->x_tlastrec.tv_usec ) + 
                ( trec.tv_sec - x->x_tlastrec.tv_sec )*1000000;
      nbaudiosamples = (sys_getsr()*1000000)/nbusecs;
      memcpy( &x->x_tlastrec, &trec, sizeof( struct timeval) );

      if ( x->x_audioin_position > nbaudiosamples )
      {
         nbrecorded = nbaudiosamples;
      }
      else
      {
         nbrecorded = x->x_audioin_position;
      }

      vbuffer=vorbis_analysis_buffer( &x->x_dsp_state, nbrecorded );
      memcpy( (void*)&vbuffer[0][0], (void*)&x->x_audio_buf[0][0], nbrecorded*sizeof( t_float ) );
      memcpy( (void*)&vbuffer[1][0], (void*)&x->x_audio_buf[1][0], nbrecorded*sizeof( t_float ) );

      vorbis_analysis_wrote( &x->x_dsp_state, nbrecorded);

      while(vorbis_analysis_blockout( &x->x_dsp_state, &x->x_vorbis_block)==1)
      {

        // analysis, assume we want to use bitrate management
        vorbis_analysis( &x->x_vorbis_block, NULL);
        vorbis_bitrate_addblock( &x->x_vorbis_block );

        // weld packets into the bitstream 
        while(vorbis_bitrate_flushpacket( &x->x_dsp_state, &x->x_ogg_packet))
        {
          ogg_stream_packetin( &x->x_statev, &x->x_ogg_packet);
        }

      }

      while( ogg_stream_pageout( &x->x_statev, &apage) >0 )
      {
        audiotime = vorbis_granule_time(&x->x_dsp_state, ogg_page_granulepos(&apage));
        x->x_abytesout+=fwrite(apage.header, 1, apage.header_len, x->x_tfile );
        x->x_abytesout+=fwrite(apage.body, 1, apage.body_len, x->x_tfile );
      }

      memcpy( &x->x_audio_buf[0][0], &x->x_audio_buf[0][nbrecorded], 
                     ( x->x_audioin_position-nbrecorded ) * sizeof( t_float ) );
      memcpy( &x->x_audio_buf[1][0], &x->x_audio_buf[1][nbrecorded], 
                     ( x->x_audioin_position-nbrecorded ) * sizeof( t_float ) );
      x->x_audioin_position -= nbrecorded;
      // post ( "pdp_theorout~ : recorded %d samples.", nbrecorded );
       
      x->x_frameswritten++;

    } 

    if ( x->x_tfile && x->x_enduprec )
    {
      x->x_enduprec = 0;
      post( "pdp_theorout~ : ending up recording." );
      x->x_frameswritten++;

      if ( ( ret = theora_encode_YUVin( &x->x_theora_state, &x->x_yuvbuffer ) ) != 0 )
      {
         post( "pdp_theorout~ : could not encode yuv image (ret=%d).", ret );
      }  
      else
      {
         // stream one packet
         theora_encode_packetout(&x->x_theora_state, 1, &x->x_ogg_packet);
         ogg_stream_packetin( &x->x_statet, &x->x_ogg_packet);

         while( ( ret = ogg_stream_pageout( &x->x_statet, &vpage) ) > 0 )
         {
           videotime = theora_granule_time(&x->x_theora_state, ogg_page_granulepos(&vpage));
           x->x_vbytesout+=fwrite(vpage.header, 1, vpage.header_len, x->x_tfile );
           x->x_vbytesout+=fwrite(vpage.body, 1, vpage.body_len, x->x_tfile );
         }
      }

      // end up audio stream 
      vorbis_analysis_wrote( &x->x_dsp_state, 0);

      while(vorbis_analysis_blockout( &x->x_dsp_state, &x->x_vorbis_block)==1)
      {
        // analysis, assume we want to use bitrate management
        vorbis_analysis( &x->x_vorbis_block, NULL);
        vorbis_bitrate_addblock( &x->x_vorbis_block);

        // weld packets into the bitstream 
        while(vorbis_bitrate_flushpacket( &x->x_dsp_state, &x->x_ogg_packet))
        {
          ogg_stream_packetin( &x->x_statev, &x->x_ogg_packet);
        }
      }

      while( ogg_stream_pageout( &x->x_statev, &apage) >0 )
      {
        audiotime = vorbis_granule_time(&x->x_dsp_state, ogg_page_granulepos(&apage));
        x->x_abytesout+=fwrite(apage.header, 1, apage.header_len, x->x_tfile );
        x->x_abytesout+=fwrite(apage.body, 1, apage.body_len, x->x_tfile );
      }

      post("pdp_theorout~ : stop recording");

      pdp_theorout_shutdown_encoder( x );
      pdp_theorout_close(x);
    }

    return;
}

static void pdp_theorout_killpacket(t_pdp_theorout *x)
{
    /* release the packet */
    pdp_packet_mark_unused(x->x_packet0);
    x->x_packet0 = -1;
}

static void pdp_theorout_process(t_pdp_theorout *x)
{
   int encoding;
   t_pdp *header = 0;

   /* check if image data packets are compatible */
   if ( (header = pdp_packet_header(x->x_packet0))
	&& (PDP_BITMAP == header->type)){
    
	/* pdp_theorout_process inputs and write into active inlet */
	switch(pdp_packet_header(x->x_packet0)->info.image.encoding)
        {

	  case PDP_BITMAP_YV12:
            if ( x->x_tfile && x->x_recflag )
            {
              outlet_float( x->x_obj.ob_outlet, x->x_frameswritten );
            }
            pdp_queue_add(x, pdp_theorout_process_yv12, pdp_theorout_killpacket, &x->x_queue_id);
	    break;

	  default:
	    /* don't know the type, so dont pdp_theorout_process */
	    break;
	    
	}
    }

}

static void pdp_theorout_input_0(t_pdp_theorout *x, t_symbol *s, t_floatarg f)
{
    /* if this is a register_ro message or register_rw message, register with packet factory */

    if (s== gensym("register_rw"))
    {
        x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("bitmap/yv12/*") );
    }

    if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped))
    {
        /* add the process method and callback to the process queue */
        pdp_theorout_process(x);
    }

}

static void pdp_theorout_free(t_pdp_theorout *x)
{
  int i;

    pdp_queue_finish(x->x_queue_id);
    pdp_packet_mark_unused(x->x_packet0);
    // close video file if existing
    pdp_theorout_close(x);
    for ( i=0; i<x->x_channels; i++)
    {
       if ( x->x_audio_buf[i] ) freebytes( x->x_audio_buf[i], MAX_AUDIO_PACKET_SIZE*sizeof(t_float) );
    }
    if ( x->x_audio_buf ) freebytes( x->x_audio_buf, x->x_channels*sizeof(t_float*) );
    
}

t_class *pdp_theorout_class;

void *pdp_theorout_new(void)
{
  t_int i;

    t_pdp_theorout *x = (t_pdp_theorout *)pd_new(pdp_theorout_class);
    inlet_new (&x->x_obj, &x->x_obj.ob_pd, gensym ("signal"), gensym ("signal"));
    outlet_new (&x->x_obj, &s_float);

    x->x_packet0 = -1;
    x->x_packet1 = -1;
    x->x_queue_id = -1;

    x->x_tfile = NULL;
    x->x_yuvbuffer.y = NULL;
    x->x_yuvbuffer.u = NULL;
    x->x_yuvbuffer.v = NULL;

     /* audio defaults */
    x->x_samplerate = sys_getsr();
    x->x_channels = DEFAULT_CHANNELS;
    x->x_bits = DEFAULT_BITS;

    x->x_framerate = DEFAULT_FRAME_RATE;
    x->x_vkbps = DEFAULT_VIDEO_BITRATE;
    x->x_vquality = DEFAULT_VIDEO_QUALITY;
    x->x_akbps = DEFAULT_AUDIO_BITRATE;
    x->x_aquality = DEFAULT_AUDIO_QUALITY;

    x->x_audio_buf = (t_float**) getbytes( x->x_channels*sizeof(t_float*) );
    for ( i=0; i<x->x_channels; i++)
    {
       x->x_audio_buf[i] = (t_float*) getbytes( MAX_AUDIO_PACKET_SIZE*sizeof(t_float) );
    }

    x->x_newfile = 0;
    x->x_frames = 0;
    x->x_frameswritten = 0;

    x->x_tzero.tv_sec = 0;

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_theorout_tilde_setup(void)
{
    // post( pdp_theorout_version );
    pdp_theorout_class = class_new(gensym("pdp_theorout~"), (t_newmethod)pdp_theorout_new,
    	(t_method)pdp_theorout_free, sizeof(t_pdp_theorout), 0, A_NULL);

    CLASS_MAINSIGNALIN(pdp_theorout_class, t_pdp_theorout, x_f );
    class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_dsp, gensym("dsp"), 0);
    class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_open, gensym("open"), A_SYMBOL, A_NULL);
    class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_close, gensym("close"), A_NULL);
    class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_start, gensym("start"), A_NULL);
    class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_stop, gensym("stop"), A_NULL);
    class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_abitrate, gensym("audiobitrate"), A_FLOAT, A_NULL);
    class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_vbitrate, gensym("videobitrate"), A_FLOAT, A_NULL);
    class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_aquality, gensym("audioquality"), A_FLOAT, A_NULL);
    class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_vquality, gensym("videoquality"), A_FLOAT, A_NULL);
    class_sethelpsymbol( pdp_theorout_class, gensym("pdp_theorout~.pd") );

}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_binary.c ---
/*
 *   PiDiP module
 *   Copyright (c) by Yves Degoyon ( ydegoyon at free.fr )
 *
 *   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 object is an image binarizer, based on some (y,u,v) setting
 */

#include "pdp.h"
#include "yuv.h"
#include <math.h>
#include <stdio.h>

static char   *pdp_binary_version = "pdp_binary: a image binarizer version 0.1 written by Yves Degoyon (ydegoyon at free.fr)";

typedef struct pdp_binary_struct
{
    t_object x_obj;

    t_int x_packet0;
    t_int x_packet1;
    t_int x_queue_id;
    t_int x_dropped;

    t_int x_vwidth;
    t_int x_vheight;
    t_int x_vsize;
    t_int x_colorY; // YUV components of binary mask
    t_int x_colorU;
    t_int x_colorV;
    t_int x_cursX; // X position of the cursor
    t_int x_cursY; // Y position of the cursor
    t_int x_tolerance; // tolerance 
    short int *x_frame;  // keep a copy of current frame for picking color

    t_outlet *x_pdp_output; // output packets
    t_outlet *x_Y;  // output Y component of selected color
    t_outlet *x_U;  // output U component of selected color
    t_outlet *x_V;  // output V component of selected color

} t_pdp_binary;

static void pdp_binary_setcur(t_pdp_binary *x,  t_floatarg fpx, t_floatarg fpy  )
{
   if ( (fpx>=0.0) && (fpx<=1.0) && (fpy>=0.0) && (fpy<=1.0) )
   {
      x->x_cursX = fpx*(t_float)x->x_vwidth;
      x->x_cursY = fpy*(t_float)x->x_vheight;
   }
}

static void pdp_binary_y(t_pdp_binary *x, t_floatarg fy )
{
   if ( fy <= 255. )
   {
      x->x_colorY = (t_int)fy;
      outlet_float( x->x_Y, x->x_colorY );
   }
}

static void pdp_binary_u(t_pdp_binary *x, t_floatarg fu )
{
   if ( fu <= 255. )
   {
      x->x_colorU = (t_int)fu;
      outlet_float( x->x_U, x->x_colorU );
   }
}

static void pdp_binary_v(t_pdp_binary *x, t_floatarg fv )
{
   if ( fv < 255 )
   {
      x->x_colorV = (t_int)fv;
      outlet_float( x->x_V, x->x_colorV );
   }
}

static void pdp_binary_cursx(t_pdp_binary *x, t_floatarg fx )
{
   if ( ( fx >= 0 ) && ( fx < x->x_vwidth) )
   {
      x->x_cursX = (int)fx;
   }
}

static void pdp_binary_cursy(t_pdp_binary *x, t_floatarg fy )
{
   if ( ( fy >= 0 ) && ( fy < x->x_vheight) )
   {
      x->x_cursY = (int)fy;
   }
}

static void pdp_binary_tolerance(t_pdp_binary *x, t_floatarg ftolerance )
{
   if ( ftolerance >= 0 ) 
   {
      x->x_tolerance = (int)ftolerance;
   }
}

static void pdp_binary_pick(t_pdp_binary *x)
{
   if ( x->x_frame && ( x->x_cursX > 0 ) && ( x->x_cursX < x->x_vwidth ) 
        && ( x->x_cursY > 0 ) && ( x->x_cursY < x->x_vheight ) )
   {
      // post( "pdp_binary : picking up color : x=%d y=%d", x->x_cursX, x->x_cursY );
      x->x_colorY = x->x_frame[ x->x_cursY*x->x_vwidth+x->x_cursX ];
      x->x_colorV = x->x_frame[ x->x_vsize + (x->x_cursY>>1)*(x->x_vwidth>>1)+(x->x_cursX>>1) ];
      x->x_colorU = x->x_frame[ x->x_vsize + (x->x_vsize>>2) + (x->x_cursY>>1)*(x->x_vwidth>>1)+(x->x_cursX>>1) ];
      x->x_colorY = (x->x_colorY)>>7;
      x->x_colorV = (x->x_colorV>>8)+128;
      x->x_colorU = (x->x_colorU>>8)+128;
      outlet_float( x->x_Y, x->x_colorY );
      outlet_float( x->x_V, x->x_colorV );
      outlet_float( x->x_U, x->x_colorU );
   }
}

static void pdp_binary_allocate(t_pdp_binary *x)
{
    x->x_frame = (short int *) getbytes ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );

    if ( !x->x_frame )
    {
       post( "pdp_binary : severe error : cannot allocate buffer !!! ");
       return;
    }
}

static void pdp_binary_free_ressources(t_pdp_binary *x)
{
    if ( x->x_frame ) freebytes ( x->x_frame, ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );
}

static void pdp_binary_process_yv12(t_pdp_binary *x)
{
    t_pdp     *header = pdp_packet_header(x->x_packet0);
    short int *data   = (short int *)pdp_packet_data(x->x_packet0);
    t_pdp     *newheader = pdp_packet_header(x->x_packet1);
    short int *newdata = (short int *)pdp_packet_data(x->x_packet1);
    t_int     i;
    t_int     px=0, py=0; 
    t_int     y=0, u=0, v=0;
    short int *pfY, *pfU, *pfV;
    t_int     diff;

    /* allocate all ressources */
    if ( ( (int)header->info.image.width != x->x_vwidth ) ||
         ( (int)header->info.image.height != x->x_vheight ) )
    {
        pdp_binary_free_ressources( x ); 
        x->x_vwidth = header->info.image.width;
        x->x_vheight = header->info.image.height;
        x->x_vsize = x->x_vwidth*x->x_vheight;
        pdp_binary_allocate( x ); 
        post( "pdp_binary : reallocated buffers" );
    }

    memcpy(x->x_frame, data, (x->x_vsize + (x->x_vsize>>1))<<1 );

    // post( "pdp_binary : newheader:%x", newheader );

    newheader->info.image.encoding = header->info.image.encoding;
    newheader->info.image.width = x->x_vwidth;
    newheader->info.image.height = x->x_vheight;

    // binarize
    pfY = data;
    pfV = data+x->x_vsize;
    pfU = data+x->x_vsize+(x->x_vsize>>2);
    for ( py=0; py<x->x_vheight; py++ )
    {
      for ( px=0; px<x->x_vwidth; px++ )
      {
         y = (*pfY)>>7;
         v = ((*pfV)>>8)+128;
         u = ((*pfU)>>8)+128;

         // post( "pdp_binary : y=%d, u=%d, v=%d", y, u, v );

         diff = 0;
         if ( x->x_colorY >= 0 )
         {
            diff += abs(y-x->x_colorY );
         }
         if ( x->x_colorV >= 0 )
         {
            diff += abs(v-x->x_colorV );
         }
         if ( x->x_colorU >=0 )
         {
            diff += abs(u-x->x_colorU );
         }
       
         if ( diff <= x->x_tolerance )
         {
            *(newdata+(py*x->x_vwidth+px)) = 0xff<<7;
         }
         else
         {
            *(newdata+(py*x->x_vwidth+px)) = 0;
         }
            
         pfY++;
         if ( (px%2==0) && (py%2==0) )
         {
            pfU++;pfV++;
         }
       }
    }

    memset( newdata+x->x_vsize, 0x0, (x->x_vsize>>1)<<1 );

    return;
}

static void pdp_binary_sendpacket(t_pdp_binary *x)
{
    /* release the packet */
    pdp_packet_mark_unused(x->x_packet0);
    x->x_packet0 = -1;

    /* unregister and propagate if valid dest packet */
    pdp_packet_pass_if_valid(x->x_pdp_output, &x->x_packet1);
}

static void pdp_binary_process(t_pdp_binary *x)
{
   int encoding;
   t_pdp *header = 0;

   /* check if image data packets are compatible */
   if ( (header = pdp_packet_header(x->x_packet0))
	&& (PDP_IMAGE == header->type)){
    
	/* pdp_binary_process inputs and write into active inlet */
	switch(pdp_packet_header(x->x_packet0)->info.image.encoding)
        {

	case PDP_IMAGE_YV12:
            x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
            pdp_queue_add(x, pdp_binary_process_yv12, pdp_binary_sendpacket, &x->x_queue_id);
	    break;

	case PDP_IMAGE_GREY:
            // should write something to handle these one day
            // but i don't use this mode                      
	    break;

	default:
	    /* don't know the type, so dont pdp_binary_process */
	    break;
	    
	}
    }

}

static void pdp_binary_input_0(t_pdp_binary *x, t_symbol *s, t_floatarg f)
{
    /* if this is a register_ro message or register_rw message, register with packet factory */

    if (s== gensym("register_rw"))
    {
       x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("image/YCrCb/*") );
    }

    if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped))
    {
        pdp_binary_process(x);
    }
}

static void pdp_binary_free(t_pdp_binary *x)
{
  int i;

    pdp_packet_mark_unused(x->x_packet0);
    pdp_binary_free_ressources( x );
}

t_class *pdp_binary_class;

void *pdp_binary_new(void)
{
    int i;

    t_pdp_binary *x = (t_pdp_binary *)pd_new(pdp_binary_class);
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("Y"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("U"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("V"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("cursx"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("cursy"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("tolerance"));

    x->x_pdp_output = outlet_new(&x->x_obj, &s_anything); 
    x->x_Y  = outlet_new(&x->x_obj, &s_float); 
    x->x_U  = outlet_new(&x->x_obj, &s_float); 
    x->x_V  = outlet_new(&x->x_obj, &s_float); 

    x->x_colorY = 200;
    x->x_colorU = -1;
    x->x_colorV = -1;

    x->x_packet0 = -1;
    x->x_packet1 = -1;

    x->x_cursX = -1;
    x->x_cursY = -1;
    x->x_tolerance = 55;

    x->x_vwidth = -1;
    x->x_vheight = -1;
    x->x_vsize = -1;
    x->x_frame = NULL;

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_binary_setup(void)
{
    // post( pdp_binary_version );
    pdp_binary_class = class_new(gensym("pdp_binary"), (t_newmethod)pdp_binary_new,
    	(t_method)pdp_binary_free, sizeof(t_pdp_binary), 0, A_NULL);

    class_addmethod(pdp_binary_class, (t_method)pdp_binary_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_binary_class, (t_method)pdp_binary_y, gensym("Y"),  A_FLOAT, A_NULL);
    class_addmethod(pdp_binary_class, (t_method)pdp_binary_u, gensym("U"),  A_FLOAT, A_NULL);
    class_addmethod(pdp_binary_class, (t_method)pdp_binary_v, gensym("V"),  A_FLOAT, A_NULL);
    class_addmethod(pdp_binary_class, (t_method)pdp_binary_cursx, gensym("cursx"),  A_FLOAT, A_NULL);
    class_addmethod(pdp_binary_class, (t_method)pdp_binary_cursy, gensym("cursy"),  A_FLOAT, A_NULL);
    class_addmethod(pdp_binary_class, (t_method)pdp_binary_pick, gensym("pick"),  A_NULL);
    class_addmethod(pdp_binary_class, (t_method)pdp_binary_tolerance, gensym("tolerance"), A_FLOAT, A_NULL);
    class_addmethod(pdp_binary_class, (t_method)pdp_binary_setcur, gensym("setcur"), A_DEFFLOAT, A_DEFFLOAT, A_NULL);
    class_sethelpsymbol( pdp_binary_class, gensym("pdp_binary.pd") );
}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_background.c ---
/*
 *   PiDiP module.
 *   Copyright (c) by Yves Degoyon (ydegoyon at free.fr)
 *
 *   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 "yuv.h"
#include "time.h"
#include "sys/time.h"

#define DEFAULT_RED_VALUE  255
#define DEFAULT_GREEN_VALUE 255
#define DEFAULT_BLUE_VALUE 255
#define DEFAULT_WIDTH 320
#define DEFAULT_HEIGHT 240

typedef struct pdp_background_struct
{
    t_object x_obj;

    t_outlet *x_outlet0;

    t_int x_packet0;

    t_int x_colorR;
    t_int x_colorG;
    t_int x_colorB;
    t_int x_colorY;
    t_int x_colorU;
    t_int x_colorV;

    t_int x_width;
    t_int x_height;

} t_pdp_background;

static void pdp_background_bang(t_pdp_background *x)
{

  t_pdp *header;
  unsigned char *data;
  unsigned char *pY, *pU, *pV;
  t_int px, py;

    x->x_packet0 = pdp_packet_new_bitmap_yv12( x->x_width, x->x_height );

    data = (char *)pdp_packet_data(x->x_packet0);
    pY = data;
    pV = data+(x->x_width*x->x_height);
    pU = data+(x->x_width*x->x_height)+((x->x_width*x->x_height)>>2);

    memset( pY, (unsigned char)x->x_colorY, x->x_width*x->x_height );
    memset( pV, (unsigned char)x->x_colorV, (x->x_width*x->x_height>>2) );
    memset( pU, (unsigned char)x->x_colorU, (x->x_width*x->x_height>>2) );

    pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet0);

}

static void pdp_background_dim(t_pdp_background *x, t_floatarg fwidth, t_floatarg fheight)
{
   if ( ( (t_int)fwidth>0 ) && ( (t_int) fheight>0 ) )
   {
      if ( ((t_int)fwidth)%8 == 0 )
      {
        x->x_width = (t_int)fwidth; 
      }
      else
      {
        x->x_width = (t_int)fwidth + (8-((t_int)fwidth)%8); // align on 8 
      }
      if ( ((t_int)fheight)%8 == 0 )
      {
        x->x_height = (t_int)fheight; 
      }
      else
      {
        x->x_height = (t_int)fheight + (8-((t_int)fheight)%8); // align on 8 
      }
   }
}

static void pdp_background_red(t_pdp_background *x, t_floatarg fred)
{
   if ( ( (t_int)fred>=0 ) && ( (t_int) fred <= 255 ) )
   {
      x->x_colorR = (t_int) fred;
      x->x_colorY = yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB );
      x->x_colorU = yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB );
      x->x_colorV = yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB );
   }
}

static void pdp_background_green(t_pdp_background *x, t_floatarg fgreen)
{
   if ( ( (t_int)fgreen>=0 ) && ( (t_int) fgreen <= 255 ) )
   {
      x->x_colorG = (t_int) fgreen;
      x->x_colorY = yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB );
      x->x_colorU = yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB );
      x->x_colorV = yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB );
   }
}

static void pdp_background_blue(t_pdp_background *x, t_floatarg fblue)
{
   if ( ( (t_int)fblue>=0 ) && ( (t_int) fblue <= 255 ) )
   {
      x->x_colorB = (t_int) fblue;
      x->x_colorY = yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB );
      x->x_colorU = yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB );
      x->x_colorV = yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB );
   }
}

static void pdp_background_free(t_pdp_background *x)
{
   // nothing to do
}

t_class *pdp_background_class;

void *pdp_background_new(void)
{
    t_pdp_background *x = (t_pdp_background *)pd_new(pdp_background_class);

    inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("red"));
    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_outlet0 = outlet_new(&x->x_obj, &s_anything);

    x->x_colorR = DEFAULT_RED_VALUE;
    x->x_colorG = DEFAULT_GREEN_VALUE;
    x->x_colorB = DEFAULT_BLUE_VALUE;

    x->x_colorY = yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB );
    x->x_colorU = yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB );
    x->x_colorV = yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB );

    x->x_width = DEFAULT_WIDTH;
    x->x_height = DEFAULT_HEIGHT;

    x->x_packet0 = -1;

    return (void *)x;
}

#ifdef __cplusplus
extern "C"
{
#endif


void pdp_background_setup(void)
{
    pdp_background_class = class_new(gensym("pdp_background"), (t_newmethod)pdp_background_new,
    	(t_method)pdp_background_free, sizeof(t_pdp_background), 0, A_NULL);

    class_addmethod(pdp_background_class, (t_method)pdp_background_bang, gensym("bang"), A_NULL);
    class_addmethod(pdp_background_class, (t_method)pdp_background_red, gensym("red"), A_FLOAT, A_NULL);
    class_addmethod(pdp_background_class, (t_method)pdp_background_green, gensym("green"), A_FLOAT, A_NULL);
    class_addmethod(pdp_background_class, (t_method)pdp_background_blue, gensym("blue"), A_FLOAT, A_NULL);
    class_addmethod(pdp_background_class, (t_method)pdp_background_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL);
    class_sethelpsymbol( pdp_background_class, gensym("pdp_background.pd") );

}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_dilate.c ---
/*
 *   PiDiP module
 *   Copyright (c) by Yves Degoyon ( ydegoyon at free.fr )
 *
 *   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 object is a morphological operator for dilation using as a structuring element a WxH square
 */

#include "pdp.h"
#include "yuv.h"
#include <math.h>
#include <stdio.h>

static char   *pdp_dilate_version = "pdp_dilate: morphology : dilation version 0.1 written by Yves Degoyon (ydegoyon at free.fr)";

typedef struct pdp_dilate_struct
{
    t_object x_obj;

    t_int x_packet0;
    t_int x_packet1;
    t_int x_queue_id;
    t_int x_dropped;

    t_int x_vwidth;
    t_int x_vheight;
    t_int x_vsize;
    t_int x_kernelw; // width of the (square) kernel
    t_int x_kernelh; // height of the square kernel
    t_int x_nbpasses; // number of passes
    short int *x_frame;  // keep a copy of current frame for transformations

    t_outlet *x_pdp_output; // output packets

} t_pdp_dilate;

static void pdp_dilate_nbpasses(t_pdp_dilate *x,  t_floatarg fpasses )
{
   if ( fpasses>=1.) 
   {
      x->x_nbpasses = (t_int)fpasses;
   }
}

static void pdp_dilate_kernelw(t_pdp_dilate *x,  t_floatarg fkernelw )
{
   if ( fkernelw>=0.) 
   {
      x->x_kernelw = (t_int)fkernelw;
   }
}

static void pdp_dilate_kernelh(t_pdp_dilate *x,  t_floatarg fkernelh )
{
   if ( fkernelh>=0.) 
   {
      x->x_kernelh = (t_int)fkernelh;
   }
}

static void pdp_dilate_allocate(t_pdp_dilate *x)
{
    x->x_frame = (short int *) getbytes ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );

    if ( !x->x_frame )
    {
       post( "pdp_dilate : severe error : cannot allocate buffer !!! ");
       return;
    }
}

static void pdp_dilate_free_ressources(t_pdp_dilate *x)
{
    if ( x->x_frame ) freebytes ( x->x_frame, ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );
}

static void pdp_dilate_process_yv12(t_pdp_dilate *x)
{
    t_pdp     *header = pdp_packet_header(x->x_packet0);
    short int *data   = (short int *)pdp_packet_data(x->x_packet0);
    t_pdp     *newheader = pdp_packet_header(x->x_packet1);
    short int *newdata = (short int *)pdp_packet_data(x->x_packet1);
    t_int     i;
    t_int     px=0, py=0; 
    short int *pfY, *pfU, *pfV;
    t_int     ppx, ppy, ix, iy, pn, kx, ky;

    // allocate all ressources
    if ( ( (int)header->info.image.width != x->x_vwidth ) ||
         ( (int)header->info.image.height != x->x_vheight ) )
    {
        pdp_dilate_free_ressources( x );
        x->x_vwidth = header->info.image.width;
        x->x_vheight = header->info.image.height;
        x->x_vsize = x->x_vwidth*x->x_vheight;
        pdp_dilate_allocate( x );
        post( "pdp_dilate : reallocated buffers" );
    }

    // post( "pdp_dilate : newheader:%x", newheader );

    newheader->info.image.encoding = header->info.image.encoding;
    newheader->info.image.width = x->x_vwidth;
    newheader->info.image.height = x->x_vheight;

    memcpy( newdata, data, x->x_vsize+(x->x_vsize>>1)<<1 );
    memcpy( x->x_frame, data, x->x_vsize+(x->x_vsize>>1)<<1 );

    // dilate (supposedly) binary image by using a 3x3 square as a structuring element
    pfY = x->x_frame;
    pfV = x->x_frame+x->x_vsize;
    pfU = x->x_frame+x->x_vsize+(x->x_vsize>>2);
    kx = (x->x_kernelw/2);
    ky = (x->x_kernelh/2);
    for ( pn=0; pn<x->x_nbpasses; pn++ )
    {
      memcpy( x->x_frame, newdata, x->x_vsize+(x->x_vsize>>1)<<1 );
      for ( py=0; py<x->x_vheight; py++ )
      {
        for ( px=0; px<x->x_vwidth; px++ )
        {
          if ( *(pfY+py*x->x_vwidth+px) == 0 )
          {
            for (ix=-kx; ix<=kx; ix++)
            {
              ppx=px+ix;
              if ( (ppx>=0) && (ppx<x->x_vwidth) )
              {
                for (iy=-ky; iy<=ky; iy++)
                {
                  ppy=py+iy;
                  if ( (ppy>=0) && (ppy<x->x_vheight) )
                  {
                     if( *(pfY+ppy*x->x_vwidth+ppx) == ((255)<<7) )
                     {
                       *(newdata+py*x->x_vwidth+px) = ((255)<<7);
                       break;
                     }
                  }
                }
                if ( *(newdata+py*x->x_vwidth+px) == ((255)<<7) ) break;
              }
            }
          }
        }
      }
    }

    return;
}

static void pdp_dilate_sendpacket(t_pdp_dilate *x)
{
    /* release the packet */
    pdp_packet_mark_unused(x->x_packet0);
    x->x_packet0 = -1;

    /* unregister and propagate if valid dest packet */
    pdp_packet_pass_if_valid(x->x_pdp_output, &x->x_packet1);
}

static void pdp_dilate_process(t_pdp_dilate *x)
{
   int encoding;
   t_pdp *header = 0;

   /* check if image data packets are compatible */
   if ( (header = pdp_packet_header(x->x_packet0))
	&& (PDP_IMAGE == header->type)){
    
	/* pdp_dilate_process inputs and write into active inlet */
	switch(pdp_packet_header(x->x_packet0)->info.image.encoding)
        {

	case PDP_IMAGE_YV12:
            x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
            pdp_queue_add(x, pdp_dilate_process_yv12, pdp_dilate_sendpacket, &x->x_queue_id);
	    break;

	case PDP_IMAGE_GREY:
            // should write something to handle these one day
            // but i don't use this mode                      
	    break;

	default:
	    /* don't know the type, so dont pdp_dilate_process */
	    break;
	    
	}
    }

}

static void pdp_dilate_input_0(t_pdp_dilate *x, t_symbol *s, t_floatarg f)
{
    /* if this is a register_ro message or register_rw message, register with packet factory */

    if (s== gensym("register_rw"))
    {
       x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("image/YCrCb/*") );
    }

    if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped))
    {
        pdp_dilate_process(x);
    }
}

static void pdp_dilate_free(t_pdp_dilate *x)
{
  int i;

    pdp_packet_mark_unused(x->x_packet0);
    pdp_dilate_free_ressources( x );
}

t_class *pdp_dilate_class;

void *pdp_dilate_new(void)
{
    int i;

    t_pdp_dilate *x = (t_pdp_dilate *)pd_new(pdp_dilate_class);
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("nbpasses"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("kernelw"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("kernelh"));

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

    x->x_packet0 = -1;
    x->x_packet1 = -1;
    x->x_vwidth = -1;
    x->x_vheight = -1;
    x->x_vsize = -1;
    x->x_frame = NULL;
    x->x_kernelw = 3;
    x->x_kernelh = 3;

    x->x_nbpasses = 1;

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_dilate_setup(void)
{
    // post( pdp_dilate_version );
    pdp_dilate_class = class_new(gensym("pdp_dilate"), (t_newmethod)pdp_dilate_new,
    	(t_method)pdp_dilate_free, sizeof(t_pdp_dilate), 0, A_NULL);

    class_addmethod(pdp_dilate_class, (t_method)pdp_dilate_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_dilate_class, (t_method)pdp_dilate_nbpasses, gensym("nbpasses"), A_FLOAT, A_NULL);
    class_addmethod(pdp_dilate_class, (t_method)pdp_dilate_kernelw, gensym("kernelw"), A_FLOAT, A_NULL);
    class_addmethod(pdp_dilate_class, (t_method)pdp_dilate_kernelh, gensym("kernelh"), A_FLOAT, A_NULL);
    class_sethelpsymbol( pdp_dilate_class, gensym("pdp_dilate.pd") );
}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_hitandmiss.c ---
/*
 *   PiDiP module
 *   Copyright (c) by Yves Degoyon ( ydegoyon at free.fr )
 *
 *   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 object is a morphological operator for hit and miss agorithm 
 *  using as a structuring element a WxH square
 */

#include "pdp.h"
#include "yuv.h"
#include <math.h>
#include <stdio.h>

static char   *pdp_hitandmiss_version = "pdp_hitandmiss: morphology : hit&miss version 0.1 written by Yves Degoyon (ydegoyon at free.fr)";

typedef struct pdp_hitandmiss_struct
{
    t_object x_obj;

    t_int x_packet0;
    t_int x_packet1;
    t_int x_queue_id;
    t_int x_dropped;

    t_int x_vwidth;
    t_int x_vheight;
    t_int x_vsize;
    t_int x_kernelw; // width of the (square) kernel
    t_int x_kernelh; // height of the square kernel
    char  *x_kdata;  // kernel data
    t_int x_nbpasses; // number of passes
    short int *x_frame;  // keep a copy of current frame for transformations

    t_outlet *x_pdp_output; // output packets

} t_pdp_hitandmiss;

static void pdp_hitandmiss_nbpasses(t_pdp_hitandmiss *x,  t_floatarg fpasses )
{
   if ( fpasses>=1.) 
   {
      x->x_nbpasses = (t_int)fpasses;
   }
}

static void pdp_hitandmiss_kernelw(t_pdp_hitandmiss *x,  t_floatarg fkernelw )
{
 t_int oldw, minw;
 char *nkdata;

   if ( fkernelw>=0.) 
   {
      oldw = x->x_kernelw;
      x->x_kernelw = (t_int)fkernelw;

      nkdata= (char*) malloc( x->x_kernelw*x->x_kernelh );

      minw = (x->x_kernelw>oldw?oldw:x->x_kernelw );
      memcpy( nkdata, x->x_kdata, minw*x->x_kernelh );

      if ( x->x_kdata ) 
      {
         free( x->x_kdata );
      }
      x->x_kdata = nkdata;
   }

}

static void pdp_hitandmiss_kernelh(t_pdp_hitandmiss *x,  t_floatarg fkernelh )
{
 t_int oldh, minh;
 char *nkdata;

   if ( fkernelh>=0.) 
   {
      oldh = x->x_kernelh;
      x->x_kernelh = (t_int)fkernelh;

      nkdata= (char*) malloc( x->x_kernelw*x->x_kernelh );

      minh = (x->x_kernelh>oldh?oldh:x->x_kernelh );
      memcpy( nkdata, x->x_kdata, x->x_kernelw*minh );

      if ( x->x_kdata ) 
      {
         free( x->x_kdata );
      }
      x->x_kdata = nkdata;
   }
}

static void pdp_hitandmiss_kdata(t_pdp_hitandmiss *x, t_symbol *s, int argc, t_atom *argv)
{
 t_int nbvalues, ivalue, iv;

   if ( argc > x->x_kernelw*x->x_kernelh )
   {
      nbvalues = x->x_kernelh*x->x_kernelw;
      post( "pdp_hitandmiss : too many data for the kernel, it should be %dx%d", x->x_kernelw, x->x_kernelh ); 
      post( "pdp_hitandmiss : truncated to %d", nbvalues ); 
   }
   else if ( argc < x->x_kernelw*x->x_kernelh )
   {
      nbvalues = argc;
      post( "pdp_hitandmiss : too few data for the kernel, it should be %dx%d", x->x_kernelw, x->x_kernelh ); 
      post( "pdp_hitandmiss : padding with -1 (as if not used)" ); 
      for ( iv=argc; iv<x->x_kernelw*x->x_kernelh; iv++ )
      {
        x->x_kdata[iv] = -1;
      }
   }
   else
   {
      nbvalues = argc;
   }

   for ( iv=0; iv<nbvalues; iv++ )
   {
      if ( argv[iv].a_type != A_FLOAT )
      {
         post( "pdp_hitandmiss : wrong data (%d), unchanged", iv );
      }
      else
      {
         ivalue = (t_int) argv[iv].a_w.w_float;
         if ( ( ivalue != 0 ) && ( ivalue != 1 ) && ( ivalue != -1 ) )
         {
           post( "pdp_hitandmiss : wrong data (%d), unchanged", iv );
         }
         else
         {
           x->x_kdata[iv] = ivalue;
         }
      }
   }
}

static void pdp_hitandmiss_allocate(t_pdp_hitandmiss *x)
{
    x->x_frame = (short int *) getbytes ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );

    if ( !x->x_frame )
    {
       post( "pdp_hitandmiss : severe error : cannot allocate buffer !!! ");
       return;
    }
}

static void pdp_hitandmiss_free_ressources(t_pdp_hitandmiss *x)
{
    if ( x->x_frame ) freebytes ( x->x_frame, ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );
}

static void pdp_hitandmiss_process_yv12(t_pdp_hitandmiss *x)
{
    t_pdp     *header = pdp_packet_header(x->x_packet0);
    short int *data   = (short int *)pdp_packet_data(x->x_packet0);
    t_pdp     *newheader = pdp_packet_header(x->x_packet1);
    short int *newdata = (short int *)pdp_packet_data(x->x_packet1);
    t_int     i;
    t_int     px=0, py=0; 
    short int *pfY, *pfU, *pfV;
    t_int     ppx, ppy, ix, iy, pn, kx, ky;
    short int pvalue;

    // allocate all ressources
    if ( ( (int)header->info.image.width != x->x_vwidth ) ||
         ( (int)header->info.image.height != x->x_vheight ) )
    {
        pdp_hitandmiss_free_ressources( x );
        x->x_vwidth = header->info.image.width;
        x->x_vheight = header->info.image.height;
        x->x_vsize = x->x_vwidth*x->x_vheight;
        pdp_hitandmiss_allocate( x );
        post( "pdp_hitandmiss : reallocated buffers" );
    }

    // post( "pdp_hitandmiss : newheader:%x", newheader );

    newheader->info.image.encoding = header->info.image.encoding;
    newheader->info.image.width = x->x_vwidth;
    newheader->info.image.height = x->x_vheight;

    memcpy( newdata, data, x->x_vsize+(x->x_vsize>>1)<<1 );
    memcpy( x->x_frame, data, x->x_vsize+(x->x_vsize>>1)<<1 );

    // hit and miss (supposedly) binary image by using a 3x3 square as a structuring element
    pfY = x->x_frame;
    pfV = x->x_frame+x->x_vsize;
    pfU = x->x_frame+x->x_vsize+(x->x_vsize>>2);
    kx = (x->x_kernelw/2);
    ky = (x->x_kernelh/2);
    for ( pn=0; pn<x->x_nbpasses; pn++ )
    {
      memcpy( x->x_frame, newdata, x->x_vsize+(x->x_vsize>>1)<<1 );
      for ( py=0; py<x->x_vheight; py++ )
      {
        for ( px=0; px<x->x_vwidth; px++ )
        {
          *(newdata+py*x->x_vwidth+px) = ((255)<<7);
          for (ix=-kx; ix<=kx; ix++)
          {
            ppx=px+ix;
            if ( (ppx>=0) && (ppx<x->x_vwidth) )
            {
              for (iy=-ky; iy<=ky; iy++)
              {
                ppy=py+iy;
                if ( (ppy>=0) && (ppy<x->x_vheight) )
                {
                   if ( x->x_kdata[(ky+iy)*x->x_kernelw+(kx+ix)] == 1 )
                   {
                      pvalue = ((255)<<7);
                   }
                   else if ( x->x_kdata[(ky+iy)*x->x_kernelw+(kx+ix)] == 0 )
                   {
                      pvalue = 0;
                   }
                   else // unused bit in the kernel, usually -1
                   {
                      continue;
                   }
                   if( *(pfY+ppy*x->x_vwidth+ppx) != pvalue )
                   {
                     *(newdata+py*x->x_vwidth+px) = 0;
                     break;
                   }
                }
              }
              if ( *(newdata+py*x->x_vwidth+px) == 0 ) break;
            }
          }
        }
      }
    }

    return;
}

static void pdp_hitandmiss_sendpacket(t_pdp_hitandmiss *x)
{
    /* release the packet */
    pdp_packet_mark_unused(x->x_packet0);
    x->x_packet0 = -1;

    /* unregister and propagate if valid dest packet */
    pdp_packet_pass_if_valid(x->x_pdp_output, &x->x_packet1);
}

static void pdp_hitandmiss_process(t_pdp_hitandmiss *x)
{
   int encoding;
   t_pdp *header = 0;

   /* check if image data packets are compatible */
   if ( (header = pdp_packet_header(x->x_packet0))
	&& (PDP_IMAGE == header->type)){
    
	/* pdp_hitandmiss_process inputs and write into active inlet */
	switch(pdp_packet_header(x->x_packet0)->info.image.encoding)
        {

	case PDP_IMAGE_YV12:
            x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
            pdp_queue_add(x, pdp_hitandmiss_process_yv12, pdp_hitandmiss_sendpacket, &x->x_queue_id);
	    break;

	case PDP_IMAGE_GREY:
            // should write something to handle these one day
            // but i don't use this mode                      
	    break;

	default:
	    /* don't know the type, so dont pdp_hitandmiss_process */
	    break;
	    
	}
    }

}

static void pdp_hitandmiss_input_0(t_pdp_hitandmiss *x, t_symbol *s, t_floatarg f)
{
    /* if this is a register_ro message or register_rw message, register with packet factory */

    if (s== gensym("register_rw"))
    {
       x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("image/YCrCb/*") );
    }

    if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped))
    {
        pdp_hitandmiss_process(x);
    }
}

static void pdp_hitandmiss_free(t_pdp_hitandmiss *x)
{
  int i;

    pdp_packet_mark_unused(x->x_packet0);
    pdp_hitandmiss_free_ressources( x );
}

t_class *pdp_hitandmiss_class;

void *pdp_hitandmiss_new(void)
{
    int i;

    t_pdp_hitandmiss *x = (t_pdp_hitandmiss *)pd_new(pdp_hitandmiss_class);
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("nbpasses"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("kernelw"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("kernelh"));

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

    x->x_packet0 = -1;
    x->x_packet1 = -1;
    x->x_vwidth = -1;
    x->x_vheight = -1;
    x->x_vsize = -1;
    x->x_frame = NULL;
    x->x_kernelw = 3;
    x->x_kernelh = 3;
    x->x_kdata = (char *)malloc( x->x_kernelw*x->x_kernelh );
    x->x_kdata[0] = -1;
    x->x_kdata[1] = 1;
    x->x_kdata[2] = -1;
    x->x_kdata[3] = 0;
    x->x_kdata[4] = 1;
    x->x_kdata[5] = 1;
    x->x_kdata[6] = 0;
    x->x_kdata[7] = 0;
    x->x_kdata[8] = -1;
    // that is :
    // | -1 1 -1 |
    // | 0  1  1 |
    // | 0  0 -1 |

    x->x_nbpasses = 1;

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_hitandmiss_setup(void)
{
    // post( pdp_hitandmiss_version );
    pdp_hitandmiss_class = class_new(gensym("pdp_hitandmiss"), (t_newmethod)pdp_hitandmiss_new,
    	(t_method)pdp_hitandmiss_free, sizeof(t_pdp_hitandmiss), 0, A_NULL);

    class_addmethod(pdp_hitandmiss_class, (t_method)pdp_hitandmiss_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_hitandmiss_class, (t_method)pdp_hitandmiss_nbpasses, gensym("nbpasses"), A_FLOAT, A_NULL);
    class_addmethod(pdp_hitandmiss_class, (t_method)pdp_hitandmiss_kernelw, gensym("kernelw"), A_FLOAT, A_NULL);
    class_addmethod(pdp_hitandmiss_class, (t_method)pdp_hitandmiss_kernelh, gensym("kernelh"), A_FLOAT, A_NULL);
    class_addmethod(pdp_hitandmiss_class, (t_method)pdp_hitandmiss_kdata, gensym("kernel"), A_GIMME, A_NULL);
    class_sethelpsymbol( pdp_hitandmiss_class, gensym("pdp_hitandmiss.pd") );
}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_distance.c ---
/*
 *   PiDiP module
 *   Copyright (c) by Yves Degoyon ( ydegoyon at free.fr )
 *
 *   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 object is a salience distance operator 
 *  ( inspired by Paul Rosin, 91, http://www.cs.cf.ac.uk/User/Paul.Rosin/resources/sdt/ )
 */

#include "pdp.h"
#include "yuv.h"
#include <math.h>
#include <stdio.h>

static char   *pdp_distance_version = "pdp_distance: morphology : distance operator version 0.1 written by Yves Degoyon (ydegoyon at free.fr)";

typedef struct pdp_distance_struct
{
    t_object x_obj;

    t_int x_packet0;
    t_int x_packet1;
    t_int x_queue_id;
    t_int x_dropped;

    t_int x_vwidth;
    t_int x_vheight;
    t_int x_vsize;
    short int *x_frame;  // keep a copy of current frame for transformations

    t_int x_coeff1;
    t_int x_coeff2;
    t_int x_coeff3;
    t_int x_coeff4;

    t_outlet *x_pdp_output; // output packets

} t_pdp_distance;

static void pdp_distance_allocate(t_pdp_distance *x)
{
    x->x_frame = (short int *) getbytes ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );

    if ( !x->x_frame )
    {
       post( "pdp_distance : severe error : cannot allocate buffer !!! ");
       return;
    }
}

static void pdp_distance_coeff1(t_pdp_distance *x, t_floatarg fcoeff1 )
{
   x->x_coeff1 = (int) fcoeff1;
}

static void pdp_distance_coeff2(t_pdp_distance *x, t_floatarg fcoeff2 )
{
   x->x_coeff2 = (int) fcoeff2;
}

static void pdp_distance_coeff3(t_pdp_distance *x, t_floatarg fcoeff3 )
{
   x->x_coeff3 = (int) fcoeff3;
}

static void pdp_distance_coeff4(t_pdp_distance *x, t_floatarg fcoeff4 )
{
   x->x_coeff4 = (int) fcoeff4;
}

static void pdp_distance_free_ressources(t_pdp_distance *x)
{
    if ( x->x_frame ) freebytes ( x->x_frame, ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );
}

static void pdp_distance_process_yv12(t_pdp_distance *x)
{
    t_pdp     *header = pdp_packet_header(x->x_packet0);
    short int *data   = (short int *)pdp_packet_data(x->x_packet0);
    t_pdp     *newheader = pdp_packet_header(x->x_packet1);
    short int *newdata = (short int *)pdp_packet_data(x->x_packet1);
    t_int     i;
    t_int     px=0, py=0; 
    short int *pfY, *pfU, *pfV;
    t_int     nvalues, values[5], ival, mval;

    // allocate all ressources
    if ( ( (int)header->info.image.width != x->x_vwidth ) ||
         ( (int)header->info.image.height != x->x_vheight ) )
    {
        pdp_distance_free_ressources( x );
        x->x_vwidth = header->info.image.width;
        x->x_vheight = header->info.image.height;
        x->x_vsize = x->x_vwidth*x->x_vheight;
        pdp_distance_allocate( x );
        post( "pdp_distance : reallocated buffers" );
    }

    // post( "pdp_distance : newheader:%x", newheader );

    newheader->info.image.encoding = header->info.image.encoding;
    newheader->info.image.width = x->x_vwidth;
    newheader->info.image.height = x->x_vheight;

    memcpy( newdata, data, x->x_vsize+(x->x_vsize>>1)<<1 );
    memcpy( x->x_frame, data, x->x_vsize+(x->x_vsize>>1)<<1 );

    pfY = x->x_frame;
    pfV = x->x_frame+x->x_vsize;
    pfU = x->x_frame+x->x_vsize+(x->x_vsize>>2);
    
    // thresholding
    for ( py=0; py<x->x_vheight; py++ )
    {
      for ( px=0; px<x->x_vwidth; px++ )
      {
         if ( *(pfY+py*x->x_vwidth+px) > ((128)<<7) )
         {
            *(pfY+py*x->x_vwidth+px) = ((128)<<7);
         }
      }
    }

    // forward pass
    for ( py=0; py<x->x_vheight; py++ )
    {
      for ( px=0; px<x->x_vwidth; px++ )
      {
        nvalues = 0;
        if ( ((px-1)>=0) && ((py-1)>=0) )
        {
           values[nvalues] = *(pfY+(py-1)*x->x_vwidth+(px-1)) + (x->x_coeff1<<7);
           nvalues++;
        }
        if ( (py-1)>=0 )
        {
           values[nvalues] = *(pfY+(py-1)*x->x_vwidth+px) + (x->x_coeff2<<7);
           nvalues++;
        }
        if ( ((px+1)<x->x_vwidth) && ((py-1)>=0) )
        {
           values[nvalues] = *(pfY+(py-1)*x->x_vwidth+(px+1)) + (x->x_coeff3<<7);
           nvalues++;
        }
        if ( (px-1)>=0 )
        {
           values[nvalues] = *(pfY+py*x->x_vwidth+(px-1)) + (x->x_coeff4<<7);
           nvalues++;
        }
        values[nvalues] = *(pfY+py*x->x_vwidth+px);
        nvalues++;

        mval = values[0];
        for (ival=0; ival<nvalues; ival++)
        {
           if (values[ival]<mval) mval=values[ival];
        }
        *(x->x_frame+py*x->x_vwidth+px)=mval;
      }
    }

    // backward pass
    for ( py=x->x_vheight-1; py>=0; py-- )
    {
      for ( px=x->x_vwidth-1; px>=0; px-- )
      {
        nvalues = 0;
        if ( ((px-1)>=0) && ((py+1)<x->x_vheight) )
        {
           values[nvalues] = *(pfY+(py+1)*x->x_vwidth+(px-1)) + (x->x_coeff1<<7);
           nvalues++;
        }
        if ( (py+1)<x->x_vheight )
        {
           values[nvalues] = *(pfY+(py+1)*x->x_vwidth+px) + (x->x_coeff2<<7);
           nvalues++;
        }
        if ( ((px+1)<x->x_vwidth) && ((py+1)<x->x_vheight) )
        {
           values[nvalues] = *(pfY+(py+1)*x->x_vwidth+(px+1)) + (x->x_coeff3<<7);
           nvalues++;
        }
        if ( (px+1)<x->x_vwidth )
        {
           values[nvalues] = *(pfY+py*x->x_vwidth+(px+1)) + (x->x_coeff4<<7);
           nvalues++;
        }
        values[nvalues] = *(pfY+py*x->x_vwidth+px);
        nvalues++;

        mval = values[0];
        for (ival=0; ival<nvalues; ival++)
        {
           if (values[ival]<mval) mval=values[ival];
        }
        *(x->x_frame+py*x->x_vwidth+px)=mval;
      }
    }

    memcpy( newdata, x->x_frame, x->x_vsize+(x->x_vsize>>1)<<1 );

    return;
}

static void pdp_distance_sendpacket(t_pdp_distance *x)
{
    /* release the packet */
    pdp_packet_mark_unused(x->x_packet0);
    x->x_packet0 = -1;

    /* unregister and propagate if valid dest packet */
    pdp_packet_pass_if_valid(x->x_pdp_output, &x->x_packet1);
}

static void pdp_distance_process(t_pdp_distance *x)
{
   int encoding;
   t_pdp *header = 0;

   /* check if image data packets are compatible */
   if ( (header = pdp_packet_header(x->x_packet0))
	&& (PDP_IMAGE == header->type)){
    
	/* pdp_distance_process inputs and write into active inlet */
	switch(pdp_packet_header(x->x_packet0)->info.image.encoding)
        {

	case PDP_IMAGE_YV12:
            x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
            pdp_queue_add(x, pdp_distance_process_yv12, pdp_distance_sendpacket, &x->x_queue_id);
	    break;

	case PDP_IMAGE_GREY:
            // should write something to handle these one day
            // but i don't use this mode                      
	    break;

	default:
	    /* don't know the type, so dont pdp_distance_process */
	    break;
	    
	}
    }

}

static void pdp_distance_input_0(t_pdp_distance *x, t_symbol *s, t_floatarg f)
{
    /* if this is a register_ro message or register_rw message, register with packet factory */

    if (s== gensym("register_rw"))
    {
       x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("image/YCrCb/*") );
    }

    if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped))
    {
        pdp_distance_process(x);
    }
}

static void pdp_distance_free(t_pdp_distance *x)
{
  int i;

    pdp_packet_mark_unused(x->x_packet0);
    pdp_distance_free_ressources( x );
}

t_class *pdp_distance_class;

void *pdp_distance_new(void)
{
    int i;

    t_pdp_distance *x = (t_pdp_distance *)pd_new(pdp_distance_class);
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("coeff1"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("coeff2"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("coeff3"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("coeff4"));

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

    x->x_packet0 = -1;
    x->x_packet1 = -1;
    x->x_vwidth = -1;
    x->x_vheight = -1;
    x->x_vsize = -1;
    x->x_frame = NULL;

    x->x_coeff1 = 4;
    x->x_coeff2 = 3;
    x->x_coeff3 = 4;
    x->x_coeff4 = 3;

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_distance_setup(void)
{
    // post( pdp_distance_version );
    pdp_distance_class = class_new(gensym("pdp_distance"), (t_newmethod)pdp_distance_new,
    	(t_method)pdp_distance_free, sizeof(t_pdp_distance), 0, A_NULL);

    class_addmethod(pdp_distance_class, (t_method)pdp_distance_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_distance_class, (t_method)pdp_distance_coeff1, gensym("coeff1"),  A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_distance_class, (t_method)pdp_distance_coeff2, gensym("coeff2"),  A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_distance_class, (t_method)pdp_distance_coeff3, gensym("coeff3"),  A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_distance_class, (t_method)pdp_distance_coeff4, gensym("coeff4"),  A_DEFFLOAT, A_NULL);
    class_sethelpsymbol( pdp_distance_class, gensym("pdp_distance.pd") );
}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_erode.c ---
/*
 *   PiDiP module
 *   Copyright (c) by Yves Degoyon ( ydegoyon at free.fr )
 *
 *   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 object is a morphological operator for erosion using as a structuring element a WxH square
 */

#include "pdp.h"
#include "yuv.h"
#include <math.h>
#include <stdio.h>

static char   *pdp_erode_version = "pdp_erode: morphology : erosion version 0.1 written by Yves Degoyon (ydegoyon at free.fr)";

typedef struct pdp_erode_struct
{
    t_object x_obj;

    t_int x_packet0;
    t_int x_packet1;
    t_int x_queue_id;
    t_int x_dropped;

    t_int x_vwidth;
    t_int x_vheight;
    t_int x_vsize;
    t_int x_kernelw; // width of the (square) kernel
    t_int x_kernelh; // height of the square kernel
    t_int x_nbpasses; // number of passes
    short int *x_frame;  // keep a copy of current frame for transformations

    t_outlet *x_pdp_output; // output packets

} t_pdp_erode;

static void pdp_erode_nbpasses(t_pdp_erode *x,  t_floatarg fpasses )
{
   if ( fpasses>=1.) 
   {
      x->x_nbpasses = (t_int)fpasses;
   }
}

static void pdp_erode_kernelw(t_pdp_erode *x,  t_floatarg fkernelw )
{
   if ( fkernelw>=0.) 
   {
      x->x_kernelw = (t_int)fkernelw;
   }
}

static void pdp_erode_kernelh(t_pdp_erode *x,  t_floatarg fkernelh )
{
   if ( fkernelh>=0.) 
   {
      x->x_kernelh = (t_int)fkernelh;
   }
}

static void pdp_erode_allocate(t_pdp_erode *x)
{
    x->x_frame = (short int *) getbytes ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );

    if ( !x->x_frame )
    {
       post( "pdp_erode : severe error : cannot allocate buffer !!! ");
       return;
    }
}

static void pdp_erode_free_ressources(t_pdp_erode *x)
{
    if ( x->x_frame ) freebytes ( x->x_frame, ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );
}

static void pdp_erode_process_yv12(t_pdp_erode *x)
{
    t_pdp     *header = pdp_packet_header(x->x_packet0);
    short int *data   = (short int *)pdp_packet_data(x->x_packet0);
    t_pdp     *newheader = pdp_packet_header(x->x_packet1);
    short int *newdata = (short int *)pdp_packet_data(x->x_packet1);
    t_int     i;
    t_int     px=0, py=0; 
    short int *pfY, *pfU, *pfV;
    t_int     ppx, ppy, ix, iy, pn, kx, ky;

    // allocate all ressources
    if ( ( (int)header->info.image.width != x->x_vwidth ) ||
         ( (int)header->info.image.height != x->x_vheight ) )
    {
        pdp_erode_free_ressources( x );
        x->x_vwidth = header->info.image.width;
        x->x_vheight = header->info.image.height;
        x->x_vsize = x->x_vwidth*x->x_vheight;
        pdp_erode_allocate( x );
        post( "pdp_erode : reallocated buffers" );
    }

    // post( "pdp_erode : newheader:%x", newheader );

    newheader->info.image.encoding = header->info.image.encoding;
    newheader->info.image.width = x->x_vwidth;
    newheader->info.image.height = x->x_vheight;

    memcpy( newdata, data, x->x_vsize+(x->x_vsize>>1)<<1 );
    memcpy( x->x_frame, data, x->x_vsize+(x->x_vsize>>1)<<1 );

    // erode (supposedly) binary image by using a 3x3 square as a structuring element
    pfY = x->x_frame;
    pfV = x->x_frame+x->x_vsize;
    pfU = x->x_frame+x->x_vsize+(x->x_vsize>>2);
    kx = (x->x_kernelw/2);
    ky = (x->x_kernelh/2);
    for ( pn=0; pn<x->x_nbpasses; pn++ )
    {
      memcpy( x->x_frame, newdata, x->x_vsize+(x->x_vsize>>1)<<1 );
      for ( py=0; py<x->x_vheight; py++ )
      {
        for ( px=0; px<x->x_vwidth; px++ )
        {
          if ( *(pfY+py*x->x_vwidth+px) != 0 )
          {
            for (ix=-kx; ix<=kx; ix++)
            {
              ppx=px+ix;
              if ( (ppx>=0) && (ppx<x->x_vwidth) )
              {
                for (iy=-ky; iy<=ky; iy++)
                {
                  ppy=py+iy;
                  if ( (ppy>=0) && (ppy<x->x_vheight) )
                  {
                     if( *(pfY+ppy*x->x_vwidth+ppx) != ((255)<<7) )
                     {
                       *(newdata+py*x->x_vwidth+px) = 0;
                       break;
                     }
                  }
                }
                if ( *(newdata+py*x->x_vwidth+px) == 0 ) break;
              }
            }
          }
        }
      }
    }

    return;
}

static void pdp_erode_sendpacket(t_pdp_erode *x)
{
    /* release the packet */
    pdp_packet_mark_unused(x->x_packet0);
    x->x_packet0 = -1;

    /* unregister and propagate if valid dest packet */
    pdp_packet_pass_if_valid(x->x_pdp_output, &x->x_packet1);
}

static void pdp_erode_process(t_pdp_erode *x)
{
   int encoding;
   t_pdp *header = 0;

   /* check if image data packets are compatible */
   if ( (header = pdp_packet_header(x->x_packet0))
	&& (PDP_IMAGE == header->type)){
    
	/* pdp_erode_process inputs and write into active inlet */
	switch(pdp_packet_header(x->x_packet0)->info.image.encoding)
        {

	case PDP_IMAGE_YV12:
            x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
            pdp_queue_add(x, pdp_erode_process_yv12, pdp_erode_sendpacket, &x->x_queue_id);
	    break;

	case PDP_IMAGE_GREY:
            // should write something to handle these one day
            // but i don't use this mode                      
	    break;

	default:
	    /* don't know the type, so dont pdp_erode_process */
	    break;
	    
	}
    }

}

static void pdp_erode_input_0(t_pdp_erode *x, t_symbol *s, t_floatarg f)
{
    /* if this is a register_ro message or register_rw message, register with packet factory */

    if (s== gensym("register_rw"))
    {
       x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("image/YCrCb/*") );
    }

    if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped))
    {
        pdp_erode_process(x);
    }
}

static void pdp_erode_free(t_pdp_erode *x)
{
  int i;

    pdp_packet_mark_unused(x->x_packet0);
    pdp_erode_free_ressources( x );
}

t_class *pdp_erode_class;

void *pdp_erode_new(void)
{
    int i;

    t_pdp_erode *x = (t_pdp_erode *)pd_new(pdp_erode_class);
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("nbpasses"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("kernelw"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("kernelh"));

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

    x->x_packet0 = -1;
    x->x_packet1 = -1;
    x->x_vwidth = -1;
    x->x_vheight = -1;
    x->x_vsize = -1;
    x->x_frame = NULL;
    x->x_kernelw = 3;
    x->x_kernelh = 3;

    x->x_nbpasses = 1;

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_erode_setup(void)
{
    // post( pdp_erode_version );
    pdp_erode_class = class_new(gensym("pdp_erode"), (t_newmethod)pdp_erode_new,
    	(t_method)pdp_erode_free, sizeof(t_pdp_erode), 0, A_NULL);

    class_addmethod(pdp_erode_class, (t_method)pdp_erode_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_erode_class, (t_method)pdp_erode_nbpasses, gensym("nbpasses"), A_FLOAT, A_NULL);
    class_addmethod(pdp_erode_class, (t_method)pdp_erode_kernelw, gensym("kernelw"), A_FLOAT, A_NULL);
    class_addmethod(pdp_erode_class, (t_method)pdp_erode_kernelh, gensym("kernelh"), A_FLOAT, A_NULL);
    class_sethelpsymbol( pdp_erode_class, gensym("pdp_erode.pd") );
}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_theorin~.c ---
/*
 *   PiDiP module.
 *   Copyright (c) by Yves Degoyon (ydegoyon at free.fr)
 *
 *   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 object is a theora file decoder object
 *  It uses libtheora and some of it code samples ( copyright xiph.org )
 *  Copyleft by Yves Degoyon ( ydegoyon at free.fr )                             
 */


#include "pdp.h"
#include "yuv.h"
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <signal.h>

#include <theora/theora.h>  /* theora stuff */
#include <vorbis/codec.h>   /* vorbis stuff */

#define VIDEO_BUFFER_SIZE (1024*1024)
#define MAX_AUDIO_PACKET_SIZE (64 * 1024)
#define MIN_AUDIO_SIZE (64*1024)

#define DEFAULT_CHANNELS 1
#define DEFAULT_WIDTH 320
#define DEFAULT_HEIGHT 240
#define DEFAULT_FRAME_RATE 25
#define END_OF_STREAM 20
#define MIN_PRIORITY 0
#define DEFAULT_PRIORITY 1
#define MAX_PRIORITY 20

#define THEORA_NUM_HEADER_PACKETS 3

static char   *pdp_theorin_version = "pdp_theorin~: version 0.1, a theora file reader ( ydegoyon at free.fr).";

typedef struct pdp_theorin_struct
{
    t_object x_obj;
    t_float x_f;

    t_int x_packet0;
    t_int x_dropped;

    t_pdp *x_header;
    unsigned char *x_data;
    t_int x_vwidth;
    t_int x_vheight;
    t_int x_vsize;

    t_outlet *x_pdp_out;           // output decoded pdp packets
    t_outlet *x_outlet_left;       // left audio output
    t_outlet *x_outlet_right;      // right audio output
    t_outlet *x_outlet_nbframes;   // number of frames emitted
    t_outlet *x_outlet_framerate;  // real framerate
    t_outlet *x_outlet_endoffile;  // for signaling the end of the file
    t_outlet *x_outlet_filesize;   // for informing of the file size

    pthread_t x_decodechild;       // file decoding thread
    t_int x_usethread;             // flag to activate decoding in a thread
    t_int x_autoplay;              // flag to autoplay the file ( default = true )
    t_int x_nextimage;             // flag to play next image in manual mode
    t_int x_priority;              // priority of decoding thread

    char  *x_filename;
    FILE  *x_infile;        // file descriptor
    t_int x_decoding;       // decoding flag
    t_int x_theorainit;     // flag for indicating that theora is initialized
    t_int x_videoready;     // video ready flag
    t_int x_newpicture;     // new picture flag
    t_int x_newpictureready;// new picture ready flag
    t_int x_loop;           // looping flag ( default = on )
    t_int x_notpackets;     // number of theora packets decoded
    t_int x_novpackets;     // number of vorbis packets decoded
    t_int x_endoffile;      // end of the file reached
    t_int x_nbframes;       // number of frames emitted
    t_int x_framerate;      // framerate
    t_int x_samplerate;     // audio sample rate
    t_int x_audiochannels;  // audio channels
    t_int x_blocksize;      // audio block size
    t_int x_audioon;        // audio buffer filling flag
    t_int x_reading;        // file reading flag
    t_int x_cursec;         // current second
    t_int x_secondcount;    // number of frames received in the current second
    struct timeval x_starttime; // reading starting time

      /* vorbis/theora structures */
    ogg_sync_state   x_sync_state;     // ogg sync state
    ogg_page         x_ogg_page;       // ogg page
    ogg_packet       x_ogg_packet;     // ogg packet
    ogg_stream_state x_statev;         // vorbis stream state
    ogg_stream_state x_statet;         // theora stream state
    theora_info      x_theora_info;    // theora info
    theora_comment   x_theora_comment; // theora comment
    theora_state     x_theora_state;   // theora state
    vorbis_info      x_vorbis_info;    // vorbis info
    vorbis_dsp_state x_dsp_state;      // vorbis dsp state
    vorbis_block     x_vorbis_block;   // vorbis block
    vorbis_comment   x_vorbis_comment; // vorbis comment
    yuv_buffer       x_yuvbuffer;      // yuv buffer

      /* audio structures */
    t_int x_audio;           // flag to activate the decoding of audio
    t_float x_audio_inl[4*MAX_AUDIO_PACKET_SIZE]; /* buffer for float audio decoded from ogg */
    t_float x_audio_inr[4*MAX_AUDIO_PACKET_SIZE]; /* buffer for float audio decoded from ogg */
    t_int x_audioin_position; // writing position for incoming audio

} t_pdp_theorin;

static void pdp_theorin_priority(t_pdp_theorin *x, t_floatarg fpriority )
{
   if ( ( x->x_priority >= MIN_PRIORITY ) && ( x->x_priority <= MAX_PRIORITY ) )
   {
     x->x_priority = (int)fpriority;
   }
}

static void pdp_theorin_threadify(t_pdp_theorin *x, t_floatarg fusethread )
{
   if ( ( fusethread == 0 ) || ( fusethread == 1 ) ) 
   {
      x->x_usethread = (int)fusethread;
   }
}

static void pdp_theorin_audio(t_pdp_theorin *x, t_floatarg faudio )
{
   if ( ( faudio == 0. ) || ( faudio == 1. ) )
   {
      x->x_audio = (int)faudio;
   }
}

static void pdp_theorin_autoplay(t_pdp_theorin *x, t_floatarg fautoplay )
{
   if ( ( fautoplay == 0. ) || ( fautoplay == 1. ) )
   {
      x->x_autoplay = (int)fautoplay;
   }
}

static void pdp_theorin_loop(t_pdp_theorin *x, t_floatarg floop )
{
   if ( ( floop == 0. ) || ( floop == 1. ) )
   {
      x->x_loop = (int)floop;
   }
}

static void pdp_theorin_bang(t_pdp_theorin *x)
{
   if ( x->x_nextimage == 1 )
   {
      // post( "pdp_theorin~ : banging too fast, previous image is not decoded yet... ignored" );
      return;
   }
   x->x_nextimage = 1;
}

static t_int pdp_theorin_get_buffer_from_file(FILE *in, ogg_sync_state *oy)
{
  char *buffer;
  t_int bytes;

    buffer=ogg_sync_buffer(oy,4096);
    bytes=fread(buffer,1,4096,in);
    ogg_sync_wrote(oy,bytes);
    return(bytes);
}

static t_int pdp_theorin_queue_page(t_pdp_theorin *x)
{
  if(x->x_notpackets) ogg_stream_pagein(&x->x_statet, &x->x_ogg_page);
  if(x->x_novpackets) ogg_stream_pagein(&x->x_statev, &x->x_ogg_page); 
  return 0;
}

static t_int pdp_theorin_decode_packet(t_pdp_theorin *x)
{
  int ret, count, maxsamples, samples, si=0, sj=0;
  float **pcm;
  struct timespec mwait;
  struct timeval ctime;
  long long tplaying;
  long long ttheoretical;
  unsigned char *pY, *pU, *pV; 
  unsigned char *psY, *psU, *psV; 
  t_int px, py;

   // post( "pdp_theorin~ : decode packet" );

   if ( !x->x_reading ) return -1;

   while ( x->x_novpackets && !x->x_audioon )
   {
     /* if there's pending, decoded audio, grab it */
     if((ret=vorbis_synthesis_pcmout(&x->x_dsp_state, &pcm))>0)
     {
       if (x->x_audio) 
       {
         maxsamples=(3*MAX_AUDIO_PACKET_SIZE-x->x_audioin_position);
         samples=(ret<maxsamples)?ret:maxsamples;

         if ( x->x_audioin_position + samples*x->x_audiochannels < 3*MAX_AUDIO_PACKET_SIZE )
         {        
           memcpy( (void*)&x->x_audio_inl[x->x_audioin_position], pcm[0], samples*sizeof(t_float) );
           memcpy( (void*)&x->x_audio_inr[x->x_audioin_position], pcm[1], samples*sizeof(t_float) );
           x->x_audioin_position = ( x->x_audioin_position + samples ) % (4*MAX_AUDIO_PACKET_SIZE);
         }
         else
         {
           post( "pdp_theorin~ : audio overflow : packet ignored...");
           x->x_audioin_position = 0;
         }
         if ( ( x->x_audioin_position > MIN_AUDIO_SIZE ) && (!x->x_audioon) )
         {
           x->x_audioon = 1;
           // post( "pdp_theorin~ : audio on (audioin=%d)", x->x_audioin_position );
         }
         // tell vorbis how many samples were read
         // post( "pdp_theorin~ : got %d audio samples (audioin=%d)", samples, x->x_audioin_position );
         vorbis_synthesis_read(&x->x_dsp_state, samples);
       }
       else
       {
         break;
       }
     }
     else
     {
       // no pending audio: is there a pending packet to decode? 
       if( ogg_stream_packetout(&x->x_statev, &x->x_ogg_packet)>0 )
       {
         if(vorbis_synthesis(&x->x_vorbis_block, &x->x_ogg_packet)==0)
         {
           vorbis_synthesis_blockin(&x->x_dsp_state, &x->x_vorbis_block);
         }
       }
       else   /* we need more data; suck in another page */
       {
         break;
       }
     }
   }

   if ( !x->x_newpictureready && !x->x_newpicture )
   {
     while(x->x_notpackets && !x->x_videoready)
     {
       // theora is one in, one out...
       if(ogg_stream_packetout(&x->x_statet, &x->x_ogg_packet)>0)
       {
         theora_decode_packetin(&x->x_theora_state, &x->x_ogg_packet);
         // post( "pdp_theorin~ : got one video frame" );
         x->x_videoready=1;
       }
       else
       {
         // post( "pdp_theorin~ : no more video frame (frames=%d)", x->x_nbframes );
         if ( x->x_nbframes > 0 ) 
         {
           if ( !x->x_loop )
           {
             x->x_endoffile = 1;
           }
           else
           {
             // restart a new loop
             if ( gettimeofday(&x->x_starttime, NULL) == -1)
             {
               post("pdp_theorin~ : could not set start time" );
             }
           } 
           x->x_nbframes = 0;
           x->x_audioin_position = 0; // reset audio
           x->x_audioon = 0; 
         }
         break;
       }
     }

     if ( x->x_videoready )
     {
       theora_decode_YUVout(&x->x_theora_state, &x->x_yuvbuffer); 

       // create a new pdp packet from PIX_FMT_YUV420P image format
       x->x_vwidth = x->x_yuvbuffer.y_width;
       x->x_vheight = x->x_yuvbuffer.y_height;
       x->x_vsize = x->x_vwidth*x->x_vheight;
       x->x_packet0 = pdp_packet_new_bitmap_yv12( x->x_vwidth, x->x_vheight );
       // post( "pdp_theorin~ : allocated packet %d", x->x_packet0 );
       x->x_header = pdp_packet_header(x->x_packet0);
       x->x_data = (unsigned char*) pdp_packet_data(x->x_packet0);

       x->x_header->info.image.encoding = PDP_BITMAP_YV12;
       x->x_header->info.image.width = x->x_vwidth;
       x->x_header->info.image.height = x->x_vheight;

       pY = x->x_data;
       pV = x->x_data+x->x_vsize;
       pU = x->x_data+x->x_vsize+(x->x_vsize>>2);

       psY = x->x_yuvbuffer.y;
       psU = x->x_yuvbuffer.u;
       psV = x->x_yuvbuffer.v;

       for ( py=0; py<x->x_vheight; py++)
       {
          memcpy( (void*)pY, (void*)psY, x->x_vwidth );
          pY += x->x_vwidth;
          psY += x->x_yuvbuffer.y_stride;
          if ( py%2==0 )
          {
            memcpy( (void*)pU, (void*)psU, (x->x_vwidth>>1) );
            memcpy( (void*)pV, (void*)psV, (x->x_vwidth>>1) );
            pU += (x->x_vwidth>>1);
            pV += (x->x_vwidth>>1);
            psU += x->x_yuvbuffer.uv_stride;
            psV += x->x_yuvbuffer.uv_stride;
          }
       }
       if ( !x->x_autoplay )
       {
         x->x_newpicture = 1;
       }
       else
       {
         x->x_newpictureready = 1;
       }
     }
   }

   if ( x->x_newpictureready )
   {
     if ( gettimeofday(&ctime, NULL) == -1)
     {
       post("pdp_theorin~ : could not read time" );
     }

     tplaying = ( ctime.tv_sec-x->x_starttime.tv_sec )*1000 + 
                ( ctime.tv_usec-x->x_starttime.tv_usec )/1000;
     ttheoretical = ((x->x_nbframes)*1000 )/x->x_framerate;
     // post( "pdp-theorin~ : %d playing since : %lldms ( theory : %lldms )", 
     //        x->x_nbframes, tplaying, ttheoretical );

     if ( ttheoretical <= tplaying ) 
     {
       x->x_newpicture = 1;
       x->x_newpictureready = 0;
     }

   }

   // check end of file
   if(!x->x_videoready && feof(x->x_infile)) 
   {
     if ( x->x_loop )
     {
        if ( fseek( x->x_infile, 0x0, SEEK_SET ) < 0 )
        {
          post( "pdp_theorin~ : could not reset file." );
          perror( "fseek" );
        } 
     }
   }

   // read more data in
   if( ( x->x_audioin_position < MIN_AUDIO_SIZE ) || ( !x->x_newpicture && !x->x_newpictureready ) )
   {
     ret=pdp_theorin_get_buffer_from_file(x->x_infile, &x->x_sync_state);
     // post( "pdp_theorin~ : read %d bytes from file", ret );
     while( ogg_sync_pageout(&x->x_sync_state, &x->x_ogg_page)>0 )
     {
       pdp_theorin_queue_page(x);
     }
   }

   x->x_videoready = 0;

   return 0;

}

static void *pdp_decode_file(void *tdata)
{
  t_pdp_theorin *x = (t_pdp_theorin*)tdata;
  struct sched_param schedprio;
  t_int pmin, pmax, p1;
  struct timespec twait;

    twait.tv_sec = 0; 
    twait.tv_nsec = 5000000; // 5 ms
 
    schedprio.sched_priority = sched_get_priority_min(SCHED_FIFO) + x->x_priority;
    if ( sched_setscheduler(0, SCHED_FIFO, &schedprio) == -1)
    {
        post("pdp_theorin~ : couldn't set priority for decoding thread.");
    }

    while ( x->x_decodechild )
    {
      if ( ( x->x_reading ) && ( ( x->x_autoplay ) || ( x->x_nextimage == 1 ) ) )
      {
        x->x_decoding = 1;
     
        // decode incoming packets
        if ( x->x_reading ) pdp_theorin_decode_packet( x );
        nanosleep( &twait, NULL ); 
        x->x_nextimage = -1;
      }
      else
      {
        x->x_decoding = 0;
        nanosleep( &twait, NULL ); // nothing to do, just wait
      }
    }

    x->x_decoding = 0;
    post("pdp_theorin~ : decoding child exiting." );
    return NULL;
}

static void pdp_theorin_close(t_pdp_theorin *x)
{
 t_int ret, i, count=0;
 struct timespec twait;

   twait.tv_sec = 0; 
   twait.tv_nsec = 10000000; // 10 ms

   if ( x->x_infile == NULL )
   {
     post("pdp_theorin~ : close request but no file is played ... ignored" );
     return;
   }

   if ( x->x_reading )
   {
     x->x_newpicture = 0;
     x->x_reading = 0;
     post("pdp_theorin~ : waiting end of decoding..." );
     while ( x->x_decoding ) nanosleep( &twait, NULL );

     if ( fclose( x->x_infile ) < 0 )
     {
        post( "pdp_theorin~ : could not close input file" );
        perror( "fclose" );
     }
     x->x_infile = NULL;

     if ( x->x_notpackets > 0 )
     {
       ogg_stream_clear(&x->x_statet);
       theora_clear(&x->x_theora_state);
       theora_comment_clear(&x->x_theora_comment);
       theora_info_clear(&x->x_theora_info);
     }

     if ( x->x_novpackets > 0 )
     {
       ogg_stream_clear(&x->x_statev);
       vorbis_block_clear(&x->x_vorbis_block);
       vorbis_dsp_clear(&x->x_dsp_state);
       vorbis_comment_clear(&x->x_vorbis_comment);
       vorbis_info_clear(&x->x_vorbis_info);
     }

   }

   x->x_notpackets = 0;
   x->x_novpackets = 0;
   x->x_endoffile = 0;
   x->x_nbframes = 0;
   x->x_decoding = 0;
   x->x_theorainit = 0;

   x->x_videoready = 0;
   x->x_newpicture = 0;

   x->x_nbframes = 0;
   outlet_float( x->x_outlet_nbframes, x->x_nbframes );
   x->x_framerate = 0;
   outlet_float( x->x_outlet_framerate, x->x_framerate );
}

static void pdp_theorin_open(t_pdp_theorin *x, t_symbol *s)
{
  t_int ret, i;
  pthread_attr_t decode_child_attr;
  ogg_stream_state o_tempstate;
  struct stat fileinfos;

   if ( x->x_infile != NULL )
   {
     post("pdp_theorin~ : open request but a file is open ... closing" );
     pdp_theorin_close(x);
   }

   if ( x->x_filename ) free( x->x_filename );
   x->x_filename = (char*) malloc( strlen( s->s_name ) + 1 );
   strcpy( x->x_filename, s->s_name );
   post( "pdp_theorin~ : opening file : %s", x->x_filename );

   if ( ( x->x_infile = fopen(x->x_filename,"r") ) == NULL )
   {
      post( "pdp_theorin~ : unable to open file >%s<", x->x_filename );
      return;
   }

   ogg_sync_init(&x->x_sync_state);

   // init supporting Vorbis structures needed in header parsing
   vorbis_info_init(&x->x_vorbis_info);
   vorbis_comment_init(&x->x_vorbis_comment);

   // init supporting Theora structures needed in header parsing
   theora_comment_init(&x->x_theora_comment);
   theora_info_init(&x->x_theora_info);

   // parse headers
   while( !x->x_theorainit )
   {
    if ( ( ret = pdp_theorin_get_buffer_from_file(x->x_infile, &x->x_sync_state) )==0) break;

    while( ogg_sync_pageout(&x->x_sync_state, &x->x_ogg_page) > 0 )
    {
      /* is this a mandated initial header? If not, stop parsing */
      if(!ogg_page_bos(&x->x_ogg_page))
      {
        pdp_theorin_queue_page(x);
        x->x_theorainit = 1;
        break;
      }

      ogg_stream_init(&o_tempstate, ogg_page_serialno(&x->x_ogg_page));
      ogg_stream_pagein(&o_tempstate, &x->x_ogg_page);
      ogg_stream_packetout(&o_tempstate, &x->x_ogg_packet);

      /* identify the codec: try theora */
      if(!x->x_notpackets && 
          theora_decode_header(&x->x_theora_info, &x->x_theora_comment, &x->x_ogg_packet)>=0)
      {
        /* it is theora */
        memcpy(&x->x_statet, &o_tempstate, sizeof(o_tempstate));
        x->x_notpackets=1;
      }else 
      if(!x->x_novpackets && 
         vorbis_synthesis_headerin(&x->x_vorbis_info, &x->x_vorbis_comment, &x->x_ogg_packet)>=0){
        memcpy(&x->x_statev, &o_tempstate, sizeof(o_tempstate));
        x->x_novpackets=1;
      }else{
        /* whatever it is, we don't care about it */
        ogg_stream_clear(&o_tempstate);
      }
    }
   }

   // we're expecting more header packets.
   while( (x->x_notpackets && x->x_notpackets<3) || (x->x_novpackets && x->x_novpackets<3) )
   {
     // look for further theora headers
     while(x->x_notpackets && (x->x_notpackets<3) && 
           (ret=ogg_stream_packetout(&x->x_statet, &x->x_ogg_packet)))
     {
       if( ret<0 )
       {
         post("pdp_theorin~ : error parsing theora stream headers\n");
         x->x_theorainit = 0;
         return;
       }
       if( theora_decode_header(&x->x_theora_info, &x->x_theora_comment, &x->x_ogg_packet) )
       {
         post("pdp_theorin~ : error parsing theora stream headers\n");
         x->x_theorainit = 0;
         return;
       }
       x->x_notpackets++;
       if(x->x_notpackets==3) break;
     }
 
     /* look for more vorbis header packets */
     while(x->x_novpackets && (x->x_novpackets<3) && 
           (ret=ogg_stream_packetout(&x->x_statev, &x->x_ogg_packet)))
     {
       if(ret<0)
       {
         post("pdp_theorin~ : error parsing theora stream headers\n");
         x->x_theorainit = 0;
         return;
       }
       if( vorbis_synthesis_headerin(&x->x_vorbis_info, &x->x_vorbis_comment, &x->x_ogg_packet) )
       {
         post("pdp_theorin~ : error parsing theora stream headers\n");
         x->x_theorainit = 0;
         return;
       }
       x->x_novpackets++;
       if(x->x_novpackets==3) break;
     }
 
     if(ogg_sync_pageout(&x->x_sync_state, &x->x_ogg_page)>0)
     {
       pdp_theorin_queue_page(x); 
     }
     else
     {
       if( (ret=pdp_theorin_get_buffer_from_file(x->x_infile, &x->x_sync_state))==0 )
       {
         post("pdp_theorin~ : end of file while parsing headers\n");
         x->x_theorainit = 0;
         return;
       }
     }
   }
   post( "pdp_theorin~ : parsed headers ok." );

   // initialize decoders
   if( x->x_notpackets )
   {
     theora_decode_init(&x->x_theora_state, &x->x_theora_info);
     x->x_framerate = (t_int)x->x_theora_info.fps_numerator/x->x_theora_info.fps_denominator;
     post("pdp_theorin~ : stream %x is theora %dx%d %d fps video.",
                          x->x_statet.serialno,
                          x->x_theora_info.width,x->x_theora_info.height,
                          x->x_framerate);
     if(x->x_theora_info.width!=x->x_theora_info.frame_width || 
        x->x_theora_info.height!=x->x_theora_info.frame_height)
     {
       post("pdp_theorin~ : frame content is %dx%d with offset (%d,%d).",
                          x->x_theora_info.frame_width, x->x_theora_info.frame_height, 
                          x->x_theora_info.offset_x, x->x_theora_info.offset_y);
     }
     x->x_vwidth = x->x_theora_info.width;
     x->x_vheight = x->x_theora_info.height;
     x->x_vsize = x->x_vwidth*x->x_vheight;

     switch(x->x_theora_info.colorspace)
     {
      case OC_CS_UNSPECIFIED:
        /* nothing to report */
        break;;
      case OC_CS_ITU_REC_470M:
        post("pdp_theorin~ : encoder specified ITU Rec 470M (NTSC) color.");
        break;;
      case OC_CS_ITU_REC_470BG:
        post("pdp_theorin~ : encoder specified ITU Rec 470BG (PAL) color.");
        break;;
      default:
        post("pdp_theorin~ : warning: encoder specified unknown colorspace (%d).", 
                             x->x_theora_info.colorspace);
        break;;
     }
   }
   else
   {
     // tear down the partial theora setup 
     theora_info_clear(&x->x_theora_info);
     theora_comment_clear(&x->x_theora_comment);
     post("pdp_theorin~ : could not initialize theora decoder.");
     x->x_theorainit = 0;
     return;
   }

   if( x->x_novpackets )
   {
     vorbis_synthesis_init(&x->x_dsp_state, &x->x_vorbis_info);
     vorbis_block_init(&x->x_dsp_state, &x->x_vorbis_block); 
     x->x_audiochannels = x->x_vorbis_info.channels;
     x->x_samplerate = x->x_vorbis_info.rate;
     post("pdp_theorin~ : ogg logical stream %x is vorbis %d channel %d Hz audio.",
                          x->x_statev.serialno,
                          x->x_audiochannels, x->x_samplerate);
   }
   else
   {
     /* tear down the partial vorbis setup */
     vorbis_info_clear(&x->x_vorbis_info);
     vorbis_comment_clear(&x->x_vorbis_comment);
     post("pdp_theorin~ : could not initialize vorbis decoder.");
     // x->x_theorainit = 0;
     // return;
     x->x_audio = 0;
   }
   // everything seems to be ready
   x->x_reading = 1;

   if ( x->x_usethread && ( x->x_decodechild == 0 ) )
   {
     x->x_decodechild = 1; // trick & treets
     // launch decoding thread
     if ( pthread_attr_init( &decode_child_attr ) < 0 ) 
     {
        post( "pdp_theorin~ : could not launch decoding thread" );
        perror( "pthread_attr_init" );
        pthread_exit(NULL);
     }
     if ( pthread_create( &x->x_decodechild, &decode_child_attr, pdp_decode_file, x ) < 0 ) 
     {
        post( "pdp_theorin~ : could not launch decoding thread" );
        perror( "pthread_create" );
        pthread_exit(NULL);
     }
     else
     {
        // post( "pdp_theorin~ : decoding thread %d launched", (int)x->x_decodechild );
     }
   }

   if ( stat( x->x_filename, &fileinfos ) < 0 )
   {
     post("pdp_theorin~ : couldn't get file informations" );
     perror( "stat" );
   }
   else
   {
     outlet_float( x->x_outlet_filesize, (fileinfos.st_size)/1024 );
   }

   if ( gettimeofday(&x->x_starttime, NULL) == -1)
   {
     post("pdp_theorin~ : could not set start time" );
   }

   x->x_nbframes = 0;
   x->x_endoffile = -1;

   return;
}

static void pdp_theorin_frame_cold(t_pdp_theorin *x, t_floatarg kbytes)
{
    int pos = (int)kbytes;
    int ret;

    if (x->x_infile==NULL) return;

    pdp_theorin_open(x, gensym(x->x_filename));

    // it's very approximative, we're are positioning the file on the number of requested kilobytes
    if ( fseek( x->x_infile, pos*1024, SEEK_SET ) < 0 )
    {
       post( "pdp_theorin~ : could not set file at that position (%d kilobytes)", pos );
       perror( "fseek" );
       return;
    }
    // post( "pdp_theorin~ : file seeked at %d kilobytes", pos );
} 

    /* decode the audio buffer */
static t_int *pdp_theorin_perform(t_int *w)
{
  t_float *out1   = (t_float *)(w[1]);       // left audio inlet
  t_float *out2   = (t_float *)(w[2]);       // right audio inlet 
  t_pdp_theorin *x = (t_pdp_theorin *)(w[3]);
  int n = (int)(w[4]);                      // number of samples 
  struct timeval etime;
  t_int sn;

    // decode a packet if not in thread mode
    if ( !x->x_usethread && x->x_reading )
    {
      pdp_theorin_decode_packet( x );
    }

    x->x_blocksize = n;

    // just read the buffer
    if ( x->x_audioon )
    {
      sn=0;
      while (n--) 
      {
        *(out1)=x->x_audio_inl[ sn ];
        if ( x->x_audiochannels == 1 )
        {
          *(out2) = *(out1);
          sn++;
        }
        if ( x->x_audiochannels == 2 )
        {
          *(out2)=x->x_audio_inr[ sn++ ];
        }
        out1++;
        out2++;
      }
      memcpy( &x->x_audio_inl[0], &x->x_audio_inl[sn], (x->x_audioin_position-sn)*sizeof(t_float) );
      memcpy( &x->x_audio_inr[0], &x->x_audio_inr[sn], (x->x_audioin_position-sn)*sizeof(t_float) );
      x->x_audioin_position-=sn;
      // post( "pdp_theorin~ : audio in position : %d", x->x_audioin_position );
      if ( x->x_audioin_position <= sn )
      {
         x->x_audioon = 0;
         // post( "pdp_theorin~ : audio off ( audioin : %d, channels=%d )", 
         //       x->x_audioin_position, x->x_audiochannels );
      }
    }
    else
    {
      // post("pdp_theorin~ : no available audio" );
      while (n--)
      {
        *(out1++) = 0.0;
        *(out2++) = 0.0;
      }
    }	

    // check if the framerate has been exceeded
    if ( gettimeofday(&etime, NULL) == -1)
    {
       post("pdp_theorin~ : could not read time" );
    }
    if ( etime.tv_sec != x->x_cursec )
    {
       x->x_cursec = etime.tv_sec;
       if (x->x_reading) outlet_float( x->x_outlet_framerate, x->x_secondcount );
       x->x_secondcount = 0;
    }

    // output image if there's a new one decoded
    if ( x->x_newpicture )
    {
       pdp_packet_pass_if_valid(x->x_pdp_out, &x->x_packet0);
       x->x_newpicture = 0;

       // update streaming status
       x->x_nbframes++;
       x->x_secondcount++;
       outlet_float( x->x_outlet_nbframes, x->x_nbframes );

    }
    if ( x->x_endoffile == 1 ) // only once
    {
      outlet_float( x->x_outlet_endoffile, x->x_endoffile );
      x->x_endoffile = 0;
    }
    if ( x->x_endoffile == -1 ) // reset
    {
      x->x_endoffile = 0;
      outlet_float( x->x_outlet_endoffile, x->x_endoffile );
    }

    return (w+5);
}

static void pdp_theorin_dsp(t_pdp_theorin *x, t_signal **sp)
{
    dsp_add(pdp_theorin_perform, 4, sp[0]->s_vec, sp[1]->s_vec, x, sp[0]->s_n);
}

static void pdp_theorin_free(t_pdp_theorin *x)
{
  int i;

    if ( x->x_decodechild )
    {
      x->x_decodechild = 0;
    }

    if ( x->x_reading )
    {
       pdp_theorin_close(x);
    }

    post( "pdp_theorin~ : freeing object" );
}

t_class *pdp_theorin_class;

void *pdp_theorin_new(void)
{
    int i;

    t_pdp_theorin *x = (t_pdp_theorin *)pd_new(pdp_theorin_class);

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

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

    x->x_outlet_left = outlet_new(&x->x_obj, &s_signal);
    x->x_outlet_right = outlet_new(&x->x_obj, &s_signal);

    x->x_outlet_nbframes = outlet_new(&x->x_obj, &s_float);
    x->x_outlet_framerate = outlet_new(&x->x_obj, &s_float);
    x->x_outlet_endoffile = outlet_new(&x->x_obj, &s_float);
    x->x_outlet_filesize = outlet_new(&x->x_obj, &s_float);

    x->x_packet0 = -1;
    x->x_decodechild = 0;
    x->x_decoding = 0;
    x->x_theorainit = 0;
    x->x_usethread = 1;
    x->x_priority = DEFAULT_PRIORITY;
    x->x_framerate = DEFAULT_FRAME_RATE;
    x->x_nbframes = 0;
    x->x_samplerate = 0;
    x->x_audio = 1;
    x->x_audiochannels = 0;
    x->x_audioin_position = 0;
    x->x_videoready = 0;
    x->x_newpicture = 0;
    x->x_newpictureready = 0;
    x->x_endoffile = 0;
    x->x_notpackets = 0;
    x->x_novpackets = 0;
    x->x_blocksize = MIN_AUDIO_SIZE;
    x->x_autoplay = 1;
    x->x_loop = 1;
    x->x_nextimage = 0;
    x->x_infile = NULL;
    x->x_reading = 0;

    memset( &x->x_audio_inl[0], 0x0, 4*MAX_AUDIO_PACKET_SIZE*sizeof(t_float) );
    memset( &x->x_audio_inr[0], 0x0, 4*MAX_AUDIO_PACKET_SIZE*sizeof(t_float) );

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_theorin_tilde_setup(void)
{
    // post( pdp_theorin_version );
    pdp_theorin_class = class_new(gensym("pdp_theorin~"), (t_newmethod)pdp_theorin_new,
    	(t_method)pdp_theorin_free, sizeof(t_pdp_theorin), 0, A_NULL);

    class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_dsp, gensym("dsp"), A_NULL);
    class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_open, gensym("open"), A_SYMBOL, A_NULL);
    class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_close, gensym("close"), A_NULL);
    class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_priority, gensym("priority"), A_FLOAT, A_NULL);
    class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_audio, gensym("audio"), A_FLOAT, A_NULL);
    class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_autoplay, gensym("autoplay"), A_FLOAT, A_NULL);
    class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_loop, gensym("loop"), A_FLOAT, A_NULL);
    class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_threadify, gensym("thread"), A_FLOAT, A_NULL);
    class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_bang, gensym("bang"), A_NULL);
    class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_frame_cold, gensym("frame_cold"), A_FLOAT, A_NULL);
    class_sethelpsymbol( pdp_theorin_class, gensym("pdp_theorin~.pd") );

}

#ifdef __cplusplus
}
#endif





More information about the Pd-cvs mailing list