aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/Makefile18
-rw-r--r--modules/Makefile.in18
-rw-r--r--modules/pdp_aa.c324
-rw-r--r--modules/pdp_aging.c380
-rw-r--r--modules/pdp_aging.c~0
-rw-r--r--modules/pdp_ascii.c258
-rw-r--r--modules/pdp_baltan.c232
-rw-r--r--modules/pdp_capture.c938
-rw-r--r--modules/pdp_cmap.c539
-rw-r--r--modules/pdp_compose.c459
-rw-r--r--modules/pdp_ctrack.c676
-rw-r--r--modules/pdp_cycle.c246
-rw-r--r--modules/pdp_dice.c345
-rw-r--r--modules/pdp_edge.c300
-rw-r--r--modules/pdp_ffmpeg~.c740
-rw-r--r--modules/pdp_form.c608
-rw-r--r--modules/pdp_i.c454
-rw-r--r--modules/pdp_imgloader.c300
-rw-r--r--modules/pdp_imgsaver.c340
-rw-r--r--modules/pdp_intrusion.c428
-rw-r--r--modules/pdp_juxta.c319
-rw-r--r--modules/pdp_lens.c339
-rw-r--r--modules/pdp_live~.c789
-rw-r--r--modules/pdp_lumafilt.c255
-rw-r--r--modules/pdp_mgrid.c336
-rw-r--r--modules/pdp_mosaic.c312
-rw-r--r--modules/pdp_nervous.c283
-rw-r--r--modules/pdp_noquark.c279
-rw-r--r--modules/pdp_o.c589
-rw-r--r--modules/pdp_puzzle.c421
-rw-r--r--modules/pdp_quark.c268
-rw-r--r--modules/pdp_radioactiv.c516
-rw-r--r--modules/pdp_rec~.c705
-rw-r--r--modules/pdp_rev.c261
-rw-r--r--modules/pdp_ripple.c567
-rw-r--r--modules/pdp_segsnd~.c412
-rw-r--r--modules/pdp_shagadelic.c307
-rw-r--r--modules/pdp_simura.c443
-rw-r--r--modules/pdp_smuck.c228
-rw-r--r--modules/pdp_spigot.c168
-rw-r--r--modules/pdp_spiral.c519
-rw-r--r--modules/pdp_text.c630
-rw-r--r--modules/pdp_transform.c357
-rw-r--r--modules/pdp_transition.c787
-rw-r--r--modules/pdp_underwatch.c244
-rw-r--r--modules/pdp_vertigo.c349
-rw-r--r--modules/pdp_warhol.c285
-rw-r--r--modules/pdp_warp.c352
-rw-r--r--modules/pdp_yqt.c444
-rw-r--r--modules/pdp_yvu2rgb.c185
50 files changed, 19552 insertions, 0 deletions
diff --git a/modules/Makefile b/modules/Makefile
new file mode 100644
index 0000000..996f668
--- /dev/null
+++ b/modules/Makefile
@@ -0,0 +1,18 @@
+current: all_modules
+
+include ../Makefile
+
+OBJECTS = pdp_intrusion.o pdp_yqt.o pdp_simura.o pdp_underwatch.o \
+ pdp_vertigo.o pdp_yvu2rgb.o pdp_lens.o pdp_baltan.o \
+ pdp_aging.o pdp_ripple.o pdp_warp.o pdp_rev.o \
+ pdp_mosaic.o pdp_edge.o pdp_spiral.o pdp_radioactiv.o \
+ pdp_warhol.o pdp_nervous.o pdp_quark.o pdp_spigot.o \
+ pdp_rec~.o pdp_o.o pdp_i.o pdp_mgrid.o pdp_ctrack.o \
+ pdp_cycle.o pdp_transform.o pdp_shagadelic.o \
+ pdp_dice.o pdp_puzzle.o pdp_text.o pdp_form.o \
+ pdp_compose.o pdp_cmap.o pdp_aa.o pdp_ascii.o \
+ pdp_ffmpeg~.o pdp_live~.o pdp_segsnd~.o pdp_noquark.o \
+ pdp_juxta.o pdp_capture.o pdp_smuck.o pdp_lumafilt.o \
+ pdp_transition.o pdp_imgloader.o pdp_imgsaver.o
+
+all_modules: $(OBJECTS)
diff --git a/modules/Makefile.in b/modules/Makefile.in
new file mode 100644
index 0000000..996f668
--- /dev/null
+++ b/modules/Makefile.in
@@ -0,0 +1,18 @@
+current: all_modules
+
+include ../Makefile
+
+OBJECTS = pdp_intrusion.o pdp_yqt.o pdp_simura.o pdp_underwatch.o \
+ pdp_vertigo.o pdp_yvu2rgb.o pdp_lens.o pdp_baltan.o \
+ pdp_aging.o pdp_ripple.o pdp_warp.o pdp_rev.o \
+ pdp_mosaic.o pdp_edge.o pdp_spiral.o pdp_radioactiv.o \
+ pdp_warhol.o pdp_nervous.o pdp_quark.o pdp_spigot.o \
+ pdp_rec~.o pdp_o.o pdp_i.o pdp_mgrid.o pdp_ctrack.o \
+ pdp_cycle.o pdp_transform.o pdp_shagadelic.o \
+ pdp_dice.o pdp_puzzle.o pdp_text.o pdp_form.o \
+ pdp_compose.o pdp_cmap.o pdp_aa.o pdp_ascii.o \
+ pdp_ffmpeg~.o pdp_live~.o pdp_segsnd~.o pdp_noquark.o \
+ pdp_juxta.o pdp_capture.o pdp_smuck.o pdp_lumafilt.o \
+ pdp_transition.o pdp_imgloader.o pdp_imgsaver.o
+
+all_modules: $(OBJECTS)
diff --git a/modules/pdp_aa.c b/modules/pdp_aa.c
new file mode 100644
index 0000000..ee159f9
--- /dev/null
+++ b/modules/pdp_aa.c
@@ -0,0 +1,324 @@
+/*
+ * PiDiP module
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 interface to aalib ( http://aa-project.sourceforge.net/aalib/ )
+ * converting an image to ASCII art
+ * Written by Yves Degoyon ( ydegoyon@free.fr )
+ */
+
+
+#include "pdp.h"
+#include "yuv.h"
+#include <math.h>
+#include <aalib.h>
+
+#define MAX_OPTIONS 20
+#define MAX_OPTION_LENGTH 20
+
+static char *pdp_aa_version = "pdp_aa: version 0.1, ASCII art output written by ydegoyon@free.fr ";
+
+typedef struct pdp_aa_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_packet1;
+ t_int x_dropped;
+ t_int x_queue_id;
+
+ t_outlet *x_outlet0;
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+
+ /* aalib structures */
+ aa_context *x_context; // a lot of things and image data
+ aa_renderparams x_renderparams; // rendering parameters
+ char* x_driver; // name of driver
+ t_int x_render; // rendering option
+
+ char **x_aa_options; // aa options passed as arguments
+ t_int x_nb_options; // number of aa options
+
+} t_pdp_aa;
+
+static void pdp_aa_allocate(t_pdp_aa *x)
+{
+ if ( !strcmp( x->x_driver, "X11" ) )
+ {
+ x->x_context = aa_init(&X11_d, &aa_defparams, NULL);
+ }
+ else if ( !strcmp( x->x_driver, "slang" ) )
+ {
+ x->x_context = aa_init(&slang_d, &aa_defparams, NULL);
+ }
+ else if ( !strcmp( x->x_driver, "stdout" ) )
+ {
+ x->x_context = aa_init(&stdout_d, &aa_defparams, NULL);
+ }
+ else if ( !strcmp( x->x_driver, "stderr" ) )
+ {
+ x->x_context = aa_init(&stderr_d, &aa_defparams, NULL);
+ }
+ else
+ {
+ post( "pdp_aa : unsupported driver : %s : using X11", x->x_driver );
+ strcpy( x->x_driver, "X11" );
+ pdp_aa_allocate( x );
+ return;
+ }
+
+ if (x->x_context == NULL)
+ {
+ post("pdp_aa : severe error : cannot initialize aalib !!!");
+ return;
+ }
+ else
+ {
+ post("pdp_aa : initialized context");
+ }
+ aa_setfont( x->x_context, &aa_font8 );
+}
+
+static void pdp_aa_free_ressources(t_pdp_aa *x)
+{
+ // if ( x->x_context ) aa_close( x->x_context ); // this crashes unfortunately
+}
+
+static void pdp_aa_render(t_pdp_aa *x, t_floatarg frender)
+{
+ if ( ((int)frender == 0) || ((int)frender == 1) )
+ {
+ x->x_render = (int)frender;
+ }
+}
+
+static void pdp_aa_driver(t_pdp_aa *x, t_symbol *sdriver)
+{
+ if ( ( !strcmp( sdriver->s_name, "X11" ) ) ||
+ ( !strcmp( sdriver->s_name, "slang" ) ) ||
+ ( !strcmp( sdriver->s_name, "stdout" ) ) ||
+ ( !strcmp( sdriver->s_name, "stderr" ) ) )
+ {
+ strcpy( x->x_driver, sdriver->s_name );
+ }
+ else
+ {
+ post( "pdp_aa : unsupported driver : %s : using X11", sdriver->s_name );
+ strcpy( x->x_driver, "X11" );
+ }
+ pdp_aa_free_ressources(x);
+ pdp_aa_allocate(x);
+}
+
+static void pdp_aa_process_yv12(t_pdp_aa *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, pixsum;
+ t_int px, py, ppx, ppy;
+ t_int hratio, wratio;
+
+ if ( ( (int)header->info.image.width != x->x_vwidth ) ||
+ ( (int)header->info.image.height != x->x_vheight ) )
+ {
+ pdp_aa_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_aa_allocate( x );
+ }
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ if ( aa_imgwidth(x->x_context) < x->x_vwidth )
+ {
+ wratio = x->x_vwidth / aa_imgwidth(x->x_context);
+ }
+ else
+ {
+ wratio = 1;
+ }
+ if ( aa_imgheight(x->x_context) < x->x_vheight )
+ {
+ hratio = x->x_vheight / aa_imgheight(x->x_context);
+ }
+ else
+ {
+ hratio = 1;
+ }
+
+ for(py=1; py<x->x_vheight; py+=hratio)
+ {
+ for(px=0; px<x->x_vwidth; px+=wratio)
+ {
+ pixsum = 0;
+ for ( ppy=0; ppy<hratio; ppy++ )
+ {
+ for ( ppx=0; ppx<wratio; ppx++ )
+ {
+ pixsum += (data[(py+ppy)*x->x_vwidth + (px+ppx)]>>7);
+ }
+ }
+ aa_putpixel(x->x_context, px/wratio, py/hratio, pixsum/(wratio*hratio));
+ }
+ }
+
+ if ( x->x_render )
+ {
+ aa_fastrender(x->x_context, 0, 0, aa_scrwidth(x->x_context), aa_scrheight(x->x_context));
+ aa_flush( x->x_context );
+ }
+
+ // post( "pdp_aa : ascii text : %s", x->x_context->textbuffer );
+
+ memcpy( newdata, data, (x->x_vsize+(x->x_vsize>>1))<<1 );
+
+ return;
+}
+
+static void pdp_aa_sendpacket(t_pdp_aa *x)
+{
+ /* delete source 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_aa_process(t_pdp_aa *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_aa_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_aa_process_yv12, pdp_aa_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_aa_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_aa_input_0(t_pdp_aa *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_aa_process(x);
+ }
+
+}
+
+static void pdp_aa_free(t_pdp_aa *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_aa_free_ressources(x);
+ for (i=0; i<MAX_OPTIONS; i++)
+ {
+ if (x->x_aa_options[ i ]) freebytes( x->x_aa_options[ i ], MAX_OPTION_LENGTH );
+ }
+ if (x->x_aa_options) freebytes( x->x_aa_options, MAX_OPTIONS*sizeof(char*) );
+ if (x->x_driver) freebytes( x->x_driver, MAX_OPTION_LENGTH );
+}
+
+t_class *pdp_aa_class;
+
+void *pdp_aa_new(void)
+{
+ int i;
+
+ t_pdp_aa *x = (t_pdp_aa *)pd_new(pdp_aa_class);
+
+ 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_driver = (char*) getbytes( MAX_OPTION_LENGTH );
+ strcpy( x->x_driver, "X11" );
+ x->x_render = 1;
+
+ // aa_setsupported( x->x_context, AA_EXTENDED );
+ x->x_aa_options = (char **) getbytes( MAX_OPTIONS*sizeof(char*) );
+ for (i=0; i<MAX_OPTIONS; i++)
+ {
+ x->x_aa_options[ i ] = (char*) getbytes( MAX_OPTION_LENGTH );
+ }
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_aa_setup(void)
+{
+ post( pdp_aa_version );
+ pdp_aa_class = class_new(gensym("pdp_aa"), (t_newmethod)pdp_aa_new,
+ (t_method)pdp_aa_free, sizeof(t_pdp_aa), 0, A_NULL);
+
+ class_addmethod(pdp_aa_class, (t_method)pdp_aa_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_aa_class, (t_method)pdp_aa_driver, gensym("driver"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_aa_class, (t_method)pdp_aa_render, gensym("render"), A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_aging.c b/modules/pdp_aging.c
new file mode 100644
index 0000000..f2317b2
--- /dev/null
+++ b/modules/pdp_aging.c
@@ -0,0 +1,380 @@
+/*
+ * PiDiP module
+ * Copyright (c) by Yves Degoyon ( ydegoyon@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 adaptation of aging effect from effectv
+ * Originally written by Fukuchi Kentaro & others
+ * Pd-fication by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+static char *pdp_aging_version = "pdp_aging: version 0.1, port of aging from effectv( Fukuchi Kentaro ) adapted by Yves Degoyon (ydegoyon@free.fr)";
+
+#define PDP_AGING_MAX_SCRATCHES 100
+static unsigned int fastrand_val;
+#define inline_fastrand() (fastrand_val=fastrand_val*1103515245+12345)
+
+typedef struct _scratch
+{
+ t_int life;
+ t_int x;
+ t_int dx;
+ t_int init;
+} scratch;
+
+typedef struct pdp_aging_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_area_scale;
+ t_int x_nb_scratches;
+ t_int x_dust_interval;
+ t_int x_pits_interval;
+ scratch x_scratches[PDP_AGING_MAX_SCRATCHES];
+
+} t_pdp_aging;
+
+static void pdp_aging_area_scale(t_pdp_aging *x, t_floatarg fscale )
+{
+ if ( (int) fscale > 1 )
+ {
+ x->x_area_scale = (int)fscale;
+ }
+}
+
+static void pdp_aging_scratches(t_pdp_aging *x, t_floatarg fscratches )
+{
+ if ( ( (int)fscratches < PDP_AGING_MAX_SCRATCHES ) && ( (int)fscratches>=0) )
+ {
+ x->x_nb_scratches = (int)fscratches;
+ }
+}
+
+static void pdp_aging_coloraging(t_pdp_aging *x, short int *src, short int *dest)
+{
+ short int a, b;
+ int i;
+
+ for(i=0; i<x->x_vsize; i++)
+ {
+ a = *src++;
+ b = (a & 0xfcfc)>>2;
+ *dest++ = a - b + 0x1818 + ((inline_fastrand()>>8)&0x1010);
+ }
+ // set all to b&w
+ for(i=x->x_vsize; i<( x->x_vsize + (x->x_vsize>>1) ); i++)
+ {
+ *dest++ = 0;
+ }
+}
+
+static void pdp_aging_scratching(t_pdp_aging *x, short int *dest)
+{
+ int i, y, y1, y2;
+ short int *p, a, b;
+ const int width = x->x_vwidth;
+ const int height = x->x_vheight;
+
+ for(i=0; i<x->x_nb_scratches; i++)
+ {
+ if(x->x_scratches[i].life)
+ {
+ x->x_scratches[i].x = x->x_scratches[i].x + x->x_scratches[i].dx;
+ if(x->x_scratches[i].x < 0 || x->x_scratches[i].x > width*256)
+ {
+ x->x_scratches[i].life = 0;
+ break;
+ }
+ p = dest + (x->x_scratches[i].x>>8);
+ if(x->x_scratches[i].init)
+ {
+ y1 = x->x_scratches[i].init;
+ x->x_scratches[i].init = 0;
+ }
+ else
+ {
+ y1 = 0;
+ }
+ x->x_scratches[i].life--;
+ if(x->x_scratches[i].life)
+ {
+ y2 = height;
+ }
+ else
+ {
+ y2 = inline_fastrand() % height;
+ }
+ for(y=y1; y<y2; y++)
+ {
+ a = *p & 0xfeff;
+ a += 0x2020;
+ b = a & 0x10100;
+ *p = a | (b - (b>>8));
+ p += width;
+ }
+ }
+ else
+ {
+ if((inline_fastrand()&0xf0000000) == 0)
+ {
+ x->x_scratches[i].life = 2 + (inline_fastrand()>>27);
+ x->x_scratches[i].x = inline_fastrand() % (width * 256);
+ x->x_scratches[i].dx = ((int)inline_fastrand())>>23;
+ x->x_scratches[i].init = (inline_fastrand() % (height-1))+1;
+ }
+ }
+ }
+}
+
+static void pdp_aging_dusts(t_pdp_aging *x, short int *dest)
+{
+ int dx[8] = { 1, 1, 0, -1, -1, -1, 0, 1};
+ int dy[8] = { 0, -1, -1, -1, 0, 1, 1, 1};
+ int i, j;
+ int dnum;
+ int d, len;
+ int px, py;
+ const int width = x->x_vwidth;
+ const int height = x->x_vheight;
+
+ if(x->x_dust_interval == 0)
+ {
+ if((inline_fastrand()&0xf0000000) == 0) {
+ x->x_dust_interval = inline_fastrand()>>29;
+ }
+ return;
+ }
+
+ dnum = x->x_area_scale*4 + (inline_fastrand()>>27);
+ for(i=0; i<dnum; i++)
+ {
+ px = inline_fastrand()%width;
+ py = inline_fastrand()%height;
+ d = inline_fastrand()>>29;
+ len = inline_fastrand()%x->x_area_scale + 5;
+ for(j=0; j<len; j++) {
+ dest[py*width + px] = 0x1010;
+ py += dy[d];
+ px += dx[d];
+ if(px<0 || px>=width) break;
+ if(py<0 || py>=height) break;
+ d = (d + inline_fastrand()%3 - 1) & 7;
+ }
+ }
+ x->x_dust_interval--;
+}
+
+static void pdp_aging_pits(t_pdp_aging *x, short int *dest)
+{
+ int i, j;
+ int pnum, size, pnumscale;
+ int px, py;
+ const int width = x->x_vwidth;
+ const int height = x->x_vheight;
+
+ pnumscale = x->x_area_scale * 2;
+ if(x->x_pits_interval)
+ {
+ pnum = pnumscale + (inline_fastrand()%pnumscale);
+ x->x_pits_interval--;
+ }
+ else
+ {
+ pnum = inline_fastrand()%pnumscale;
+ if((inline_fastrand()&0xf8000000) == 0)
+ {
+ x->x_pits_interval = (inline_fastrand()>>28) + 20;
+ }
+ }
+ for(i=0; i<pnum; i++)
+ {
+ px = inline_fastrand()%(width-1);
+ py = inline_fastrand()%(height-1);
+ size = inline_fastrand()>>28;
+ for(j=0; j<size; j++)
+ {
+ px = px + inline_fastrand()%3-1;
+ py = py + inline_fastrand()%3-1;
+ if(px<0 || px>=width) break;
+ if(py<0 || py>=height) break;
+ dest[py*width + px] = 0xc0c0;
+ }
+ }
+}
+
+static void pdp_aging_process_yv12(t_pdp_aging *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);
+ int i;
+
+ unsigned int totalnbpixels;
+ unsigned int u_offset;
+ unsigned int v_offset;
+ unsigned int totnbpixels;
+ short int *poy, *pou, *pov, *pny, *pnu, *pnv;
+ int px, py;
+ int noy, pos, nox;
+ int *p;
+
+ x->x_vwidth = header->info.image.width;
+ x->x_vheight = header->info.image.height;
+ x->x_vsize = x->x_vwidth*x->x_vheight;
+
+ totalnbpixels = x->x_vsize;
+ u_offset = x->x_vsize;
+ v_offset = x->x_vsize + (x->x_vsize>>2);
+ totnbpixels = x->x_vsize + (x->x_vsize>>1);
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ pdp_aging_coloraging( x, data, newdata );
+ pdp_aging_scratching( x, newdata );
+ pdp_aging_pits( x, newdata );
+ if ( x->x_area_scale > 1 ) pdp_aging_dusts( x, newdata );
+
+ return;
+}
+
+static void pdp_aging_sendpacket(t_pdp_aging *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_aging_process(t_pdp_aging *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_aging_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_aging_process_yv12, pdp_aging_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ // pdp_aging_process_packet(x);
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_aging_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_aging_input_0(t_pdp_aging *x, t_symbol *s, t_floatarg f)
+{
+ 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_aging_process(x);
+
+ }
+
+}
+
+static void pdp_aging_free(t_pdp_aging *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+
+}
+
+t_class *pdp_aging_class;
+
+void *pdp_aging_new(void)
+{
+ int i;
+
+ t_pdp_aging *x = (t_pdp_aging *)pd_new(pdp_aging_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("area_scale"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("scratches"));
+
+ 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_nb_scratches = 7;
+ x->x_area_scale=5;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_aging_setup(void)
+{
+// post( pdp_aging_version );
+ pdp_aging_class = class_new(gensym("pdp_aging"), (t_newmethod)pdp_aging_new,
+ (t_method)pdp_aging_free, sizeof(t_pdp_aging), 0, A_NULL);
+
+ class_addmethod(pdp_aging_class, (t_method)pdp_aging_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_aging_class, (t_method)pdp_aging_area_scale, gensym("area_scale"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_aging_class, (t_method)pdp_aging_scratches, gensym("scratches"), A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_aging.c~ b/modules/pdp_aging.c~
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/modules/pdp_aging.c~
diff --git a/modules/pdp_ascii.c b/modules/pdp_ascii.c
new file mode 100644
index 0000000..5d2dc50
--- /dev/null
+++ b/modules/pdp_ascii.c
@@ -0,0 +1,258 @@
+/*
+ * PiDiP module
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 ASCII art object replacing blocks with ASCII characters
+ * Written by Yves Degoyon ( ydegoyon@free.fr )
+ */
+
+
+#include "pdp.h"
+#include "yuv.h"
+#include "charmaps.h"
+#include <math.h>
+
+static char *pdp_ascii_version = "pdp_ascii: version 0.1, ASCII art output written by ydegoyon@free.fr";
+
+typedef struct pdp_ascii_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_packet1;
+ t_int x_dropped;
+ t_int x_queue_id;
+
+ t_outlet *x_outlet0;
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+
+ t_int x_color; // rendering color option
+ t_int x_brightness; // added value for brightness
+ t_float x_ratio; // character to pixel ratio
+
+} t_pdp_ascii;
+
+static void pdp_ascii_color(t_pdp_ascii *x, t_floatarg fcolor)
+{
+ if ( ((int)fcolor == 0) || ((int)fcolor == 1) )
+ {
+ x->x_color = (int)fcolor;
+ }
+}
+
+static void pdp_ascii_ratio(t_pdp_ascii *x, t_floatarg fratio)
+{
+ if ( ( fratio > 0) && ( x->x_ratio < x->x_vwidth/2 ) )
+ {
+ x->x_ratio = fratio;
+ }
+}
+
+static void pdp_ascii_brightness(t_pdp_ascii *x, t_floatarg fbrightness)
+{
+ if ( ((int)fbrightness > 0) && ((int)fbrightness < 255) )
+ {
+ x->x_brightness = (int)fbrightness;
+ }
+}
+
+static void pdp_ascii_process_yv12(t_pdp_ascii *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, pixsum;
+ t_int px, py, ppx, ppy;
+ t_int rank, value;
+ t_int pwidth, pheight;
+
+ x->x_vwidth = header->info.image.width;
+ x->x_vheight = header->info.image.height;
+ x->x_vsize = x->x_vwidth*x->x_vheight;
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ memset( newdata, 0x00, (x->x_vsize+(x->x_vsize>>1))<<1 );
+
+ pwidth = (int) CHARWIDTH*x->x_ratio;
+ if (pwidth==0) pwidth=1;
+ if (pwidth>x->x_vwidth) return;
+ pheight = (int) CHARHEIGHT*x->x_ratio;
+ if (pheight==0) pheight=1;
+ if (pheight>x->x_vheight) return;
+
+ for(py=1; py<x->x_vheight; py+=pheight)
+ {
+ for(px=0; px<x->x_vwidth; px+=pwidth)
+ {
+ pixsum = 0;
+ for ( ppy=0; ppy<pheight; ppy++ )
+ {
+ for ( ppx=0; ppx<pwidth; ppx++ )
+ {
+ pixsum += (data[(py+ppy)*x->x_vwidth + (px+ppx)]>>7);
+ }
+ }
+ rank = (pixsum/(pheight*pwidth))/2; // set the chosen character
+ for ( ppy=0; ppy<pheight; ppy++ )
+ {
+ for ( ppx=0; ppx<pwidth; ppx++ )
+ {
+ if ( ( px+ppx > x->x_vwidth ) ||
+ ( py+ppy > x->x_vheight ) )
+ {
+ break;
+ }
+ if ( charmaps[rank][((int)(ppy/x->x_ratio))*CHARWIDTH+((int)(ppx/x->x_ratio))] )
+ {
+ value = ( (2*rank+x->x_brightness) > 255 ) ? 255 : (2*rank+x->x_brightness);
+ newdata[(py+ppy)*x->x_vwidth+(px+ppx)] = (value)<<7;
+ if ( x->x_color )
+ {
+ newdata[x->x_vsize+((py+ppy)>>1)*(x->x_vwidth>>1)+((px+ppx)>>1)] =
+ data[x->x_vsize+((py+ppy)>>1)*(x->x_vwidth>>1)+((px+ppx)>>1)];
+ newdata[x->x_vsize+(x->x_vsize>>2)+((py+ppy)>>1)*(x->x_vwidth>>1)+((px+ppx)>>1)] =
+ data[x->x_vsize+(x->x_vsize>>2)+((py+ppy)>>1)*(x->x_vwidth>>1)+((px+ppx)>>1)];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return;
+}
+
+static void pdp_ascii_sendpacket(t_pdp_ascii *x)
+{
+ /* delete source 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_ascii_process(t_pdp_ascii *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_ascii_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_ascii_process_yv12, pdp_ascii_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_ascii_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_ascii_input_0(t_pdp_ascii *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_ascii_process(x);
+ }
+
+}
+
+static void pdp_ascii_free(t_pdp_ascii *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_ascii_class;
+
+void *pdp_ascii_new(void)
+{
+ int i;
+
+ t_pdp_ascii *x = (t_pdp_ascii *)pd_new(pdp_ascii_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ratio"));
+
+ 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_color = 1;
+ x->x_ratio = 1.;
+ x->x_brightness = 25;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_ascii_setup(void)
+{
+ post( pdp_ascii_version );
+ pdp_ascii_class = class_new(gensym("pdp_ascii"), (t_newmethod)pdp_ascii_new,
+ (t_method)pdp_ascii_free, sizeof(t_pdp_ascii), 0, A_NULL);
+
+ class_addmethod(pdp_ascii_class, (t_method)pdp_ascii_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_ascii_class, (t_method)pdp_ascii_color, gensym("color"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_ascii_class, (t_method)pdp_ascii_brightness, gensym("brightness"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_ascii_class, (t_method)pdp_ascii_ratio, gensym("ratio"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_baltan.c b/modules/pdp_baltan.c
new file mode 100644
index 0000000..b75c074
--- /dev/null
+++ b/modules/pdp_baltan.c
@@ -0,0 +1,232 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 adaptation of baltan effect from freej
+ * Originally written by Fukuchi Kentarou
+ * Adapted by Yves Degoyon
+ * Do not expect it to behave like effectv : well, it does things ....
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+#define PLANES 32
+
+#define STRIDE 8
+
+typedef struct pdp_baltan_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_planebuf;
+ t_int x_plane;
+ t_int x_pixels;
+ t_int x_dfts; /* the factor */
+
+} t_pdp_baltan;
+
+static void pdp_baltan_process_yv12(t_pdp_baltan *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);
+
+ unsigned int w = header->info.image.width;
+ unsigned int h = header->info.image.height;
+
+ unsigned int size = w*h;
+ unsigned int totalnbpixels = size;
+ unsigned int u_offset = size;
+ unsigned int v_offset = size + (size>>2);
+ unsigned int totnbpixels = size + (size>>1);
+
+ t_int i, cf;
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = w;
+ newheader->info.image.height = h;
+
+ /* allocate buffers if necessary */
+ if ( ( x->x_planebuf == NULL ) || ( (int)size != x->x_pixels ) )
+ {
+ if ( x->x_planebuf ) freebytes( x->x_planebuf, x->x_pixels*PLANES*sizeof(t_int) );
+
+ x->x_pixels = size;
+ x->x_planebuf = (t_int*)getbytes(x->x_pixels*PLANES*sizeof(t_int));
+ post("pdp_baltan : allocated plane buffer (size=%d)", x->x_pixels*PLANES*sizeof(t_int) );
+ bzero(x->x_planebuf, x->x_pixels*PLANES*sizeof(t_int));
+ x->x_plane = 0;
+ if ( !x->x_planebuf )
+ {
+ post( "pdp_baltan : serious error : unable to allocate buffers " ) ;
+ return;
+ }
+ }
+
+ /* process data packet */
+ for(i=0; i<x->x_pixels; i++)
+ {
+ *(x->x_planebuf+x->x_plane*x->x_pixels+i) = (data[i] & x->x_dfts)>>2;
+ }
+
+ cf = x->x_plane & (STRIDE-1);
+
+ for(i=0; i<x->x_pixels; i++) {
+ newdata[i] = *(x->x_planebuf+cf*x->x_pixels+i)
+ + *(x->x_planebuf+((cf+STRIDE)*x->x_pixels)+i)
+ + *(x->x_planebuf+((cf+2*STRIDE)*x->x_pixels)+i)
+ + *(x->x_planebuf+((cf+3*STRIDE)*x->x_pixels)+i);
+ *(x->x_planebuf+x->x_plane*x->x_pixels+i) = (newdata[i]&x->x_dfts)>>2;
+ }
+
+ x->x_plane++;
+ x->x_plane = x->x_plane & (PLANES-1);
+
+ /* leave the colors unchanged */
+ for( i=size; i<(int)totnbpixels; i++)
+ {
+ newdata[i] = data[i];
+ }
+
+ return;
+}
+
+static void pdp_baltan_sendpacket(t_pdp_baltan *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_baltan_process(t_pdp_baltan *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_baltan_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_baltan_process_yv12, pdp_baltan_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ // pdp_baltan_process_packet(x);
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_baltan_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_baltan_input_0(t_pdp_baltan *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_baltan_process(x);
+
+ }
+}
+
+static void pdp_baltan_dfts(t_pdp_baltan *x, t_floatarg fdfts )
+{
+ x->x_dfts = (t_int)fdfts;
+}
+
+static void pdp_baltan_free(t_pdp_baltan *x)
+{
+ if ( x->x_planebuf ) freebytes( x->x_planebuf, x->x_pixels*PLANES*sizeof(t_int) );
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_baltan_class;
+
+void *pdp_baltan_new(void)
+{
+ int i;
+
+ t_pdp_baltan *x = (t_pdp_baltan *)pd_new(pdp_baltan_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("dfts"));
+
+ 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_planebuf = NULL;
+ x->x_pixels = 0;
+ x->x_dfts = 0xfcfcfc;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_baltan_setup(void)
+{
+
+
+ pdp_baltan_class = class_new(gensym("pdp_baltan"), (t_newmethod)pdp_baltan_new,
+ (t_method)pdp_baltan_free, sizeof(t_pdp_baltan), 0, A_NULL);
+
+ class_addmethod(pdp_baltan_class, (t_method)pdp_baltan_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_baltan_class, (t_method)pdp_baltan_dfts, gensym("dfts"), A_DEFFLOAT, A_NULL);
+
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_capture.c b/modules/pdp_capture.c
new file mode 100644
index 0000000..f7e9292
--- /dev/null
+++ b/modules/pdp_capture.c
@@ -0,0 +1,938 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 lets you capture a portion of the screen
+ * and turn it into pdp packets
+ * ( inspired by ImageMagick code )
+ */
+
+#include "pdp.h"
+#include "yuv.h"
+#include <math.h>
+#include <assert.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <magick/api.h>
+#include <magick/magick.h>
+#include <magick/xwindow.h>
+
+#define PDP_DISPLAY_LENGTH 1024
+
+static char *pdp_capture_version = "pdp_capture: version 0.1, capture of screen written by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_capture_struct
+{
+ t_object x_obj;
+
+ t_outlet *x_outlet0;
+ t_int x_packet0;
+ short int *x_data;
+ t_pdp *x_header;
+ t_int x_displayopen;
+
+ char *x_display;
+ t_int x_screen;
+ t_int x_x;
+ t_int x_y;
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+
+ Image *x_Ximage;
+ Display *x_dpy;
+} t_pdp_capture;
+
+/***********************************************/
+/* this code is borrowed from ImageMagick */
+/* but not exported, sorry, guys and girls, */
+/* i only need that */
+/***********************************************/
+
+static Window XMyGetSubwindow(t_pdp_capture *o, Display *display, Window window, int x, int y)
+{
+ Window source_window, target_window;
+ int status, x_offset, y_offset;
+
+ assert(display != (Display *) NULL);
+ source_window=XRootWindow(display, o->x_screen);
+ if (window == (Window) NULL)
+ {
+ return(source_window);
+ }
+ target_window=window;
+ for ( ; ; )
+ {
+ status=XTranslateCoordinates(display,source_window,window,x,y, &x_offset,&y_offset,&target_window);
+ if (status != 1)
+ {
+ break;
+ }
+ if (target_window == (Window) NULL)
+ {
+ break;
+ }
+ source_window=window;
+ window=target_window;
+ x=x_offset;
+ y=y_offset;
+ }
+ if (target_window == (Window) NULL)
+ {
+ target_window=window;
+ }
+ return(target_window);
+}
+
+static Window XMyClientWindow(t_pdp_capture *o, Display *display,Window target_window)
+{
+ Atom state, type;
+ int format, status;
+ unsigned char *data;
+ unsigned long after, number_items;
+ Window client_window;
+
+ assert(display != (Display *) NULL);
+ state=XInternAtom(display,"WM_STATE",1);
+ if (state == (Atom) NULL)
+ {
+ return(target_window);
+ }
+ type=(Atom) NULL;
+ status=XGetWindowProperty(display,target_window,state,0L,0L,0, (Atom) AnyPropertyType,&type,&format,&number_items,&after,&data);
+ if ((status == Success) && (type != (Atom) NULL))
+ {
+ return(target_window);
+ }
+ client_window=XWindowByProperty(display,target_window,state);
+ if (client_window == (Window) NULL)
+ {
+ return(target_window);
+ }
+ return(client_window);
+}
+
+static Image *XMyGetWindowImage(t_pdp_capture *o, Display *display,const Window window, const unsigned int level)
+{
+ typedef struct _ColormapInfo
+ {
+ Colormap colormap;
+ XColor *colors;
+ struct _ColormapInfo *next;
+ } ColormapInfo;
+
+ typedef struct _WindowInfo
+ {
+ Window window, parent;
+ Visual *visual;
+ Colormap colormap;
+ XSegment bounds;
+ RectangleInfo crop_info;
+ } WindowInfo;
+
+ IndexPacket index;
+ int display_height, display_width, id, status, x_offset, y_offset;
+ RectangleInfo crop_info;
+ register IndexPacket *indexes;
+ register int i;
+ static ColormapInfo *colormap_info = (ColormapInfo *) NULL;
+ static int max_windows = 0, number_windows = 0;
+ static WindowInfo *window_info;
+ Window child, root_window;
+ XWindowAttributes window_attributes;
+
+ assert(display != (Display *) NULL);
+ status=XGetWindowAttributes(display,window,&window_attributes);
+ if ((status == 0) || (window_attributes.map_state != IsViewable))
+ {
+ return((Image *) NULL);
+ }
+ root_window=XRootWindow(display, o->x_screen );
+ (void) XTranslateCoordinates(display,window,root_window,0,0,&x_offset, &y_offset,&child);
+ crop_info.x=x_offset;
+ crop_info.y=y_offset;
+ crop_info.width=window_attributes.width;
+ crop_info.height=window_attributes.height;
+ if (crop_info.x < 0)
+ {
+ crop_info.width+=crop_info.x;
+ crop_info.x=0;
+ }
+ if (crop_info.y < 0)
+ {
+ crop_info.height+=crop_info.y;
+ crop_info.y=0;
+ }
+ display_width=XDisplayWidth(display, o->x_screen);
+ if ((int) (crop_info.x+crop_info.width) > display_width)
+ {
+ crop_info.width=display_width-crop_info.x;
+ }
+ display_height=XDisplayHeight(display, o->x_screen);
+ if ((int) (crop_info.y+crop_info.height) > display_height)
+ {
+ crop_info.height=display_height-crop_info.y;
+ }
+ if (number_windows >= max_windows)
+ {
+ max_windows+=1024;
+ if (window_info == (WindowInfo *) NULL)
+ {
+ window_info=(WindowInfo *) AcquireMemory(max_windows*sizeof(WindowInfo));
+ }
+ else
+ {
+ ReacquireMemory((void **) &window_info,max_windows*sizeof(WindowInfo));
+ }
+ }
+ if (window_info == (WindowInfo *) NULL)
+ {
+ post("pdp_capture : MemoryAllocationFailed : UnableToReadXImage");
+ return((Image *) NULL);
+ }
+ id=number_windows++;
+ window_info[id].window=window;
+ window_info[id].visual=window_attributes.visual;
+ window_info[id].colormap=window_attributes.colormap;
+ window_info[id].bounds.x1=(short) crop_info.x;
+ window_info[id].bounds.y1=(short) crop_info.y;
+ window_info[id].bounds.x2=(short) (crop_info.x+(int) crop_info.width-1);
+ window_info[id].bounds.y2=(short) (crop_info.y+(int) crop_info.height-1);
+ crop_info.x-=x_offset;
+ crop_info.y-=y_offset;
+
+ window_info[id].crop_info=crop_info;
+ if (level != 0)
+ {
+ unsigned int number_children;
+ Window *children;
+
+ status=XQueryTree(display,window,&root_window,&window_info[id].parent, &children,&number_children);
+ for (i=0; i < id; i++)
+ {
+ if ((window_info[i].window == window_info[id].parent) &&
+ (window_info[i].visual == window_info[id].visual) &&
+ (window_info[i].colormap == window_info[id].colormap))
+ {
+ if ((window_info[id].bounds.x1 <= window_info[i].bounds.x1) ||
+ (window_info[id].bounds.x1 >= window_info[i].bounds.x2) ||
+ (window_info[id].bounds.y1 <= window_info[i].bounds.y1) ||
+ (window_info[id].bounds.y1 >= window_info[i].bounds.y2))
+ {
+ number_windows--;
+ break;
+ }
+ }
+ }
+ if ((status == 1) && (number_children != 0))
+ {
+ (void) XFree((void *) children);
+ }
+ }
+ if (level <= 1)
+ {
+ ColormapInfo *next;
+ Image *composite_image, *image;
+ int y;
+ register int j, x;
+ register PixelPacket *q;
+ register unsigned long pixel;
+ unsigned int import, number_colors;
+ XColor *colors;
+ XImage *ximage;
+
+ image=(Image *) NULL;
+ for (id=0; id < number_windows; id++)
+ {
+ import=(window_info[id].bounds.x2 >= window_info[0].bounds.x1) &&
+ (window_info[id].bounds.x1 <= window_info[0].bounds.x2) &&
+ (window_info[id].bounds.y2 >= window_info[0].bounds.y1) &&
+ (window_info[id].bounds.y1 <= window_info[0].bounds.y2);
+ for (j=0; j < id; j++)
+ {
+ if ((window_info[id].visual == window_info[j].visual) &&
+ (window_info[id].colormap == window_info[j].colormap) &&
+ (window_info[id].bounds.x1 >= window_info[j].bounds.x1) &&
+ (window_info[id].bounds.y1 >= window_info[j].bounds.y1) &&
+ (window_info[id].bounds.x2 <= window_info[j].bounds.x2) &&
+ (window_info[id].bounds.y2 <= window_info[j].bounds.y2))
+ {
+ import=0;
+ }
+ else
+ {
+ if ((window_info[id].visual != window_info[j].visual) ||
+ (window_info[id].colormap != window_info[j].colormap))
+ {
+ if ((window_info[id].bounds.x2 > window_info[j].bounds.x1) &&
+ (window_info[id].bounds.x1 < window_info[j].bounds.x2) &&
+ (window_info[id].bounds.y2 > window_info[j].bounds.y1) &&
+ (window_info[id].bounds.y1 < window_info[j].bounds.y2))
+ {
+ import=1;
+ }
+ }
+ }
+ }
+ if (!import)
+ {
+ continue;
+ }
+ // post( "pdp_capture : get image : %ld [%d,%d,%d,%d]", window_info[id].window,
+ // (int) window_info[id].crop_info.x,
+ // (int) window_info[id].crop_info.y,
+ // (unsigned int) window_info[id].crop_info.width,
+ // (unsigned int) window_info[id].crop_info.height );
+ ximage=XGetImage(display,window_info[id].window,
+ (int) window_info[id].crop_info.x,(int) window_info[id].crop_info.y,
+ (unsigned int) window_info[id].crop_info.width,
+ (unsigned int) window_info[id].crop_info.height,AllPlanes,ZPixmap);
+ if (ximage == (XImage *) NULL)
+ {
+ continue;
+ }
+ number_colors=0;
+ colors=(XColor *) NULL;
+ if (window_info[id].colormap != (Colormap) NULL)
+ {
+ ColormapInfo *p;
+
+ number_colors=window_info[id].visual->map_entries;
+ for (p=colormap_info; p != (ColormapInfo *) NULL; p=p->next)
+ {
+ if (p->colormap == window_info[id].colormap)
+ {
+ break;
+ }
+ }
+ if (p == (ColormapInfo *) NULL)
+ {
+ colors=(XColor *) AcquireMemory(number_colors*sizeof(XColor));
+ if (colors == (XColor *) NULL)
+ {
+ XDestroyImage(ximage);
+ return((Image *) NULL);
+ }
+ if ((window_info[id].visual->storage_class != DirectColor) &&
+ (window_info[id].visual->storage_class != TrueColor))
+ {
+ for (i=0; i < (int) number_colors; i++)
+ {
+ colors[i].pixel=i;
+ colors[i].pad=0;
+ }
+ }
+ else
+ {
+ unsigned long blue, blue_bit, green, green_bit, red, red_bit;
+
+ red=0;
+ green=0;
+ blue=0;
+ red_bit=window_info[id].visual->red_mask &
+ (~(window_info[id].visual->red_mask)+1);
+ green_bit=window_info[id].visual->green_mask &
+ (~(window_info[id].visual->green_mask)+1);
+ blue_bit=window_info[id].visual->blue_mask &
+ (~(window_info[id].visual->blue_mask)+1);
+ for (i=0; i < (int) number_colors; i++)
+ {
+ colors[i].pixel=red | green | blue;
+ colors[i].pad=0;
+ red+=red_bit;
+ if (red > window_info[id].visual->red_mask)
+ red=0;
+ green+=green_bit;
+ if (green > window_info[id].visual->green_mask)
+ green=0;
+ blue+=blue_bit;
+ if (blue > window_info[id].visual->blue_mask)
+ blue=0;
+ }
+ }
+ (void) XQueryColors(display,window_info[id].colormap,colors, (int) number_colors);
+ p=(ColormapInfo *) AcquireMemory(sizeof(ColormapInfo));
+ if (p == (ColormapInfo *) NULL)
+ return((Image *) NULL);
+ p->colormap=window_info[id].colormap;
+ p->colors=colors;
+ p->next=colormap_info;
+ colormap_info=p;
+ }
+ colors=p->colors;
+ }
+ composite_image=AllocateImage((ImageInfo *) NULL);
+ if (composite_image == (Image *) NULL)
+ {
+ XDestroyImage(ximage);
+ return((Image *) NULL);
+ }
+ if ((window_info[id].visual->storage_class != TrueColor) &&
+ (window_info[id].visual->storage_class != DirectColor))
+ {
+ composite_image->storage_class=PseudoClass;
+ }
+ composite_image->columns=ximage->width;
+ composite_image->rows=ximage->height;
+ switch (composite_image->storage_class)
+ {
+ case DirectClass:
+ default:
+ {
+ register unsigned long color, index;
+ unsigned long blue_mask, blue_shift, green_mask, green_shift, red_mask, red_shift;
+
+ red_mask=window_info[id].visual->red_mask;
+ red_shift=0;
+ while ((red_mask & 0x01) == 0)
+ {
+ red_mask>>=1;
+ red_shift++;
+ }
+ green_mask=window_info[id].visual->green_mask;
+ green_shift=0;
+ while ((green_mask & 0x01) == 0)
+ {
+ green_mask>>=1;
+ green_shift++;
+ }
+ blue_mask=window_info[id].visual->blue_mask;
+ blue_shift=0;
+ while ((blue_mask & 0x01) == 0)
+ {
+ blue_mask>>=1;
+ blue_shift++;
+ }
+ if ((number_colors != 0) &&
+ (window_info[id].visual->storage_class == DirectColor))
+ {
+ for (y=0; y < (long) composite_image->rows; y++)
+ {
+ q=SetImagePixels(composite_image,0,y,
+ composite_image->columns,1);
+ if (q == (PixelPacket *) NULL)
+ break;
+ for (x=0; x < (long) composite_image->columns; x++)
+ {
+ pixel=XGetPixel(ximage,x,y);
+ index=(pixel >> red_shift) & red_mask;
+ q->red=ScaleShortToQuantum(colors[index].red);
+ index=(pixel >> green_shift) & green_mask;
+ q->green=ScaleShortToQuantum(colors[index].green);
+ index=(pixel >> blue_shift) & blue_mask;
+ q->blue=ScaleShortToQuantum(colors[index].blue);
+ q++;
+ }
+ if (!SyncImagePixels(composite_image))
+ break;
+ }
+ }
+ else
+ {
+ for (y=0; y < (long) composite_image->rows; y++)
+ {
+ q=SetImagePixels(composite_image,0,y,
+ composite_image->columns,1);
+ if (q == (PixelPacket *) NULL)
+ break;
+ for (x=0; x < (long) composite_image->columns; x++)
+ {
+ pixel=XGetPixel(ximage,x,y);
+ color=(pixel >> red_shift) & red_mask;
+ q->red=ScaleShortToQuantum((65535L*color)/red_mask);
+ color=(pixel >> green_shift) & green_mask;
+ q->green=ScaleShortToQuantum((65535L*color)/green_mask);
+ color=(pixel >> blue_shift) & blue_mask;
+ q->blue=ScaleShortToQuantum((65535L*color)/blue_mask);
+ q++;
+ }
+ if (!SyncImagePixels(composite_image))
+ {
+ break;
+ }
+ }
+ }
+ break;
+ }
+ case PseudoClass:
+ {
+ if (!AllocateImageColormap(composite_image,number_colors))
+ {
+ XDestroyImage(ximage);
+ DestroyImage(composite_image);
+ return((Image *) NULL);
+ }
+ for (i=0; i < (int) composite_image->colors; i++)
+ {
+ composite_image->colormap[colors[i].pixel].red=
+ ScaleShortToQuantum(colors[i].red);
+ composite_image->colormap[colors[i].pixel].green=
+ ScaleShortToQuantum(colors[i].green);
+ composite_image->colormap[colors[i].pixel].blue=
+ ScaleShortToQuantum(colors[i].blue);
+ }
+ for (y=0; y < (long) composite_image->rows; y++)
+ {
+ q=SetImagePixels(composite_image,0,y,composite_image->columns,1);
+ if (q == (PixelPacket *) NULL)
+ break;
+ indexes=GetIndexes(composite_image);
+ for (x=0; x < (long) composite_image->columns; x++)
+ {
+ index=(IndexPacket) XGetPixel(ximage,x,y);
+ indexes[x]=index;
+ *q++=composite_image->colormap[index];
+ }
+ if (!SyncImagePixels(composite_image))
+ {
+ break;
+ }
+ }
+ break;
+ }
+ }
+ XDestroyImage(ximage);
+ if (image == (Image *) NULL)
+ {
+ image=composite_image;
+ continue;
+ }
+ (void) XTranslateCoordinates(display,window_info[id].window,window,0,0, &x_offset,&y_offset,&child);
+ x_offset-=(int) crop_info.x;
+ if (x_offset < 0)
+ {
+ x_offset=0;
+ }
+ y_offset-=(int) crop_info.y;
+ if (y_offset < 0)
+ {
+ y_offset=0;
+ }
+ (void) CompositeImage(image,CopyCompositeOp,composite_image, x_offset,y_offset);
+ }
+ while (colormap_info != (ColormapInfo *) NULL)
+ {
+ next=colormap_info->next;
+ LiberateMemory((void **) &colormap_info->colors);
+ LiberateMemory((void **) &colormap_info);
+ colormap_info=next;
+ }
+ /*
+ Free resources and restore initial state.
+ */
+ LiberateMemory((void **) &window_info);
+ window_info=(WindowInfo *) NULL;
+ max_windows=0;
+ number_windows=0;
+ colormap_info=(ColormapInfo *) NULL;
+ return(image);
+ }
+ return((Image *) NULL);
+}
+
+/*************************************************/
+/* this code is adapted from ImageMagick */
+/* mainly because i don't want user interactions */
+/* and i want to chose the screen also */
+/*************************************************/
+
+static void pdp_capture_do_capture(t_pdp_capture *x)
+{
+ Colormap *colormaps;
+ Image *image;
+ int number_colormaps, number_windows, status, X, Y;
+ RectangleInfo crop_info;
+ Window *children, client, prior_target, root, target;
+ XTextProperty window_name;
+ Window child;
+ XWindowAttributes window_attributes;
+
+ /*
+ Open X server connection.
+ */
+ if (!x->x_displayopen)
+ {
+ post( "pdp_capture : display not open : no capture" );
+ return;
+ }
+ (void) XSetErrorHandler(XError);
+ crop_info.x=x->x_x;
+ crop_info.y=x->x_y;
+ crop_info.width=x->x_vwidth;
+ crop_info.height=x->x_vheight;
+ root=XRootWindow(x->x_dpy, x->x_screen);
+ target=(Window) NULL;
+ prior_target=target;
+
+ target = XMyGetSubwindow(x, x->x_dpy,root,x->x_x,x->x_y);
+
+ client=target; /* obsolete */
+ if (target != root)
+ {
+ unsigned int d;
+ status=XGetGeometry(x->x_dpy,target,&root,&X,&X,&d,&d,&d,&d);
+ if (status != 0)
+ {
+ for ( ; ; )
+ {
+ Window parent;
+
+ status=XQueryTree(x->x_dpy,target,&root,&parent,&children,&d);
+ if (status && (children != (Window *) NULL))
+ {
+ (void) XFree((char *) children);
+ }
+ if (!status || (parent == (Window) NULL) || (parent == root)) break;
+ target=parent;
+ }
+ client=XMyClientWindow(x, x->x_dpy, target);
+ target=client;
+ if (prior_target) target=prior_target;
+ }
+ }
+ status=XGetWindowAttributes(x->x_dpy,target,&window_attributes);
+ if (status == 0)
+ {
+ post( "pdp_capture : unable to read window attributes" );
+ (void) XCloseDisplay(x->x_dpy);
+ return;
+ }
+ (void) XTranslateCoordinates(x->x_dpy,target,root,0,0,&X,&Y,&child);
+ crop_info.x=x->x_x;
+ crop_info.y=x->x_y;
+ crop_info.width=x->x_vwidth;
+ crop_info.height=x->x_vheight;
+ target=root;
+
+ number_windows=0;
+ status=XGetWMColormapWindows(x->x_dpy,target,&children,&number_windows);
+ if ((status == 1) && (number_windows > 0))
+ {
+ (void) XFree ((char *) children);
+ }
+ colormaps=XListInstalledColormaps(x->x_dpy,target,&number_colormaps);
+ if (number_colormaps > 0)
+ {
+ (void) XFree((char *) colormaps);
+ }
+
+ image=XMyGetWindowImage(x, x->x_dpy, target, 1);
+ if (image == (Image *) NULL)
+ {
+ post( "pdp_capture : unable to read xwindow image" );
+ }
+ else
+ {
+ Image *clone_image;
+
+ clone_image=CloneImage(image,0,0,1,&image->exception);
+ if (clone_image != (Image *) NULL)
+ {
+ x->x_Ximage=CropImage(clone_image,&crop_info,&image->exception);
+ if (x->x_Ximage != (Image *) NULL)
+ {
+ DestroyImage(image);
+ DestroyImage(clone_image);
+ image=x->x_Ximage;
+ }
+ }
+ status=XGetWMName(x->x_dpy,target,&window_name);
+ }
+ return;
+}
+
+static void pdp_capture_display(t_pdp_capture *x, t_symbol *s)
+{
+ if ( x->x_displayopen )
+ {
+ if ( XCloseDisplay(x->x_dpy) == -1 )
+ {
+ post( "pdp_capture : could not close display" );
+ }
+ }
+ strcpy( x->x_display, s->s_name );
+ if ( ( x->x_dpy = XOpenDisplay( x->x_display ) ) != NULL )
+ {
+ x->x_displayopen = 1;
+
+ x->x_vwidth=XDisplayWidth(x->x_dpy, x->x_screen);
+ x->x_vheight=XDisplayHeight(x->x_dpy, x->x_screen);
+ x->x_vsize=x->x_vwidth*x->x_vheight;
+
+ }
+}
+
+static void pdp_capture_screen(t_pdp_capture *x, t_floatarg fscreen)
+{
+ if ( (int)fscreen > 0 )
+ {
+ x->x_screen = (int) fscreen;
+ }
+}
+
+static void pdp_capture_x(t_pdp_capture *x, t_floatarg fx)
+{
+ t_int width;
+ t_int err;
+
+ if (!x->x_displayopen)
+ {
+ post( "pdp_capture : display not open : not setting x" );
+ return;
+ }
+ width = XDisplayWidth( x->x_dpy, x->x_screen );
+ if ( ( (int)fx > 0 ) && ( (int)fx <= width ) )
+ {
+ x->x_x = (int) fx;
+ if ( x->x_x + x->x_vwidth > width )
+ {
+ x->x_vwidth = width - x->x_x;
+ x->x_vsize = x->x_vwidth * x->x_vheight;
+ }
+ }
+ else
+ {
+ post( "pdp_capture : x position out of range : [0, %d]", width );
+ }
+}
+
+static void pdp_capture_y(t_pdp_capture *x, t_floatarg fy)
+{
+ t_int height;
+ t_int err;
+
+ if (!x->x_displayopen)
+ {
+ post( "pdp_capture : display not open : not setting y" );
+ return;
+ }
+ height = XDisplayHeight( x->x_dpy, x->x_screen );
+ if ( ( (int)fy > 0 ) && ( (int)fy <= height ) )
+ {
+ x->x_y = (int) fy;
+ if ( x->x_y + x->x_vheight > height )
+ {
+ x->x_vheight = height - x->x_y;
+ x->x_vsize = x->x_vwidth * x->x_vheight;
+ }
+ }
+ else
+ {
+ post( "pdp_capture : y position out of range : [0, %d]", height );
+ }
+}
+
+static void pdp_capture_width(t_pdp_capture *x, t_floatarg fwidth)
+{
+ t_int width;
+ t_int err;
+
+ if (!x->x_displayopen)
+ {
+ post( "pdp_capture : display not open : not setting width" );
+ return;
+ }
+ width = XDisplayWidth( x->x_dpy, x->x_screen );
+ if ( ( (int)fwidth > 0 ) && ( (int)fwidth <= (width-x->x_x) ) )
+ {
+ x->x_vwidth = (int) fwidth;
+ x->x_vsize = x->x_vwidth * x->x_vheight;
+ }
+ else
+ {
+ post( "pdp_capture : width out of range : [0, %d]", width-x->x_x );
+ }
+}
+
+static void pdp_capture_height(t_pdp_capture *x, t_floatarg fheight)
+{
+ t_int height;
+ t_int err;
+
+ if (!x->x_displayopen)
+ {
+ post( "pdp_capture : display not open : not setting height" );
+ return;
+ }
+ height = XDisplayWidth( x->x_dpy, x->x_screen );
+ if ( ( (int)fheight > 0 ) && ( (int)fheight <= (height-x->x_y) ) )
+ {
+ x->x_vheight = (int) fheight;
+ x->x_vsize = x->x_vwidth * x->x_vheight;
+ }
+ else
+ {
+ post( "pdp_capture : width out of range : [0, %d]", height-x->x_y );
+ }
+}
+
+static void pdp_capture_sendpacket(t_pdp_capture *x)
+{
+ /* unregister and propagate if valid dest packet */
+ if (x->x_packet0 != -1 )
+ {
+ pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet0);
+ }
+}
+
+static void pdp_capture_bang(t_pdp_capture *x)
+{
+ PixelPacket pixel;
+ short int *pY, *pU, *pV;
+ unsigned char y, u, v;
+ t_int px, py, r, g, b;
+ long number_pixels;
+
+ // capture the image and output a PDP packet
+ pdp_capture_do_capture( x );
+
+ x->x_vwidth = x->x_Ximage->columns;
+ x->x_vheight = x->x_Ximage->rows;
+ x->x_vsize = x->x_vwidth*x->x_vheight;
+
+ x->x_packet0 = pdp_packet_new_image_YCrCb( x->x_vwidth, x->x_vheight );
+ x->x_data = (short int *)pdp_packet_data(x->x_packet0);
+ x->x_header = pdp_packet_header(x->x_packet0);
+
+ x->x_header->info.image.encoding = PDP_IMAGE_YV12;
+ x->x_header->info.image.width = x->x_vwidth;
+ x->x_header->info.image.height = x->x_vheight;
+
+ number_pixels=(long) GetPixelCacheArea(x->x_Ximage);
+
+ // post( "pdp_capture : capture done : w=%d h=%d pixels=%ld", x->x_vwidth, x->x_vheight, number_pixels );
+
+ pY = x->x_data;
+ pV = x->x_data+x->x_vsize;
+ pU = x->x_data+x->x_vsize+(x->x_vsize>>2);
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ pixel = GetOnePixel(x->x_Ximage, px, py);
+ // scale values
+ r = (pixel.red*255)/65535;
+ g = (pixel.green*255)/65535;
+ b = (pixel.blue*255)/65535;
+ // post( "pdp_capture : pixel : [%d, %d] : %d,%d,%d", px, py, r, g, b );
+ y = yuv_RGBtoY(((r)<<16)+((g)<<8)+(b));
+ u = yuv_RGBtoU(((r)<<16)+((g)<<8)+(b));
+ v = yuv_RGBtoV(((r)<<16)+((g)<<8)+(b));
+
+ *(pY) = y<<7;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ *(pV) = (v-128)<<8;
+ *(pU) = (u-128)<<8;
+ }
+ pY++;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ pV++;pU++;
+ }
+ }
+ }
+
+ // output the new packet
+ pdp_capture_sendpacket( x );
+
+ DestroyImage( x->x_Ximage );
+}
+
+static void pdp_capture_free(t_pdp_capture *x)
+{
+ int i;
+
+ if ( x->x_packet0 != -1 )
+ {
+ pdp_packet_mark_unused(x->x_packet0);
+ }
+ if ( x->x_displayopen )
+ {
+ if ( XCloseDisplay(x->x_dpy) == -1 )
+ {
+ post( "pdp_capture : could not close display" );
+ }
+ }
+}
+
+t_class *pdp_capture_class;
+
+void *pdp_capture_new(void)
+{
+ int i;
+
+ t_pdp_capture *x = (t_pdp_capture *)pd_new(pdp_capture_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("x"));
+ 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("width"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("height"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ x->x_packet0 = -1;
+
+ x->x_display = (char *) malloc( PDP_DISPLAY_LENGTH );
+ strcpy( x->x_display, ":0.0" );
+
+ x->x_displayopen = 0;
+ if ( ( x->x_dpy = XOpenDisplay( x->x_display ) ) != NULL )
+ {
+ x->x_displayopen = 1;
+
+ x->x_vwidth=XDisplayWidth(x->x_dpy, x->x_screen);
+ x->x_vheight=XDisplayWidth(x->x_dpy, x->x_screen);
+ x->x_vsize=x->x_vwidth*x->x_vheight;
+
+ }
+
+ x->x_screen = 0;
+ x->x_x = 0;
+ x->x_y = 0;
+ x->x_vwidth = 320;
+ x->x_vheight = 240;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_capture_setup(void)
+{
+ post( pdp_capture_version );
+ pdp_capture_class = class_new(gensym("pdp_capture"), (t_newmethod)pdp_capture_new,
+ (t_method)pdp_capture_free, sizeof(t_pdp_capture), 0, A_NULL);
+
+ class_addmethod(pdp_capture_class, (t_method)pdp_capture_bang, gensym("bang"), A_NULL);
+ class_addmethod(pdp_capture_class, (t_method)pdp_capture_display, gensym("display"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_capture_class, (t_method)pdp_capture_screen, gensym("screen"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_capture_class, (t_method)pdp_capture_x, gensym("x"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_capture_class, (t_method)pdp_capture_y, gensym("y"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_capture_class, (t_method)pdp_capture_width, gensym("width"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_capture_class, (t_method)pdp_capture_height, gensym("height"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_cmap.c b/modules/pdp_cmap.c
new file mode 100644
index 0000000..3d8524f
--- /dev/null
+++ b/modules/pdp_cmap.c
@@ -0,0 +1,539 @@
+/*
+ * PiDiP module
+ * Copyright (c) by Yves Degoyon ( ydegoyon@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 color mapper that lets you change the colors within the image
+ */
+
+#include "pdp.h"
+#include "yuv.h"
+#include <math.h>
+#include <stdio.h>
+
+struct _rtext
+{
+ char *x_buf;
+ int x_bufsize;
+ int x_selstart;
+ int x_selend;
+ int x_active;
+ int x_dragfrom;
+ int x_height;
+ int x_drawnwidth;
+ int x_drawnheight;
+ t_text *x_text;
+ t_glist *x_glist;
+ char x_tag[50];
+ struct _rtext *x_next;
+};
+
+#define t_rtext struct _rtext
+
+extern int rtext_width(t_rtext *x);
+extern int rtext_height(t_rtext *x);
+extern t_rtext *glist_findrtext(t_glist *gl, t_text *who);
+
+typedef struct _color
+{
+ t_int on;
+ t_int y,u,v;
+ t_int oy,ou,ov;
+ t_int tolerance;
+} t_color;
+
+#define COLORHEIGHT 5
+#define DEFAULT_CAPACITY 10
+
+static char *pdp_cmap_version = "pdp_cmap: a color mapper version 0.1 written by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_cmap_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_dropped;
+
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+
+ t_int x_capacity; // number of mapped colors
+ t_int x_current; // current color
+ t_color *x_colors; // color substitution table
+
+ t_int x_cursor; // show cursor or not
+ t_int x_luminosity; // use luminosity or not
+
+ t_int x_colorR; // setable r
+ t_int x_colorG; // setable g
+ t_int x_colorB; // setable b
+
+ t_int x_cursX; // X coordinate of cursor
+ t_int x_cursY; // Y coordinate of cursor
+ short int *x_frame; // keep a copy of current frame for picking color
+
+ t_outlet *x_pdp_output; // output packets
+
+ t_canvas *x_canvas;
+
+} t_pdp_cmap;
+
+static void pdp_cmap_draw_color(t_pdp_cmap *x, t_int r, t_int g, t_int b)
+{
+ t_int width, height;
+ char color[32];
+
+ sprintf( color, "#%.2X%.2X%.2X", r, g, b );
+ width = rtext_width( glist_findrtext( (t_glist*)x->x_canvas, (t_text *)x ) );
+ height = rtext_height( glist_findrtext( (t_glist*)x->x_canvas, (t_text *)x ) );
+ sys_vgui(".x%x.c delete rectangle %xCOLOR\n", x->x_canvas, x );
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -fill %s -tags %xCOLOR\n",
+ x->x_canvas, x->x_obj.te_xpix+width+5, x->x_obj.te_ypix,
+ x->x_obj.te_xpix+width+height+5,
+ x->x_obj.te_ypix+height, color, x );
+}
+
+static void pdp_cmap_r(t_pdp_cmap *x, t_floatarg fr )
+{
+ if ( ( fr >= 0 ) && ( fr < 255 ) )
+ {
+ x->x_colorR = (int)fr;
+ x->x_colors[x->x_current].y = (yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ))<<7;
+ x->x_colors[x->x_current].u = (yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ x->x_colors[x->x_current].v = (yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ pdp_cmap_draw_color( x, x->x_colorR, x->x_colorG, x->x_colorB );
+ }
+}
+
+static void pdp_cmap_g(t_pdp_cmap *x, t_floatarg fg )
+{
+ if ( ( fg >= 0 ) && ( fg < 255 ) )
+ {
+ x->x_colorG = (int)fg;
+ x->x_colors[x->x_current].y = (yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ))<<7;
+ x->x_colors[x->x_current].u = (yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ x->x_colors[x->x_current].v = (yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ pdp_cmap_draw_color( x, x->x_colorR, x->x_colorG, x->x_colorB );
+ }
+}
+
+static void pdp_cmap_b(t_pdp_cmap *x, t_floatarg fb )
+{
+ if ( ( fb >= 0 ) && ( fb < 255 ) )
+ {
+ x->x_colorB = (int)fb;
+ x->x_colors[x->x_current].y = (yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ))<<7;
+ x->x_colors[x->x_current].u = (yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ x->x_colors[x->x_current].v = (yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ pdp_cmap_draw_color( x, x->x_colorR, x->x_colorG, x->x_colorB );
+ }
+}
+
+static void pdp_cmap_cursx(t_pdp_cmap *x, t_floatarg fx )
+{
+ if ( ( fx >= 0 ) && ( fx < x->x_vwidth) )
+ {
+ x->x_cursX = (int)fx;
+ }
+}
+
+static void pdp_cmap_cursy(t_pdp_cmap *x, t_floatarg fy )
+{
+ if ( ( fy >= 0 ) && ( fy < x->x_vheight) )
+ {
+ x->x_cursY = (int)fy;
+ }
+}
+
+static void pdp_cmap_tolerance(t_pdp_cmap *x, t_floatarg ftolerance )
+{
+ if ( ftolerance >= 0 )
+ {
+ x->x_colors[x->x_current].tolerance = (int)ftolerance;
+ }
+}
+
+static void pdp_cmap_luminosity(t_pdp_cmap *x, t_floatarg fluminosity )
+{
+ if ( ( fluminosity == 0 ) || ( fluminosity == 1 ) )
+ {
+ x->x_luminosity = (int)fluminosity;
+ }
+}
+
+static void pdp_cmap_delete(t_pdp_cmap *x, t_floatarg fcolor )
+{
+ if ( ( fcolor >= 0 ) && ( fcolor < x->x_capacity ) )
+ {
+ x->x_colors[(int)fcolor].on = 0;
+ }
+}
+
+static void pdp_cmap_clear(t_pdp_cmap *x)
+{
+ t_int ci;
+
+ for ( ci=0; ci<x->x_capacity; ci++)
+ {
+ x->x_colors[ci].on = 0;
+ }
+ x->x_current = 0;
+}
+
+static void pdp_cmap_resize(t_pdp_cmap *x, t_floatarg fnewsize )
+{
+ t_color *colors;
+ t_int ci, csize;
+
+ if ( (int) fnewsize<=0 ) return;
+
+ // allocate new structures
+ colors = (t_color*) getbytes( fnewsize*sizeof(t_color) );
+
+ for ( ci=0; ci<fnewsize; ci++ )
+ {
+ colors[ci].on = 0;
+ colors[ci].tolerance = 10;
+ }
+
+ if ( fnewsize < x->x_capacity )
+ {
+ post( "pdp_form : new size is too small : texts lost !!" );
+ csize = fnewsize;
+ }
+ else
+ {
+ csize = x->x_capacity;
+ }
+
+ // copy all values
+ for ( ci=0; ci<csize; ci++ )
+ {
+ memcpy( &colors[ci], &x->x_colors[ci], sizeof( t_color ) );
+ }
+
+ // free old structures
+ if ( x->x_colors ) freebytes( x->x_colors, x->x_capacity*sizeof(t_color) );
+
+ // set new structures
+ x->x_colors = colors;
+ x->x_capacity = fnewsize;
+ x->x_current = 0;
+}
+
+static void pdp_cmap_setcur(t_pdp_cmap *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_cmap_current(t_pdp_cmap *x, t_floatarg fcurrent )
+{
+ if ( ( fcurrent >= 0 ) && ( fcurrent < x->x_capacity ) )
+ {
+ x->x_current = (int)fcurrent;
+ post( "pdp_cmap : color index set to : %d", x->x_current );
+ }
+}
+
+static void pdp_cmap_cursor(t_pdp_cmap *x, t_floatarg fcursor )
+{
+ if ( ( fcursor == 0 ) || ( fcursor == 1 ) )
+ {
+ x->x_cursor = (int)fcursor;
+ }
+}
+
+static void pdp_cmap_pick(t_pdp_cmap *x)
+{
+ t_int y,u,v;
+
+ if ( x->x_frame && ( x->x_cursX > 0 ) && ( x->x_cursX < x->x_vwidth )
+ && ( x->x_cursY > 0 ) && ( x->x_cursY < x->x_vheight ) )
+ {
+ x->x_colors[x->x_current].oy = x->x_frame[ x->x_cursY*x->x_vwidth+x->x_cursX ];
+ x->x_colors[x->x_current].ov = x->x_frame[ x->x_vsize+((x->x_cursY>>1)*(x->x_vwidth>>1)+(x->x_cursX>>1)) ];
+ x->x_colors[x->x_current].ou = x->x_frame[ x->x_vsize+(x->x_vsize>>2)+((x->x_cursY>>1)*(x->x_vwidth>>1)+(x->x_cursX>>1)) ];
+ y = (x->x_colors[x->x_current].oy)>>7;
+ v = (x->x_colors[x->x_current].ov>>8)+128;
+ u = (x->x_colors[x->x_current].ou>>8)+128;
+ x->x_colorR = yuv_YUVtoR( y, u, v );
+ x->x_colorG = yuv_YUVtoG( y, u, v );
+ x->x_colorB = yuv_YUVtoB( y, u, v );
+ pdp_cmap_draw_color( x, x->x_colorR, x->x_colorG, x->x_colorB );
+ x->x_colors[x->x_current].y = 255;
+ x->x_colors[x->x_current].u = 255;
+ x->x_colors[x->x_current].v = 255;
+ x->x_colors[x->x_current].on = 1;
+ }
+}
+
+static void pdp_cmap_allocate(t_pdp_cmap *x)
+{
+ x->x_frame = (short int *) getbytes ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );
+
+ if ( !x->x_frame )
+ {
+ post( "pdp_mgrid : severe error : cannot allocate buffer !!! ");
+ return;
+ }
+}
+
+static void pdp_cmap_free_ressources(t_pdp_cmap *x)
+{
+ if ( x->x_frame ) freebytes ( x->x_frame, ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );
+}
+
+static void pdp_cmap_process_yv12(t_pdp_cmap *x)
+{
+ t_pdp *header = pdp_packet_header(x->x_packet0);
+ short int *data = (short int *)pdp_packet_data(x->x_packet0);
+ t_int i, ci;
+ t_int px=0, py=0, ppx=0, ppy=0;
+ t_int y=0, u=0, v=0;
+ short int *pfY, *pfU, *pfV;
+ short int *poY, *poU, *poV;
+ t_int diff;
+
+ /* allocate all ressources */
+ if ( ( (int)header->info.image.width != x->x_vwidth ) ||
+ ( (int)header->info.image.height != x->x_vheight ) )
+ {
+ pdp_cmap_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_cmap_allocate( x );
+ post( "pdp_cmap : reallocated buffers" );
+ }
+
+ memcpy(x->x_frame, data, (x->x_vsize + (x->x_vsize>>1))<<1 );
+
+ // map colors
+ for ( ci=0; ci<x->x_capacity; ci++ )
+ {
+ if ( x->x_colors[ci].on )
+ {
+ pfY = data;
+ pfV = data+x->x_vsize;
+ pfU = data+x->x_vsize+(x->x_vsize>>2);
+ poY = x->x_frame;
+ poV = x->x_frame+x->x_vsize;
+ poU = x->x_frame+x->x_vsize+(x->x_vsize>>2);
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ y = *poY;
+ v = *poV;
+ u = *poU;
+
+ if ( x->x_luminosity )
+ {
+ diff = (abs(y-x->x_colors[ci].oy)>>7)+(abs(u-x->x_colors[ci].ou)>>8)+(abs(v-x->x_colors[ci].ov)>>8);
+ }
+ else
+ {
+ diff = (abs(u-x->x_colors[ci].ou)>>8)+(abs(v-x->x_colors[ci].ov)>>8);
+ }
+
+ if ( diff <= x->x_colors[ci].tolerance )
+ {
+ // change color not luminosity
+ // *pfY = x->x_colors[ci].y;
+ *pfV = x->x_colors[ci].v;
+ *pfU = x->x_colors[ci].u;
+ }
+
+ pfY++;poY++;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ pfU++;pfV++;
+ poU++;poV++;
+ }
+ }
+ }
+ }
+ }
+
+ // draw cursor
+ if ( ( x->x_cursX > 0 ) && ( x->x_cursY > 0 ) && ( x->x_cursor ) )
+ {
+ for ( px=(x->x_cursX-5); px<=(x->x_cursX+5); px++ )
+ {
+ if ( ( px > 0 ) && ( px < x->x_vwidth ) )
+ {
+ if ( ((*(data+x->x_cursY*x->x_vwidth+px))>>7) < 128 )
+ {
+ *(data+x->x_cursY*x->x_vwidth+px) = 0xff<<7;
+ }
+ else
+ {
+ *(data+x->x_cursY*x->x_vwidth+px) = 0x00<<7;
+ }
+ }
+ }
+ for ( py=(x->x_cursY-5); py<=(x->x_cursY+5); py++ )
+ {
+ if ( ( py > 0 ) && ( py < x->x_vheight ) )
+ {
+ if ( ((*(data+py*x->x_vwidth+x->x_cursX))>>7) < 128 )
+ {
+ *(data+py*x->x_vwidth+x->x_cursX) = 0xff<<7;
+ }
+ else
+ {
+ *(data+py*x->x_vwidth+x->x_cursX) = 0x00<<7;
+ }
+ }
+ }
+ }
+
+ pdp_packet_pass_if_valid(x->x_pdp_output, &x->x_packet0);
+
+ return;
+}
+
+static void pdp_cmap_process(t_pdp_cmap *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_cmap_process inputs and write into active inlet */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_cmap_process_yv12(x);
+ 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_cmap_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_cmap_input_0(t_pdp_cmap *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_cmap_process(x);
+
+ }
+}
+
+static void pdp_cmap_free(t_pdp_cmap *x)
+{
+ int i;
+
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_cmap_free_ressources( x );
+}
+
+t_class *pdp_cmap_class;
+
+void *pdp_cmap_new(void)
+{
+ t_int ci;
+
+ t_pdp_cmap *x = (t_pdp_cmap *)pd_new(pdp_cmap_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("current"));
+ 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("R"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("G"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("B"));
+ 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_packet0 = -1;
+
+ x->x_cursX = -1;
+ x->x_cursY = -1;
+ x->x_cursor = 1;
+ x->x_luminosity = 1;
+
+ x->x_capacity = DEFAULT_CAPACITY;
+ x->x_current = 0;
+ x->x_colors = (t_color *) getbytes( x->x_capacity*sizeof(t_color) );
+ for ( ci=0; ci<x->x_capacity; ci++)
+ {
+ x->x_colors[ci].on = 0;
+ x->x_colors[ci].tolerance = 10;
+ }
+
+ x->x_canvas = canvas_getcurrent();
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_cmap_setup(void)
+{
+ post( pdp_cmap_version );
+ pdp_cmap_class = class_new(gensym("pdp_cmap"), (t_newmethod)pdp_cmap_new,
+ (t_method)pdp_cmap_free, sizeof(t_pdp_cmap), 0, A_NULL);
+
+ class_addmethod(pdp_cmap_class, (t_method)pdp_cmap_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_cmap_class, (t_method)pdp_cmap_r, gensym("R"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_cmap_class, (t_method)pdp_cmap_g, gensym("G"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_cmap_class, (t_method)pdp_cmap_b, gensym("B"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_cmap_class, (t_method)pdp_cmap_cursx, gensym("cursx"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_cmap_class, (t_method)pdp_cmap_cursy, gensym("cursy"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_cmap_class, (t_method)pdp_cmap_pick, gensym("pick"), A_NULL);
+ class_addmethod(pdp_cmap_class, (t_method)pdp_cmap_tolerance, gensym("tolerance"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_cmap_class, (t_method)pdp_cmap_cursor, gensym("cursor"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_cmap_class, (t_method)pdp_cmap_luminosity, gensym("luminosity"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_cmap_class, (t_method)pdp_cmap_current, gensym("current"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_cmap_class, (t_method)pdp_cmap_clear, gensym("clear"), A_NULL);
+ class_addmethod(pdp_cmap_class, (t_method)pdp_cmap_delete, gensym("delete"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_cmap_class, (t_method)pdp_cmap_resize, gensym("resize"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_cmap_class, (t_method)pdp_cmap_setcur, gensym("setcur"), A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_compose.c b/modules/pdp_compose.c
new file mode 100644
index 0000000..ed2a5b3
--- /dev/null
+++ b/modules/pdp_compose.c
@@ -0,0 +1,459 @@
+/*
+ * PiDiP module
+ * Copyright (c) by Yves Degoyon ( ydegoyon@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 compositor mixing two sources
+ * idea expressed by liz
+ */
+
+#include "pdp.h"
+#include "yuv.h"
+#include <math.h>
+#include <stdio.h>
+
+struct _rtext
+{
+ char *x_buf;
+ t_int x_bufsize;
+ t_int x_selstart;
+ t_int x_selend;
+ t_int x_active;
+ t_int x_dragfrom;
+ t_int x_height;
+ t_int x_drawnwidth;
+ t_int x_drawnheight;
+ t_text *x_text;
+ t_glist *x_glist;
+ char x_tag[50];
+ struct _rtext *x_next;
+};
+
+#define t_rtext struct _rtext
+
+extern int rtext_width(t_rtext *x);
+extern int rtext_height(t_rtext *x);
+extern t_rtext *glist_findrtext(t_glist *gl, t_text *who);
+
+#define COLORHEIGHT 5
+
+static char *pdp_compose_version = "pdp_compose: a video compositor version 0.1 written by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_compose_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_dropped;
+
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+ t_int x_colorR; // RGB components of mixing color
+ t_int x_colorG;
+ t_int x_colorB;
+ t_int x_colorY; // YUV components of mixing color
+ t_int x_colorU;
+ t_int x_colorV;
+ t_int x_tolerance; // tolerance
+ t_int x_cursX; // X coordinate of cursor
+ t_int x_cursY; // Y coordinate of cursor
+ t_int x_cursor; // cursor drawing flag
+ t_int x_luminosity; // flag to indicate if luminosity is used
+ short int *x_frame; // keep a copy of current frame for picking color
+ short int *x_right_frame; // 2nd video source
+
+ t_outlet *x_pdp_output; // output packets
+
+ t_canvas *x_canvas;
+
+} t_pdp_compose;
+
+static void pdp_compose_draw_color(t_pdp_compose *x)
+{
+ t_int width, height;
+ char color[32];
+
+ sprintf( color, "#%.2X%.2X%.2X", x->x_colorR, x->x_colorG, x->x_colorB );
+ width = rtext_width( glist_findrtext( (t_glist*)x->x_canvas, (t_text *)x ) );
+ height = rtext_height( glist_findrtext( (t_glist*)x->x_canvas, (t_text *)x ) );
+ sys_vgui(".x%x.c delete rectangle %xCOLOR\n", x->x_canvas, x );
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -fill %s -tags %xCOLOR\n",
+ x->x_canvas, x->x_obj.te_xpix+width+5, x->x_obj.te_ypix,
+ x->x_obj.te_xpix+width+height+5,
+ x->x_obj.te_ypix+height, color, x );
+}
+
+static void pdp_compose_setcur(t_pdp_compose *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_compose_r(t_pdp_compose *x, t_floatarg fr )
+{
+ if ( ( fr >= 0 ) && ( fr < 255 ) )
+ {
+ x->x_colorR = (int)fr;
+ x->x_colorY = (yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ))<<7;
+ x->x_colorU = (yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ x->x_colorV = (yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ pdp_compose_draw_color( x );
+ }
+}
+
+static void pdp_compose_g(t_pdp_compose *x, t_floatarg fg )
+{
+ if ( ( fg >= 0 ) && ( fg < 255 ) )
+ {
+ x->x_colorG = (int)fg;
+ x->x_colorY = (yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ))<<7;
+ x->x_colorU = (yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ x->x_colorV = (yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ pdp_compose_draw_color( x );
+ }
+}
+
+static void pdp_compose_b(t_pdp_compose *x, t_floatarg fb )
+{
+ if ( ( fb >= 0 ) && ( fb < 255 ) )
+ {
+ x->x_colorB = (int)fb;
+ x->x_colorY = (yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ))<<7;
+ x->x_colorU = (yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ x->x_colorV = (yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ pdp_compose_draw_color( x );
+ }
+}
+
+static void pdp_compose_cursor(t_pdp_compose *x, t_floatarg fcursor )
+{
+ if ( ( (int)fcursor == 0 ) || ( (int)fcursor == 1 ) )
+ {
+ x->x_cursor = (int)fcursor;
+ }
+}
+
+static void pdp_compose_tolerance(t_pdp_compose *x, t_floatarg ftolerance )
+{
+ if ( ftolerance >= 0 )
+ {
+ x->x_tolerance = (int)ftolerance;
+ }
+}
+
+static void pdp_compose_cursx(t_pdp_compose *x, t_floatarg fx )
+{
+ if ( ( fx >= 0 ) && ( fx < x->x_vwidth) )
+ {
+ x->x_cursX = (int)fx;
+ }
+}
+
+static void pdp_compose_cursy(t_pdp_compose *x, t_floatarg fy )
+{
+ if ( ( fy >= 0 ) && ( fy < x->x_vheight) )
+ {
+ x->x_cursY = (int)fy;
+ }
+}
+
+static void pdp_compose_luminosity(t_pdp_compose *x, t_floatarg fluminosity )
+{
+ if ( ( fluminosity == 0 ) || ( fluminosity == 1 ) )
+ {
+ x->x_luminosity = (int)fluminosity;
+ }
+}
+
+static void pdp_compose_pick(t_pdp_compose *x)
+{
+ t_int y,u,v;
+
+ if ( x->x_frame && ( x->x_cursX > 0 ) && ( x->x_cursX < x->x_vwidth )
+ && ( x->x_cursY > 0 ) && ( x->x_cursY < x->x_vheight ) )
+ {
+ 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) ];
+ y = (x->x_colorY)>>7;
+ u = (x->x_colorU>>8)+128;
+ v = (x->x_colorV>>8)+128;
+ x->x_colorR = yuv_YUVtoR( y, u, v );
+ x->x_colorG = yuv_YUVtoG( y, u, v );
+ x->x_colorB = yuv_YUVtoB( y, u, v );
+ pdp_compose_draw_color( x );
+ }
+}
+
+static void pdp_compose_allocate(t_pdp_compose *x)
+{
+ x->x_frame = (short int *) getbytes ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );
+ x->x_right_frame = (short int *) getbytes ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );
+
+ if ( !x->x_frame || !x->x_right_frame )
+ {
+ post( "pdp_mgrid : severe error : cannot allocate buffer !!! ");
+ return;
+ }
+}
+
+static void pdp_compose_free_ressources(t_pdp_compose *x)
+{
+ if ( x->x_frame ) freebytes ( x->x_frame, ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );
+ if ( x->x_right_frame ) freebytes ( x->x_right_frame, ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );
+}
+
+static void pdp_compose_process_yv12(t_pdp_compose *x)
+{
+ t_pdp *header = pdp_packet_header(x->x_packet0);
+ short int *data = (short int *)pdp_packet_data(x->x_packet0);
+ t_int i, cf;
+ t_int px=0, py=0, ppx=0, ppy=0, found=0, xcell=0, ycell=0;
+ t_int celldiff=0, cellwidth=0, cellheight=0;
+ t_int y=0, u=0, v=0;
+ t_int sum;
+ short int *pfY, *pfV, *pfU, *prY, *prV, *prU, *pdY, *pdV, *pdU;
+
+ /* allocate all ressources */
+ if ( ( (int)header->info.image.width != x->x_vwidth ) ||
+ ( (int)header->info.image.height != x->x_vheight ) )
+ {
+ pdp_compose_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_compose_allocate( x );
+ post( "pdp_compose : reallocated buffers" );
+ }
+
+ memcpy(x->x_frame, data, (x->x_vsize + (x->x_vsize>>1))<<1 );
+
+ // draw cursor
+ if ( ( x->x_cursor ) && ( x->x_cursX > 0 ) && ( x->x_cursY > 0 ) )
+ {
+ for ( px=(x->x_cursX-5); px<=(x->x_cursX+5); px++ )
+ {
+ if ( ( px > 0 ) && ( px < x->x_vwidth ) )
+ {
+ if ( ((*(data+x->x_cursY*x->x_vwidth+px))>>7) < 128 )
+ {
+ *(data+x->x_cursY*x->x_vwidth+px) = 0xff<<7;
+ }
+ else
+ {
+ *(data+x->x_cursY*x->x_vwidth+px) = 0x00<<7;
+ }
+ }
+ }
+ for ( py=(x->x_cursY-5); py<=(x->x_cursY+5); py++ )
+ {
+ if ( ( py > 0 ) && ( py < x->x_vheight ) )
+ {
+ if ( ((*(data+py*x->x_vwidth+x->x_cursX))>>7) < 128 )
+ {
+ *(data+py*x->x_vwidth+x->x_cursX) = 0xff<<7;
+ }
+ else
+ {
+ *(data+py*x->x_vwidth+x->x_cursX) = 0x00<<7;
+ }
+ }
+ }
+ }
+
+ pfY = x->x_frame;
+ pfV = x->x_frame+x->x_vsize;
+ pfU = x->x_frame+x->x_vsize+(x->x_vsize>>2);
+ pdY = data;
+ pdV = data+x->x_vsize;
+ pdU = data+x->x_vsize+(x->x_vsize>>2);
+ prY = x->x_right_frame;
+ prV = x->x_right_frame+x->x_vsize;
+ prU = x->x_right_frame+x->x_vsize+(x->x_vsize>>2);
+ // track color
+ if ( x->x_colorR != -1 )
+ {
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ y = *pfY;
+ v = *pfV;
+ u = *pfU;
+ if ( x->x_luminosity )
+ {
+ sum = (abs(y-x->x_colorY)>>7);
+ }
+ else
+ {
+ sum = (abs(y-x->x_colorY)>>7)+(abs(u-x->x_colorU)>>8)+(abs(v-x->x_colorV)>>8);
+ }
+ if ( sum <= x->x_tolerance )
+ {
+ *pdY = *prY;
+ *pdV = *prV;
+ *pdU = *prU;
+ }
+ prY++;pdY++;pfY++;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ prU++; prV++;
+ pfU++; pfV++;
+ pdU++; pdV++;
+ }
+ }
+ }
+ }
+
+ pdp_packet_pass_if_valid(x->x_pdp_output, &x->x_packet0);
+
+ return;
+}
+
+static void pdp_compose_process(t_pdp_compose *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_compose_process inputs and write into active inlet */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_compose_process_yv12(x);
+ 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_compose_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_compose_input_1(t_pdp_compose *x, t_symbol *s, t_floatarg f)
+{
+ short int *rightdata = (short int *)pdp_packet_data((int)f);
+
+ if (s== gensym("register_rw")) memcpy(x->x_right_frame, rightdata, (x->x_vsize + (x->x_vsize>>1))<<1 );
+}
+
+static void pdp_compose_input_0(t_pdp_compose *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_compose_process(x);
+
+ }
+}
+
+static void pdp_compose_free(t_pdp_compose *x)
+{
+ int i;
+
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_compose_free_ressources( x );
+}
+
+t_class *pdp_compose_class;
+
+void *pdp_compose_new(void)
+{
+ int i;
+
+ t_pdp_compose *x = (t_pdp_compose *)pd_new(pdp_compose_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("R"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("G"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("B"));
+ 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_colorR = -1;
+ x->x_colorG = -1;
+ x->x_colorB = -1;
+
+ x->x_colorY = (yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ))<<7;
+ x->x_colorU = (yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ x->x_colorV = (yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+
+ x->x_packet0 = -1;
+
+ x->x_cursX = -1;
+ x->x_cursY = -1;
+ x->x_tolerance = 20;
+ x->x_luminosity = 1;
+ x->x_cursor = 1;
+
+ x->x_canvas = canvas_getcurrent();
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_compose_setup(void)
+{
+ post( pdp_compose_version );
+ pdp_compose_class = class_new(gensym("pdp_compose"), (t_newmethod)pdp_compose_new,
+ (t_method)pdp_compose_free, sizeof(t_pdp_compose), 0, A_NULL);
+
+ class_addmethod(pdp_compose_class, (t_method)pdp_compose_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_compose_class, (t_method)pdp_compose_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_compose_class, (t_method)pdp_compose_r, gensym("R"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_compose_class, (t_method)pdp_compose_g, gensym("G"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_compose_class, (t_method)pdp_compose_b, gensym("B"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_compose_class, (t_method)pdp_compose_cursx, gensym("cursx"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_compose_class, (t_method)pdp_compose_cursy, gensym("cursy"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_compose_class, (t_method)pdp_compose_pick, gensym("pick"), A_NULL);
+ class_addmethod(pdp_compose_class, (t_method)pdp_compose_cursor, gensym("cursor"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_compose_class, (t_method)pdp_compose_tolerance, gensym("tolerance"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_compose_class, (t_method)pdp_compose_luminosity, gensym("luminosity"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_compose_class, (t_method)pdp_compose_setcur, gensym("setcur"), A_FLOAT, A_FLOAT, A_NULL);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_ctrack.c b/modules/pdp_ctrack.c
new file mode 100644
index 0000000..45e1ccb
--- /dev/null
+++ b/modules/pdp_ctrack.c
@@ -0,0 +1,676 @@
+/*
+ * PiDiP module
+ * Copyright (c) by Yves Degoyon ( ydegoyon@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 color tracker that lets you follow the movement of objects
+ */
+
+#include "pdp.h"
+#include "yuv.h"
+#include <math.h>
+#include <stdio.h>
+
+struct _rtext
+{
+ char *x_buf;
+ int x_bufsize;
+ int x_selstart;
+ int x_selend;
+ int x_active;
+ int x_dragfrom;
+ int x_height;
+ int x_drawnwidth;
+ int x_drawnheight;
+ t_text *x_text;
+ t_glist *x_glist;
+ char x_tag[50];
+ struct _rtext *x_next;
+};
+
+#define t_rtext struct _rtext
+
+extern int rtext_width(t_rtext *x);
+extern int rtext_height(t_rtext *x);
+extern t_rtext *glist_findrtext(t_glist *gl, t_text *who);
+
+#define COLORHEIGHT 5
+
+static char *pdp_ctrack_version = "pdp_ctrack: a color tracker version 0.1 written by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_ctrack_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_dropped;
+
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+ t_int x_colorR; // RGB components of tracked color
+ t_int x_colorG;
+ t_int x_colorB;
+ t_int x_colorY; // YUV components of tracked color
+ t_int x_colorU;
+ t_int x_colorV;
+ t_int x_tolerance; // tolerance
+ t_int x_luminosity; // use luminosity or not
+ t_int x_steady; // steady mode : the zone is searched around the cursor
+ t_int x_cursor; // show cursor or not
+ t_int x_showframe; // show frame or not
+ t_int x_cursX; // X coordinate of cursor
+ t_int x_cursY; // Y coordinate of cursor
+ short int *x_frame; // keep a copy of current frame for picking color
+
+ t_outlet *x_pdp_output; // output packets
+ t_outlet *x_x1; // output x1 coordinate of block which has been detected
+ t_outlet *x_y1; // output y1 coordinate of block which has been detected
+ t_outlet *x_x2; // output x2 coordinate of block which has been detected
+ t_outlet *x_y2; // output y2 coordinate of block which has been detected
+ t_outlet *x_R; // output R component of selected color
+ t_outlet *x_G; // output R component of selected color
+ t_outlet *x_B; // output R component of selected color
+
+ t_canvas *x_canvas;
+
+} t_pdp_ctrack;
+
+static void pdp_ctrack_draw_color(t_pdp_ctrack *x)
+{
+ t_int width, height;
+ char color[32];
+
+ sprintf( color, "#%.2X%.2X%.2X", x->x_colorR, x->x_colorG, x->x_colorB );
+ width = rtext_width( glist_findrtext( (t_glist*)x->x_canvas, (t_text *)x ) );
+ height = rtext_height( glist_findrtext( (t_glist*)x->x_canvas, (t_text *)x ) );
+ sys_vgui(".x%x.c delete rectangle %xCOLOR\n", x->x_canvas, x );
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -fill %s -tags %xCOLOR\n",
+ x->x_canvas, x->x_obj.te_xpix+width+5, x->x_obj.te_ypix,
+ x->x_obj.te_xpix+width+height+5,
+ x->x_obj.te_ypix+height, color, x );
+}
+
+static void pdp_ctrack_setcur(t_pdp_ctrack *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_ctrack_r(t_pdp_ctrack *x, t_floatarg fr )
+{
+ if ( ( fr >= 0 ) && ( fr < 255 ) )
+ {
+ x->x_colorR = (int)fr;
+ x->x_colorY = (yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ))<<7;
+ x->x_colorU = (yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ x->x_colorV = (yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ pdp_ctrack_draw_color( x );
+ outlet_float( x->x_R, x->x_colorR );
+ }
+}
+
+static void pdp_ctrack_g(t_pdp_ctrack *x, t_floatarg fg )
+{
+ if ( ( fg >= 0 ) && ( fg < 255 ) )
+ {
+ x->x_colorG = (int)fg;
+ x->x_colorY = (yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ))<<7;
+ x->x_colorU = (yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ x->x_colorV = (yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ pdp_ctrack_draw_color( x );
+ outlet_float( x->x_G, x->x_colorG );
+ }
+}
+
+static void pdp_ctrack_b(t_pdp_ctrack *x, t_floatarg fb )
+{
+ if ( ( fb >= 0 ) && ( fb < 255 ) )
+ {
+ x->x_colorB = (int)fb;
+ x->x_colorY = (yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ))<<7;
+ x->x_colorU = (yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ x->x_colorV = (yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ pdp_ctrack_draw_color( x );
+ outlet_float( x->x_B, x->x_colorB );
+ }
+}
+
+static void pdp_ctrack_cursx(t_pdp_ctrack *x, t_floatarg fx )
+{
+ if ( ( fx >= 0 ) && ( fx < x->x_vwidth) )
+ {
+ x->x_cursX = (int)fx;
+ }
+}
+
+static void pdp_ctrack_tolerance(t_pdp_ctrack *x, t_floatarg ftolerance )
+{
+ if ( ftolerance >= 0 )
+ {
+ x->x_tolerance = (int)ftolerance;
+ }
+}
+
+static void pdp_ctrack_cursy(t_pdp_ctrack *x, t_floatarg fy )
+{
+ if ( ( fy >= 0 ) && ( fy < x->x_vheight) )
+ {
+ x->x_cursY = (int)fy;
+ }
+}
+
+static void pdp_ctrack_luminosity(t_pdp_ctrack *x, t_floatarg fluminosity )
+{
+ if ( ( fluminosity == 0 ) || ( fluminosity == 1 ) )
+ {
+ x->x_luminosity = (int)fluminosity;
+ }
+}
+
+static void pdp_ctrack_cursor(t_pdp_ctrack *x, t_floatarg fcursor )
+{
+ if ( ( fcursor == 0 ) || ( fcursor == 1 ) )
+ {
+ x->x_cursor = (int)fcursor;
+ }
+}
+
+static void pdp_ctrack_frame(t_pdp_ctrack *x, t_floatarg fframe )
+{
+ if ( ( fframe == 0 ) || ( fframe == 1 ) )
+ {
+ x->x_showframe = (int)fframe;
+ }
+}
+
+static void pdp_ctrack_steady(t_pdp_ctrack *x, t_floatarg fsteady )
+{
+ if ( ( fsteady == 0 ) || ( fsteady == 1 ) )
+ {
+ x->x_steady = (int)fsteady;
+ }
+}
+
+static void pdp_ctrack_pick(t_pdp_ctrack *x)
+{
+ t_int y,u,v;
+
+ if ( x->x_frame && ( x->x_cursX > 0 ) && ( x->x_cursX < x->x_vwidth )
+ && ( x->x_cursY > 0 ) && ( x->x_cursY < x->x_vheight ) )
+ {
+ 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) ];
+ y = (x->x_colorY)>>7;
+ u = (x->x_colorU>>8)+128;
+ v = (x->x_colorV>>8)+128;
+ x->x_colorR = yuv_YUVtoR( y, u, v );
+ outlet_float( x->x_R, x->x_colorR );
+ x->x_colorG = yuv_YUVtoG( y, u, v );
+ outlet_float( x->x_G, x->x_colorG );
+ x->x_colorB = yuv_YUVtoB( y, u, v );
+ outlet_float( x->x_B, x->x_colorB );
+ pdp_ctrack_draw_color( x );
+ }
+}
+
+static void pdp_ctrack_allocate(t_pdp_ctrack *x)
+{
+ x->x_frame = (short int *) getbytes ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );
+
+ if ( !x->x_frame )
+ {
+ post( "pdp_mgrid : severe error : cannot allocate buffer !!! ");
+ return;
+ }
+}
+
+static void pdp_ctrack_free_ressources(t_pdp_ctrack *x)
+{
+ if ( x->x_frame ) freebytes ( x->x_frame, ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );
+}
+
+static void pdp_ctrack_process_yv12(t_pdp_ctrack *x)
+{
+ t_pdp *header = pdp_packet_header(x->x_packet0);
+ short int *data = (short int *)pdp_packet_data(x->x_packet0);
+ t_int i, cf;
+ t_int px=0, py=0, ppx=0, ppy=0, found=0, xcell=0, ycell=0;
+ t_int y=0, u=0, v=0;
+ t_int x1=0, y1=0, x2=0, y2=0;
+ t_int X1=0, Y1=0, X2=0, Y2=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_ctrack_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_ctrack_allocate( x );
+ post( "pdp_ctrack : reallocated buffers" );
+ }
+
+ memcpy(x->x_frame, data, (x->x_vsize + (x->x_vsize>>1))<<1 );
+
+ // draw cursor
+ if ( ( x->x_cursX > 0 ) && ( x->x_cursY > 0 ) && ( x->x_cursor ) )
+ {
+ for ( px=(x->x_cursX-5); px<=(x->x_cursX+5); px++ )
+ {
+ if ( ( px > 0 ) && ( px < x->x_vwidth ) )
+ {
+ if ( ((*(data+x->x_cursY*x->x_vwidth+px))>>7) < 128 )
+ {
+ *(data+x->x_cursY*x->x_vwidth+px) = 0xff<<7;
+ }
+ else
+ {
+ *(data+x->x_cursY*x->x_vwidth+px) = 0x00<<7;
+ }
+ }
+ }
+ for ( py=(x->x_cursY-5); py<=(x->x_cursY+5); py++ )
+ {
+ if ( ( py > 0 ) && ( py < x->x_vheight ) )
+ {
+ if ( ((*(data+py*x->x_vwidth+x->x_cursX))>>7) < 128 )
+ {
+ *(data+py*x->x_vwidth+x->x_cursX) = 0xff<<7;
+ }
+ else
+ {
+ *(data+py*x->x_vwidth+x->x_cursX) = 0x00<<7;
+ }
+ }
+ }
+ }
+
+ // track color
+ pfY = x->x_frame;
+ pfV = x->x_frame+x->x_vsize;
+ pfU = x->x_frame+x->x_vsize+(x->x_vsize>>2);
+ if ( x->x_colorR != -1 )
+ {
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ y = *pfY++;
+ v = *pfV;
+ u = *pfU;
+
+ if ( x->x_luminosity )
+ {
+ diff = (abs(y-x->x_colorY)>>7)+(abs(u-x->x_colorU)>>8)+(abs(v-x->x_colorV)>>8);
+ }
+ else
+ {
+ diff = (abs(u-x->x_colorU)>>8)+(abs(v-x->x_colorV)>>8);
+ }
+
+ if ( diff <= x->x_tolerance )
+ {
+ x1=x2=px;
+ y1=y2=py;
+ found=0;
+
+ for (ppy=y1; ppy<x->x_vheight; ppy++)
+ {
+ found = 0;
+ for (ppx=x1; ppx<x->x_vwidth; ppx++)
+ {
+ y = x->x_frame[ ppy*x->x_vwidth+ppx ];
+ v = x->x_frame[ x->x_vsize + (((ppy>>1)*(x->x_vwidth>>1))+(ppx>>1)) ];
+ u = x->x_frame[ x->x_vsize + (x->x_vsize>>2) + (((ppy>>1)*(x->x_vwidth>>1))+(ppx>>1)) ];
+
+ if ( x->x_luminosity )
+ {
+ diff = (abs(y-x->x_colorY)>>7)+(abs(u-x->x_colorU)>>8)+(abs(v-x->x_colorV)>>8);
+ }
+ else
+ {
+ diff = (abs(u-x->x_colorU)>>8)+(abs(v-x->x_colorV)>>8);
+ }
+
+ if ( diff <= x->x_tolerance )
+ {
+ if ( ppx > x2 ) x2 = ppx;
+ y2 = ppy;
+ found=1;
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (!found) break; // a whole line without the looked-up color
+ }
+ // check further extensions
+ // to the bottom
+ for (ppx=x1; ppx<x2; ppx++)
+ {
+ for (ppy=y2; ppy<x->x_vheight; ppy++)
+ {
+ y = x->x_frame[ ppy*x->x_vwidth+ppx ];
+ v = x->x_frame[ x->x_vsize + (((ppy>>1)*(x->x_vwidth>>1))+(ppx>>1)) ];
+ u = x->x_frame[ x->x_vsize + (x->x_vsize>>2) + (((ppy>>1)*(x->x_vwidth>>1))+(ppx>>1)) ];
+
+ if ( x->x_luminosity )
+ {
+ diff = (abs(y-x->x_colorY)>>7)+(abs(u-x->x_colorU)>>8)+(abs(v-x->x_colorV)>>8);
+ }
+ else
+ {
+ diff = (abs(u-x->x_colorU)>>8)+(abs(v-x->x_colorV)>>8);
+ }
+
+ if ( diff <= x->x_tolerance )
+ {
+ y2 = ppy;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ // to the left
+ for (ppy=y1; ppy<=y2; ppy++)
+ {
+ for (ppx=x1; ppx>0; ppx--)
+ {
+ y = x->x_frame[ ppy*x->x_vwidth+ppx ];
+ v = x->x_frame[ x->x_vsize + (((ppy>>1)*(x->x_vwidth>>1))+(ppx>>1)) ];
+ u = x->x_frame[ x->x_vsize + (x->x_vsize>>2) + (((ppy>>1)*(x->x_vwidth>>1))+(ppx>>1)) ];
+
+ if ( x->x_luminosity )
+ {
+ diff = (abs(y-x->x_colorY)>>7)+(abs(u-x->x_colorU)>>8)+(abs(v-x->x_colorV)>>8);
+ }
+ else
+ {
+ diff = (abs(u-x->x_colorU)>>8)+(abs(v-x->x_colorV)>>8);
+ }
+
+ if ( diff <= x->x_tolerance )
+ {
+ x1 = ppx;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ // to the right
+ for (ppy=y1; ppy<=y2; ppy++)
+ {
+ for (ppx=x2; ppx<x->x_vwidth; ppx++)
+ {
+ y = x->x_frame[ ppy*x->x_vwidth+ppx ];
+ v = x->x_frame[ x->x_vsize + (((ppy>>1)*(x->x_vwidth>>1))+(ppx>>1)) ];
+ u = x->x_frame[ x->x_vsize + (x->x_vsize>>2) + (((ppy>>1)*(x->x_vwidth>>1))+(ppx>>1)) ];
+
+ if ( x->x_luminosity )
+ {
+ diff = (abs(y-x->x_colorY)>>7)+(abs(u-x->x_colorU)>>8)+(abs(v-x->x_colorV)>>8);
+ }
+ else
+ {
+ diff = (abs(u-x->x_colorU)>>8)+(abs(v-x->x_colorV)>>8);
+ }
+
+ if ( diff <= x->x_tolerance )
+ {
+ x2 = ppx;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ // select zone
+ if ( !x->x_steady )
+ {
+ // track the biggest object
+ if ( abs(x2-x1)*abs(y2-y1) > abs(X2-X1)*abs(Y2-Y1) )
+ {
+ X1=x1; X2=x2; Y1=y1; Y2=y2;
+ }
+ }
+ else
+ {
+ // check if the cursor is in selected zone
+ if ( (x->x_cursX>=x1) && (x->x_cursX<=x2)
+ && (x->x_cursY>=y1) && (x->x_cursY<=y2 ) )
+ {
+ X1=x1; X2=x2; Y1=y1; Y2=y2;
+ // set new cursor position
+ x->x_cursX = ( X1+X2 )/2;
+ x->x_cursY = ( Y1+Y2 )/2;
+ }
+ }
+
+ px=x2+1; py=y2;
+ // post( "pdp_ctrack : px=%d py=%d", px, py );
+ }
+
+ if ( (px%2==0) && (py%2==0) )
+ {
+ pfU++;pfV++;
+ }
+ }
+ }
+ if ( X1!=0 || X2!=0 || Y1!=0 || Y2!=0 )
+ {
+ outlet_float( x->x_x1, X1 );
+ outlet_float( x->x_y1, Y1 );
+ outlet_float( x->x_x2, X2 );
+ outlet_float( x->x_y2, Y2 );
+
+ // draw the frame
+ if ( x->x_showframe )
+ {
+ for (ppy=Y1; ppy<=Y2; ppy++)
+ {
+ if ( ((*(data+ppy*x->x_vwidth+X1))>>7) < 128 )
+ {
+ *(data+ppy*x->x_vwidth+X1) = 0xff<<7;
+ }
+ else
+ {
+ *(data+ppy*x->x_vwidth+X1) = 0x00<<7;
+ }
+ if ( ((*(data+ppy*x->x_vwidth+X2))>>7) < 128 )
+ {
+ *(data+ppy*x->x_vwidth+X2) = 0xff<<7;
+ }
+ else
+ {
+ *(data+ppy*x->x_vwidth+X2) = 0x00<<7;
+ }
+ }
+ for (ppx=X1; ppx<=X2; ppx++)
+ {
+ if ( ((*(data+Y1*x->x_vwidth+ppx))>>7) < 128 )
+ {
+ *(data+Y1*x->x_vwidth+ppx) = 0xff<<7;
+ }
+ else
+ {
+ *(data+Y1*x->x_vwidth+ppx) = 0x00<<7;
+ }
+ if ( ((*(data+Y2*x->x_vwidth+ppx))>>7) < 128 )
+ {
+ *(data+Y2*x->x_vwidth+ppx) = 0xff<<7;
+ }
+ else
+ {
+ *(data+Y2*x->x_vwidth+ppx) = 0x00<<7;
+ }
+ }
+ }
+ }
+ }
+
+ pdp_packet_pass_if_valid(x->x_pdp_output, &x->x_packet0);
+
+ return;
+}
+
+static void pdp_ctrack_process(t_pdp_ctrack *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_ctrack_process inputs and write into active inlet */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_ctrack_process_yv12(x);
+ 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_ctrack_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_ctrack_input_0(t_pdp_ctrack *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_ctrack_process(x);
+
+ }
+}
+
+static void pdp_ctrack_free(t_pdp_ctrack *x)
+{
+ int i;
+
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_ctrack_free_ressources( x );
+}
+
+t_class *pdp_ctrack_class;
+
+void *pdp_ctrack_new(void)
+{
+ int i;
+
+ t_pdp_ctrack *x = (t_pdp_ctrack *)pd_new(pdp_ctrack_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("R"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("G"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("B"));
+ 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_x1 = outlet_new(&x->x_obj, &s_float);
+ x->x_y1 = outlet_new(&x->x_obj, &s_float);
+ x->x_x2 = outlet_new(&x->x_obj, &s_float);
+ x->x_y2 = outlet_new(&x->x_obj, &s_float);
+ x->x_R = outlet_new(&x->x_obj, &s_float);
+ x->x_G = outlet_new(&x->x_obj, &s_float);
+ x->x_B = outlet_new(&x->x_obj, &s_float);
+
+ x->x_colorR = -1;
+ x->x_colorG = -1;
+ x->x_colorB = -1;
+
+ x->x_colorY = (yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ))<<7;
+ x->x_colorU = (yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+ x->x_colorV = (yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB )-128)<<8;
+
+ x->x_packet0 = -1;
+
+ x->x_cursX = -1;
+ x->x_cursY = -1;
+ x->x_tolerance = 50;
+ x->x_luminosity = 1;
+ x->x_steady = 0;
+ x->x_cursor = 1;
+ x->x_showframe = 1;
+
+ x->x_canvas = canvas_getcurrent();
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_ctrack_setup(void)
+{
+ post( pdp_ctrack_version );
+ pdp_ctrack_class = class_new(gensym("pdp_ctrack"), (t_newmethod)pdp_ctrack_new,
+ (t_method)pdp_ctrack_free, sizeof(t_pdp_ctrack), 0, A_NULL);
+
+ class_addmethod(pdp_ctrack_class, (t_method)pdp_ctrack_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_ctrack_class, (t_method)pdp_ctrack_r, gensym("R"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_ctrack_class, (t_method)pdp_ctrack_g, gensym("G"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_ctrack_class, (t_method)pdp_ctrack_b, gensym("B"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_ctrack_class, (t_method)pdp_ctrack_cursx, gensym("cursx"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_ctrack_class, (t_method)pdp_ctrack_cursy, gensym("cursy"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_ctrack_class, (t_method)pdp_ctrack_pick, gensym("pick"), A_NULL);
+ class_addmethod(pdp_ctrack_class, (t_method)pdp_ctrack_tolerance, gensym("tolerance"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_ctrack_class, (t_method)pdp_ctrack_luminosity, gensym("luminosity"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_ctrack_class, (t_method)pdp_ctrack_steady, gensym("steady"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_ctrack_class, (t_method)pdp_ctrack_cursor, gensym("cursor"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_ctrack_class, (t_method)pdp_ctrack_frame, gensym("frame"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_ctrack_class, (t_method)pdp_ctrack_setcur, gensym("setcur"), A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_cycle.c b/modules/pdp_cycle.c
new file mode 100644
index 0000000..f2d0085
--- /dev/null
+++ b/modules/pdp_cycle.c
@@ -0,0 +1,246 @@
+/*
+ * PiDiP module
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 port of cycle effect from EffecTV
+ * Originally written by clifford smith <nullset@dookie.net>
+ * Pd-fication by Yves Degoyon ( ydegoyon@free.fr )
+ */
+
+
+#include "pdp.h"
+#include <math.h>
+
+#define NEWCOLOR(c,o) ((c+o)%230)
+
+static char *pdp_cycle_version = "pdp_cycle: version 0.1, port of cycle from EffecTV by clifford smith, adapted by ydegoyon@free.fr ";
+
+typedef struct pdp_cycle_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_packet1;
+ t_int x_dropped;
+ t_int x_queue_id;
+
+ t_outlet *x_outlet0;
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+
+ t_int x_cycley; // flag to activate y cycling
+ t_int x_cycleu; // flag to activate u cycling
+ t_int x_cyclev; // flag to activate v cycling
+
+ t_int x_yoffset;
+ t_int x_uoffset;
+ t_int x_voffset;
+
+} t_pdp_cycle;
+
+static void pdp_cycle_cycley(t_pdp_cycle *x, t_floatarg fcycley )
+{
+ if ( ( fcycley == 0 ) || ( fcycley == 1 ) )
+ {
+ x->x_cycley = fcycley;
+ }
+}
+
+static void pdp_cycle_cycleu(t_pdp_cycle *x, t_floatarg fcycleu )
+{
+ if ( ( fcycleu == 0 ) || ( fcycleu == 1 ) )
+ {
+ x->x_cycleu = fcycleu;
+ }
+}
+
+static void pdp_cycle_cyclev(t_pdp_cycle *x, t_floatarg fcyclev )
+{
+ if ( ( fcyclev == 0 ) || ( fcyclev == 1 ) )
+ {
+ x->x_cyclev = fcyclev;
+ }
+}
+
+static void pdp_cycle_process_yv12(t_pdp_cycle *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, py, y, u, v;
+
+ x->x_vwidth = header->info.image.width;
+ x->x_vheight = header->info.image.height;
+ x->x_vsize = x->x_vwidth*x->x_vheight;
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ x->x_yoffset += 1;
+ x->x_uoffset += 3;
+ x->x_voffset += 7;
+
+ for(py=1; py<x->x_vheight; py++)
+ {
+ for(px=0; px<x->x_vwidth; px++)
+ {
+ if ( x->x_cycley )
+ {
+ y = *(data+py*x->x_vwidth+px)>>7;
+ *(newdata+py*x->x_vwidth+px) = NEWCOLOR(y,x->x_yoffset)<<7;
+ }
+ if ( x->x_cycleu )
+ {
+ u = ( *(data+x->x_vsize+(x->x_vsize>>2)+((py*x->x_vwidth>>2)+(px>>1))) >>8 ) + 128;
+ *(newdata+x->x_vsize+(x->x_vsize>>2)+((py*x->x_vwidth>>2)+(px>>1))) = (NEWCOLOR(u,x->x_uoffset)-128)<<8;
+ }
+ if ( x->x_cyclev )
+ {
+ v = ( *(data+x->x_vsize+((py*x->x_vwidth>>2)+(px>>1))) >>8 ) + 128;
+ *(newdata+x->x_vsize+((py*x->x_vwidth>>2)+(px>>1))) = (NEWCOLOR(v,x->x_voffset)-128)<<8;
+ }
+ }
+ }
+
+ return;
+}
+
+static void pdp_cycle_sendpacket(t_pdp_cycle *x)
+{
+ /* delete source 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_cycle_process(t_pdp_cycle *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_cycle_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_cycle_process_yv12, pdp_cycle_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_cycle_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_cycle_input_0(t_pdp_cycle *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_cycle_process(x);
+
+ }
+
+}
+
+static void pdp_cycle_free(t_pdp_cycle *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_cycle_class;
+
+void *pdp_cycle_new(void)
+{
+ int i;
+
+ t_pdp_cycle *x = (t_pdp_cycle *)pd_new(pdp_cycle_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("cycley"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("cycleu"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("cyclev"));
+
+ 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_cycley = 1;
+ x->x_cycleu = 0;
+ x->x_cyclev = 0;
+
+ x->x_yoffset = 0;
+ x->x_uoffset = 0;
+ x->x_voffset = 0;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_cycle_setup(void)
+{
+// post( pdp_cycle_version );
+ pdp_cycle_class = class_new(gensym("pdp_cycle"), (t_newmethod)pdp_cycle_new,
+ (t_method)pdp_cycle_free, sizeof(t_pdp_cycle), 0, A_NULL);
+
+ class_addmethod(pdp_cycle_class, (t_method)pdp_cycle_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_cycle_class, (t_method)pdp_cycle_cycley, gensym("cycley"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_cycle_class, (t_method)pdp_cycle_cycleu, gensym("cycleu"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_cycle_class, (t_method)pdp_cycle_cyclev, gensym("cyclev"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_dice.c b/modules/pdp_dice.c
new file mode 100644
index 0000000..ddb6007
--- /dev/null
+++ b/modules/pdp_dice.c
@@ -0,0 +1,345 @@
+/*
+ * PiDiP module
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 port of dice effect from EffecTV
+ * Originally written by clifford smith <nullset@dookie.net>
+ * Pd-fication by Yves Degoyon ( ydegoyon@free.fr )
+ */
+
+
+#include "pdp.h"
+#include <math.h>
+
+#define DEFAULT_CUBE_BITS 4
+#define MAX_CUBE_BITS 5
+#define MIN_CUBE_BITS 0
+
+typedef enum _pdp_dice_dir {
+ up = 0,
+ right = 1,
+ down = 2,
+ left = 3
+} t_pdp_dice_dir;
+
+static unsigned int fastrand_val;
+#define inline_fastrand() (fastrand_val=fastrand_val*1103515245+12345)
+
+static char *pdp_dice_version = "pdp_dice: version 0.1, port of dice from EffecTV by clifford smith, adapted by ydegoyon@free.fr ";
+
+typedef struct pdp_dice_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_packet1;
+ t_int x_dropped;
+ t_int x_queue_id;
+
+ t_outlet *x_outlet0;
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+
+ char *x_dicemap;
+
+ t_int x_cube_bits;
+ t_int x_cube_size;
+ t_int x_map_height;
+ t_int x_map_width;
+
+} t_pdp_dice;
+
+static void pdp_dice_create_map(t_pdp_dice *x)
+{
+ int px, py, i;
+
+ if ( x->x_dicemap == NULL )
+ {
+ post( "pdp_dice : tried to create map but it's not allocated" );
+ return;
+ }
+
+ x->x_map_height = x->x_vheight >> x->x_cube_bits;
+ x->x_map_width = x->x_vwidth >> x->x_cube_bits;
+ x->x_cube_size = 1 << x->x_cube_bits;
+
+ i = 0;
+ for (py=0; py<x->x_map_height; py++)
+ {
+ for(px=0; px<x->x_map_width; px++)
+ {
+ x->x_dicemap[i] = (inline_fastrand() >> 24) & 0x03;
+ i++;
+ }
+ }
+
+ return;
+}
+
+static void pdp_dice_cubebits(t_pdp_dice *x, t_floatarg fcubebits )
+{
+ if ( ( fcubebits >= MIN_CUBE_BITS ) || ( fcubebits <= MAX_CUBE_BITS ) )
+ {
+ x->x_cube_bits = fcubebits;
+ pdp_dice_create_map(x);
+ }
+}
+
+static void pdp_dice_free_ressources(t_pdp_dice *x)
+{
+ if ( x->x_dicemap ) freebytes( x->x_dicemap, x->x_vsize );
+}
+
+static void pdp_dice_allocate(t_pdp_dice *x)
+{
+ x->x_dicemap = (char *) getbytes( x->x_vsize );
+}
+
+static void pdp_dice_process_yv12(t_pdp_dice *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, iuv;
+ t_int mapx, mapy, mapi;
+ t_int base, baseuv, dx, dy, di, diuv;
+
+ /* allocate all ressources */
+ if ( ((int)header->info.image.width != x->x_vwidth) ||
+ ((int)header->info.image.height != x->x_vheight) )
+ {
+ pdp_dice_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_dice_allocate(x);
+ post( "pdp_dice : reallocated buffers" );
+ pdp_dice_create_map(x);
+ post( "pdp_dice : initialized map" );
+ }
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ mapi = 0;
+ for(mapy = 0; mapy < x->x_map_height; mapy++)
+ {
+ for(mapx = 0; mapx < x->x_map_width; mapx++)
+ {
+ base = (mapy << x->x_cube_bits) * x->x_vwidth + (mapx << x->x_cube_bits);
+ baseuv = (((mapy << x->x_cube_bits)>>1) * (x->x_vwidth>>1)) + ((mapx << x->x_cube_bits)>>1);
+ switch (x->x_dicemap[mapi])
+ {
+ case up:
+ for (dy = 0; dy < x->x_cube_size; dy++)
+ {
+ i = base + dy * x->x_vwidth;
+ iuv = baseuv + ((dy>>1) * (x->x_vwidth>>1));
+ for (dx = 0; dx < x->x_cube_size; dx++)
+ {
+ newdata[i] = data[i];
+ newdata[x->x_vsize+iuv] = data[x->x_vsize+iuv];
+ newdata[x->x_vsize+(x->x_vsize>>2)+iuv] = data[x->x_vsize+(x->x_vsize>>2)+iuv];
+ i++;
+ if ( (dx%2==0) && (dy%2==0) ) iuv++;
+ }
+ }
+ break;
+
+ case left:
+ for (dy = 0; dy < x->x_cube_size; dy++)
+ {
+ i = base + dy * x->x_vwidth;
+ iuv = baseuv + ((dy>>1) * (x->x_vwidth>>1));
+ for (dx = 0; dx < x->x_cube_size; dx++)
+ {
+ di = base + (dx * x->x_vwidth) + (x->x_cube_size - dy - 1);
+ diuv = baseuv + ((dx>>1) * (x->x_vwidth>>1)) + ((x->x_cube_size - dy - 1)>>1);
+ newdata[di] = data[i];
+ newdata[x->x_vsize+diuv] = data[x->x_vsize+iuv];
+ newdata[x->x_vsize+(x->x_vsize>>2)+diuv] = data[x->x_vsize+(x->x_vsize>>2)+iuv];
+ i++;
+ if ( (dx%2==0) && (dy%2==0) ) iuv++;
+ }
+ }
+ break;
+
+ case down:
+ for (dy = 0; dy < x->x_cube_size; dy++)
+ {
+ di = base + dy * x->x_vwidth;
+ diuv = baseuv + ((dy>>1) * (x->x_vwidth>>1));
+ i = base + (x->x_cube_size - dy - 1) * x->x_vwidth + x->x_cube_size;
+ iuv = baseuv + (((x->x_cube_size - dy - 1)>>1) * (x->x_vwidth>>1)) + (x->x_cube_size>>1);
+ for (dx = 0; dx < x->x_cube_size; dx++)
+ {
+ i--;
+ if ( dx%2==0) iuv--;
+ newdata[di] = data[i];
+ newdata[x->x_vsize+diuv] = data[x->x_vsize+iuv];
+ newdata[x->x_vsize+(x->x_vsize>>2)+diuv] = data[x->x_vsize+(x->x_vsize>>2)+iuv];
+ di++;
+ if ( (dx%2==0) && (dy%2==0) ) iuv++;
+ }
+ }
+ break;
+
+ case right:
+ for (dy = 0; dy < x->x_cube_size; dy++)
+ {
+ i = base + (dy * x->x_vwidth);
+ iuv = baseuv + ((dy>>1) * (x->x_vwidth>>1));
+ for (dx = 0; dx < x->x_cube_size; dx++)
+ {
+ di = base + dy + (x->x_cube_size - dx - 1) * x->x_vwidth;
+ diuv = baseuv + (dy>>1) + (((x->x_cube_size - dx - 1)>>1) * (x->x_vwidth>>1));
+ newdata[di] = data[i];
+ newdata[x->x_vsize+diuv] = data[x->x_vsize+iuv];
+ newdata[x->x_vsize+(x->x_vsize>>2)+diuv] = data[x->x_vsize+(x->x_vsize>>2)+iuv];
+ i++;
+ if ( (dx%2==0) && (dy%2==0) ) iuv++;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ mapi++;
+ }
+ }
+
+ return;
+}
+
+static void pdp_dice_sendpacket(t_pdp_dice *x)
+{
+ /* delete source 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_dice_process(t_pdp_dice *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_dice_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_dice_process_yv12, pdp_dice_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_dice_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_dice_input_0(t_pdp_dice *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_dice_process(x);
+
+ }
+
+}
+
+static void pdp_dice_free(t_pdp_dice *x)
+{
+ int i;
+
+ pdp_dice_free_ressources(x);
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_dice_class;
+
+void *pdp_dice_new(void)
+{
+ int i;
+
+ t_pdp_dice *x = (t_pdp_dice *)pd_new(pdp_dice_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("cubebits"));
+
+ 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_cube_bits = DEFAULT_CUBE_BITS;
+ x->x_cube_size = 0;
+ x->x_map_height = 0;
+ x->x_map_width = 0;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_dice_setup(void)
+{
+// post( pdp_dice_version );
+ pdp_dice_class = class_new(gensym("pdp_dice"), (t_newmethod)pdp_dice_new,
+ (t_method)pdp_dice_free, sizeof(t_pdp_dice), 0, A_NULL);
+
+ class_addmethod(pdp_dice_class, (t_method)pdp_dice_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_dice_class, (t_method)pdp_dice_cubebits, gensym("cubebits"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_edge.c b/modules/pdp_edge.c
new file mode 100644
index 0000000..89e3cd8
--- /dev/null
+++ b/modules/pdp_edge.c
@@ -0,0 +1,300 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 adaptation of edge effect from effectv
+ * Originally written by Fukuchi Kentaro & others
+ * Pd-fication by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+static char *pdp_edge_version = "pdp_edge: version 0.1, port of edge from effectv( Fukuchi Kentaro ) adapted by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_edge_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_mapw;
+ t_int x_maph;
+ t_int x_video_width_margin;
+ t_int *x_map;
+
+} t_pdp_edge;
+
+static void pdp_edge_allocate(t_pdp_edge *x)
+{
+ x->x_map = (t_int*) getbytes ( ( x->x_vwidth * x->x_vheight * sizeof (t_int) ) << 1 );
+ bzero(x->x_map, ( x->x_vwidth * x->x_vheight * sizeof (t_int) ) << 1 );
+}
+
+static void pdp_edge_free_ressources(t_pdp_edge *x)
+{
+ if ( x->x_map ) freebytes ( x->x_map, ( x->x_vwidth * x->x_vheight * sizeof (t_int) ) << 1 );
+}
+
+static void pdp_edge_process_yv12(t_pdp_edge *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);
+ int i;
+
+ t_int px, py;
+ t_int y, u, v;
+ t_int y0, u0, v0;
+ t_int y1, u1, v1;
+ t_int y2, u2, v2;
+ t_int y3, u3, v3;
+ short int *pdata, *pnewdata;
+
+ /* allocate all ressources */
+ if ( (int)(header->info.image.width*header->info.image.height) != x->x_vsize )
+ {
+ pdp_edge_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;
+ x->x_mapw = x->x_vwidth >> 2;
+ x->x_maph = x->x_vheight >> 2;
+ x->x_video_width_margin = x->x_vwidth - ( x->x_mapw << 2 );
+ pdp_edge_allocate(x);
+ }
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ pdata = data + x->x_vwidth*4+4;
+ pnewdata = newdata + x->x_vwidth*4+4;
+ for(py=1; py<x->x_vheight-4; py+=4)
+ {
+ for(px=1; px<x->x_vwidth-4; px+=4)
+ {
+ /* difference between the current pixel and right neighbor. */
+ y2 = (*(pdata+(py*x->x_vwidth+px))>>8) - (*(pdata+(py*x->x_vwidth+px)-4)>>8);
+ u2 = (*(pdata+x->x_vsize+(py*x->x_vwidth>>2)+(px>>1))>>8) -
+ (*(pdata+x->x_vsize+(py*x->x_vwidth>>2)+(px>>1)-2)>>8);
+ v2 = (*(pdata+x->x_vsize+(x->x_vsize>>2)+(py*x->x_vwidth>>2)+(px>>1))>>8) -
+ (*(pdata+x->x_vsize+(x->x_vsize>>2)+(py*x->x_vwidth>>2)+(px>>1)-2)>>8);
+ y2 *= y2;
+ u2 *= u2;
+ v2 *= v2;
+ y2 = y2>>5; /* To lack the lower bit for saturated addition, */
+ u2 = u2>>5; /* devide the value with 32, instead of 16. It is */
+ v2 = v2>>4; /* same as `v2 &= 0xfefeff' */
+ if(y2>127) y2 = 127;
+ if(u2>127) u2 = 127;
+ if(v2>255) v2 = 255;
+
+ /* difference between the current pixel and upper neighbor. */
+ y3 = (*(pdata+(py*x->x_vwidth+px))>>8) - (*(pdata+(py*x->x_vwidth+px)-4*x->x_vwidth)>>8);
+ u3 = (*(pdata+x->x_vsize+(py*x->x_vwidth>>2)+(px>>1))>>8) -
+ (*(pdata+x->x_vsize+(py*x->x_vwidth>>2)+(px>>1)-2*x->x_vwidth)>>8);
+ v3 = (*(pdata+x->x_vsize+(x->x_vsize>>2)+(py*x->x_vwidth>>2)+(px>>1))>>8) -
+ (*(pdata+x->x_vsize+(x->x_vsize>>2)+(py*x->x_vwidth>>2)+(px>>1)-2*x->x_vwidth)>>8);
+ y3 *= y3;
+ u3 *= u3;
+ v3 *= v3;
+ y3 = y3>>5; /* To lack the lower bit for saturated addition, */
+ u3 = u3>>5; /* devide the value with 32, instead of 16. It is */
+ v3 = v3>>4; /* same as `v2 &= 0xfefeff' */
+ if(y3>127) y3 = 127;
+ if(u3>127) u3 = 127;
+ if(v3>255) v3 = 255;
+
+ y0 = (x->x_map[(py-1)*x->x_vwidth*2+px*2]>>17);
+ u0 = (x->x_map[(py-1)*x->x_vwidth*2+px*2]>>9)&0xff;
+ v0 = x->x_map[(py-1)*x->x_vwidth*2+px*2]&0xff;
+ y1 = (x->x_map[py*x->x_vwidth*2+(px-1)*2+1]>>17);
+ u1 = (x->x_map[py*x->x_vwidth*2+(px-1)*2+1]>>9)&0xff;
+ v1 = x->x_map[py*x->x_vwidth*2+(px-1)*2+1]&0xff;
+ x->x_map[py*x->x_vwidth*2+px*2] = (y2<<17)|(u2<<9)|v2;
+ x->x_map[py*x->x_vwidth*2+px*2+1] = (y3<<17)|(u3<<9)|v3;
+ y = y0 + y1;
+ u = y & 0x01010100;
+ *(pnewdata+(py*x->x_vwidth+px)) = (y | (u - (u>>8)))<<8;
+ *(pnewdata+x->x_vsize+(py*x->x_vwidth>>2)+(px>>1)) = (y | (u - (u>>8)))<<8;
+ *(pnewdata+x->x_vsize+(x->x_vsize>>2)+(py*x->x_vwidth>>2)+(px>>1)) = (y | (u - (u>>8)))<<8;
+ y = y0 + y3;
+ u = y & 0x01010100;
+ *(pnewdata+(py*x->x_vwidth+px)+1) = (y | (u - (u>>8)))<<8;
+ *(pnewdata+x->x_vsize+(py*x->x_vwidth>>2)+(px>>1+1)) = (y | (u - (u>>8)))<<8;
+ *(pnewdata+x->x_vsize+(x->x_vsize>>2)+(py*x->x_vwidth>>2)+(px>>1+1)) = (y | (u - (u>>8)))<<8;
+ *(pnewdata+(py*x->x_vwidth+px)+2) = y3<<8;
+ *(pnewdata+x->x_vsize+(py*x->x_vwidth>>2)+((px+2)>>1)) = u3<<8;
+ *(pnewdata+x->x_vsize+(x->x_vsize>>2)+(py*x->x_vwidth>>2)+((px+2)>>1)) = v3<<8;
+ *(pnewdata+(py*x->x_vwidth+px)+3) = y3<<8;
+ *(pnewdata+x->x_vsize+(py*x->x_vwidth>>2)+((px+3)>>1)) = u3<<8;
+ *(pnewdata+x->x_vsize+(x->x_vsize>>2)+(py*x->x_vwidth>>2)+((px+3)>>1)) = v3<<8;
+ y = y2 + y1;
+ u = y & 0x01010100;
+ *(pnewdata+(py*x->x_vwidth+px)+x->x_vwidth) = (y | (u - (u>>8)))<<8;
+ *(pnewdata+x->x_vsize+((py+1)*x->x_vwidth>>2)+(px>>1)) = (y | (u - (u>>8)))<<8;
+ *(pnewdata+x->x_vsize+(x->x_vsize>>2)+((py+1)*x->x_vwidth>>2)+(px>>1)) = (y | (u - (u>>8)))<<8;
+ y = y2 + y3;
+ u = y & 0x01010100;
+
+ *(pnewdata+(py*x->x_vwidth+px)+x->x_vwidth+1) = (y | (u - (u>>8)))<<8;
+ *(pnewdata+x->x_vsize+((py+1)*x->x_vwidth>>2)+((px+1)>>1)) = (y | (u - (u>>8)))<<8;
+ *(pnewdata+x->x_vsize+(x->x_vsize>>2)+((py+1)*x->x_vwidth>>2)+((px+1)>>1)) = (y | (u - (u>>8)))<<8;
+
+ *(pnewdata+(py*x->x_vwidth+px)+x->x_vwidth+2) = y3<<8;
+ *(pnewdata+x->x_vsize+((py+1)*x->x_vwidth>>2)+((px+2)>>1)) = u3<<8;
+ *(pnewdata+x->x_vsize+(x->x_vsize>>2)+((py+1)*x->x_vwidth>>2)+((px+2)>>1)) = v3<<8;
+
+ *(pnewdata+(py*x->x_vwidth+px)+x->x_vwidth+3) = y3<<8;
+ *(pnewdata+x->x_vsize+((py+1)*x->x_vwidth>>2)+((px+3)>>1)) = u3<<8;
+ *(pnewdata+x->x_vsize+(x->x_vsize>>2)+((py+1)*x->x_vwidth>>2)+((px+3)>>1)) = v3<<8;
+
+ *(pnewdata+(py*x->x_vwidth+px)+2*x->x_vwidth) = y2<<8;
+ *(pnewdata+x->x_vsize+((py+2)*x->x_vwidth>>2)+((px)>>1)) = u2<<8;
+ *(pnewdata+x->x_vsize+(x->x_vsize>>2)+((py+2)*x->x_vwidth>>2)+((px)>>1)) = v2<<8;
+
+ *(pnewdata+(py*x->x_vwidth+px)+2*x->x_vwidth+1) = y2<<8;
+ *(pnewdata+x->x_vsize+((py+2)*x->x_vwidth>>2)+((px+1)>>1)) = u2<<8;
+ *(pnewdata+x->x_vsize+(x->x_vsize>>2)+((py+2)*x->x_vwidth>>2)+((px+1)>>1)) = v2<<8;
+
+ *(pnewdata+(py*x->x_vwidth+px)+3*x->x_vwidth) = y2<<8;
+ *(pnewdata+x->x_vsize+((py+3)*x->x_vwidth>>2)+((px)>>1)) = u2<<8;
+ *(pnewdata+x->x_vsize+(x->x_vsize>>2)+((py+3)*x->x_vwidth>>2)+((px)>>1)) = v2<<8;
+
+ *(pnewdata+(py*x->x_vwidth+px)+3*x->x_vwidth+1) = y2<<8;
+ *(pnewdata+x->x_vsize+((py+3)*x->x_vwidth>>2)+((px+1)>>1)) = u2<<8;
+ *(pnewdata+x->x_vsize+(x->x_vsize>>2)+((py+3)*x->x_vwidth>>2)+((px+1)>>1)) = v2<<8;
+ }
+ }
+
+ return;
+}
+
+static void pdp_edge_sendpacket(t_pdp_edge *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_edge_process(t_pdp_edge *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_edge_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_edge_process_yv12, pdp_edge_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_edge_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_edge_input_0(t_pdp_edge *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_edge_process(x);
+
+ }
+}
+
+static void pdp_edge_free(t_pdp_edge *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_edge_free_ressources(x);
+}
+
+t_class *pdp_edge_class;
+
+void *pdp_edge_new(void)
+{
+ int i;
+
+ t_pdp_edge *x = (t_pdp_edge *)pd_new(pdp_edge_class);
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_queue_id = -1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_edge_setup(void)
+{
+// post( pdp_edge_version );
+ pdp_edge_class = class_new(gensym("pdp_edge"), (t_newmethod)pdp_edge_new,
+ (t_method)pdp_edge_free, sizeof(t_pdp_edge), 0, A_NULL);
+
+ class_addmethod(pdp_edge_class, (t_method)pdp_edge_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_ffmpeg~.c b/modules/pdp_ffmpeg~.c
new file mode 100644
index 0000000..30e321f
--- /dev/null
+++ b/modules/pdp_ffmpeg~.c
@@ -0,0 +1,740 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* This object is a streaming object towards a ffmeg server
+ * A lot of this object code is inspired by the excellent ffmpeg.c
+ * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
+ * The rest is written by Yves Degoyon ( ydegoyon@free.fr )
+ */
+
+
+#include "pdp.h"
+#include <math.h>
+#include <time.h>
+#include <sys/time.h>
+#include <avformat.h>
+
+#define VIDEO_BUFFER_SIZE (1024*1024)
+#define MAX_AUDIO_PACKET_SIZE (128 * 1024)
+#define AUDIO_PACKET_SIZE (2*1152)
+
+static char *pdp_ffmpeg_version = "pdp_ffmpeg~: version 0.1, a video streaming object (towards ffserver)";
+
+typedef struct pdp_ffmpeg_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_dropped;
+ t_int x_queue_id;
+
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+
+ t_outlet *x_outlet_streaming; // indicates the action of streaming
+ t_outlet *x_outlet_nbframes; // number of frames emitted
+ t_outlet *x_outlet_nbframes_dropped; // number of frames dropped
+
+ char *x_feedname;
+ t_int x_streaming; // streaming flag
+ t_int x_nbframes; // number of frames emitted
+ t_int x_nbframes_dropped; // number of frames dropped
+ t_int x_nbvideostreams; // number of video streams
+ t_int x_nbaudiostreams; // number of audio streams
+ t_int x_cursec; // current second
+ t_int *x_secondcount; // number of frames emitted in the current second ( per video stream )
+
+ /* AV data structures */
+ AVFormatContext *x_avcontext;
+ AVFormatParameters x_avparameters; // unused but the call is necessary to allocate structures
+ AVPicture *x_final_picture;
+ AVPicture *x_formatted_picture;
+ AVPicture x_picture_format;
+ AVPicture x_picture_final;
+ ImgReSampleContext *x_img_resample_ctx;
+ uint8_t *x_video_buffer;
+ uint8_t *x_rdata;
+ uint8_t *x_buf1;
+ uint8_t *x_buf2;
+
+ /* audio structures */
+ short x_audio_buf[2*MAX_AUDIO_PACKET_SIZE]; /* buffer for incoming audio */
+ short x_audio_enc_buf[2*MAX_AUDIO_PACKET_SIZE]; /* buffer for audio to be encoded */
+ uint8_t x_audio_out[4*MAX_AUDIO_PACKET_SIZE]; /* buffer for encoded audio */
+ t_int x_audioin_position; // writing position for incoming audio
+ t_int x_audio_per_frame; // number of audio samples to transmit for each frame
+ ReSampleContext *x_audio_resample_ctx; // structures for audio resample
+ FifoBuffer *x_audio_fifo; // audio fifos ( one per codec )
+
+} t_pdp_ffmpeg;
+
+static int pdp_ffmpeg_read_ffserver_streams(t_pdp_ffmpeg *x)
+{
+ int i, err;
+ AVFormatContext *ic;
+
+ err = av_open_input_file(&ic, x->x_feedname, NULL, FFM_PACKET_SIZE, NULL);
+ if (err < 0)
+ {
+ return err;
+ }
+
+ /* copy stream format */
+ x->x_avcontext->nb_streams = ic->nb_streams;
+ x->x_nbvideostreams = 0;
+ x->x_nbaudiostreams = 0;
+
+ for(i=0;i<ic->nb_streams;i++)
+ {
+ AVStream *st;
+
+ st = av_mallocz(sizeof(AVFormatContext));
+ memcpy(st, ic->streams[i], sizeof(AVStream));
+ x->x_avcontext->streams[i] = st;
+
+ if ( ic->streams[i]->codec.codec_type == CODEC_TYPE_UNKNOWN )
+ {
+ post( "pdp_ffmpeg~ : stream #%d # type : unknown", i );
+ }
+ if ( ic->streams[i]->codec.codec_type == CODEC_TYPE_AUDIO )
+ {
+ post( "pdp_ffmpeg~ : stream #%d # type : audio # id : %d # bitrate : %d",
+ i, ic->streams[i]->codec.codec_id, ic->streams[i]->codec.bit_rate );
+ post( "pdp_ffmpeg~ : sample rate : %d # channels : %d",
+ ic->streams[i]->codec.sample_rate, ic->streams[i]->codec.channels );
+ x->x_nbaudiostreams++;
+ }
+ if ( ic->streams[i]->codec.codec_type == CODEC_TYPE_VIDEO )
+ {
+ post( "pdp_ffmpeg~ : stream #%d # type : video # id : %d # bitrate : %d",
+ i, ic->streams[i]->codec.codec_id, ic->streams[i]->codec.bit_rate );
+ post( "pdp_ffmpeg~ : framerate : %d # width : %d # height : %d",
+ ic->streams[i]->codec.frame_rate/10000, ic->streams[i]->codec.width, ic->streams[i]->codec.height );
+ x->x_nbvideostreams++;
+ }
+ }
+
+ if ( x->x_secondcount ) free( x->x_secondcount );
+ x->x_secondcount = (t_int*) malloc( x->x_nbvideostreams*sizeof(t_int) );
+ memset( x->x_secondcount, 0x00, x->x_nbvideostreams*sizeof(t_int) );
+ x->x_audio_fifo = (FifoBuffer*) malloc( x->x_nbaudiostreams*sizeof(FifoBuffer) );
+ for ( i=0; i<x->x_nbaudiostreams; i++)
+ {
+ fifo_init(&x->x_audio_fifo[i], 2 * MAX_AUDIO_PACKET_SIZE);
+ }
+
+ av_close_input_file(ic);
+
+ return 0;
+}
+
+static void pdp_ffmpeg_starve(t_pdp_ffmpeg *x)
+{
+ t_int ret, i;
+
+ if (!x->x_streaming)
+ {
+ post("pdp_ffmpeg~ : close request but no feed is opened ... ignored" );
+ return;
+ }
+
+ x->x_streaming = 0;
+ outlet_float( x->x_outlet_streaming, x->x_streaming );
+ x->x_nbframes = 0;
+ outlet_float( x->x_outlet_nbframes, x->x_nbframes );
+ x->x_nbframes_dropped = 0;
+ outlet_float( x->x_outlet_nbframes_dropped, x->x_nbframes_dropped );
+ if ( x->x_buf1 ) free( x->x_buf1 );
+ x->x_buf1 = NULL;
+ if ( x->x_buf2 ) free( x->x_buf2 );
+ x->x_buf2 = NULL;
+
+ if (x->x_img_resample_ctx)
+ {
+ img_resample_close(x->x_img_resample_ctx);
+ x->x_img_resample_ctx = NULL;
+ }
+
+ if (x->x_audio_resample_ctx)
+ {
+ audio_resample_close(x->x_audio_resample_ctx);
+ x->x_audio_resample_ctx = NULL;
+ }
+
+ if ( ( ret = url_fclose(&x->x_avcontext->pb) ) < 0 )
+ {
+ post("pdp_ffmpeg~ : could not close stream (ret=%d)", ret );
+ }
+
+ for(i=0;i<x->x_avcontext->nb_streams;i++)
+ {
+ avcodec_close( &x->x_avcontext->streams[i]->codec );
+ av_free( x->x_avcontext->streams[i] );
+ }
+
+}
+
+static void pdp_ffmpeg_feed(t_pdp_ffmpeg *x, t_symbol *s)
+{
+ t_int ret, i;
+
+ if (x->x_streaming)
+ {
+ post("pdp_ffmpeg~ : feed request but a feed is running ... ignored" );
+ return;
+ }
+
+ if ( !strstr( s->s_name, "http:" ) || !strstr( s->s_name, ".ffm" ) )
+ {
+ post( "pdp_ffmpeg~ : wrong feed format <%s>: should be like http://localhost:8090/test.ffm", s->s_name );
+ }
+ if ( x->x_feedname ) free( x->x_feedname );
+ x->x_feedname = (char*) malloc( strlen( s->s_name ) + 1 );
+ strcpy( x->x_feedname, s->s_name );
+
+ /* set output format */
+ x->x_avcontext->oformat = guess_format(NULL, s->s_name, NULL);
+
+ if ( ( ret = pdp_ffmpeg_read_ffserver_streams(x) ) < 0 )
+ {
+ post( "pdp_ffmpeg~ : error encountered while reading feed informations :", ret );
+ if ( ret == -1 ) post( "pdp_ffmpeg~ : unknown error" );
+ if ( ret == -2 ) post( "pdp_ffmpeg~ : i/o error" );
+ if ( ret == -3 ) post( "pdp_ffmpeg~ : number syntax expected in filename" );
+ if ( ret == -4 ) post( "pdp_ffmpeg~ : invalid data found" );
+ if ( ret == -5 ) post( "pdp_ffmpeg~ : not enough memory" );
+ if ( ret == -6 ) post( "pdp_ffmpeg~ : unknown format" );
+
+ x->x_streaming = 0;
+ outlet_float( x->x_outlet_streaming, x->x_streaming );
+ return;
+ }
+
+ /* open the stream now */
+ if (url_fopen(&x->x_avcontext->pb, s->s_name, URL_WRONLY) < 0)
+ {
+ post("pdp_ffmpeg~ : could not open stream '%s'", s->s_name);
+ x->x_streaming = 0;
+ outlet_float( x->x_outlet_streaming, x->x_streaming );
+ return;
+ }
+ else
+ {
+ post("pdp_ffmpeg~ : opened stream '%s'", s->s_name);
+ }
+
+ /* open each encoder */
+ for(i=0;i<x->x_avcontext->nb_streams;i++)
+ {
+ AVCodec *codec;
+ codec = avcodec_find_encoder(x->x_avcontext->streams[i]->codec.codec_id);
+ if (!codec)
+ {
+ post("pdp_ffmpeg~ : unsupported codec for output stream #%d\n", i );
+ x->x_streaming = 0;
+ outlet_float( x->x_outlet_streaming, x->x_streaming );
+ return;
+ }
+ if (avcodec_open(&x->x_avcontext->streams[i]->codec, codec) < 0)
+ {
+ post("pdp_ffmpeg~ : error while opening codec for stream #%d - maybe incorrect parameters such as bit_rate, rate, width or height\n", i);
+ x->x_streaming = 0;
+ outlet_float( x->x_outlet_streaming, x->x_streaming );
+ return;
+ }
+ else
+ {
+ post("pdp_ffmpeg~ : opened encoder for stream #%d", i);
+ }
+ }
+
+ /* set parameters */
+ if (av_set_parameters(x->x_avcontext, &x->x_avparameters) < 0)
+ {
+ post("pdp_ffmpeg~ : severe error : could not set encoding parameters" );
+ x->x_streaming = 0;
+ outlet_float( x->x_outlet_streaming, x->x_streaming );
+ return;
+ }
+
+ /* write header */
+ if (av_write_header(x->x_avcontext) < 0)
+ {
+ post("pdp_ffmpeg~ : could not write header (incorrect codec parameters ?)\n", i);
+ x->x_streaming = 0;
+ outlet_float( x->x_outlet_streaming, x->x_streaming );
+ return;
+ }
+
+ x->x_streaming = 1;
+ outlet_float( x->x_outlet_streaming, x->x_streaming );
+ x->x_nbframes = 0;
+ outlet_float( x->x_outlet_nbframes, x->x_nbframes );
+ x->x_nbframes_dropped = 0;
+ outlet_float( x->x_outlet_nbframes_dropped, x->x_nbframes_dropped );
+
+}
+
+static void pdp_ffmpeg_allocate(t_pdp_ffmpeg *x)
+{
+ x->x_rdata = (uint8_t*) getbytes( (x->x_vsize+(x->x_vsize>>1))*sizeof(uint8_t) );
+}
+
+static void pdp_ffmpeg_free_ressources(t_pdp_ffmpeg *x)
+{
+ if (x->x_rdata) freebytes( x->x_rdata, (x->x_vsize+(x->x_vsize>>1))*sizeof(uint8_t) );
+}
+
+static void pdp_ffmpeg_process_yv12(t_pdp_ffmpeg *x)
+{
+ t_pdp *header = pdp_packet_header(x->x_packet0);
+ short int *data = (short int *)pdp_packet_data(x->x_packet0);
+ t_pdp *newheader = 0;
+ short int *newdata = 0;
+ t_int newpacket = -1, i;
+ short int *pY, *pU, *pV;
+ uint8_t *pnY, *pnU, *pnV;
+ t_int px, py;
+ t_int svideoindex;
+ t_int saudioindex;
+ struct timeval etime;
+ t_int sizeout, size, encsize;
+ t_int framebytes;
+ t_int owidth, oheight;
+ short *pencbuf;
+
+ /* allocate all ressources */
+ if ( ((int)header->info.image.width != x->x_vwidth) ||
+ ((int)header->info.image.height != x->x_vheight) )
+ {
+ pdp_ffmpeg_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_ffmpeg_allocate(x);
+ }
+
+ if ( x->x_streaming )
+ {
+ AVPicture pdppict;
+
+ pY = data;
+ pV = data+x->x_vsize;
+ pU = data+x->x_vsize+(x->x_vsize>>2);
+ pnY = x->x_rdata;
+ pnU = x->x_rdata+x->x_vsize;
+ pnV = x->x_rdata+x->x_vsize+(x->x_vsize>>2);
+ for(py=0; py<x->x_vheight; py++)
+ {
+ for(px=0; px<x->x_vwidth; px++)
+ {
+ *pnY = (uint8_t) (*(pY++)>>7);
+ if ( *pnY > 255 ) *pnY=255;
+ pnY++;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ *pnV = (uint8_t) (((*(pV++))>>8)+128);
+ if ( *pnV > 255 ) *pnV=255;
+ *pnU = (uint8_t) (((*(pU++))>>8)+128);
+ if ( *pnU > 255 ) *pnU=255;
+ pnU++;pnV++;
+ }
+ }
+ }
+
+ if ( avpicture_fill(&pdppict, x->x_rdata,
+ PIX_FMT_YUV420P,
+ x->x_vwidth,
+ x->x_vheight) < 0 )
+ {
+ post( "pdp_ffmpeg~ : could not build av picture" );
+ }
+
+ // output all video streams
+ svideoindex=0;
+ saudioindex=0;
+ for (i=0; i<x->x_avcontext->nb_streams; i++)
+ {
+ /* convert pixel format and size if needed */
+ if ( x->x_avcontext->streams[i]->codec.codec_type == CODEC_TYPE_VIDEO )
+ {
+ t_int size;
+
+ // check if the framerate has been exceeded
+ if ( gettimeofday(&etime, NULL) == -1)
+ {
+ post("pdp_ffmpeg~ : could not read time" );
+ }
+ if ( etime.tv_sec != x->x_cursec )
+ {
+ x->x_cursec = etime.tv_sec;
+ x->x_secondcount[ svideoindex ] = 0;
+ }
+ if ( x->x_secondcount[ svideoindex ] >= x->x_avcontext->streams[i]->codec.frame_rate/10000 )
+ {
+ x->x_nbframes_dropped++;
+ continue;
+ }
+
+ if ( x->x_avcontext->streams[i]->codec.pix_fmt != PIX_FMT_YUV420P )
+ {
+ /* create temporary picture */
+ size = avpicture_get_size(x->x_avcontext->streams[i]->codec.pix_fmt,
+ x->x_vwidth, x->x_vheight );
+ if (!x->x_buf1) x->x_buf1 = (uint8_t*) malloc(size);
+ if (!x->x_buf1)
+ {
+ post ("pdp_ffmpeg~ : severe error : could not allocate image buffer" );
+ return;
+ }
+ x->x_formatted_picture = &x->x_picture_format;
+ avpicture_fill(x->x_formatted_picture, x->x_buf1,
+ x->x_avcontext->streams[i]->codec.pix_fmt,
+ x->x_vwidth, x->x_vheight );
+
+ if (img_convert(x->x_formatted_picture,
+ x->x_avcontext->streams[i]->codec.pix_fmt,
+ &pdppict, PIX_FMT_YUV420P,
+ x->x_vwidth, x->x_vheight ) < 0)
+ {
+ post ("pdp_ffmpeg~ : error : image conversion failed" );
+ }
+ }
+ else
+ {
+ x->x_formatted_picture = &pdppict;
+ }
+
+ // post ( "pdp_ffmpeg~ : resampling [%d,%d] -> [%d,%d]",
+ // x->x_vwidth, x->x_vheight,
+ // x->x_avcontext->streams[i]->codec.width,
+ // x->x_avcontext->streams[i]->codec.height );
+ if ( ( x->x_avcontext->streams[i]->codec.width < x->x_vwidth ) &&
+ ( x->x_avcontext->streams[i]->codec.height < x->x_vheight ) )
+ {
+ owidth = x->x_avcontext->streams[i]->codec.width;
+ oheight = x->x_avcontext->streams[i]->codec.height;
+
+ if (x->x_img_resample_ctx) img_resample_close(x->x_img_resample_ctx);
+ x->x_img_resample_ctx = img_resample_full_init(
+ owidth, oheight,
+ x->x_vwidth, x->x_vheight, 0, 0, 0, 0);
+
+ size = avpicture_get_size(x->x_avcontext->streams[i]->codec.pix_fmt,
+ owidth, oheight );
+ if ( !x->x_buf2 )
+ {
+ x->x_buf2 = (uint8_t*) malloc(size);
+ }
+ if (!x->x_buf2)
+ {
+ post ("pdp_ffmpeg~ : severe error : could not allocate image buffer" );
+ return;
+ }
+ x->x_final_picture = &x->x_picture_final;
+ avpicture_fill(x->x_final_picture, x->x_buf2,
+ x->x_avcontext->streams[i]->codec.pix_fmt,
+ owidth, oheight );
+
+ img_resample(x->x_img_resample_ctx, x->x_final_picture, x->x_formatted_picture);
+
+ }
+ else
+ {
+ x->x_final_picture = x->x_formatted_picture;
+ }
+
+ // encode and send the picture
+ {
+ AVFrame aframe;
+ t_int fsize, ret;
+
+ memset(&aframe, 0, sizeof(AVFrame));
+ *(AVPicture*)&aframe= *x->x_final_picture;
+
+ aframe.quality = x->x_avcontext->streams[i]->quality;
+
+ fsize = avcodec_encode_video(&x->x_avcontext->streams[i]->codec,
+ x->x_video_buffer, VIDEO_BUFFER_SIZE,
+ &aframe);
+ if ( ( ret = av_write_frame( x->x_avcontext, i, x->x_video_buffer, fsize) ) < 0 )
+ {
+ post ("pdp_ffmpeg~ : error : could not send frame : (ret=%d)", ret );
+ return;
+ }
+ else
+ {
+ x->x_nbframes++;
+ x->x_secondcount[ svideoindex++ ]++;
+ }
+ }
+ }
+
+ /* convert and stream audio data */
+ if ( x->x_avcontext->streams[i]->codec.codec_type == CODEC_TYPE_AUDIO )
+ {
+ // we assume audio is synchronized on next video stream
+ if ( ( (i+1) < x->x_avcontext->nb_streams ) &&
+ ( x->x_avcontext->streams[i+1]->codec.codec_type == CODEC_TYPE_VIDEO ) )
+ {
+ x->x_audio_per_frame =
+ // 2*( (int) sys_getsr() ) / ( x->x_avcontext->streams[i+1]->codec.frame_rate/10000);
+ AUDIO_PACKET_SIZE;
+ // post ("pdp_ffmpeg~ : transmit %d samples", x->x_audio_per_frame );
+ }
+ else
+ {
+ post ("pdp_ffmpeg~ : can't stream audio : video stream is not found" );
+ continue;
+ }
+
+ if ( x->x_audioin_position > x->x_audio_per_frame )
+ {
+ size = x->x_audioin_position;
+ if ( ( x->x_avcontext->streams[i]->codec.sample_rate != (int)sys_getsr() ) ||
+ ( x->x_avcontext->streams[i]->codec.channels != 2 ) )
+ {
+ if (x->x_audio_resample_ctx) audio_resample_close(x->x_audio_resample_ctx);
+ x->x_audio_resample_ctx =
+ audio_resample_init(x->x_avcontext->streams[i]->codec.channels, 2,
+ x->x_avcontext->streams[i]->codec.sample_rate,
+ (int)sys_getsr());
+ sizeout = audio_resample(x->x_audio_resample_ctx,
+ x->x_audio_enc_buf,
+ x->x_audio_buf,
+ size / (x->x_avcontext->streams[i]->codec.channels * 2));
+ pencbuf = (short*) &x->x_audio_enc_buf;
+ sizeout = sizeout * x->x_avcontext->streams[i]->codec.channels * 2;
+ }
+ else
+ {
+ pencbuf = (short*) &x->x_audio_buf;
+ sizeout = size;
+ }
+
+ /* output resampled raw samples */
+ fifo_write(&x->x_audio_fifo[saudioindex], (uint8_t*)pencbuf, sizeout,
+ &x->x_audio_fifo[saudioindex].wptr);
+
+ framebytes = x->x_avcontext->streams[i]->codec.frame_size * 2 *
+ x->x_avcontext->streams[i]->codec.channels;
+
+ while (fifo_read(&x->x_audio_fifo[saudioindex], (uint8_t*)pencbuf, framebytes,
+ &x->x_audio_fifo[saudioindex].rptr) == 0)
+ {
+ encsize = avcodec_encode_audio(&x->x_avcontext->streams[i]->codec,
+ (uint8_t*)&x->x_audio_out, sizeof(x->x_audio_out),
+ (short *)pencbuf);
+ av_write_frame(x->x_avcontext, i, x->x_audio_out, encsize);
+ }
+ saudioindex++;
+ }
+ }
+ }
+ x->x_audioin_position=0;
+ }
+ return;
+}
+
+static void pdp_ffmpeg_killpacket(t_pdp_ffmpeg *x)
+{
+ /* delete source packet */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = -1;
+}
+
+ /* store audio data in PCM format and stream it */
+static t_int *pdp_ffmpeg_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_ffmpeg *x = (t_pdp_ffmpeg *)(w[3]);
+ int n = (int)(w[4]); // number of samples
+ t_float fsample;
+ t_int isample, i;
+
+ // just fills the buffer
+ while (n--)
+ {
+ fsample=*(in1++);
+ if (fsample > 1.0) { fsample = 1.0; }
+ if (fsample < -1.0) { fsample = -1.0; }
+ isample=(short) (32767.0 * fsample);
+ *(x->x_audio_buf+x->x_audioin_position)=isample;
+ x->x_audioin_position=(x->x_audioin_position+1)%(2*MAX_AUDIO_PACKET_SIZE);
+ if ( x->x_audioin_position == 2*MAX_AUDIO_PACKET_SIZE-1 )
+ {
+ post( "pdp_ffmpeg~ : reaching end of audio buffer" );
+ }
+ fsample=*(in2++);
+ if (fsample > 1.0) { fsample = 1.0; }
+ if (fsample < -1.0) { fsample = -1.0; }
+ isample=(short) (32767.0 * fsample);
+ *(x->x_audio_buf+x->x_audioin_position)=isample;
+ x->x_audioin_position=(x->x_audioin_position+1)%(2*MAX_AUDIO_PACKET_SIZE);
+ if ( x->x_audioin_position == 2*MAX_AUDIO_PACKET_SIZE-1 )
+ {
+ post( "pdp_ffmpeg~ : reaching end of audio buffer" );
+ }
+ }
+
+ return (w+5);
+}
+
+static void pdp_ffmpeg_dsp(t_pdp_ffmpeg *x, t_signal **sp)
+{
+ dsp_add(pdp_ffmpeg_perform, 4, sp[0]->s_vec, sp[1]->s_vec, x, sp[0]->s_n);
+}
+
+static void pdp_ffmpeg_process(t_pdp_ffmpeg *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_ffmpeg_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_ffmpeg_process_yv12, pdp_ffmpeg_killpacket, &x->x_queue_id);
+ outlet_float( x->x_outlet_nbframes, x->x_nbframes );
+ outlet_float( x->x_outlet_nbframes_dropped, x->x_nbframes_dropped );
+ 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_ffmpeg_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_ffmpeg_input_0(t_pdp_ffmpeg *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_ffmpeg_process(x);
+ }
+
+}
+
+static void pdp_ffmpeg_free(t_pdp_ffmpeg *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_ffmpeg_free_ressources(x);
+ if (x->x_img_resample_ctx)
+ {
+ img_resample_close(x->x_img_resample_ctx);
+ x->x_img_resample_ctx = NULL;
+ }
+ if (x->x_audio_resample_ctx)
+ {
+ audio_resample_close(x->x_audio_resample_ctx);
+ x->x_audio_resample_ctx = NULL;
+ }
+ av_free_static();
+}
+
+t_class *pdp_ffmpeg_class;
+
+void *pdp_ffmpeg_new(void)
+{
+ int i;
+
+ t_pdp_ffmpeg *x = (t_pdp_ffmpeg *)pd_new(pdp_ffmpeg_class);
+ inlet_new (&x->x_obj, &x->x_obj.ob_pd, gensym ("signal"), gensym ("signal"));
+
+ x->x_outlet_streaming = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet_nbframes = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet_nbframes_dropped = outlet_new(&x->x_obj, &s_float);
+
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+ x->x_nbframes = 0;
+ x->x_nbframes_dropped = 0;
+ x->x_img_resample_ctx = NULL;
+ x->x_audio_resample_ctx = NULL;
+ x->x_secondcount = NULL;
+ x->x_nbvideostreams = 0;
+ x->x_audioin_position = 0;
+
+ x->x_rdata = NULL;
+ x->x_buf1 = NULL;
+ x->x_buf2 = NULL;
+ x->x_avcontext = av_mallocz(sizeof(AVFormatContext));
+ x->x_video_buffer = av_malloc( VIDEO_BUFFER_SIZE );
+ if ( !x->x_video_buffer || !x->x_avcontext )
+ {
+ post( "pdp_ffmpeg~ : severe error : could not allocate video structures." );
+ return NULL;
+ }
+
+ // activate codecs
+ av_register_all();
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_ffmpeg_tilde_setup(void)
+{
+ post( pdp_ffmpeg_version );
+ pdp_ffmpeg_class = class_new(gensym("pdp_ffmpeg~"), (t_newmethod)pdp_ffmpeg_new,
+ (t_method)pdp_ffmpeg_free, sizeof(t_pdp_ffmpeg), 0, A_NULL);
+
+ CLASS_MAINSIGNALIN(pdp_ffmpeg_class, t_pdp_ffmpeg, x_f );
+ class_addmethod(pdp_ffmpeg_class, (t_method)pdp_ffmpeg_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_ffmpeg_class, (t_method)pdp_ffmpeg_dsp, gensym("dsp"), 0);
+ class_addmethod(pdp_ffmpeg_class, (t_method)pdp_ffmpeg_feed, gensym("feed"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_ffmpeg_class, (t_method)pdp_ffmpeg_starve, gensym("starve"), A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_form.c b/modules/pdp_form.c
new file mode 100644
index 0000000..5b92fe8
--- /dev/null
+++ b/modules/pdp_form.c
@@ -0,0 +1,608 @@
+/*
+ * PiDiP module
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 geometric forms generator object for PDP
+ * It uses imlib2 for all graphical operations
+ */
+
+/* Listening to :
+ * Culturcide - Bruce
+ * This Heat - Independence
+ */
+
+#include "pdp.h"
+#include "yuv.h"
+#include <math.h>
+#include <ctype.h>
+#include <Imlib2.h> // imlib2 is required
+
+
+/* forms type */
+enum _form_type
+{
+ IMLIB_LINE,
+ IMLIB_RECTANGLE,
+ IMLIB_ELLIPSE
+};
+typedef enum _form_type t_form_type;
+
+typedef struct _form
+{
+ t_form_type type;
+ t_int n1,n2,n3,n4; // numerical coordinates or rays
+ t_int r,g,b;
+} t_form;
+
+
+#define DEFAULT_CAPACITY 10
+
+static char *pdp_form_version = "pdp_form: version 0.1 : forms rendering object written by ydegoyon@free.fr ";
+
+typedef struct pdp_form_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_packet1;
+ t_int x_dropped;
+ t_int x_queue_id;
+
+ t_outlet *x_outlet0;
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+
+ t_form *x_forms;
+ t_int x_nbforms;
+ t_int x_current;
+ t_int x_capacity;
+
+ /* imlib data */
+ Imlib_Image x_image;
+
+} t_pdp_form;
+
+ /* add a line */
+static void pdp_form_line(t_pdp_form *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if ( x->x_nbforms >= x->x_capacity )
+ {
+ post( "pdp_form : sorry, maximum capacity has been reached... try resize" );
+ return;
+ }
+
+ if ( argc < 4 )
+ {
+ post( "pdp_form : error in the number of arguments ( minimum is 4 )", argc );
+ return;
+ }
+ if ( argv[0].a_type != A_FLOAT || argv[1].a_type != A_FLOAT ||
+ argv[2].a_type != A_FLOAT || argv[3].a_type != A_FLOAT ) {
+ post( "pdp_form : add : wrong arguments" );
+ return;
+ }
+
+ x->x_forms[x->x_nbforms].type = IMLIB_LINE;
+ x->x_forms[x->x_nbforms].n1 = (int)argv[0].a_w.w_float;
+ x->x_forms[x->x_nbforms].n2 = (int)argv[1].a_w.w_float;
+ x->x_forms[x->x_nbforms].n3 = (int)argv[2].a_w.w_float;
+ x->x_forms[x->x_nbforms].n4 = (int)argv[3].a_w.w_float;
+
+ if ( (argc>=5) && (argv[4].a_type == A_FLOAT) )
+ {
+ x->x_forms[x->x_nbforms].r = (int)argv[4].a_w.w_float;
+ }
+ if ( (argc>=6) && (argv[5].a_type == A_FLOAT) )
+ {
+ x->x_forms[x->x_nbforms].g = (int)argv[5].a_w.w_float;
+ }
+ if ( (argc>=7) && (argv[6].a_type == A_FLOAT) )
+ {
+ x->x_forms[x->x_nbforms].b = (int)argv[6].a_w.w_float;
+ }
+
+ post( "pdp_form : added line [%d,%d,%d,%d] @ %d (r=%d g=%d b=%d)",
+ x->x_forms[x->x_nbforms].n1, x->x_forms[x->x_nbforms].n2,
+ x->x_forms[x->x_nbforms].n3, x->x_forms[x->x_nbforms].n4, x->x_nbforms,
+ x->x_forms[x->x_nbforms].r, x->x_forms[x->x_nbforms].g, x->x_forms[x->x_nbforms].b );
+
+ if ( x->x_current == -1 ) x->x_current = x->x_nbforms;
+ x->x_nbforms++;
+
+}
+
+ /* add a rectangle */
+static void pdp_form_rectangle(t_pdp_form *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if ( x->x_nbforms >= x->x_capacity )
+ {
+ post( "pdp_form : sorry, maximum capacity has been reached... try resize" );
+ return;
+ }
+
+ if ( argc < 4 )
+ {
+ post( "pdp_form : error in the number of arguments ( minimum is 4 )", argc );
+ return;
+ }
+ if ( argv[0].a_type != A_FLOAT || argv[1].a_type != A_FLOAT ||
+ argv[2].a_type != A_FLOAT || argv[3].a_type != A_FLOAT ) {
+ post( "pdp_form : add : wrong arguments" );
+ return;
+ }
+
+ x->x_forms[x->x_nbforms].type = IMLIB_RECTANGLE;
+ x->x_forms[x->x_nbforms].n1 = (int)argv[0].a_w.w_float;
+ x->x_forms[x->x_nbforms].n2 = (int)argv[1].a_w.w_float;
+ x->x_forms[x->x_nbforms].n3 = (int)argv[2].a_w.w_float;
+ x->x_forms[x->x_nbforms].n4 = (int)argv[3].a_w.w_float;
+
+ if ( (argc>=5) && (argv[4].a_type == A_FLOAT) )
+ {
+ x->x_forms[x->x_nbforms].r = (int)argv[4].a_w.w_float;
+ }
+ if ( (argc>=6) && (argv[5].a_type == A_FLOAT) )
+ {
+ x->x_forms[x->x_nbforms].g = (int)argv[5].a_w.w_float;
+ }
+ if ( (argc>=7) && (argv[6].a_type == A_FLOAT) )
+ {
+ x->x_forms[x->x_nbforms].b = (int)argv[6].a_w.w_float;
+ }
+
+ post( "pdp_form : added rectangle [%d,%d,%d,%d] @ %d (r=%d g=%d b=%d)",
+ x->x_forms[x->x_nbforms].n1, x->x_forms[x->x_nbforms].n2,
+ x->x_forms[x->x_nbforms].n3, x->x_forms[x->x_nbforms].n4, x->x_nbforms,
+ x->x_forms[x->x_nbforms].r, x->x_forms[x->x_nbforms].g, x->x_forms[x->x_nbforms].b );
+
+ if ( x->x_current == -1 ) x->x_current = x->x_nbforms;
+ x->x_nbforms++;
+
+}
+
+ /* add an ellipse */
+static void pdp_form_ellipse(t_pdp_form *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if ( x->x_nbforms >= x->x_capacity )
+ {
+ post( "pdp_form : sorry, maximum capacity has been reached... try resize" );
+ return;
+ }
+
+ if ( argc < 4 )
+ {
+ post( "pdp_form : error in the number of arguments ( minimum is 4 )", argc );
+ return;
+ }
+ if ( argv[0].a_type != A_FLOAT || argv[1].a_type != A_FLOAT ||
+ argv[2].a_type != A_FLOAT || argv[3].a_type != A_FLOAT ) {
+ post( "pdp_form : add : wrong arguments" );
+ return;
+ }
+
+ x->x_forms[x->x_nbforms].type = IMLIB_ELLIPSE;
+ x->x_forms[x->x_nbforms].n1 = (int)argv[0].a_w.w_float;
+ x->x_forms[x->x_nbforms].n2 = (int)argv[1].a_w.w_float;
+ x->x_forms[x->x_nbforms].n3 = (int)argv[2].a_w.w_float;
+ x->x_forms[x->x_nbforms].n4 = (int)argv[3].a_w.w_float;
+
+ if ( (argc>=5) && (argv[4].a_type == A_FLOAT) )
+ {
+ x->x_forms[x->x_nbforms].r = (int)argv[4].a_w.w_float;
+ }
+ if ( (argc>=6) && (argv[5].a_type == A_FLOAT) )
+ {
+ x->x_forms[x->x_nbforms].g = (int)argv[5].a_w.w_float;
+ }
+ if ( (argc>=7) && (argv[6].a_type == A_FLOAT) )
+ {
+ x->x_forms[x->x_nbforms].b = (int)argv[6].a_w.w_float;
+ }
+
+ post( "pdp_form : added ellipse [%d,%d,%d,%d] @ %d (r=%d g=%d b=%d)",
+ x->x_forms[x->x_nbforms].n1, x->x_forms[x->x_nbforms].n2,
+ x->x_forms[x->x_nbforms].n3, x->x_forms[x->x_nbforms].n4, x->x_nbforms,
+ x->x_forms[x->x_nbforms].r, x->x_forms[x->x_nbforms].g, x->x_forms[x->x_nbforms].b );
+
+ if ( x->x_current == -1 ) x->x_current = x->x_nbforms;
+ x->x_nbforms++;
+
+}
+
+static void pdp_form_current(t_pdp_form *x, t_floatarg fcurrent )
+{
+ if ( ( fcurrent >= 0 ) && ( fcurrent < x->x_nbforms ) )
+ {
+ // post( "pdp_form : current item set to %d", x->x_current );
+ x->x_current = fcurrent;
+ }
+}
+
+static void pdp_form_x1(t_pdp_form *x, t_floatarg fx )
+{
+ if ( ( x->x_current >= 0 ) && ( x->x_current < x->x_nbforms ) )
+ {
+ x->x_forms[x->x_current].n1 = fx;
+ }
+}
+
+static void pdp_form_y1(t_pdp_form *x, t_floatarg fy )
+{
+ if ( ( x->x_current >= 0 ) && ( x->x_current < x->x_nbforms ) )
+ {
+ x->x_forms[x->x_current].n2 = fy;
+ }
+}
+
+static void pdp_form_x2(t_pdp_form *x, t_floatarg fx )
+{
+ if ( ( x->x_current >= 0 ) && ( x->x_current < x->x_nbforms ) )
+ {
+ x->x_forms[x->x_current].n3 = fx;
+ }
+}
+
+static void pdp_form_y2(t_pdp_form *x, t_floatarg fy )
+{
+ if ( ( x->x_current >= 0 ) && ( x->x_current < x->x_nbforms ) )
+ {
+ x->x_forms[x->x_current].n4 = fy;
+ }
+}
+
+static void pdp_form_r(t_pdp_form *x, t_floatarg fr )
+{
+ if ( ( x->x_current >= 0 ) && ( x->x_current < x->x_nbforms ) )
+ {
+ x->x_forms[x->x_current].r = fr;
+ }
+}
+
+static void pdp_form_g(t_pdp_form *x, t_floatarg fg )
+{
+ if ( ( x->x_current >= 0 ) && ( x->x_current < x->x_nbforms ) )
+ {
+ x->x_forms[x->x_current].g = fg;
+ }
+}
+
+static void pdp_form_b(t_pdp_form *x, t_floatarg fb )
+{
+ if ( ( x->x_current >= 0 ) && ( x->x_current < x->x_nbforms ) )
+ {
+ x->x_forms[x->x_current].b = fb;
+ }
+}
+
+static void pdp_form_clear(t_pdp_form *x )
+{
+ x->x_nbforms = 0;
+}
+
+static void pdp_form_delete(t_pdp_form *x, t_floatarg fnum )
+{
+ t_int i;
+ char *lostword;
+
+ if ( ( fnum>0 ) && ( fnum<=x->x_nbforms ) )
+ {
+ for ( i=(int)fnum; i<x->x_nbforms; i++ )
+ {
+ memcpy( &x->x_forms[ i-1 ], &x->x_forms[ i ], sizeof( t_form ) );
+ }
+ x->x_nbforms--;
+ }
+}
+
+static void pdp_form_resize(t_pdp_form *x, t_floatarg fnewsize )
+{
+ t_form *forms;
+ t_int i, csize;
+
+ if ( (int) fnewsize<=0 ) return;
+
+ // allocate new structures
+ forms = (t_form*) getbytes( fnewsize*sizeof(t_form) );
+
+ for ( i=0; i<fnewsize; i++ )
+ {
+ forms[i].r = forms[i].g = forms[i].b = 255;
+ }
+
+ if ( fnewsize < x->x_nbforms )
+ {
+ post( "pdp_form : new size is too small : texts lost !!" );
+ csize = fnewsize;
+ }
+ else
+ {
+ csize = x->x_nbforms;
+ }
+
+ // copy all values
+ for ( i=0; i<csize; i++ )
+ {
+ memcpy( &forms[i], &x->x_forms[i], sizeof( t_form ) );
+ }
+
+ // free old structures
+ if ( x->x_forms ) freebytes( x->x_forms, x->x_capacity*sizeof(t_form) );
+
+ // set new structures
+ x->x_forms = forms;
+ x->x_nbforms = csize;
+ x->x_capacity = fnewsize;
+ if ( x->x_nbforms > 0 )
+ {
+ x->x_current = 0;
+ }
+ else
+ {
+ x->x_current = -1;
+ }
+}
+
+static void pdp_form_allocate(t_pdp_form *x)
+{
+ x->x_image = imlib_create_image( x->x_vwidth, x->x_vheight );
+ if ( x->x_image == NULL )
+ {
+ post( "pdp_form : severe error : could not allocate image !!" );
+ }
+ imlib_context_set_image(x->x_image);
+}
+
+static void pdp_form_free_ressources(t_pdp_form *x)
+{
+ if ( x->x_image != NULL ) imlib_free_image();
+}
+
+static void pdp_form_process_yv12(t_pdp_form *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 ti;
+ t_int px, py;
+ unsigned char y, u, v;
+ DATA32 *imdata;
+ DATA32 bgcolor;
+ short int *pY, *pU, *pV;
+
+ if ( ( (int)(header->info.image.width) != x->x_vwidth ) ||
+ ( (int)(header->info.image.height) != x->x_vheight ) )
+ {
+ pdp_form_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_form_allocate(x);
+ }
+
+ 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 );
+
+ // draw all texts
+ imlib_image_clear();
+ imlib_context_set_direction(IMLIB_TEXT_TO_ANGLE);
+ imdata = imlib_image_get_data();
+ bgcolor = imdata[0];
+
+ for (ti=0; ti<x->x_nbforms; ti++)
+ {
+ imlib_context_set_color( x->x_forms[ti].r, x->x_forms[ti].g, x->x_forms[ti].b, 255 );
+
+ switch ( x->x_forms[ti].type )
+ {
+ case IMLIB_LINE :
+ imlib_image_draw_line( x->x_forms[ti].n1, x->x_forms[ti].n2, x->x_forms[ti].n3, x->x_forms[ti].n4, 1);
+ break;
+
+ case IMLIB_RECTANGLE :
+ imlib_image_draw_rectangle( x->x_forms[ti].n1, x->x_forms[ti].n2,
+ x->x_forms[ti].n3-x->x_forms[ti].n1, x->x_forms[ti].n4-x->x_forms[ti].n2 );
+ imlib_image_fill_rectangle( x->x_forms[ti].n1, x->x_forms[ti].n2,
+ x->x_forms[ti].n3-x->x_forms[ti].n1, x->x_forms[ti].n4-x->x_forms[ti].n2 );
+ break;
+
+ case IMLIB_ELLIPSE :
+ imlib_image_draw_ellipse( x->x_forms[ti].n1, x->x_forms[ti].n2, x->x_forms[ti].n3, x->x_forms[ti].n4 );
+ imlib_image_fill_ellipse( x->x_forms[ti].n1, x->x_forms[ti].n2, x->x_forms[ti].n3, x->x_forms[ti].n4 );
+ break;
+ }
+ }
+
+ pY = newdata;
+ pV = newdata+x->x_vsize;
+ pU = newdata+x->x_vsize+(x->x_vsize>>2);
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ if ( imdata[py*x->x_vwidth+px] != bgcolor )
+ {
+ y = yuv_RGBtoY(imdata[py*x->x_vwidth+px]);
+ u = yuv_RGBtoU(imdata[py*x->x_vwidth+px]);
+ v = yuv_RGBtoV(imdata[py*x->x_vwidth+px]);
+
+ *(pY) = y<<7;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ *(pV) = (v-128)<<8;
+ *(pU) = (u-128)<<8;
+ }
+ }
+ pY++;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ pV++;pU++;
+ }
+ }
+ }
+
+ return;
+}
+
+static void pdp_form_sendpacket(t_pdp_form *x)
+{
+ /* delete source 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_form_process(t_pdp_form *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_form_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_form_process_yv12, pdp_form_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_form_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_form_input_0(t_pdp_form *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_form_process(x);
+
+ }
+
+}
+
+static void pdp_form_free(t_pdp_form *x)
+{
+ int i;
+
+ pdp_form_free_ressources(x);
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_form_class;
+
+void *pdp_form_new(void)
+{
+ int i;
+
+ t_pdp_form *x = (t_pdp_form *)pd_new(pdp_form_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("current"));
+ 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("y1"));
+ 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("y2"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("r"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("g"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("b"));
+
+ 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_image = NULL;
+
+ x->x_capacity = DEFAULT_CAPACITY;
+
+ x->x_forms = (t_form *) getbytes( x->x_capacity*sizeof(t_form) );
+
+ for ( i=0; i<x->x_capacity; i++ )
+ {
+ x->x_forms[i].r = x->x_forms[i].g = x->x_forms[i].b = 255;
+ }
+
+ x->x_nbforms = 0;
+ x->x_current = -1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_form_setup(void)
+{
+
+ post( pdp_form_version );
+ pdp_form_class = class_new(gensym("pdp_form"), (t_newmethod)pdp_form_new,
+ (t_method)pdp_form_free, sizeof(t_pdp_form), 0, A_NULL);
+
+ class_addmethod(pdp_form_class, (t_method)pdp_form_input_0, gensym("pdp"),
+ A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_form_class, (t_method)pdp_form_line, gensym("line"), A_GIMME, A_NULL);
+ class_addmethod(pdp_form_class, (t_method)pdp_form_rectangle, gensym("rectangle"), A_GIMME, A_NULL);
+ class_addmethod(pdp_form_class, (t_method)pdp_form_ellipse, gensym("ellipse"), A_GIMME, A_NULL);
+ class_addmethod(pdp_form_class, (t_method)pdp_form_current, gensym("current"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_form_class, (t_method)pdp_form_x1, gensym("x1"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_form_class, (t_method)pdp_form_y1, gensym("y1"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_form_class, (t_method)pdp_form_x2, gensym("x2"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_form_class, (t_method)pdp_form_y2, gensym("y2"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_form_class, (t_method)pdp_form_r, gensym("r"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_form_class, (t_method)pdp_form_g, gensym("g"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_form_class, (t_method)pdp_form_b, gensym("b"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_form_class, (t_method)pdp_form_clear, gensym("clear"), A_NULL);
+ class_addmethod(pdp_form_class, (t_method)pdp_form_delete, gensym("delete"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_form_class, (t_method)pdp_form_resize, gensym("resize"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_i.c b/modules/pdp_i.c
new file mode 100644
index 0000000..4ea749c
--- /dev/null
+++ b/modules/pdp_i.c
@@ -0,0 +1,454 @@
+
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon <ydegoyon@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 streaming receiver
+ * It receives PDP packets sent by a pdp_o object
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <bzlib.h> // bz2 decompression routines
+#include "pdp.h"
+#include "pdp_streaming.h"
+
+typedef void (*t_fdpollfn)(void *ptr, int fd);
+extern void sys_rmpollfn(int fd);
+extern void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr);
+
+#define SOCKET_ERROR -1
+#define INPUT_BUFFER_SIZE 1048578 /* 1 M */
+
+/* time-out used for select() call */
+static struct timeval ztout;
+
+static char *pdp_i_version = "pdp_i : a video stream receiver, written by ydegoyon@free.fr";
+
+extern void sys_sockerror(char *s);
+
+void pdp_i_closesocket(int fd)
+{
+ if ( close(fd) < 0 )
+ {
+ perror( "close" );
+ }
+ else
+ {
+ post( "pdp_i : closed socket : %d", fd );
+ }
+}
+
+int pdp_i_setsocketoptions(int sockfd)
+{
+ int sockopt = 1;
+ if (setsockopt(sockfd, SOL_TCP, TCP_NODELAY, (const char*) &sockopt, sizeof(int)) < 0)
+ {
+ post("pdp_i : setsockopt TCP_NODELAY failed");
+ perror( "setsockopt" );
+ return -1;
+ }
+ else
+ {
+ post("pdp_i : TCP_NODELAY set");
+ }
+
+ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) < 0)
+ {
+ post("pdp_i : setsockopt SO_REUSEADDR failed");
+ perror( "setsockopt" );
+ return -1;
+ }
+ else
+ {
+ post("pdp_i : setsockopt SO_REUSEADDR done.");
+ }
+ return 0;
+}
+
+/* ------------------------ pdp_i ----------------------------- */
+
+static t_class *pdp_i_class;
+
+typedef struct _pdp_i
+{
+ t_object x_obj;
+ t_int x_socket;
+ t_outlet *x_connection_status;
+ t_outlet *x_frames;
+ t_outlet *x_connectionip;
+ t_outlet *x_pdp_output;
+ t_int x_serversocket;
+ t_int x_framesreceived; // total number of frames received
+
+ void *x_inbuffer; /* accumulation buffer for incoming frames */
+ t_int x_inwriteposition;
+ t_int x_inbuffersize;
+
+ /* PDP data structures */
+ t_int x_packet;
+ t_pdp *x_header;
+ t_int x_vheight;
+ t_int x_vwidth;
+ t_int x_vsize;
+ t_int x_psize;
+ t_int x_hsize;
+ t_int x_bsize;
+ t_int x_bzsize;
+ short int *x_data;
+ unsigned char *x_hdata; // huffman coded data
+ unsigned char *x_ddata; // decompressed data
+ unsigned short *x_bdata; // previous data
+
+} t_pdp_i;
+
+ /* huffman decoding */
+static int pdp_i_huffman(t_pdp_i *x, char *source, char *dest, t_int size, t_int *dsize)
+{
+ char *pcount=source;
+ char *pvalue=(source+1);
+
+ *dsize=0;
+ while ( pcount < (source+size) )
+ {
+ while ( (*pcount) > 0 )
+ {
+ *(dest++)=*(pvalue);
+ *pcount-=1;
+ *dsize+=1;
+ }
+ pcount+=2;
+ pvalue+=2;
+ }
+
+ // post( "pdp_i : dsize=%d", *dsize );
+ return *dsize;
+}
+
+static void pdp_i_free_ressources(t_pdp_i *x)
+{
+ if ( x->x_ddata ) freebytes( x->x_ddata, x->x_psize );
+ if ( x->x_hdata ) freebytes( x->x_hdata, x->x_hsize );
+ if ( x->x_bdata ) freebytes( x->x_hdata, x->x_bsize );
+}
+
+static void pdp_i_allocate(t_pdp_i *x)
+{
+ x->x_psize = x->x_vsize + (x->x_vsize>>1);
+ x->x_hsize = (x->x_vsize + (x->x_vsize>>1));
+ x->x_bsize = (x->x_vsize + (x->x_vsize>>1))*sizeof(unsigned short);
+ x->x_ddata = (unsigned char*) getbytes(x->x_psize);
+ x->x_hdata = (unsigned char*) getbytes(x->x_hsize);
+ x->x_bdata = (unsigned short*) getbytes(x->x_bsize);
+ if ( !x->x_ddata || !x->x_hdata )
+ {
+ post( "pdp_i : severe error : could not allocate buffer" );
+ }
+}
+
+static void pdp_i_recv(t_pdp_i *x)
+{
+ int ret, i;
+ t_hpacket *pheader;
+
+ if ( ( ret = recv(x->x_socket, (void*) (x->x_inbuffer + x->x_inwriteposition),
+ (size_t)((x->x_inbuffersize-x->x_inwriteposition)),
+ MSG_NOSIGNAL) ) < 0 )
+ {
+ post( "pdp_i : receive error" );
+ perror( "recv" );
+ return;
+ }
+ else
+ {
+ // post( "pdp_i : received %d bytes at %d on %d ( up to %d)",
+ // ret, x->x_inwriteposition, x->x_socket,
+ // x->x_inbuffersize-x->x_inwriteposition*sizeof( unsigned long) );
+
+ if ( ret == 0 )
+ {
+ /* peer has reset connection */
+ outlet_float( x->x_connection_status, 0 );
+ pdp_i_closesocket( x->x_socket );
+ sys_rmpollfn(x->x_socket);
+ x->x_socket = -1;
+ }
+ else
+ {
+ // check we don't overflow input buffer
+ if ( x->x_inwriteposition+ret >= x->x_inbuffersize )
+ {
+ // post( "pdp_i : too much input...resetting" );
+ x->x_inwriteposition=0;
+ return;
+ }
+ x->x_inwriteposition += ret;
+ if ( pheader = (t_hpacket*) strstr( (char*) x->x_inbuffer, PDP_PACKET_START ) )
+ {
+ // check if a full packet is present
+ if ( x->x_inwriteposition >= (int)((char*)pheader - (char*)(x->x_inbuffer)) + (int)sizeof(t_hpacket) + (int)pheader->clength )
+ {
+ if ( ( x->x_vwidth != pheader->width ) ||
+ ( x->x_vheight != pheader->height ) )
+ {
+ pdp_i_free_ressources(x);
+ x->x_vheight = pheader->height;
+ x->x_vwidth = pheader->width;
+ x->x_vsize = x->x_vheight*x->x_vwidth;
+ pdp_i_allocate(x);
+ post( "pdp_i : allocated buffers : vsize=%d : hsize=%d", x->x_vsize, x->x_hsize );
+ }
+
+ x->x_packet = pdp_packet_new_image_YCrCb( x->x_vwidth, x->x_vheight );
+ x->x_header = pdp_packet_header(x->x_packet);
+ x->x_data = (short int *)pdp_packet_data(x->x_packet);
+ memcpy( x->x_data, x->x_bdata, x->x_bsize );
+
+ // post( "pdp_i : decompress %d in %d bytes", pheader->clength, x->x_hsize );
+ x->x_bzsize = x->x_hsize;
+
+ if ( ( ret = BZ2_bzBuffToBuffDecompress( (char*)x->x_hdata,
+ &x->x_bzsize,
+ (char *) pheader+sizeof(t_hpacket),
+ pheader->clength,
+ 0, 0 ) ) == BZ_OK )
+ {
+ // post( "pdp_i : bz2 decompression (%d)->(%d)", pheader->clength, x->x_bzsize );
+
+ switch( pheader->encoding )
+ {
+ case REGULAR :
+ memcpy( x->x_ddata, x->x_hdata, x->x_bzsize );
+ break;
+
+ case HUFFMAN :
+ pdp_i_huffman( x, x->x_hdata, x->x_ddata, x->x_bzsize, &x->x_psize );
+ break;
+ }
+
+ for ( i=0; i<x->x_vsize; i++ )
+ {
+ if ( !strcmp( pheader->tag, PDP_PACKET_TAG ) )
+ {
+ x->x_data[i] = x->x_ddata[i]<<7;
+ }
+ else
+ {
+ if ( x->x_ddata[i] != 0 )
+ {
+ x->x_data[i] = x->x_ddata[i]<<7;
+ }
+ }
+ }
+ for ( i=x->x_vsize; i<(x->x_vsize+(x->x_vsize>>1)); i++ )
+ {
+ if ( !strcmp( pheader->tag, PDP_PACKET_TAG ) )
+ {
+ x->x_data[i] = (x->x_ddata[i])<<8;
+ }
+ else
+ {
+ if ( x->x_ddata[i] != 0 )
+ {
+ x->x_data[i] = (x->x_ddata[i])<<8;
+ }
+ }
+ }
+
+ x->x_header->info.image.encoding = PDP_IMAGE_YV12;
+ x->x_header->info.image.width = x->x_vwidth;
+ x->x_header->info.image.height = x->x_vheight;
+
+ pdp_packet_pass_if_valid(x->x_pdp_output, &x->x_packet);
+ // post( "pdp_i : propagate packet : %d", x->x_packet );
+ outlet_float( x->x_frames, ++x->x_framesreceived );
+ }
+ else
+ {
+ post( "pdp_i : bz2 decompression failed (ret=%d)", ret );
+ }
+
+ memcpy( x->x_bdata, x->x_data, x->x_bsize );
+
+ // roll buffer
+ x->x_inwriteposition -= (int)((char*)pheader-(char*)(x->x_inbuffer)) + sizeof(t_hpacket) + pheader->clength;
+ memcpy( x->x_inbuffer, pheader+sizeof(t_hpacket) + pheader->clength, x->x_inwriteposition );
+ }
+ }
+ }
+
+ }
+}
+
+static void pdp_i_acceptconnection(t_pdp_i *x)
+{
+ struct sockaddr_in incomer_address;
+ int sockaddrl = (int) sizeof( struct sockaddr );
+
+ int fd = accept(x->x_serversocket, (struct sockaddr*)&incomer_address, &sockaddrl );
+
+ if (fd < 0) {
+ post("pdp_i : accept failed");
+ return;
+ }
+
+ if ( x->x_socket > 0 )
+ {
+ post( "pdp_i : accepting a new source : %s", inet_ntoa( incomer_address.sin_addr) );
+ pdp_i_closesocket( x->x_socket );
+ sys_rmpollfn(x->x_socket);
+ outlet_float( x->x_connection_status, 0 );
+ }
+
+ x->x_socket = fd;
+ x->x_framesreceived = 0;
+ sys_addpollfn(x->x_socket, (t_fdpollfn)pdp_i_recv, x);
+ post("pdp_i : new source : %s.", inet_ntoa( incomer_address.sin_addr ));
+ outlet_float( x->x_connection_status, 1 );
+ outlet_float( x->x_frames, x->x_framesreceived );
+ outlet_symbol( x->x_connectionip, gensym( inet_ntoa( incomer_address.sin_addr) ) );
+
+}
+
+
+static int pdp_i_startservice(t_pdp_i* x, int portno)
+{
+ struct sockaddr_in server;
+ int sockfd;
+
+ /* create a socket */
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (sockfd < 0)
+ {
+ sys_sockerror("socket");
+ return (0);
+ }
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = INADDR_ANY;
+
+ /* assign server port number */
+ server.sin_port = htons((u_short)portno);
+ post("listening to port number %d", portno);
+
+ pdp_i_setsocketoptions(sockfd);
+
+ /* name the socket */
+ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) {
+ sys_sockerror("bind");
+ pdp_i_closesocket(sockfd);
+ return (0);
+ }
+
+ if (listen(sockfd, 5) < 0) {
+ sys_sockerror("listen");
+ pdp_i_closesocket(sockfd);
+ }
+ else
+ {
+ x->x_serversocket = sockfd;
+ sys_addpollfn(x->x_serversocket, (t_fdpollfn)pdp_i_acceptconnection, x);
+ }
+
+ return 1;
+}
+
+static void pdp_i_free(t_pdp_i *x)
+{
+ post( "pdp_i : free %x", x );
+ if (x->x_serversocket > 0) {
+ post( "pdp_i : closing server socket" );
+ pdp_i_closesocket(x->x_serversocket);
+ sys_rmpollfn(x->x_serversocket);
+ x->x_serversocket = -1;
+ }
+ if (x->x_socket > 0) {
+ post( "pdp_i : closing socket" );
+ pdp_i_closesocket(x->x_socket);
+ sys_rmpollfn(x->x_socket);
+ x->x_socket = -1;
+ }
+ if ( x->x_inbuffer ) freebytes( x->x_inbuffer, x->x_inbuffersize );
+ pdp_i_free_ressources( x );
+}
+
+static void *pdp_i_new(t_floatarg fportno)
+{
+ t_pdp_i *x;
+ int i;
+
+ if ( fportno <= 0 || fportno > 65535 )
+ {
+ post( "pdp_i : error : wrong portnumber : %d", (int)fportno );
+ return NULL;
+ }
+
+ x = (t_pdp_i *)pd_new(pdp_i_class);
+ x->x_pdp_output = outlet_new(&x->x_obj, &s_anything);
+ x->x_connection_status = outlet_new(&x->x_obj, &s_float);
+ x->x_frames = outlet_new(&x->x_obj, &s_float);
+ x->x_connectionip = outlet_new(&x->x_obj, &s_symbol);
+
+ x->x_serversocket = -1;
+
+ x->x_inbuffersize = INPUT_BUFFER_SIZE;
+ x->x_inbuffer = (char*) getbytes( x->x_inbuffersize );
+ memset( x->x_inbuffer, 0x0, INPUT_BUFFER_SIZE );
+
+ if ( !x->x_inbuffer )
+ {
+ post( "pdp_i : could not allocate buffer." );
+ return NULL;
+ }
+
+ x->x_inwriteposition = 0;
+ x->x_socket = -1;
+ x->x_packet = -1;
+ x->x_ddata = NULL;
+ x->x_hdata = NULL;
+ x->x_bdata = NULL;
+
+ ztout.tv_sec = 0;
+ ztout.tv_usec = 0;
+
+ post( "pdp_i : starting service on port %d", (int)fportno );
+ pdp_i_startservice(x, (int)fportno);
+
+ return (x);
+}
+
+
+void pdp_i_setup(void)
+{
+ post( pdp_i_version );
+ pdp_i_class = class_new(gensym("pdp_i"),
+ (t_newmethod) pdp_i_new, (t_method) pdp_i_free,
+ sizeof(t_pdp_i), CLASS_NOINLET, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+}
diff --git a/modules/pdp_imgloader.c b/modules/pdp_imgloader.c
new file mode 100644
index 0000000..13cae1e
--- /dev/null
+++ b/modules/pdp_imgloader.c
@@ -0,0 +1,300 @@
+/*
+ * PiDiP module
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 loads an image from a file and blends it with a video
+ * It uses imlib2 for all graphical operations
+ */
+
+#include "pdp.h"
+#include "yuv.h"
+#include <math.h>
+#include <ctype.h>
+#include <Imlib2.h> // imlib2 is required
+
+static char *pdp_imgloader_version = "pdp_imgloader: version 0.1 : image loading object written by ydegoyon@free.fr ";
+
+typedef struct pdp_imgloader_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_packet1;
+ t_int x_dropped;
+ t_int x_queue_id;
+
+ t_outlet *x_outlet0;
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+
+ t_int x_xoffset; // x offset of the image
+ t_int x_yoffset; // y offset of the image
+
+ /* imlib data */
+ Imlib_Image x_image;
+ DATA32 *x_imdata;
+ t_int x_iwidth;
+ t_int x_iheight;
+
+ t_float x_blend;
+
+} t_pdp_imgloader;
+
+ /* load an image */
+static void pdp_imgloader_load(t_pdp_imgloader *x, t_symbol *filename, t_floatarg fx, t_floatarg fy)
+{
+ Imlib_Load_Error imliberr;
+
+ post( "pdp_imgloader : loading : %s", filename->s_name );
+
+ if ( x->x_image != NULL )
+ {
+ imlib_free_image();
+ }
+ x->x_image = imlib_load_image_with_error_return( filename->s_name, &imliberr );
+ if ( imliberr != IMLIB_LOAD_ERROR_NONE )
+ {
+ post( "pdp_imgloader : severe error : could not load image (err=%d)!!", imliberr );
+ x->x_image = NULL;
+ return;
+ }
+ imlib_context_set_image(x->x_image);
+ x->x_imdata = imlib_image_get_data();
+ x->x_iwidth = imlib_image_get_width();
+ x->x_iheight = imlib_image_get_height();
+ post( "pdp_imgloader : loaded : %s (%dx%d)", filename->s_name, x->x_iwidth, x->x_iheight );
+ x->x_xoffset = (int) fx;
+ x->x_yoffset = (int) fy;
+}
+
+static void pdp_imgloader_xoffset(t_pdp_imgloader *x, t_floatarg fx )
+{
+ x->x_xoffset = (int) fx;
+}
+
+static void pdp_imgloader_yoffset(t_pdp_imgloader *x, t_floatarg fy )
+{
+ x->x_yoffset = (int) fy;
+}
+
+static void pdp_imgloader_blend(t_pdp_imgloader *x, t_floatarg fblend )
+{
+ if ( ( fblend > 0.0 ) && ( fblend < 1.0 ) )
+ {
+ x->x_blend = fblend;
+ }
+}
+
+static void pdp_imgloader_clear(t_pdp_imgloader *x )
+{
+ if ( x->x_image != NULL )
+ {
+ imlib_free_image();
+ }
+ x->x_image = NULL;
+}
+
+static void pdp_imgloader_process_yv12(t_pdp_imgloader *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 px, py;
+ t_float alpha, factor;
+ unsigned char y, u, v;
+ short int *pY, *pU, *pV;
+
+ if ( ( (int)(header->info.image.width) != x->x_vwidth ) ||
+ ( (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;
+ }
+
+ 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 );
+
+ pY = newdata;
+ pV = newdata+x->x_vsize;
+ pU = newdata+x->x_vsize+(x->x_vsize>>2);
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ if ( ( x->x_image != NULL )
+ && (px >= x->x_xoffset) && ( px < x->x_xoffset + x->x_iwidth )
+ && (py >= x->x_yoffset) && ( py < x->x_yoffset + x->x_iheight )
+ )
+ {
+ y = yuv_RGBtoY(x->x_imdata[(py-x->x_yoffset)*x->x_iwidth+(px-x->x_xoffset)]);
+ u = yuv_RGBtoU(x->x_imdata[(py-x->x_yoffset)*x->x_iwidth+(px-x->x_xoffset)]);
+ v = yuv_RGBtoV(x->x_imdata[(py-x->x_yoffset)*x->x_iwidth+(px-x->x_xoffset)]);
+
+
+ if ( imlib_image_has_alpha() )
+ {
+ alpha = (x->x_imdata[(py-x->x_yoffset)*x->x_iwidth+(px-x->x_xoffset)] >> 24)/255;
+ }
+ else
+ {
+ alpha = 1.0;
+ }
+ factor = x->x_blend*alpha;
+
+ *(pY) = (int)((1-factor)*(*(pY)) + factor*(y<<7));
+ if ( (px%2==0) && (py%2==0) )
+ {
+ *(pV) = (int)((1-factor)*(*(pV)) + factor*((v-128)<<8));
+ *(pU) = (int)((1-factor)*(*(pU)) + factor*((u-128)<<8));
+ }
+ }
+ pY++;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ pV++;pU++;
+ }
+ }
+ }
+
+ return;
+}
+
+static void pdp_imgloader_sendpacket(t_pdp_imgloader *x)
+{
+ /* delete source 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_imgloader_process(t_pdp_imgloader *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_imgloader_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_imgloader_process_yv12, pdp_imgloader_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_imgloader_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_imgloader_input_0(t_pdp_imgloader *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_imgloader_process(x);
+
+ }
+
+}
+
+static void pdp_imgloader_free(t_pdp_imgloader *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_imgloader_class;
+
+void *pdp_imgloader_new(void)
+{
+ int i;
+
+ t_pdp_imgloader *x = (t_pdp_imgloader *)pd_new(pdp_imgloader_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("xoffset"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("yoffset"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("blend"));
+
+ 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_image = NULL;
+
+ x->x_blend = 1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_imgloader_setup(void)
+{
+
+ post( pdp_imgloader_version );
+ pdp_imgloader_class = class_new(gensym("pdp_imgloader"), (t_newmethod)pdp_imgloader_new,
+ (t_method)pdp_imgloader_free, sizeof(t_pdp_imgloader), 0, A_NULL);
+
+ class_addmethod(pdp_imgloader_class, (t_method)pdp_imgloader_input_0, gensym("pdp"),
+ A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_imgloader_class, (t_method)pdp_imgloader_load, gensym("load"), A_SYMBOL, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_imgloader_class, (t_method)pdp_imgloader_clear, gensym("clear"), A_NULL);
+ class_addmethod(pdp_imgloader_class, (t_method)pdp_imgloader_xoffset, gensym("xoffset"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_imgloader_class, (t_method)pdp_imgloader_yoffset, gensym("yoffset"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_imgloader_class, (t_method)pdp_imgloader_blend, gensym("blend"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_imgsaver.c b/modules/pdp_imgsaver.c
new file mode 100644
index 0000000..5f11098
--- /dev/null
+++ b/modules/pdp_imgsaver.c
@@ -0,0 +1,340 @@
+/*
+ * PiDiP module
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 saves a snaphot to a file
+ * Image type is specified by extension
+ * It uses imlib2 for all graphical operations
+ */
+
+#include "pdp.h"
+#include "yuv.h"
+#include <math.h>
+#include <ctype.h>
+#include <pthread.h>
+#include <Imlib2.h> // imlib2 is required
+
+static char *pdp_imgsaver_version = "pdp_imgsaver: version 0.1 : image snapshot object written by ydegoyon@free.fr ";
+
+typedef struct pdp_imgsaver_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_packet1;
+ t_int x_dropped;
+ t_int x_queue_id;
+
+ t_outlet *x_outlet0;
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+
+ t_int x_save_pending;
+
+ /* imlib data */
+ Imlib_Image x_image;
+ DATA32 *x_imdata;
+ t_int x_iwidth;
+ t_int x_iheight;
+
+ t_symbol *x_filename;
+ short int *x_datas;
+ pthread_t x_savechild; /* thread id for the saving child */
+
+} t_pdp_imgsaver;
+
+ /* do save the image */
+static void *pdp_imgsaver_do_save(void *tdata)
+{
+ Imlib_Load_Error imliberr;
+ t_pdp_imgsaver *x = (t_pdp_imgsaver*) tdata;
+ t_int px, py;
+ short int *pY, *pU, *pV;
+ unsigned char y, u, v;
+
+ if ( ( x->x_vwidth == 0 ) || ( x->x_vheight == 0 ) )
+ {
+ post( "pdp_imgsaver : tried to save an image but no video is playing" );
+ x->x_save_pending = 0;
+ x->x_filename = NULL;
+ return NULL;
+ }
+
+ x->x_image = imlib_create_image( x->x_vwidth, x->x_vheight );
+ if ( x->x_image == NULL )
+ {
+ post( "pdp_imgsaver : severe error : could not allocate image !!" );
+ x->x_save_pending = 0;
+ x->x_filename = NULL;
+ return NULL;
+ }
+ imlib_context_set_image(x->x_image);
+
+ x->x_imdata = imlib_image_get_data();
+ x->x_iwidth = imlib_image_get_width();
+ x->x_iheight = imlib_image_get_height();
+
+ pY = x->x_datas;
+ pV = x->x_datas+x->x_vsize;
+ pU = x->x_datas+x->x_vsize+(x->x_vsize>>2);
+ for ( py=0; py<x->x_iheight; py++ )
+ {
+ for ( px=0; px<x->x_iwidth; px++ )
+ {
+ y = *(pY)>>7;
+ v = (*(pV)>>8)+128;
+ u = (*(pU)>>8)+128;
+ x->x_imdata[ py*x->x_iwidth + px ] = yuv_YUVtoRGB( y, u, v );
+ pY++;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ pV++;pU++;
+ }
+ }
+ }
+
+ post( "pdp_imgsaver : saving image to : %s", x->x_filename->s_name );
+ imlib_save_image_with_error_return(x->x_filename->s_name, &imliberr );
+ if ( imliberr != IMLIB_LOAD_ERROR_NONE )
+ {
+ post( "pdp_imgsaver : severe error : could not save image (err=%d)!!", imliberr );
+ }
+ else
+ {
+ post( "pdp_imgsaver : saved to : %s", x->x_filename->s_name );
+ }
+
+ if ( x->x_image != NULL )
+ {
+ imlib_free_image();
+ x->x_image = NULL;
+ }
+
+ x->x_save_pending = 0;
+ x->x_filename = NULL;
+
+ post( "pdp_imgsaver : saving thread %d finished", x->x_savechild );
+ x->x_savechild = 0;
+
+ return NULL;
+
+}
+
+ /* launched the thread to save the image */
+static void pdp_imgsaver_save(t_pdp_imgsaver *x, t_symbol *filename)
+{
+ pthread_attr_t save_child_attr;
+
+ if ( x->x_save_pending )
+ {
+ post( "pdp_imgsaver : a save operation is currently running...retry later" );
+ return;
+ }
+ x->x_save_pending = 1;
+ x->x_filename = filename;
+ if ( x->x_image != NULL )
+ {
+ imlib_free_image();
+ x->x_image = NULL;
+ }
+
+ // launch saving thread
+ if ( pthread_attr_init( &save_child_attr ) < 0 )
+ {
+ post( "pdp_imgsaver : could not launch save thread" );
+ perror( "pthread_attr_init" );
+ return;
+ }
+ if ( pthread_attr_setdetachstate( &save_child_attr, PTHREAD_CREATE_DETACHED ) < 0 ) {
+ post( "pdp_imgsaver : could not launch save thread" );
+ perror( "pthread_attr_setdetachstate" );
+ return;
+ }
+ if ( pthread_create( &x->x_savechild, &save_child_attr, pdp_imgsaver_do_save, x ) < 0 ) {
+ post( "pdp_imgsaver : could not launch save thread" );
+ perror( "pthread_create" );
+ return;
+ }
+ else
+ {
+ post( "pdp_imgsaver : saving thread %d launched", (int)x->x_savechild );
+ }
+}
+
+static void pdp_imgsaver_allocate(t_pdp_imgsaver *x)
+{
+ x->x_datas = (short int *)getbytes((( x->x_vsize + (x->x_vsize>>1))<<1));
+}
+
+static void pdp_imgsaver_free_ressources(t_pdp_imgsaver *x)
+{
+ if ( x->x_datas ) freebytes( x->x_datas, (( x->x_vsize + (x->x_vsize>>1))<<1));
+}
+
+static void pdp_imgsaver_process_yv12(t_pdp_imgsaver *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 px, py;
+ t_float alpha, factor;
+ unsigned char y, u, v;
+ short int *pY, *pU, *pV;
+
+ if ( ( (int)(header->info.image.width) != x->x_vwidth ) ||
+ ( (int)(header->info.image.height) != x->x_vheight ) )
+ {
+ pdp_imgsaver_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_imgsaver_allocate(x);
+ }
+
+ 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 );
+ if ( !x->x_save_pending )
+ {
+ memcpy( x->x_datas, data, (x->x_vsize+(x->x_vsize>>1))<<1 );
+ }
+
+ return;
+}
+
+static void pdp_imgsaver_sendpacket(t_pdp_imgsaver *x)
+{
+ /* delete source 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_imgsaver_process(t_pdp_imgsaver *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_imgsaver_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_imgsaver_process_yv12, pdp_imgsaver_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_imgsaver_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_imgsaver_input_0(t_pdp_imgsaver *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_imgsaver_process(x);
+
+ }
+
+}
+
+static void pdp_imgsaver_free(t_pdp_imgsaver *x)
+{
+ int i;
+
+ pdp_imgsaver_free_ressources(x);
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_imgsaver_class;
+
+void *pdp_imgsaver_new(void)
+{
+ int i;
+
+ t_pdp_imgsaver *x = (t_pdp_imgsaver *)pd_new(pdp_imgsaver_class);
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_datas = NULL;
+ x->x_queue_id = -1;
+ x->x_image = NULL;
+
+ x->x_vwidth = 0;
+ x->x_vheight = 0;
+
+ x->x_save_pending = 0;
+ x->x_filename = NULL;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_imgsaver_setup(void)
+{
+
+ post( pdp_imgsaver_version );
+ pdp_imgsaver_class = class_new(gensym("pdp_imgsaver"), (t_newmethod)pdp_imgsaver_new,
+ (t_method)pdp_imgsaver_free, sizeof(t_pdp_imgsaver), 0, A_NULL);
+
+ class_addmethod(pdp_imgsaver_class, (t_method)pdp_imgsaver_input_0, gensym("pdp"),
+ A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_imgsaver_class, (t_method)pdp_imgsaver_save, gensym("save"), A_SYMBOL, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_intrusion.c b/modules/pdp_intrusion.c
new file mode 100644
index 0000000..26c9ead
--- /dev/null
+++ b/modules/pdp_intrusion.c
@@ -0,0 +1,428 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 adaptation of hologram effect from effectv
+ * but, in these paranoid times, i found it funnier to rename it as intrusion
+ * because it can detect moving objects ( targets ?? )
+ * Originally written by Fukuchi Kentaro & others
+ * Pd-fication by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+#define NB_IMAGES 4
+#define MAGIC_THRESHOLD 10
+static unsigned int fastrand_val;
+#define inline_fastrand() (fastrand_val=fastrand_val*1103515245+12345)
+
+static char *pdp_intrusion_version = "pdp_intrusion: version 0.1, inspired by hologram from effectv( Fukuchi Kentaro ) adapted by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_intrusion_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;
+
+ unsigned int x_noisepattern[256]; // noise pattern
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+ unsigned int x_encoding;
+ short int *x_images[NB_IMAGES];
+ t_int x_rtimage;
+ short int *x_diff;
+ short int *x_bdata;
+ int x_threshold;
+ int x_phase;
+ int x_loopcount;
+ int x_threshfreq;
+
+} t_pdp_intrusion;
+
+/* check if there is a real difference with background image */
+short int *pdp_intrusion_diff(t_pdp_intrusion *x, short int *src)
+{
+ int i;
+ int Y;
+ int Yb;
+ short int *p=NULL;
+ short int *pb=NULL;
+ short int *r=NULL;
+ int v;
+
+ p = src;
+ pb = x->x_bdata;
+ r = x->x_diff;
+ for(i=0; i<(x->x_vsize); i++) {
+ Y = (*p);
+ Yb = (*pb);
+ *r = (Yb - Y);
+ p++; pb++;
+ r++;
+ }
+
+ return x->x_diff;
+}
+
+static void pdp_intrusion_threshold(t_pdp_intrusion *x, t_floatarg fthreshold )
+{
+ if ( fthreshold>0 && fthreshold<255 )
+ {
+ x->x_threshold = ((int)fthreshold ) << 8;
+ }
+}
+
+static void pdp_intrusion_background(t_pdp_intrusion *x )
+{
+ int i, j;
+
+ if ( ( x->x_images[0] == NULL ) ||
+ ( x->x_images[1] == NULL ) ||
+ ( x->x_images[2] == NULL ) ||
+ ( x->x_images[3] == NULL ) )
+ {
+ post( "pdp_intrusion_background : no images available !! " );
+ return;
+ }
+ post( "pdp_intrusion : setting background" );
+
+ memcpy( x->x_bdata, x->x_images[0], (( x->x_vsize + (x->x_vsize>>1))<<1));
+
+ for( i=1; i<NB_IMAGES; i++ )
+ {
+ for ( j=0; j<(x->x_vsize+(x->x_vsize>>1)); j++ )
+ {
+ x->x_bdata[j] = (x->x_bdata[j]&x->x_images[i][j])+((x->x_bdata[j]^x->x_images[i][j])>>1);
+ }
+ }
+}
+
+static void pdp_intrusion_allocate(t_pdp_intrusion *x, t_int newsize)
+{
+ int i;
+
+ for ( i=0; i<NB_IMAGES; i++ )
+ {
+ if ( x->x_images[i] != NULL )
+ {
+ freebytes( x->x_images[i], (x->x_vsize + (x->x_vsize>>1))<<1 );
+ }
+ }
+ if ( x->x_diff != NULL )
+ {
+ freebytes( x->x_diff, (x->x_vsize + (x->x_vsize>>1))<<1 );
+ }
+ if ( x->x_bdata ) freebytes( x->x_bdata, (( x->x_vsize + (x->x_vsize>>1))<<1));
+
+ x->x_vsize = newsize;
+ for ( i=0; i<NB_IMAGES; i++ )
+ {
+ x->x_images[i] = (short int*) getbytes((x->x_vsize + (x->x_vsize>>1))<<1);
+ }
+ x->x_diff = (short int*) getbytes((x->x_vsize + (x->x_vsize>>1))<<1);
+ x->x_bdata = (short int *)getbytes((( x->x_vsize + (x->x_vsize>>1))<<1));
+}
+
+static void pdp_intrusion_process_yv12(t_pdp_intrusion *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);
+ int i;
+
+ unsigned int totalnbpixels;
+ unsigned int u_offset;
+ unsigned int v_offset;
+ unsigned int totnbpixels;
+ int px, py;
+ short int *diff;
+ short int *sy, *su, *sv, t;
+ short int *sby, *sbu, *sbv;
+ short int *sny, *snu, *snv;
+ int Y=0, U=0, V=0;
+
+ /* allocate all ressources */
+ if ( (int)(header->info.image.width*header->info.image.height) != x->x_vsize )
+ {
+ pdp_intrusion_allocate(x, header->info.image.width*header->info.image.height );
+ post( "pdp_intrusion : reallocating buffers" );
+ }
+
+ 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_encoding = header->info.image.encoding;
+
+ totalnbpixels = x->x_vsize;
+ u_offset = x->x_vsize;
+ v_offset = x->x_vsize + (x->x_vsize>>2);
+ totnbpixels = x->x_vsize + (x->x_vsize>>1);
+
+ newheader->info.image.encoding = x->x_encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ /* copy images if necessary */
+ memcpy( x->x_images[x->x_rtimage], data, (( x->x_vsize + (x->x_vsize>>1))<<1));
+ x->x_rtimage=(x->x_rtimage+1)%4;
+
+ if ( !x->x_bdata ) return;
+
+ /* check pixels which has changed */
+ diff = pdp_intrusion_diff(x, data);
+
+ sy = data;
+ su = (data+x->x_vsize);
+ sv = (data+x->x_vsize+(x->x_vsize>>2));
+ sby = x->x_bdata;
+ sbu = (x->x_bdata+x->x_vsize);
+ sbv = (x->x_bdata+x->x_vsize+(x->x_vsize>>2));
+ sny = newdata;
+ snu = (newdata+x->x_vsize);
+ snv = (newdata+x->x_vsize+(x->x_vsize>>2));
+
+ for(py=1; py<x->x_vheight; py++)
+ {
+ if(((py+x->x_phase) & 0x7f)<0x58)
+ {
+ for(px=0; px<x->x_vwidth; px++)
+ {
+ if ( sv >= data + x->x_vsize + (x->x_vsize>>1 ) ) break;
+ if(*diff > x->x_threshold)
+ {
+ t = x->x_noisepattern[inline_fastrand()>>24];
+ Y = (*sy) + t;
+ U = (*su) + t;
+ V = (*sv) + t;
+ Y = (Y>>1)-100;
+ U = (U>>1)-100;
+ V = V>>2;
+ Y += ((*sby)>>1)+((rand()%255)<<8);
+ U += ((*sbu)>>1)+((rand()%255)<<8);
+ V += ((*sbv)>>1)+((rand()%255)<<8);
+ // clipping
+ if((Y>>8)<20) Y=20<<8;
+ if((U>>8)<-108) U=-108<<8;
+ if((V>>8)<-108) V=-108<<8;
+ if((Y>>8)>255) Y = 255;
+ if((U>>8)>128) U = 128;
+ if((V>>8)>128) V = 128;
+ *sny = Y;
+ *snu = U;
+ *snv = V;
+ }
+ else
+ {
+ *sny = *sy;
+ *snu = *su;
+ *snv = *sv;
+ }
+ diff++; sy++; sby++; sny++;
+ if ( ((px+1)%2==0) && ((py+1)%2==0))
+ {
+ su++; sbu++; snu++;
+ sv++; sbv++; snv++;
+ }
+ }
+ }
+ else
+ {
+ for(px=0; px<x->x_vwidth; px++)
+ {
+ if ( sv >= data + x->x_vsize + (x->x_vsize>>1 ) ) break;
+ if(*diff > x->x_threshold){
+ t = x->x_noisepattern[inline_fastrand()>>24];
+ Y = (*sy) + t;
+ U = (*su) + t;
+ V = (*sv) + t;
+ Y = (Y>>1)-100;
+ U = (U>>1)-100;
+ V = V>>2;
+ Y += ((*sby)>>1)+((rand()%255)<<8);
+ U += ((*sbu)>>1)+((rand()%255)<<8);
+ V += ((*sbv)>>1)+((rand()%255)<<8);
+ if((Y>>8)<0) Y=0;
+ if((U>>8)<-128) U=-128<<8;
+ if((V>>8)<-128) V=-128<<8;
+ if((Y>>8)>255) Y = 255;
+ if((U>>8)>128) U = 128;
+ if((V>>8)>128) V = 128;
+ *sny = Y;
+ *snu = U;
+ *snv = V;
+ } else {
+ *sny = *sy;
+ *snu = *su;
+ *snv = *sv;
+ }
+ diff++; sy++; sby++; sny++;
+ if ( ((px+1)%2==0) && ((py+1)%2==0) )
+ {
+ su++; sbu++; snu++;
+ sv++; sbv++; snv++;
+ }
+ }
+ }
+ }
+
+ x->x_phase-=37;
+
+ return;
+}
+
+static void pdp_intrusion_sendpacket(t_pdp_intrusion *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_intrusion_process(t_pdp_intrusion *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_intrusion_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_intrusion_process_yv12, pdp_intrusion_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ // pdp_intrusion_process_packet(x);
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_intrusion_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_intrusion_input_0(t_pdp_intrusion *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_intrusion_process(x);
+
+ }
+}
+
+static void pdp_intrusion_free(t_pdp_intrusion *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+
+ for (i=0; i<NB_IMAGES; i++ )
+ {
+ if ( x->x_images[i] ) freebytes( x->x_images[i], (x->x_vsize + (x->x_vsize>>1))<<1 );
+ }
+
+}
+
+t_class *pdp_intrusion_class;
+
+void *pdp_intrusion_new(void)
+{
+ int i;
+
+ t_pdp_intrusion *x = (t_pdp_intrusion *)pd_new(pdp_intrusion_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_bang, gensym("background"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("threshold"));
+
+ 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_threshold = MAGIC_THRESHOLD<<8;
+ x->x_phase = 0;
+ x->x_bdata = NULL;
+ x->x_diff = NULL;
+ x->x_vsize = -1;
+ x->x_loopcount = 0;
+ x->x_threshfreq = 10;
+
+ // initialize noise pattern
+ for(i=0; i<256; i++)
+ {
+ x->x_noisepattern[i] = (i * i * i / 40000)* i / 256;
+ }
+
+ // initialize images
+ for(i=0; i<NB_IMAGES; i++)
+ {
+ x->x_images[i] = NULL;
+ }
+ x->x_rtimage=0;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_intrusion_setup(void)
+{
+// post( pdp_intrusion_version );
+ pdp_intrusion_class = class_new(gensym("pdp_intrusion"), (t_newmethod)pdp_intrusion_new,
+ (t_method)pdp_intrusion_free, sizeof(t_pdp_intrusion), 0, A_NULL);
+
+ class_addmethod(pdp_intrusion_class, (t_method)pdp_intrusion_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_intrusion_class, (t_method)pdp_intrusion_background, gensym("background"), A_NULL);
+ class_addmethod(pdp_intrusion_class, (t_method)pdp_intrusion_threshold, gensym("threshold"), A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_juxta.c b/modules/pdp_juxta.c
new file mode 100644
index 0000000..e0b107a
--- /dev/null
+++ b/modules/pdp_juxta.c
@@ -0,0 +1,319 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 object allowing juxtaposition of frames from two inlets
+ * Written by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+static char *pdp_juxta_version = "pdp_juxta: version 0.1, frames juxtaposition, written by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_juxta_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+ t_int x_packet0;
+ t_int x_packet1;
+ t_int x_packet;
+ t_int x_dropped;
+ t_int x_queue_id;
+
+ t_int x_vwidth0;
+ t_int x_vheight0;
+ t_int x_vsize0;
+
+ t_int x_vwidth1;
+ t_int x_vheight1;
+ t_int x_vsize1;
+
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+
+} t_pdp_juxta;
+
+static void pdp_juxta_process_yv12(t_pdp_juxta *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ short int *data0 = (short int *)pdp_packet_data(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ short int *data1 = (short int *)pdp_packet_data(x->x_packet1);
+ t_pdp *header;
+ short int *data;
+ int i;
+ short int *poY, *poV, *poU, *p0Y, *p0V, *p0U, *p1Y, *p1V, *p1U;
+
+ int px, py;
+
+ if ( header0 )
+ {
+ x->x_vwidth0 = header0->info.image.width;
+ x->x_vheight0 = header0->info.image.height;
+ x->x_vsize0 = x->x_vwidth0*x->x_vheight0;
+ }
+ else
+ {
+ x->x_vwidth0 = x->x_vheight0 = x->x_vsize0 = 0;
+ }
+
+ if ( header1 )
+ {
+ x->x_vwidth1 = header1->info.image.width;
+ x->x_vheight1 = header1->info.image.height;
+ x->x_vsize1 = x->x_vwidth1*x->x_vheight1;
+ }
+ else
+ {
+ x->x_vwidth1 = x->x_vheight1 = x->x_vsize1 = 0;
+ }
+
+ x->x_vwidth = x->x_vwidth0 + x->x_vwidth1;
+ if ( x->x_vheight0 > x->x_vheight1 )
+ {
+ x->x_vheight = x->x_vheight0;
+ }
+ else
+ {
+ x->x_vheight = x->x_vheight1;
+ }
+ x->x_vsize = x->x_vwidth*x->x_vheight;
+ // post( "pdp_juxta : resulting frame : %dx%d", x->x_vwidth, x->x_vheight );
+
+ x->x_packet = pdp_packet_new_image_YCrCb( x->x_vwidth, x->x_vheight );
+
+ header = pdp_packet_header(x->x_packet);
+ data = (short int *)pdp_packet_data(x->x_packet);
+
+ header->info.image.encoding = PDP_IMAGE_YV12;
+ header->info.image.width = x->x_vwidth;
+ header->info.image.height = x->x_vheight;
+
+ poY = data;
+ poV = data+x->x_vsize;
+ poU = data+x->x_vsize+(x->x_vsize>>2);
+ p0Y = data0;
+ p0V = data0+x->x_vsize0;
+ p0U = data0+x->x_vsize0+(x->x_vsize0>>2);
+ p1Y = data1;
+ p1V = data1+x->x_vsize1;
+ p1U = data1+x->x_vsize1+(x->x_vsize1>>2);
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ if ( px < x->x_vwidth0 && p0Y )
+ {
+ *poY = *p0Y;
+ *poV = *p0V;
+ *poU = *p0U;
+ poY++;p0Y++;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ poU++; poV++;
+ p0U++; p0V++;
+ }
+ }
+ if ( px >= x->x_vwidth0 && p1Y )
+ {
+ *poY = *p1Y;
+ *poV = *p1V;
+ *poU = *p1U;
+ poY++;p1Y++;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ poU++; poV++;
+ p1U++; p1V++;
+ }
+ }
+ }
+ }
+
+ return;
+}
+
+static void pdp_juxta_sendpacket0(t_pdp_juxta *x)
+{
+ /* unregister and propagate if valid dest packet */
+ pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet);
+}
+
+static void pdp_juxta_sendpacket1(t_pdp_juxta *x)
+{
+ /* unregister and propagate if valid dest packet */
+ pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet);
+}
+
+static void pdp_juxta_process0(t_pdp_juxta *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_juxta_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_juxta_process_yv12, pdp_juxta_sendpacket0, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_juxta_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_juxta_process1(t_pdp_juxta *x)
+{
+ int encoding;
+ t_pdp *header = 0;
+
+ /* check if image data packets are compatible */
+ if ( (header = pdp_packet_header(x->x_packet1))
+ && (PDP_IMAGE == header->type)){
+
+ /* pdp_juxta_process inputs and write into active inlet */
+ switch(pdp_packet_header(x->x_packet1)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_queue_add(x, pdp_juxta_process_yv12, pdp_juxta_sendpacket1, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_juxta_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_juxta_input_0(t_pdp_juxta *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"))
+ {
+ /* release the packet */
+ if ( x->x_packet0 != -1 )
+ {
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = -1;
+ }
+ 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_juxta_process0(x);
+
+ }
+}
+
+static void pdp_juxta_input_1(t_pdp_juxta *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"))
+ {
+ /* release the packet */
+ if ( x->x_packet1 != -1 )
+ {
+ pdp_packet_mark_unused(x->x_packet1);
+ x->x_packet1 = -1;
+ }
+ x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet1, (int)f, pdp_gensym("image/YCrCb/*") );
+ }
+
+ if ((s == gensym("process")) && (-1 != x->x_packet1) && (!x->x_dropped)){
+
+ /* add the process method and callback to the process queue */
+ pdp_juxta_process1(x);
+
+ }
+}
+
+static void pdp_juxta_free(t_pdp_juxta *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+}
+
+t_class *pdp_juxta_class;
+
+void *pdp_juxta_new(void)
+{
+ int i;
+
+ t_pdp_juxta *x = (t_pdp_juxta *)pd_new(pdp_juxta_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp2"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_packet = -1;
+ x->x_queue_id = -1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_juxta_setup(void)
+{
+ post( pdp_juxta_version );
+ pdp_juxta_class = class_new(gensym("pdp_juxta"), (t_newmethod)pdp_juxta_new,
+ (t_method)pdp_juxta_free, sizeof(t_pdp_juxta), CLASS_NOINLET, A_NULL);
+
+ class_addmethod(pdp_juxta_class, (t_method)pdp_juxta_input_0, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_juxta_class, (t_method)pdp_juxta_input_1, gensym("pdp2"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_lens.c b/modules/pdp_lens.c
new file mode 100644
index 0000000..a46312a
--- /dev/null
+++ b/modules/pdp_lens.c
@@ -0,0 +1,339 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 adaptation of lens effect from effectv
+ * Originally written by Fukuchi Kentaro & others
+ * Pd-fication by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+static char *pdp_lens_version = "pdp_lens: version 0.1, port of lens from effectv( Fukuchi Kentaro ) adapted by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_lens_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_float x_zoom; // zoom factor
+ t_int x_cx; // coordinates of lens center
+ t_int x_cy; // coordinates of lens center
+ t_int x_csize; // width of the lens
+ t_int x_xd;
+ t_int x_yd;
+ t_int x_mode;
+ t_int *x_lens;
+ t_int x_init;
+
+} t_pdp_lens;
+
+static void pdp_lens_preset(t_pdp_lens *x, t_int oldsize, t_int newsize)
+{
+ int px, py, r;
+
+ if ( x->x_lens ) freebytes(x->x_lens, oldsize * oldsize * sizeof( t_int) );
+ x->x_lens = (t_int *) getbytes( newsize * newsize * sizeof( t_int ) );
+ r = x->x_csize / 2;
+
+ /* it is sufficient to generate 1/4 of the lens and reflect this
+ * around; a sphere is mirrored on both the x and y axes */
+ for (py = 0; py < r; py++) {
+ for (px = 0; px < r; px++) {
+ int ix, iy, offset, dist;
+ dist = px*px + py*py - r*r;
+ if(dist < 0) {
+ double shift = x->x_zoom/sqrt(x->x_zoom*x->x_zoom - dist);
+ ix = px * shift - px;
+ iy = py * shift - py;
+ } else {
+ ix = 0;
+ iy = 0;
+ }
+ offset = (iy * x->x_vwidth + ix);
+ x->x_lens[(r - py)*x->x_csize + r - px] = -offset;
+ x->x_lens[(r + py)*x->x_csize + r + px] = offset;
+ offset = (-iy * x->x_vwidth + ix);
+ x->x_lens[(r + py)*x->x_csize + r - px] = -offset;
+ x->x_lens[(r - py)*x->x_csize + r + px] = offset;
+ }
+ }
+}
+
+static void pdp_lens_cliplens(t_pdp_lens *x)
+{
+ if (x->x_cy<0-(x->x_csize/2)+1)x->x_cy=0-(x->x_csize/2)+1;
+ if (x->x_cy>=x->x_vheight-x->x_csize/2-1)x->x_cy=x->x_vheight-x->x_csize/2-1;
+
+ if (x->x_cx<0-(x->x_csize/2)+1) x->x_cx=0-x->x_csize/2+1;
+ if(x->x_cx>=x->x_vwidth-x->x_csize/2-1) x->x_cx=x->x_vwidth-x->x_csize/2-1;
+}
+
+static void pdp_lens_zoom(t_pdp_lens *x, t_floatarg fzoom )
+{
+ if ( fzoom>0 )
+ {
+ x->x_zoom = fzoom;
+ if (x->x_zoom<5) x->x_zoom=5;
+ if (x->x_zoom>200) x->x_zoom=200;
+ pdp_lens_preset(x, x->x_csize, x->x_csize);
+ }
+}
+
+static void pdp_lens_csize(t_pdp_lens *x, t_floatarg fcsize )
+{
+ if ( fcsize>0 )
+ {
+ x->x_csize = (int)fcsize;
+ if (x->x_csize>x->x_vheight) x->x_csize = x->x_vheight;
+ if (x->x_csize<3) x->x_csize = 3;
+ pdp_lens_preset(x, x->x_csize, x->x_csize);
+ pdp_lens_cliplens(x);
+ }
+}
+
+static void pdp_lens_cy(t_pdp_lens *x, t_floatarg fcy )
+{
+ if ( fcy>0 )
+ {
+ x->x_cy = (int)fcy;
+ pdp_lens_cliplens(x);
+ }
+}
+
+static void pdp_lens_cx(t_pdp_lens *x, t_floatarg fcx )
+{
+ if ( fcx>0 )
+ {
+ x->x_cx = (int)fcx;
+ pdp_lens_cliplens(x);
+ }
+}
+
+static void pdp_lens_mode(t_pdp_lens *x, t_floatarg fmode )
+{
+ if ( ( fmode == 0 ) || ( fmode == 1 ) )
+ {
+ x->x_mode = (int)fmode;
+ }
+}
+
+static void pdp_lens_process_yv12(t_pdp_lens *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);
+ int i;
+
+ unsigned int totalnbpixels;
+ unsigned int u_offset;
+ unsigned int v_offset;
+ unsigned int totnbpixels;
+ short int *poy, *pou, *pov, *pny, *pnu, *pnv;
+ int px, py;
+ int noy, pos, posu, nox;
+ int *p;
+
+ 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_init == -1 )
+ {
+ pdp_lens_preset( x, x->x_csize, x->x_csize );
+ x->x_init = 1;
+ }
+
+ totalnbpixels = x->x_vsize;
+ u_offset = x->x_vsize;
+ v_offset = x->x_vsize + (x->x_vsize>>2);
+ totnbpixels = x->x_vsize + (x->x_vsize>>1);
+
+ 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);
+
+ p = x->x_lens;
+ poy = data;
+ pou = data + x->x_vsize;
+ pov = data + x->x_vsize + (x->x_vsize>>2);
+ pny = newdata;
+ pnu = newdata + x->x_vsize;
+ pnv = newdata + x->x_vsize + (x->x_vsize>>2);
+ for (py = 0; py < x->x_csize; py++)
+ {
+ for (px = 0; px < x->x_csize; px++)
+ {
+ noy=(py+x->x_cy);
+ nox=(px+x->x_cx);
+ if ((nox>=0)&&(noy>=0)&&(nox<x->x_vwidth)&&(noy<x->x_vheight)){
+ pos = (noy * x->x_vwidth) + nox;
+ posu = ((noy>>1) * (x->x_vwidth>>1)) + (nox>>1);
+ if ( ( ( pos + *p )< x->x_vsize ) && ( pos < x->x_vsize ) )
+ {
+ *(pny+pos) = *(poy + pos + *p);
+ *(pnu+posu) = *(pou + posu + *p );
+ *(pnv+posu) = *(pov + posu + *p );
+ }
+ }
+ p++;
+ }
+ }
+
+ if (x->x_mode==1)
+ {
+ x->x_cx+= x->x_xd; x->x_cy+=x->x_yd;
+ if (x->x_cx > (x->x_vwidth - x->x_csize - 5) || x->x_cx < 5) x->x_xd = -x->x_xd;
+ if (x->x_cy > (x->x_vwidth - x->x_csize - 5) || x->x_cy < 5) x->x_yd = -x->x_yd;
+ }
+
+ return;
+}
+
+static void pdp_lens_sendpacket(t_pdp_lens *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_lens_process(t_pdp_lens *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_lens_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_lens_process_yv12, pdp_lens_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ // pdp_lens_process_packet(x);
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_lens_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_lens_input_0(t_pdp_lens *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_lens_process(x);
+
+ }
+}
+
+static void pdp_lens_free(t_pdp_lens *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_lens_class;
+
+void *pdp_lens_new(void)
+{
+ int i;
+
+ t_pdp_lens *x = (t_pdp_lens *)pd_new(pdp_lens_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("cx"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("cy"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("csize"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("zoom"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("mode"));
+
+ 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_cx = x->x_cy = 16;
+ x->x_xd = x->x_yd = 5;
+ x->x_csize = 150;
+ x->x_zoom = 30;
+ x->x_init = -1;
+ x->x_mode = 0;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_lens_setup(void)
+{
+// post( pdp_lens_version );
+ pdp_lens_class = class_new(gensym("pdp_lens"), (t_newmethod)pdp_lens_new,
+ (t_method)pdp_lens_free, sizeof(t_pdp_lens), 0, A_NULL);
+
+ class_addmethod(pdp_lens_class, (t_method)pdp_lens_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_lens_class, (t_method)pdp_lens_cx, gensym("cx"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_lens_class, (t_method)pdp_lens_cy, gensym("cy"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_lens_class, (t_method)pdp_lens_csize, gensym("csize"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_lens_class, (t_method)pdp_lens_zoom, gensym("zoom"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_lens_class, (t_method)pdp_lens_mode, gensym("mode"), A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_live~.c b/modules/pdp_live~.c
new file mode 100644
index 0000000..aa8398d
--- /dev/null
+++ b/modules/pdp_live~.c
@@ -0,0 +1,789 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* This object is a stream decoder object
+ * A lot of this object code is inspired by the excellent ffmpeg.c
+ * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
+ * The rest is written by Yves Degoyon ( ydegoyon@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 <avformat.h>
+
+#define VIDEO_BUFFER_SIZE (1024*1024)
+#define MAX_AUDIO_PACKET_SIZE (128 * 1024)
+#define MIN_AUDIO_SIZE (64 * 1024)
+#define AUDIO_PACKET_SIZE (2*1152)
+
+#define DEFAULT_CHANNELS 1
+#define DEFAULT_FRAME_RATE 25
+#define DEFAULT_WIDTH 320
+#define DEFAULT_HEIGHT 240
+#define DEFAULT_PRIORITY 0
+
+static char *pdp_live_version = "pdp_live~: version 0.1, a video stream decoder ( ydegoyon@free.fr).";
+
+typedef struct pdp_live_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_dropped;
+
+ t_pdp *x_header;
+ short int *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_streaming; // indicates the action of streaming
+ t_outlet *x_outlet_nbframes; // number of frames emitted
+
+ pthread_t x_connectchild; // thread used for connecting to a stream
+ pthread_t x_decodechild; // stream decoding thread
+ t_int x_usethread; // flag to activate decoding in a thread
+ t_int x_priority; // priority of decoding thread
+
+ char *x_url;
+ t_int x_streaming; // streaming flag
+ 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_audioon; // enough audio data to start playing
+ struct timeval x_starttime; // streaming starting time
+ t_int x_cursec; // current second
+ t_int x_secondcount; // number of frames received in the current second
+ t_int x_nbvideostreams; // number of video streams
+ t_int x_nbaudiostreams; // number of audio streams
+
+ /* AV data structures */
+ AVFormatContext *x_avcontext;
+ AVFormatParameters x_avparameters; // unused but the call is necessary to allocate structures
+ AVPacket x_pkt; // packet received on the stream
+ AVPicture x_picture_decoded;
+ t_int x_newpicture;
+
+ /* audio structures */
+ t_int x_audio; // flag to activate the decoding of audio
+ short x_audio_buf[4*MAX_AUDIO_PACKET_SIZE]; /* buffer for audio from stream*/
+ short x_audio_in[4*MAX_AUDIO_PACKET_SIZE]; /* buffer for resampled PCM audio */
+ t_int x_audioin_position; // writing position for incoming audio
+ ReSampleContext *x_audio_resample_ctx; // structures for audio resample
+
+} t_pdp_live;
+
+static void pdp_live_priority(t_pdp_live *x, t_floatarg fpriority )
+{
+ x->x_priority = (int)fpriority;
+}
+
+static void pdp_live_threadify(t_pdp_live *x, t_floatarg fusethread )
+{
+ if ( ( fusethread == 0 ) || ( fusethread == 1 ) )
+ {
+ x->x_usethread = (int)fusethread;
+ }
+}
+
+static void pdp_live_audio(t_pdp_live *x, t_floatarg faudio )
+{
+ if ( ( faudio == 0.0 ) || ( faudio == 1 ) )
+ {
+ x->x_audio = (int)faudio;
+ }
+}
+
+static t_int pdp_live_decode_packet(t_pdp_live *x)
+{
+ t_int chunksize=0, length;
+ t_int audiosize, sizeout, imagesize, pictureok;
+ AVFrame frame;
+ uint8_t *pcktptr;
+ struct timeval etime;
+
+ if ( !x->x_streaming )
+ {
+ return -1;
+ }
+
+ // read new packet on the stream
+ if (av_read_packet(x->x_avcontext, &x->x_pkt) < 0)
+ {
+ // post( "pdp_live~ : decoding thread : nothing to decode" );
+ return -1;
+ }
+ // post( "pdp_live~ : read packet ( size=%d )", x->x_pkt.size );
+
+ if (x->x_pkt.stream_index >= x->x_avcontext->nb_streams)
+ {
+ post("pdp_live~ : stream received out of range !! ");
+ return 0;
+ }
+
+ length = x->x_pkt.size;
+ pcktptr = x->x_pkt.data;
+ while (length > 0)
+ {
+ switch(x->x_avcontext->streams[x->x_pkt.stream_index]->codec.codec_type)
+ {
+ case CODEC_TYPE_AUDIO:
+ if ( !x->x_audio )
+ {
+ av_free_packet(&x->x_pkt);
+ return 0;
+ }
+ chunksize = avcodec_decode_audio(&x->x_avcontext->streams[x->x_pkt.stream_index]->codec,
+ &x->x_audio_buf[0], &audiosize,
+ pcktptr, length);
+ if (chunksize < 0)
+ {
+ post("pdp_live~ : could not decode audio input (ret=%d)", chunksize );
+ av_free_packet(&x->x_pkt);
+ continue;
+ }
+ // some bug in mpeg audio decoder gives
+ // data_size < 0, it seems they are overflows
+ if (audiosize <= 0)
+ {
+ /* no audio frame */
+ pcktptr += chunksize;
+ length -= chunksize;
+ // post("pdp_live~ : audio overflow in decoder!");
+ continue;
+ }
+
+ // resample received audio
+ // post( "pdp_live~ : resampling from %dHz-%dch to %dHz-%dch (in position=%d)",
+ // x->x_avcontext->streams[x->x_pkt.stream_index]->codec.sample_rate,
+ // x->x_avcontext->streams[x->x_pkt.stream_index]->codec.channels,
+ // (int)sys_getsr(), 2, x->x_audioin_position );
+
+ x->x_audiochannels = x->x_avcontext->streams[x->x_pkt.stream_index]->codec.channels;
+ x->x_samplerate = x->x_avcontext->streams[x->x_pkt.stream_index]->codec.sample_rate;
+ if (x->x_audio_resample_ctx) audio_resample_close(x->x_audio_resample_ctx);
+ x->x_audio_resample_ctx =
+ audio_resample_init(DEFAULT_CHANNELS,
+ x->x_avcontext->streams[x->x_pkt.stream_index]->codec.channels,
+ (int)sys_getsr(),
+ x->x_avcontext->streams[x->x_pkt.stream_index]->codec.sample_rate);
+
+ sizeout = audio_resample(x->x_audio_resample_ctx,
+ &x->x_audio_in[x->x_audioin_position],
+ &x->x_audio_buf[0],
+ audiosize/(x->x_avcontext->streams[x->x_pkt.stream_index]->codec.channels * sizeof(short)));
+ sizeout = sizeout * DEFAULT_CHANNELS;
+
+ if ( ( x->x_audioin_position + sizeout ) < 3*MAX_AUDIO_PACKET_SIZE )
+ {
+ x->x_audioin_position = x->x_audioin_position + sizeout;
+ }
+ else
+ {
+ post( "pdp_live~ : audio overflow : packet ignored...");
+ }
+ if ( ( x->x_audioin_position > MIN_AUDIO_SIZE ) && (!x->x_audioon) )
+ {
+ x->x_audioon = 1;
+ // post( "pdp_live~ : audio on" );
+ }
+ break;
+
+ case CODEC_TYPE_VIDEO:
+
+ imagesize = (x->x_avcontext->streams[x->x_pkt.stream_index]->codec.width *
+ x->x_avcontext->streams[x->x_pkt.stream_index]->codec.height * 3) / 2; // yuv planar
+
+ // do not believe the declared framerate
+ // x->x_framerate = x->x_avcontext->streams[x->x_pkt.stream_index]->codec.frame_rate / 10000;
+
+ // calculate actual frame rate
+ if ( gettimeofday(&etime, NULL) == -1)
+ {
+ post("pdp_live~ : could not read time" );
+ }
+ if ( ( etime.tv_sec - x->x_starttime.tv_sec ) > 0 )
+ {
+ x->x_framerate = x->x_nbframes / ( etime.tv_sec - x->x_starttime.tv_sec );
+ }
+ if ( x->x_framerate == 0 ) x->x_framerate = 1;
+ // post ("pdp_live~ : frame rate is %d", x->x_framerate );
+
+ chunksize = avcodec_decode_video(
+ &x->x_avcontext->streams[x->x_pkt.stream_index]->codec,
+ &frame, &pictureok,
+ pcktptr, length);
+ if ( x->x_avcontext->streams[x->x_pkt.stream_index]->codec.pix_fmt != PIX_FMT_YUV420P )
+ {
+ post( "pdp_live~ : unsupported image format : %d",
+ x->x_avcontext->streams[x->x_pkt.stream_index]->codec.pix_fmt );
+ pictureok = 0;
+ }
+ // post( "pdp_live~ : decoded new frame : type=%d format=%d (w=%d) (h=%d) (linesizes=%d,%d,%d,%d)",
+ // frame.pict_type,
+ // x->x_avcontext->streams[x->x_pkt.stream_index]->codec.pix_fmt,
+ // x->x_avcontext->streams[x->x_pkt.stream_index]->codec.width,
+ // x->x_avcontext->streams[x->x_pkt.stream_index]->codec.height,
+ // frame.linesize[0],
+ // frame.linesize[1],
+ // frame.linesize[2],
+ // frame.linesize[3] );
+ x->x_picture_decoded = *(AVPicture*)&frame;
+ x->x_avcontext->streams[x->x_pkt.stream_index]->quality= frame.quality;
+ if (chunksize < 0)
+ {
+ av_free_packet(&x->x_pkt);
+ post("pdp_live~ : could not decode video frame (ret=%d)", chunksize );
+ return 0;
+ }
+ if (!pictureok)
+ {
+ // no picture yet
+ pcktptr += chunksize;
+ length -= chunksize;
+ continue;
+ }
+ else
+ {
+ x->x_newpicture=1;
+ x->x_vwidth = x->x_avcontext->streams[x->x_pkt.stream_index]->codec.width;
+ x->x_vheight = x->x_avcontext->streams[x->x_pkt.stream_index]->codec.height;
+ x->x_vsize = x->x_vwidth*x->x_vheight;
+ }
+ break;
+ }
+ pcktptr += chunksize;
+ length -= chunksize;
+ if ( !x->x_streaming ) break;
+ }
+ av_free_packet(&x->x_pkt);
+
+ // post( "pdp_live~ : decoded one packet" );
+ return 0;
+
+}
+
+static void *pdp_decode_stream_from_url(void *tdata)
+{
+ t_pdp_live *x = (t_pdp_live*)tdata;
+ struct sched_param schedprio;
+ t_int pmin, pmax;
+ struct timespec twait;
+
+ twait.tv_sec = 0;
+ twait.tv_nsec = 10000000; // 10 ms
+
+ schedprio.sched_priority = 0;
+ if ( sched_setscheduler(0,SCHED_OTHER,&schedprio) == -1)
+ {
+ post("pdp_live~ : couldn't set scheduler for decoding thread.\n");
+ }
+ if ( setpriority( PRIO_PROCESS, 0, x->x_priority ) < 0 )
+ {
+ post("pdp_live~ : couldn't set priority to %d for decoding thread.\n", x->x_priority );
+ }
+ else
+ {
+ post("pdp_live~ : priority set to %d for thread %d.\n", x->x_priority, x->x_decodechild );
+ }
+
+ if ( ! (x->x_avcontext->iformat->flags & AVFMT_NOHEADER ) )
+ {
+ if (x->x_avcontext->iformat->read_header(x->x_avcontext, &x->x_avparameters) < 0)
+ {
+ post( "pdp_live~ : couldn't read header" );
+ }
+ post( "pdp_live~ : read header." );
+ }
+
+ while ( x->x_streaming )
+ {
+ while ( x->x_newpicture ) nanosleep( &twait, NULL );
+
+ // decode incoming packets
+ if ( pdp_live_decode_packet( x ) < 0 )
+ {
+ nanosleep( &twait, NULL ); // nothing to read, just wait
+ }
+ }
+
+ post( "pdp_live~ : decoding thread %d exiting....", x->x_decodechild );
+ x->x_decodechild = 0;
+ pthread_exit(NULL);
+}
+
+static void *pdp_live_connect_to_url(void *tdata)
+{
+ int i, err;
+ t_pdp_live *x = (t_pdp_live*)tdata;
+ pthread_attr_t decode_child_attr;
+
+ memset(&x->x_avparameters, 0, sizeof(AVFormatParameters));
+ x->x_avparameters.sample_rate = sys_getsr();
+ x->x_avparameters.channels = DEFAULT_CHANNELS;
+ x->x_avparameters.frame_rate = DEFAULT_FRAME_RATE;
+ x->x_avparameters.width = DEFAULT_WIDTH;
+ x->x_avparameters.height = DEFAULT_HEIGHT;
+ x->x_avparameters.image_format = PIX_FMT_YUV420P;
+
+ post( "pdp_live~ : opening url : %s", x->x_url );
+ err = av_open_input_file(&x->x_avcontext, x->x_url, x->x_avcontext->iformat, 0, &x->x_avparameters);
+ if (err < 0)
+ {
+ if ( err == -1 ) post( "pdp_live~ : unknown error" );
+ if ( err == -2 ) post( "pdp_live~ : i/o error" );
+ if ( err == -3 ) post( "pdp_live~ : number syntax expected in filename" );
+ if ( err == -4 ) post( "pdp_live~ : invalid data found" );
+ if ( err == -5 ) post( "pdp_live~ : not enough memory" );
+ if ( err == -6 ) post( "pdp_live~ : unknown format ( stream not found? )" );
+ x->x_connectchild = 0;
+ x->x_avcontext = av_mallocz(sizeof(AVFormatContext));
+ pthread_exit(NULL);
+ }
+ /* If not enough info to get the stream parameters, we decode the
+ first frames to get it. (used in mpeg case for example) */
+ err = av_find_stream_info(x->x_avcontext);
+ if (err < 0)
+ {
+ post( "pdp_live~ : %s: could not find codec parameters\n", x->x_url);
+ x->x_connectchild = 0;
+ av_close_input_file(x->x_avcontext);
+ x->x_avcontext = av_mallocz(sizeof(AVFormatContext));
+ pthread_exit(NULL);
+ }
+
+ // post( "pdp_live~ : stream reader : %x", x->x_avcontext->iformat );
+
+ /* copy stream format */
+ x->x_nbvideostreams = 0;
+ x->x_nbaudiostreams = 0;
+
+ for(i=0;i<x->x_avcontext->nb_streams;i++)
+ {
+ AVStream *st;
+
+ if ( x->x_avcontext->streams[i]->codec.codec_type == CODEC_TYPE_UNKNOWN )
+ {
+ post( "pdp_live~ : stream #%d # type : unknown", i );
+ }
+ if ( x->x_avcontext->streams[i]->codec.codec_type == CODEC_TYPE_AUDIO )
+ {
+ post( "pdp_live~ : stream #%d # type : audio # id : %d # bitrate : %d",
+ i, x->x_avcontext->streams[i]->codec.codec_id, x->x_avcontext->streams[i]->codec.bit_rate );
+ post( "pdp_live~ : sample rate : %d # channels : %d",
+ x->x_avcontext->streams[i]->codec.sample_rate, x->x_avcontext->streams[i]->codec.channels );
+ x->x_nbaudiostreams++;
+ }
+ if ( x->x_avcontext->streams[i]->codec.codec_type == CODEC_TYPE_VIDEO )
+ {
+ post( "pdp_live~ : stream #%d # type : video # id : %d # bitrate : %d",
+ i, x->x_avcontext->streams[i]->codec.codec_id,
+ x->x_avcontext->streams[i]->codec.bit_rate );
+ post( "pdp_live~ : framerate : %d # width : %d # height : %d",
+ x->x_avcontext->streams[i]->codec.frame_rate/10000,
+ x->x_avcontext->streams[i]->codec.width,
+ x->x_avcontext->streams[i]->codec.height );
+ x->x_nbvideostreams++;
+ }
+ }
+
+ /* open each decoder */
+ for(i=0;i<x->x_avcontext->nb_streams;i++)
+ {
+ AVCodec *codec;
+ post("pdp_live~ : opening decoder for stream #%d", i);
+ codec = avcodec_find_decoder(x->x_avcontext->streams[i]->codec.codec_id);
+ if (!codec)
+ {
+ post("pdp_live~ : unsupported codec for output stream #%d\n", i );
+ x->x_streaming = 0;
+ x->x_connectchild = 0;
+ av_close_input_file(x->x_avcontext);
+ x->x_avcontext = av_mallocz(sizeof(AVFormatContext));
+ pthread_exit(NULL);
+ }
+ if (avcodec_open(&x->x_avcontext->streams[i]->codec, codec) < 0)
+ {
+ post("pdp_live~ : error while opening codec for stream #%d - maybe incorrect parameters such as bit_rate, rate, width or height\n", i);
+ x->x_streaming = 0;
+ x->x_connectchild = 0;
+ av_close_input_file(x->x_avcontext);
+ x->x_avcontext = av_mallocz(sizeof(AVFormatContext));
+ pthread_exit(NULL);
+ }
+ else
+ {
+ post("pdp_live~ : opened decoder for stream #%d", i);
+ }
+ }
+
+ if ( gettimeofday(&x->x_starttime, NULL) == -1)
+ {
+ post("pdp_live~ : could not set start time" );
+ }
+ x->x_streaming = 1;
+ x->x_nbframes = 0;
+
+ x->x_connectchild = 0;
+
+ if ( x->x_usethread )
+ {
+ // launch decoding thread
+ if ( pthread_attr_init( &decode_child_attr ) < 0 )
+ {
+ post( "pdp_live~ : could not launch decoding thread" );
+ perror( "pthread_attr_init" );
+ av_close_input_file(x->x_avcontext);
+ x->x_avcontext = av_mallocz(sizeof(AVFormatContext));
+ pthread_exit(NULL);
+ }
+ if ( pthread_create( &x->x_decodechild, &decode_child_attr, pdp_decode_stream_from_url, x ) < 0 )
+ {
+ post( "pdp_live~ : could not launch decoding thread" );
+ perror( "pthread_create" );
+ av_close_input_file(x->x_avcontext);
+ x->x_avcontext = av_mallocz(sizeof(AVFormatContext));
+ pthread_exit(NULL);
+ }
+ else
+ {
+ post( "pdp_live~ : decoding thread %d launched", (int)x->x_decodechild );
+ }
+ }
+
+ pthread_exit(NULL);
+}
+
+static void pdp_live_disconnect(t_pdp_live *x)
+{
+ t_int ret, i, count=0;
+ struct timespec twait;
+
+ twait.tv_sec = 0;
+ twait.tv_nsec = 100000000; // 100 ms
+
+ if (!x->x_streaming)
+ {
+ post("pdp_live~ : close request but no stream is played ... ignored" );
+ return;
+ }
+
+ if ( x->x_streaming )
+ {
+ x->x_streaming = 0;
+ x->x_newpicture = 0;
+ post("pdp_live~ : waiting for the end of decoding thread..." );
+ while ( x->x_decodechild && ( count < 100 ) )
+ {
+ count++;
+ sleep( 1 );
+ }
+ if ( x->x_decodechild )
+ {
+ post("pdp_live~ : zombie thread, i guess" );
+ }
+ post("pdp_live~ : closing input file..." );
+ av_close_input_file(x->x_avcontext);
+ x->x_avcontext = av_mallocz(sizeof(AVFormatContext));
+ }
+
+ outlet_float( x->x_outlet_streaming, x->x_streaming );
+ x->x_nbframes = 0;
+ outlet_float( x->x_outlet_nbframes, x->x_nbframes );
+
+ if (x->x_audio_resample_ctx)
+ {
+ audio_resample_close(x->x_audio_resample_ctx);
+ x->x_audio_resample_ctx = NULL;
+ }
+
+}
+
+static void pdp_live_connect(t_pdp_live *x, t_symbol *s)
+{
+ t_int ret, i;
+ pthread_attr_t connect_child_attr;
+
+ if ( ( x->x_streaming ) || ( x->x_connectchild != 0 ) )
+ {
+ post("pdp_live~ : connection request but a connection is pending ... disconnecting" );
+ pdp_live_disconnect(x);
+ }
+
+ if ( x->x_url ) free( x->x_url );
+ x->x_url = (char*) malloc( strlen( s->s_name ) + 1 );
+ strcpy( x->x_url, s->s_name );
+
+ // launch connection thread
+ if ( pthread_attr_init( &connect_child_attr ) < 0 ) {
+ post( "pdp_live~ : could not launch connection thread" );
+ perror( "pthread_attr_init" );
+ return;
+ }
+ if ( pthread_attr_setdetachstate( &connect_child_attr, PTHREAD_CREATE_DETACHED ) < 0 ) {
+ post( "pdp_live~ : could not launch connection thread" );
+ perror( "pthread_attr_setdetachstate" );
+ return;
+ }
+ if ( pthread_create( &x->x_connectchild, &connect_child_attr, pdp_live_connect_to_url, x ) < 0 ) {
+ post( "pdp_live~ : could not launch connection thread" );
+ perror( "pthread_create" );
+ return;
+ }
+ else
+ {
+ post( "pdp_live~ : connection thread %d launched", (int)x->x_connectchild );
+ }
+
+ return;
+}
+
+ /* decode the stream to fill up buffers */
+static t_int *pdp_live_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_live *x = (t_pdp_live *)(w[3]);
+ int n = (int)(w[4]); // number of samples
+ short int *pY, *pU, *pV;
+ uint8_t *psY, *psU, *psV;
+ t_int pixRGB, px, py;
+ short sampleL, sampleR;
+ struct timeval etime;
+ t_int sn;
+
+ // decode a packet if not in thread mode
+ if ( !x->x_usethread )
+ {
+ pdp_live_decode_packet( x );
+ }
+
+ // just read the buffer
+ if ( x->x_audioon )
+ {
+ sn=0;
+ n=n*DEFAULT_CHANNELS;
+ while (n--)
+ {
+ sampleL=x->x_audio_in[ sn++ ];
+ *(out1) = ((t_float)sampleL)/32768.0;
+ if ( DEFAULT_CHANNELS == 1 )
+ {
+ *(out2) = *(out1);
+ }
+ if ( DEFAULT_CHANNELS == 2 )
+ {
+ sampleR=x->x_audio_in[ sn++ ];
+ *(out2) = ((t_float)sampleR)/32768.0;
+ }
+ out1++;
+ out2++;
+ }
+ x->x_audioin_position-=sn;
+ memcpy( &x->x_audio_in[0], &x->x_audio_in[sn], 4*MAX_AUDIO_PACKET_SIZE-sn );
+ // post( "pdp_live~ : audio in position : %d", x->x_audioin_position );
+ if ( x->x_audioin_position <= sn )
+ {
+ x->x_audioon = 0;
+ // post( "pdp_live~ : audio off" );
+ }
+ }
+ else
+ {
+ // post("pdp_live~ : 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_live~ : could not read time" );
+ }
+ if ( etime.tv_sec != x->x_cursec )
+ {
+ x->x_cursec = etime.tv_sec;
+ x->x_secondcount = 0;
+ }
+ if ( x->x_secondcount >= x->x_framerate )
+ {
+ // return (w+5);
+ }
+
+ // output image if there's a new one decoded
+ if ( x->x_newpicture )
+ {
+ // create a new pdp packet from PIX_FMT_YUV420P image format
+ x->x_packet0 = pdp_packet_new_image_YCrCb( x->x_vwidth, x->x_vheight );
+ x->x_header = pdp_packet_header(x->x_packet0);
+ x->x_data = (short int *)pdp_packet_data(x->x_packet0);
+
+ 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_picture_decoded.data[0];
+ psU = x->x_picture_decoded.data[1];
+ psV = x->x_picture_decoded.data[2];
+
+ for ( py=0; py<x->x_vheight; py++)
+ {
+ for ( px=0; px<x->x_vwidth; px++)
+ {
+ *(pY) = ( *(psY+px) << 7 );
+ *(pV) = ( ((*(psV+(px>>1)))-128) << 8 );
+ *(pU) = ( ((*(psU+(px>>1)))-128) << 8 );
+ pY++;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ pV++; pU++;
+ }
+ }
+ psY += x->x_picture_decoded.linesize[0];
+ if ( py%2==0 ) psU += x->x_picture_decoded.linesize[1];
+ if ( py%2==0 ) psV += x->x_picture_decoded.linesize[2];
+ }
+
+ pdp_packet_pass_if_valid(x->x_pdp_out, &x->x_packet0);
+
+ // update streaming status
+ outlet_float( x->x_outlet_streaming, x->x_streaming );
+ x->x_nbframes++;
+ x->x_secondcount++;
+ outlet_float( x->x_outlet_nbframes, x->x_nbframes );
+
+ x->x_newpicture = 0;
+ }
+
+ return (w+5);
+}
+
+static void pdp_live_dsp(t_pdp_live *x, t_signal **sp)
+{
+ dsp_add(pdp_live_perform, 4, sp[0]->s_vec, sp[1]->s_vec, x, sp[0]->s_n);
+}
+
+static void pdp_live_free(t_pdp_live *x)
+{
+ int i;
+
+ if ( x->x_streaming )
+ {
+ pdp_live_disconnect(x);
+ sleep(3);
+ }
+ post( "pdp_live~ : freeing object" );
+ pdp_packet_mark_unused(x->x_packet0);
+ if (x->x_audio_resample_ctx)
+ {
+ audio_resample_close(x->x_audio_resample_ctx);
+ x->x_audio_resample_ctx = NULL;
+ }
+ av_free_static();
+}
+
+t_class *pdp_live_class;
+
+void *pdp_live_new(void)
+{
+ int i;
+
+ t_pdp_live *x = (t_pdp_live *)pd_new(pdp_live_class);
+
+ 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_streaming = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet_nbframes = outlet_new(&x->x_obj, &s_float);
+
+ x->x_packet0 = -1;
+ x->x_connectchild = 0;
+ x->x_decodechild = 0;
+ x->x_usethread = 1;
+ x->x_priority = DEFAULT_PRIORITY;
+ x->x_nbframes = 0;
+ x->x_framerate = DEFAULT_FRAME_RATE;
+ x->x_samplerate = 0;
+ x->x_audiochannels = 0;
+ x->x_cursec = 0;
+ x->x_secondcount = 0;
+ x->x_audio_resample_ctx = NULL;
+ x->x_nbvideostreams = 0;
+ x->x_audioin_position = 0;
+ x->x_newpicture = 0;
+
+ x->x_avcontext = av_mallocz(sizeof(AVFormatContext));
+ if ( !x->x_avcontext )
+ {
+ post( "pdp_live~ : severe error : could not allocate video structures." );
+ return NULL;
+ }
+
+ // activate codecs
+ av_register_all();
+
+ memset( &x->x_audio_buf[0], 0x0, 4*MAX_AUDIO_PACKET_SIZE*sizeof(short) );
+ memset( &x->x_audio_in[0], 0x0, 4*MAX_AUDIO_PACKET_SIZE*sizeof(short) );
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_live_tilde_setup(void)
+{
+ post( pdp_live_version );
+ pdp_live_class = class_new(gensym("pdp_live~"), (t_newmethod)pdp_live_new,
+ (t_method)pdp_live_free, sizeof(t_pdp_live), 0, A_NULL);
+
+ class_addmethod(pdp_live_class, (t_method)pdp_live_dsp, gensym("dsp"), 0);
+ class_addmethod(pdp_live_class, (t_method)pdp_live_connect, gensym("connect"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_live_class, (t_method)pdp_live_disconnect, gensym("disconnect"), A_NULL);
+ class_addmethod(pdp_live_class, (t_method)pdp_live_priority, gensym("priority"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_live_class, (t_method)pdp_live_audio, gensym("audio"), A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_lumafilt.c b/modules/pdp_lumafilt.c
new file mode 100644
index 0000000..62f1a87
--- /dev/null
+++ b/modules/pdp_lumafilt.c
@@ -0,0 +1,255 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 effect filters some levels of luminosity
+ * Useful to isolate some objects
+ * Written by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+#define MAX_LUMA 256
+
+static char *pdp_lumafilt_version = "pdp_lumafilt: version 0.1, written by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_lumafilt_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_filter[MAX_LUMA]; // transform number
+
+} t_pdp_lumafilt;
+
+static void pdp_lumafilt_free_ressources(t_pdp_lumafilt *x)
+{
+ // nothing
+}
+
+static void pdp_lumafilt_allocate(t_pdp_lumafilt *x)
+{
+ // nothing
+}
+
+static void pdp_lumafilt_filter(t_pdp_lumafilt *x, t_floatarg fluma, t_floatarg fonoff )
+{
+ if ( ( (int)fluma >= 0 ) && ( (int)fluma < MAX_LUMA ) )
+ {
+ if ( ((int)fonoff == 0 ) || ((int)fonoff == 1 ) )
+ {
+ x->x_filter[ (int)fluma ] = (int)fonoff;
+ }
+ }
+}
+
+static void pdp_lumafilt_mfilter(t_pdp_lumafilt *x, t_floatarg flumas, t_floatarg flumae, t_floatarg fonoff )
+{
+ t_int li;
+
+ if ( ( (int)flumas >= 0 ) && ( (int)flumas < MAX_LUMA ) &&
+ ( (int)flumae >= 0 ) && ( (int)flumae < MAX_LUMA ) &&
+ ( flumas < flumae ) )
+ {
+ if ( ((int)fonoff == 0 ) || ((int)fonoff == 1 ) )
+ {
+ for ( li=(int)flumas; li<=(int)flumae; li++ )
+ {
+ x->x_filter[ li ] = (int)fonoff;
+ }
+ }
+ }
+}
+
+static void pdp_lumafilt_process_yv12(t_pdp_lumafilt *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 px, py, luma;
+ short int *pnY, *pnU, *pnV;
+
+ /* allocate all ressources */
+ if ( (int)(header->info.image.width*header->info.image.height) != x->x_vsize )
+ {
+ pdp_lumafilt_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_lumafilt_allocate(x);
+ post( "pdp_lumafilt : reallocated buffers" );
+ }
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ pnY = newdata;
+ pnV = newdata+x->x_vsize;
+ pnU = newdata+x->x_vsize+(x->x_vsize>>2);
+
+ memcpy( newdata, data, (x->x_vsize + (x->x_vsize>>1))<<1 );
+
+ for (py = 0; py < x->x_vheight; py++) {
+ for (px = 0; px < x->x_vwidth; px++) {
+ luma = (*(pnY)>>7);
+ if ( ( luma >0 ) && ( luma < MAX_LUMA ) ) // paranoid
+ {
+ if ( x->x_filter[luma] )
+ {
+ *(pnY) = 0;
+ *(pnU) = 0;
+ *(pnV) = 0;
+ }
+ }
+ else
+ {
+ post( "pdp_lumafilt : luminosity value out of bounds : %d", luma );
+ }
+ pnY++;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ *pnU++; *pnV++;
+ }
+ }
+ }
+
+ return;
+}
+
+static void pdp_lumafilt_sendpacket(t_pdp_lumafilt *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_lumafilt_process(t_pdp_lumafilt *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_lumafilt_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_lumafilt_process_yv12, pdp_lumafilt_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_lumafilt_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_lumafilt_input_0(t_pdp_lumafilt *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_lumafilt_process(x);
+ }
+}
+
+static void pdp_lumafilt_free(t_pdp_lumafilt *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_lumafilt_free_ressources(x);
+}
+
+t_class *pdp_lumafilt_class;
+
+void *pdp_lumafilt_new(void)
+{
+ int fi;
+
+ t_pdp_lumafilt *x = (t_pdp_lumafilt *)pd_new(pdp_lumafilt_class);
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_queue_id = -1;
+
+ for ( fi=0; fi<MAX_LUMA; fi++ )
+ {
+ x->x_filter[fi] = 0;
+ }
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_lumafilt_setup(void)
+{
+// post( pdp_lumafilt_version );
+ pdp_lumafilt_class = class_new(gensym("pdp_lumafilt"), (t_newmethod)pdp_lumafilt_new,
+ (t_method)pdp_lumafilt_free, sizeof(t_pdp_lumafilt), 0, A_NULL);
+
+ class_addmethod(pdp_lumafilt_class, (t_method)pdp_lumafilt_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_lumafilt_class, (t_method)pdp_lumafilt_filter, gensym("filter"), A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_lumafilt_class, (t_method)pdp_lumafilt_mfilter, gensym("mfilter"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_mgrid.c b/modules/pdp_mgrid.c
new file mode 100644
index 0000000..3f3939c
--- /dev/null
+++ b/modules/pdp_mgrid.c
@@ -0,0 +1,336 @@
+/*
+ * PiDiP module
+ * Copyright (c) by Yves Degoyon ( ydegoyon@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 motion detection grid
+ */
+
+#include "pdp.h"
+#include <math.h>
+
+#define DEFAULT_X_DIM 10
+#define DEFAULT_Y_DIM 10
+#define DEFAULT_THRESHOLD 20
+#define DEFAULT_COLOR 128
+
+static char *pdp_mgrid_version = "pdp_mgrid: a motion detection grid version 0.1 written by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_mgrid_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_dropped;
+
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+ short int *x_previous_frame;
+ t_int x_xdim;
+ t_int x_ydim;
+ t_int x_threshold;
+ short int x_color;
+ t_int x_firstimage;
+
+ t_outlet *x_pdp_output; // output packets
+ t_outlet *x_xmotion; // output x coordinate of block which has been detected
+ t_outlet *x_ymotion; // output y coordinate of block which has been detected
+
+
+} t_pdp_mgrid;
+
+static void pdp_mgrid_free_ressources(t_pdp_mgrid *x)
+{
+ if ( x->x_previous_frame ) freebytes ( x->x_previous_frame, ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );
+}
+
+static void pdp_mgrid_allocate(t_pdp_mgrid *x)
+{
+ x->x_previous_frame = (short int *) getbytes ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 );
+
+ if ( !x->x_previous_frame )
+ {
+ post( "pdp_mgrid : severe error : cannot allocate buffer !!! ");
+ return;
+ }
+}
+
+static void pdp_mgrid_x_dim(t_pdp_mgrid *x, t_floatarg fxdim )
+{
+ if ( x->x_previous_frame == NULL )
+ {
+ post( "pdp_mgrid : tried to set grid dimension but image dimensions are unknown" );
+ return;
+ }
+ if ( ( fxdim >= 0 ) && ( fxdim < (x->x_vwidth/3) ) )
+ {
+ x->x_xdim = (int)fxdim;
+ }
+}
+
+static void pdp_mgrid_y_dim(t_pdp_mgrid *x, t_floatarg fydim )
+{
+ if ( x->x_previous_frame == NULL )
+ {
+ post( "pdp_mgrid : tried to set grid dimension but image dimensions are unknown" );
+ return;
+ }
+
+ if ( ( fydim >= 0 ) && ( fydim < (x->x_vheight/3) ) )
+ {
+ x->x_ydim = (int)fydim;
+ }
+}
+
+static void pdp_mgrid_threshold(t_pdp_mgrid *x, t_floatarg fthreshold )
+{
+ if ( fthreshold > 0 )
+ {
+ x->x_threshold = (int)fthreshold;
+ }
+}
+
+static void pdp_mgrid_color(t_pdp_mgrid *x, t_floatarg fcolor )
+{
+ if ( ( fcolor >= 0 ) && ( fcolor < 255 ) )
+ {
+ x->x_color = (int)fcolor;
+ }
+}
+
+static void pdp_mgrid_process_yv12(t_pdp_mgrid *x)
+{
+ t_pdp *header = pdp_packet_header(x->x_packet0);
+ short int *data = (short int *)pdp_packet_data(x->x_packet0);
+ t_int i, cf;
+ t_int px=0, py=0, xcell=0, ycell=0;
+ t_int celldiff=0, cellwidth=0, cellheight=0;
+ t_int yindex=0, uindex=0, vindex=0;
+
+ /* allocate all ressources */
+ if ( ( (int)header->info.image.width != x->x_vwidth ) ||
+ ( (int)header->info.image.height != x->x_vheight ) )
+ {
+ pdp_mgrid_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_mgrid_allocate(x);
+ x->x_firstimage = 1;
+ post( "pdp_mgrid : reallocated buffers" );
+ }
+
+ // draw horizontal lines
+ if ( x->x_ydim > 0 )
+ {
+ for(py=0; py<x->x_vheight; py+=(x->x_vheight/x->x_ydim))
+ {
+ if ( py >= x->x_vheight ) break;
+ for(px=0; px<x->x_vwidth; px++)
+ {
+ data[py*x->x_vwidth+px] =
+ ( ( data[py*x->x_vwidth+px] >> 7 ) ^ x->x_color) << 7;
+ }
+ }
+ }
+
+ // draw vertical lines
+ if ( x->x_xdim > 0 )
+ {
+ for(px=0; px<x->x_vwidth; px+=(x->x_vwidth/x->x_xdim))
+ {
+ if ( px >= x->x_vwidth ) break;
+ for(py=0; py<x->x_vheight; py++)
+ {
+ data[py*x->x_vwidth+px] =
+ ( ( data[py*x->x_vwidth+px] >> 7 ) ^ x->x_color) << 7;
+ }
+ }
+ }
+
+ if ( !x->x_firstimage )
+ {
+ // detect cell where a movement occurred
+ ycell=0;
+ celldiff=0;
+ if ( x->x_xdim > 0 )
+ {
+ cellwidth=(x->x_vwidth/x->x_xdim);
+ }
+ else
+ {
+ cellwidth=x->x_vwidth;
+ }
+ if ( x->x_ydim > 0 )
+ {
+ cellheight=(x->x_vheight/x->x_ydim);
+ }
+ else
+ {
+ cellheight=x->x_vheight;
+ }
+ for(xcell=0; xcell<x->x_xdim; xcell++)
+ {
+ for(ycell=0; ycell<x->x_ydim; ycell++)
+ {
+ celldiff=0;
+ for ( px=xcell*cellwidth; px<(xcell+1)*cellwidth; px++ )
+ {
+ if ( px >= x->x_vwidth ) break;
+ for ( py=ycell*cellheight; py<(ycell+1)*cellheight; py++ )
+ {
+ if ( py >= x->x_vheight ) break;
+ yindex = py*x->x_vwidth+px;
+ uindex = x->x_vsize + ((py*x->x_vwidth>>2)+(px>>1));
+ vindex = x->x_vsize + (x->x_vsize>>2) + ((py*x->x_vwidth>>2)+(px>>1));
+
+ // this calculation although more accurate is heavy
+ // celldiff += sqrt( pow(((data[ yindex ]>>7) - (x->x_previous_frame[ yindex ]>>7)), 2)
+ // + pow(((data[ uindex ]>>8) - (x->x_previous_frame[ uindex ]>>8)), 2)
+ // + pow(((data[ vindex ]>>8) - (x->x_previous_frame[ vindex ]>>8)), 2));
+ celldiff += abs(((data[ yindex ]>>7) - (x->x_previous_frame[ yindex ]>>7)))
+ + abs(((data[ uindex ]>>8) - (x->x_previous_frame[ uindex ]>>8)))
+ + abs(((data[ vindex ]>>8) - (x->x_previous_frame[ vindex ]>>8)));
+ }
+ }
+ if ( celldiff > x->x_threshold*cellwidth*cellheight )
+ {
+ outlet_float(x->x_xmotion, xcell+1);
+ outlet_float(x->x_ymotion, ycell+1);
+ }
+ // post( "pdp_mgrid : cell [%d,%d] diff=%d", xcell, ycell, celldiff );
+ }
+ }
+ }
+ else
+ {
+ x->x_firstimage = 0;
+ }
+
+ memcpy(x->x_previous_frame, data, (x->x_vsize + (x->x_vsize>>1))<<1 );
+
+ pdp_packet_pass_if_valid(x->x_pdp_output, &x->x_packet0);
+
+ return;
+}
+
+static void pdp_mgrid_process(t_pdp_mgrid *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_mgrid_process inputs and write into active inlet */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_mgrid_process_yv12(x);
+ 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_mgrid_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_mgrid_input_0(t_pdp_mgrid *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_mgrid_process(x);
+
+ }
+}
+
+static void pdp_mgrid_free(t_pdp_mgrid *x)
+{
+ int i;
+
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_mgrid_free_ressources(x);
+}
+
+t_class *pdp_mgrid_class;
+
+void *pdp_mgrid_new(void)
+{
+ int i;
+
+ t_pdp_mgrid *x = (t_pdp_mgrid *)pd_new(pdp_mgrid_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("threshold"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("dimx"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("dimy"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("color"));
+
+ x->x_pdp_output = outlet_new(&x->x_obj, &s_anything);
+ x->x_xmotion = outlet_new(&x->x_obj, &s_float);
+ x->x_ymotion = outlet_new(&x->x_obj, &s_float);
+
+ x->x_packet0 = -1;
+
+ x->x_previous_frame = NULL;
+ x->x_xdim = DEFAULT_X_DIM;
+ x->x_ydim = DEFAULT_Y_DIM;
+ x->x_threshold = DEFAULT_THRESHOLD;
+ x->x_color = DEFAULT_COLOR;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_mgrid_setup(void)
+{
+ post( pdp_mgrid_version );
+ pdp_mgrid_class = class_new(gensym("pdp_mgrid"), (t_newmethod)pdp_mgrid_new,
+ (t_method)pdp_mgrid_free, sizeof(t_pdp_mgrid), 0, A_NULL);
+
+ class_addmethod(pdp_mgrid_class, (t_method)pdp_mgrid_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mgrid_class, (t_method)pdp_mgrid_threshold, gensym("threshold"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_mgrid_class, (t_method)pdp_mgrid_x_dim, gensym("dimx"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_mgrid_class, (t_method)pdp_mgrid_y_dim, gensym("dimy"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_mgrid_class, (t_method)pdp_mgrid_color, gensym("color"), A_FLOAT, A_NULL);
+
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_mosaic.c b/modules/pdp_mosaic.c
new file mode 100644
index 0000000..1fb3487
--- /dev/null
+++ b/modules/pdp_mosaic.c
@@ -0,0 +1,312 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 adaptation of mosaic effect from effectv
+ * Originally written by Fukuchi Kentaro & others
+ * Pd-fication by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+#define MAGIC_THRESHOLD 30
+#define CENSOR_LEVEL 20
+
+static char *pdp_mosaic_version = "pdp_mosaic: version 0.1, port of mosaic from effectv( Fukuchi Kentaro ) adapted by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_mosaic_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_censor_level;
+ t_int x_ssize;
+ short int *x_diff;
+ short int *x_bdata;
+ t_int x_snapshot;
+
+} t_pdp_mosaic;
+
+
+static void pdp_mosaic_ssize(t_pdp_mosaic *x, t_floatarg fssize )
+{
+ if ( ( fssize > 1 ) && ( fssize < x->x_vwidth ) )
+ {
+ x->x_ssize = (int)fssize;
+ }
+}
+
+static void pdp_mosaic_level(t_pdp_mosaic *x, t_floatarg flevel )
+{
+ if ( flevel > 0 )
+ {
+ x->x_censor_level = (int)flevel;
+ }
+}
+
+static void pdp_mosaic_background(t_pdp_mosaic *x )
+{
+ x->x_snapshot = 1;
+}
+
+static void pdp_mosaic_free_ressources(t_pdp_mosaic *x)
+{
+ if ( x->x_diff != NULL ) freebytes( x->x_diff, (x->x_vsize + (x->x_vsize>>1))<<1 );
+ if ( x->x_bdata != NULL ) freebytes( x->x_bdata, (( x->x_vsize + (x->x_vsize>>1))<<1));
+}
+
+static void pdp_mosaic_allocate(t_pdp_mosaic *x)
+{
+ int i;
+
+ x->x_diff = (short int*) getbytes((x->x_vsize + (x->x_vsize>>1))<<1);
+ x->x_bdata = (short int *) getbytes((( x->x_vsize + (x->x_vsize>>1))<<1));
+ if( !x->x_bdata || ! x->x_diff ) {
+ post( "pdp_mosaic : severe error : cannot allocate buffers" );
+ }
+
+}
+
+/* check if there is a real difference with background image */
+static void pdp_mosaic_diff(t_pdp_mosaic *x, short int *src)
+{
+ int i;
+ int Yy=0, Yu=0, Yv=0;
+ int Yby=0, Ybu=0, Ybv=0;
+ short int *p=NULL;
+ short int *pb=NULL;
+ short int *r=NULL;
+ int v;
+
+ p = src;
+ pb = x->x_bdata;
+ r = x->x_diff;
+ for(i=0; i<(x->x_vsize); i++)
+ {
+ Yy = (*p);
+ Yu = (*(p+x->x_vsize+(i>>2)));
+ if ( x->x_vsize+(x->x_vsize>>2)+(i>>2) > x->x_vsize+(x->x_vsize>>1) )
+ {
+ post ("pdp_mosaic : overflow : offset=%d limit=%d", x->x_vsize+(x->x_vsize>>2)+(i>>2),
+ x->x_vsize+(x->x_vsize>>1) );
+ return;
+ }
+ Yv = (*(p+x->x_vsize+(x->x_vsize>>2)+(i>>2)));
+ Yby = (*pb);
+ Ybu = (*(pb+x->x_vsize+(i>>2)));
+ Ybv = (*(pb+x->x_vsize+(x->x_vsize>>2)+(i>>2)));
+ if ( !r ) { post( "pdp_mosaic : hey, buffers are not allocated !!" ); return; };
+ *r = ( (Yy - Yby) + (Yu - Ybu) + (Yv - Ybv) );
+ r++;
+ }
+
+}
+
+static void pdp_mosaic_process_yv12(t_pdp_mosaic *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);
+ int i;
+
+ int px=0, py=0, xx, yy, y, u, v;
+ int count;
+
+ /* allocate all ressources */
+ if ( (int)(header->info.image.width*header->info.image.height) != x->x_vsize )
+ {
+ pdp_mosaic_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_mosaic_allocate(x);
+ post( "pdp_mosaic : reallocated buffers" );
+ }
+
+ if ( x->x_bdata && x->x_snapshot )
+ {
+ x->x_snapshot = 0;
+ memcpy( x->x_bdata, data, (x->x_vsize + (x->x_vsize>>1))<<1 );
+ }
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ pdp_mosaic_diff(x, data);
+
+ memcpy( newdata, data, (x->x_vsize + (x->x_vsize>>1))<<1 );
+
+ for(py=0; py<(x->x_vheight-x->x_ssize-1); py+=x->x_ssize)
+ {
+ for(px=0; px<(x->x_vwidth-x->x_ssize-1); px+=x->x_ssize)
+ {
+ count = 0;
+ for(yy=0; yy<x->x_ssize; yy++)
+ {
+ for(xx=0; xx<x->x_ssize; xx++)
+ {
+ count += *(x->x_diff + (py+yy)*x->x_vwidth + (px+xx) );
+ count += *(x->x_diff + x->x_vsize + (((py+yy)*x->x_vwidth)>>2) + ((px+xx)>>1) );
+ count += *(x->x_diff + x->x_vsize + (x->x_vsize>>2) + (((py+yy)*x->x_vwidth)>>2) + ((px+xx)>>1) );
+ }
+ }
+ if(count > x->x_censor_level)
+ {
+ // post( "pdp_mosaic : censored" );
+ y = *(data + (py+3)*x->x_vwidth + (px+3));
+ u = *(data + x->x_vsize + (((py+3)*x->x_vwidth)>>2) + ((px+3)>>1) );
+ v = *(data + x->x_vsize + (((py+3)*x->x_vwidth)>>2) + ((px+3)>>1) );
+ for(yy=0; yy<x->x_ssize; yy++)
+ {
+ for(xx=0; xx<x->x_ssize; xx++)
+ {
+ *(newdata + (py+yy)*x->x_vwidth + (px+xx)) = y;
+ *(newdata + x->x_vsize + (((py+yy)*x->x_vwidth)>>2) + ((px+xx)>>1) ) = u;
+ *(newdata + x->x_vsize + (x->x_vsize>>2) + (((py+yy)*x->x_vwidth)>>2) + ((px+xx)>>1) ) = v;
+ }
+ }
+ }
+ }
+ }
+
+ return;
+}
+
+static void pdp_mosaic_sendpacket(t_pdp_mosaic *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_mosaic_process(t_pdp_mosaic *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_mosaic_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_mosaic_process_yv12, pdp_mosaic_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_mosaic_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_mosaic_input_0(t_pdp_mosaic *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_mosaic_process(x);
+ }
+}
+
+static void pdp_mosaic_free(t_pdp_mosaic *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_mosaic_free_ressources(x);
+}
+
+t_class *pdp_mosaic_class;
+
+void *pdp_mosaic_new(void)
+{
+ int i;
+
+ t_pdp_mosaic *x = (t_pdp_mosaic *)pd_new(pdp_mosaic_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_bang, gensym("background"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("level"));
+
+ 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_vsize = -1;
+ x->x_snapshot = 1;
+ x->x_ssize = 8; // square size
+ x->x_censor_level = CENSOR_LEVEL;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_mosaic_setup(void)
+{
+// post( pdp_mosaic_version );
+ pdp_mosaic_class = class_new(gensym("pdp_mosaic"), (t_newmethod)pdp_mosaic_new,
+ (t_method)pdp_mosaic_free, sizeof(t_pdp_mosaic), 0, A_NULL);
+
+ class_addmethod(pdp_mosaic_class, (t_method)pdp_mosaic_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mosaic_class, (t_method)pdp_mosaic_background, gensym("background"), A_NULL);
+ class_addmethod(pdp_mosaic_class, (t_method)pdp_mosaic_level, gensym("level"), A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_nervous.c b/modules/pdp_nervous.c
new file mode 100644
index 0000000..df76821
--- /dev/null
+++ b/modules/pdp_nervous.c
@@ -0,0 +1,283 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 adaptation of warp effect from effectv
+ * Copyright (C) 2002 TANNENBAUM Edo
+ * Pd-fication by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+#define DEFAULT_PLANES 32
+
+static int fastrand_val=0;
+#define inline_fastrand() (fastrand_val=fastrand_val*1103515245+12345)
+
+
+static char *pdp_nervous_version = "pdp_nervous: version 0.1, port of nervous from effectv( Fukuchi Kentaro ) adapted by Yves Degoyon (ydegoyon@free.fr)";
+
+static char* the_wave_table = NULL;
+
+typedef struct pdp_nervous_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_mode;
+ short int *x_buffer;
+ short int **x_planetable;
+ t_int x_planes;
+ t_int x_plane;
+ t_int x_stock;
+ t_int x_timer;
+ t_int x_stride;
+ t_int x_readplane;
+
+} t_pdp_nervous;
+
+static void pdp_nervous_mode(t_pdp_nervous *x, t_floatarg fmode )
+{
+ if ( ( fmode == 0 ) || ( fmode == 1 ) )
+ {
+ x->x_mode = (int)fmode;
+ }
+}
+
+static void pdp_nervous_free_ressources(t_pdp_nervous *x)
+{
+ if ( x->x_buffer ) free ( x->x_buffer );
+ if ( x->x_planetable ) free ( x->x_planetable );
+}
+
+static void pdp_nervous_allocate(t_pdp_nervous *x)
+{
+ int i;
+
+ // allocate space for the frame buffers. A lot of memory is required -
+ // with the default settings, it totals nearly 5 megs.
+ x->x_buffer = (short int *) getbytes ( ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 ) * 2 * x->x_planes);
+ x->x_planetable = (short int**) getbytes ( x->x_planes*sizeof(short int*) );
+
+ // set up the array of pointers to the frame buffers
+ for(i=0;i<x->x_planes;i++)
+ {
+ x->x_planetable[i] = &x->x_buffer[ ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 ) * i];
+ }
+
+ if ( !x->x_buffer )
+ {
+ post( "pdp_nervous : severe error : cannot allocate buffers !!! ");
+ return;
+ }
+}
+
+static void pdp_nervous_planes(t_pdp_nervous *x, t_floatarg fplanes )
+{
+ if ( ( fplanes > 1 ) && ( fplanes < 100 ) )
+ {
+ pdp_nervous_free_ressources(x);
+ x->x_planes = (int)fplanes;
+ x->x_plane = x->x_planes-1;
+ x->x_readplane = 0;
+ x->x_stock = 0;
+ pdp_nervous_allocate(x);
+ }
+}
+
+static void pdp_nervous_process_yv12(t_pdp_nervous *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);
+ int i;
+
+ /* allocate all ressources */
+ if ( (int)(header->info.image.width*header->info.image.height) != x->x_vsize )
+ {
+ pdp_nervous_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;
+ x->x_plane = x->x_planes-1;
+ pdp_nervous_allocate(x);
+ post( "pdp_nervous : reallocated buffers" );
+ }
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ memcpy(x->x_planetable[x->x_plane], data, ( x->x_vsize + (x->x_vsize>>1) ) << 1 );
+ if(x->x_stock < x->x_planes) {
+ x->x_stock++;
+ }
+
+ if(x->x_mode)
+ {
+ if(x->x_timer)
+ {
+ x->x_readplane = x->x_readplane + x->x_stride;
+ while(x->x_readplane < 0) x->x_readplane += x->x_stock;
+ while(x->x_readplane >= x->x_stock) x->x_readplane -= x->x_stock;
+ x->x_timer--;
+ }
+ else
+ {
+ x->x_readplane = inline_fastrand() % x->x_stock;
+ if ( x->x_readplane < 0 ) x->x_readplane = 0;
+ x->x_stride = inline_fastrand() % 5 - 2;
+ if(x->x_stride >= 0) x->x_stride++;
+ x->x_timer = inline_fastrand() % 6 + 2;
+ }
+ }
+ else
+ {
+ if(x->x_stock > 0) x->x_readplane = ( inline_fastrand() % x->x_stock );
+ if ( x->x_readplane < 0 ) x->x_readplane = 0;
+ }
+ memcpy(newdata, x->x_planetable[x->x_readplane], ( x->x_vsize + ( x->x_vsize>>1) ) << 1 );
+ x->x_plane = ( x->x_plane + 1 ) % x->x_planes;
+
+ return;
+}
+
+static void pdp_nervous_sendpacket(t_pdp_nervous *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_nervous_process(t_pdp_nervous *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_nervous_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_nervous_process_yv12, pdp_nervous_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_nervous_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_nervous_input_0(t_pdp_nervous *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_nervous_process(x);
+ }
+}
+
+static void pdp_nervous_free(t_pdp_nervous *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_nervous_free_ressources(x);
+}
+
+t_class *pdp_nervous_class;
+
+void *pdp_nervous_new(void)
+{
+ int i;
+
+ t_pdp_nervous *x = (t_pdp_nervous *)pd_new(pdp_nervous_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("planes"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("mode"));
+
+ 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_mode = 0;
+ x->x_buffer = NULL;
+ x->x_planes = DEFAULT_PLANES;
+ x->x_readplane = 0;
+ x->x_stock = 0;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_nervous_setup(void)
+{
+// post( pdp_nervous_version );
+ pdp_nervous_class = class_new(gensym("pdp_nervous"), (t_newmethod)pdp_nervous_new,
+ (t_method)pdp_nervous_free, sizeof(t_pdp_nervous), 0, A_NULL);
+
+ class_addmethod(pdp_nervous_class, (t_method)pdp_nervous_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_nervous_class, (t_method)pdp_nervous_mode, gensym("mode"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_nervous_class, (t_method)pdp_nervous_planes, gensym("planes"), A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_noquark.c b/modules/pdp_noquark.c
new file mode 100644
index 0000000..399b11f
--- /dev/null
+++ b/modules/pdp_noquark.c
@@ -0,0 +1,279 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 adaptation of warp effect from effectv
+ * Originally written by Fukuchi Kentaro & others
+ * Pd-fication by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+#define DEFAULT_PLANES 16
+#define DEFAULT_TOLERANCE 5
+
+static int fastrand_val=0;
+#define inline_fastrand() (fastrand_val=fastrand_val*1103515245+12345)
+
+
+static char *pdp_noquark_version = "pdp_noquark: version 0.1, port of quark from effectv( Fukuchi Kentaro ) adapted by Yves Degoyon (ydegoyon@free.fr)";
+
+static char* the_wave_table = NULL;
+
+typedef struct pdp_noquark_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;
+ short int *x_buffer;
+ short int **x_planetable;
+ t_int x_plane;
+ t_int x_planes;
+ t_int x_tolerance;
+
+} t_pdp_noquark;
+
+static void pdp_noquark_free_ressources(t_pdp_noquark *x)
+{
+ if ( x->x_buffer ) free ( x->x_buffer );
+ if ( x->x_planetable ) free ( x->x_planetable );
+}
+
+static void pdp_noquark_allocate(t_pdp_noquark *x)
+{
+ int i;
+
+ // allocate space for the frame buffers. A lot of memory is required -
+ // with the default settings, it totals nearly 5 megs.
+ x->x_buffer = (short int *) getbytes ( ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 ) * 2 * x->x_planes);
+ x->x_planetable = (short int**) getbytes( x->x_planes*sizeof( short int* ) );
+
+ // set up the array of pointers to the frame buffers
+ for(i=0;i<x->x_planes;i++)
+ {
+ x->x_planetable[i] = &x->x_buffer[ ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 ) * i];
+ }
+
+ if ( !x->x_buffer )
+ {
+ post( "pdp_noquark : severe error : cannot allocate buffers !!! ");
+ return;
+ }
+}
+
+static void pdp_noquark_planes(t_pdp_noquark *x, t_floatarg fplanes)
+{
+ if ( ( (int)fplanes > 1 ) && ( (int)fplanes < 100 ) )
+ {
+ pdp_noquark_free_ressources(x);
+ x->x_planes = (int) fplanes;
+ x->x_plane=x->x_planes-1;
+ pdp_noquark_allocate(x);
+ }
+}
+
+static void pdp_noquark_tolerance(t_pdp_noquark *x, t_floatarg ftolerance)
+{
+ if ( (int)ftolerance > 1 )
+ {
+ x->x_tolerance = (int) ftolerance;
+ }
+}
+
+static void pdp_noquark_process_yv12(t_pdp_noquark *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 px, py, cf, diff, rx, ry;
+
+ /* allocate all ressources */
+ if ( (int)(header->info.image.width*header->info.image.height) != x->x_vsize )
+ {
+ pdp_noquark_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;
+ x->x_plane = x->x_planes-1;
+ pdp_noquark_allocate(x);
+ post( "pdp_noquark : reallocated buffers" );
+ }
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ memcpy(x->x_planetable[x->x_plane], data, (x->x_vsize + (x->x_vsize>>1))<<1 );
+ for(py=0; py<x->x_vheight; py++)
+ {
+ for(px=0; px<x->x_vwidth; px++)
+ {
+ cf = (x->x_plane + (inline_fastrand()>>24))&(x->x_planes-1);
+ diff = (((x->x_planetable[cf])[py*x->x_vwidth+px] - data[py*x->x_vwidth+px])>>7) +
+ ((((x->x_planetable[cf])[x->x_vsize+((py>>1)*(x->x_vwidth>>1)+(px>>1))] -
+ data[x->x_vsize+((py>>1)*(x->x_vwidth>>1)+(px>>1))] )>>8)) +
+ ((((x->x_planetable[cf])[x->x_vsize+(x->x_vsize>>2)+((py>>1)*(x->x_vwidth>>1)+(px>>1))] -
+ data[x->x_vsize+(x->x_vsize>>2)+((py>>1)*(x->x_vwidth>>1)+(px>>1))] )>>8));
+ if ( abs ( diff ) > x->x_tolerance )
+ {
+ newdata[py*x->x_vwidth+px] = data[py*x->x_vwidth+px];
+ newdata[x->x_vsize+((py>>1)*(x->x_vwidth>>1)+(px>>1))] = data[x->x_vsize+((py>>1)*(x->x_vwidth>>1)+(px>>1))];
+ newdata[x->x_vsize+(x->x_vsize>>2)+((py>>1)*(x->x_vwidth>>1)+(px>>1))] =
+ data[x->x_vsize+(x->x_vsize>>2)+((py>>1)*(x->x_vwidth>>1)+(px>>1))];
+ }
+ else
+ {
+ rx = inline_fastrand()&x->x_vwidth;
+ ry = inline_fastrand()&x->x_vheight;
+ newdata[py*x->x_vwidth+px] = data[ry*x->x_vwidth+rx];
+ newdata[x->x_vsize+((py>>1)*(x->x_vwidth>>1)+(px>>1))] =
+ data[x->x_vsize+((ry>>1)*(x->x_vwidth>>1)+(rx>>1))];
+ newdata[x->x_vsize+(x->x_vsize>>2)+((py>>1)*(x->x_vwidth>>1)+(px>>1))] =
+ data[x->x_vsize+(x->x_vsize>>2)+((ry>>1)*(x->x_vwidth>>1)+(rx>>1))];
+ }
+ /* The reason why I use high order 8 bits is written in utils.c
+ (or, 'man rand') */
+ }
+ }
+ x->x_plane--;
+ if ( x->x_plane < 0 ) x->x_plane = x->x_planes-1;
+
+ return;
+}
+
+static void pdp_noquark_sendpacket(t_pdp_noquark *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_noquark_process(t_pdp_noquark *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_noquark_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_noquark_process_yv12, pdp_noquark_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_noquark_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_noquark_input_0(t_pdp_noquark *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_noquark_process(x);
+ }
+}
+
+static void pdp_noquark_free(t_pdp_noquark *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_noquark_free_ressources(x);
+}
+
+t_class *pdp_noquark_class;
+
+void *pdp_noquark_new(void)
+{
+ int i;
+
+ t_pdp_noquark *x = (t_pdp_noquark *)pd_new(pdp_noquark_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("planes"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("tolerance"));
+
+ 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_planes = DEFAULT_PLANES;
+ x->x_tolerance = DEFAULT_TOLERANCE;
+
+ x->x_buffer = NULL;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_noquark_setup(void)
+{
+// post( pdp_noquark_version );
+ pdp_noquark_class = class_new(gensym("pdp_noquark"), (t_newmethod)pdp_noquark_new,
+ (t_method)pdp_noquark_free, sizeof(t_pdp_noquark), 0, A_NULL);
+
+ class_addmethod(pdp_noquark_class, (t_method)pdp_noquark_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_noquark_class, (t_method)pdp_noquark_planes, gensym("planes"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_noquark_class, (t_method)pdp_noquark_tolerance, gensym("tolerance"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_o.c b/modules/pdp_o.c
new file mode 100644
index 0000000..34b2b18
--- /dev/null
+++ b/modules/pdp_o.c
@@ -0,0 +1,589 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon <ydegoyon@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 streaming emitter
+ * -- compressed with a very simple codec ( smoothing + huffman + bz2 )
+ * It sends PDP packet to a pdp_i receiving object
+ */
+
+
+#include "pdp.h"
+#include "pdp_streaming.h"
+#include <math.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <quicktime/quicktime.h>
+#include <quicktime/colormodels.h>
+#include <bzlib.h> // bz2 compression routines
+
+#define DEFAULT_FRAME_RATE 25
+
+static char *pdp_o_version = "pdp_o: version 0.1, a video stream emitter, written by ydegoyon@free.fr";
+
+typedef struct pdp_o_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+ t_int x_hsize; // size of huffman coded data
+
+ t_int x_packet0;
+ t_int x_dropped;
+ t_int x_queue_id;
+
+ t_int x_emitflag;
+
+ /* connection data */
+ int x_fd; // info about connection status
+ t_int x_framessent;
+ t_int x_framesdropped;
+ t_int x_secondcount;
+ t_int x_bandwidthcount;
+ t_int x_cursec;
+ t_int x_framerate;
+ t_int x_smoothing;
+
+ t_hpacket x_hpacket; // packet header
+
+ short int *x_previous_frame;
+ char *x_diff_frame;
+ char *x_hdata; // huffman coded data
+ char *x_cdata; // compressed data to be sent
+
+ t_outlet *x_connection_status; // indicates status
+ t_outlet *x_frames; // outlet for the number of frames emitted
+ t_outlet *x_framesd; // outlet for the number of frames dropped
+ t_outlet *x_bandwidth; // outlet for bandwidth
+
+} t_pdp_o;
+
+static void pdp_o_free_ressources(t_pdp_o *x)
+{
+ if ( x->x_diff_frame ) freebytes( x->x_diff_frame, x->x_vsize + (x->x_vsize>>1) );
+ if ( x->x_previous_frame ) freebytes( x->x_previous_frame, (x->x_vsize + (x->x_vsize>>1))<<1 );
+ if ( x->x_cdata ) freebytes( x->x_cdata, (x->x_vsize + (x->x_vsize>>1))*1.01+600 ); // size is taken from bzlib manual
+ if ( x->x_hdata ) freebytes( x->x_hdata, ((x->x_vsize + (x->x_vsize>>1))<<1) ); // size is taken from bzlib manual
+}
+
+static void pdp_o_allocate(t_pdp_o *x)
+{
+ x->x_diff_frame = (char*) getbytes( x->x_vsize + (x->x_vsize>>1) );
+ memset( x->x_diff_frame, 0x00, x->x_vsize + (x->x_vsize>>1) );
+ x->x_previous_frame = (short int*) getbytes( (x->x_vsize + (x->x_vsize>>1))<<1 );
+ memset( x->x_previous_frame, 0x00, (x->x_vsize + (x->x_vsize>>1))<<1 );
+ x->x_cdata = (char*) getbytes( (x->x_vsize + (x->x_vsize>>1))*1.01+600 );
+ memset( x->x_cdata, 0x00, (x->x_vsize + (x->x_vsize>>1))*1.01+600 );
+ x->x_hdata = (char*) getbytes( (x->x_vsize + (x->x_vsize>>1))<<1 );
+ memset( x->x_hdata, 0x00, (x->x_vsize + (x->x_vsize>>1))<<1 );
+ strcpy( x->x_hpacket.tag, PDP_PACKET_TAG );
+}
+
+ /* disconnect from receiver */
+static void pdp_o_disconnect(t_pdp_o *x)
+{
+ int ret;
+
+ if(x->x_fd >= 0) /* close socket */
+ {
+ close(x->x_fd);
+ x->x_fd = -1;
+ outlet_float( x->x_connection_status, 0 );
+ post("pdp_o : connection closed");
+ }
+
+}
+
+ /* set the emission frame rate */
+static void pdp_o_framerate(t_pdp_o *x, t_floatarg fframerate)
+{
+ if ( fframerate > 1 )
+ {
+ x->x_framerate = (int)fframerate;
+ }
+}
+
+ /* set the smoothing factor */
+static void pdp_o_smoothing(t_pdp_o *x, t_floatarg fsmoothing)
+{
+ if ( ( fsmoothing >= 0 ) && ( fsmoothing < 255 ) )
+ {
+ x->x_smoothing = (int)fsmoothing;
+ }
+}
+
+ /* smoothe image */
+static void pdp_o_smoothe(t_pdp_o *x, short int *source, t_int size )
+{
+ t_int i;
+ char evalue, eevalue;
+ char value;
+
+ if ( x->x_smoothing == 0 ) return;
+
+ for(i=0;i<size;i++)
+ {
+ value = (source[i])>>7;
+ evalue = (value/x->x_smoothing)*x->x_smoothing;
+ eevalue = ((value/x->x_smoothing)+1)*x->x_smoothing;
+
+ if ( abs( value - evalue ) < x->x_smoothing/2 )
+ {
+ source[i] = evalue<<7;
+ }
+ else
+ {
+ source[i] = eevalue<<7;
+ }
+ }
+
+ for(i=size;i<(size+(size>1));i++)
+ {
+ value = ((source[i])>>8)+128;
+ evalue = (value/x->x_smoothing)*x->x_smoothing;
+ eevalue = ((value/x->x_smoothing)+1)*x->x_smoothing;
+
+ if ( abs( value - evalue ) < x->x_smoothing/2 )
+ {
+ source[i] = (evalue)<<8;
+ }
+ else
+ {
+ source[i] = (eevalue)<<8;
+ }
+ }
+}
+
+ /* huffman coding */
+static int pdp_o_huffman(t_pdp_o *x, char *source, char *dest, t_int size, t_int *csize )
+{
+ t_int i;
+ char value = source[0];
+ char count = 0;
+ t_int tcount=0;
+ char *pcount=dest;
+ char *pvalue=dest+1;
+
+ *(csize)=2;
+ dest++;
+ for( i=0; i<size; i++)
+ {
+ if ( (source[i] == value) && (count<127) )
+ {
+ count++;
+ }
+ else
+ {
+ value=source[i];
+ *(pcount)=count;
+ *(pvalue) = value;
+ tcount+=count;
+ count=1;
+ pcount+=2;
+ pvalue+=2;
+ *(csize)+=2;
+ }
+ }
+ *(pcount)=count;
+ tcount+=count;
+
+ // huffman is no good for that image
+ if ( (*csize) >= size )
+ {
+ *csize = size;
+ memcpy( dest, source, size );
+ return REGULAR;
+ }
+ else
+ {
+ // post( "pdp_o : huffman : compression ratio %d/%d : %f (total count=%d)", size, (*csize),
+ // (t_float)size/(t_float)(*csize), tcount );
+ return HUFFMAN;
+ }
+}
+
+
+ /* connect to a receiver on <hostname> <port> */
+static void pdp_o_connect(t_pdp_o *x, t_symbol *shostname, t_floatarg fportno)
+{
+ struct sockaddr_in csocket;
+ struct hostent *hp;
+ int portno = fportno; /* get port from message box */
+
+ /* variables used for communication with the receiver */
+ const char *buf = 0;
+ unsigned int len;
+ int sockfd;
+ int ret;
+
+ // close previous connection if existing
+ pdp_o_disconnect(x);
+
+ sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sockfd < 0)
+ {
+ error("pdp_o : error while attempting to create socket");
+ perror( "socket" );
+ return;
+ }
+
+ /* connect socket using hostname provided in command line */
+ csocket.sin_family = AF_INET;
+ hp = gethostbyname(shostname->s_name);
+ if (hp == 0)
+ {
+ post("pdp_o : ip address of receiver could not be found");
+ perror( "gethostbyname" );
+ close(sockfd);
+ return;
+ }
+ memcpy((char *)&csocket.sin_addr, (char *)hp->h_addr, hp->h_length);
+
+ /* assign client port number */
+ csocket.sin_port = htons((unsigned short)fportno);
+
+ /* try to connect. */
+ post("pdp_o : connecting to port %d", (int)fportno);
+ if (connect(sockfd, (struct sockaddr *) &csocket, sizeof (csocket)) < 0)
+ {
+ error("mp3streamout~: connection failed!\n");
+ perror( "connect" );
+ close(sockfd);
+ return;
+ }
+
+ x->x_fd = sockfd;
+ x->x_framessent = 0;
+ x->x_framesdropped = 0;
+ outlet_float( x->x_connection_status, 1 );
+ post( "pdp_o : connected to receiver : %s:%d", shostname->s_name, (int)fportno );
+
+}
+
+ /* refresh means forcing the emission of a full frame */
+static void pdp_o_refresh(t_pdp_o *x)
+{
+ strcpy( x->x_hpacket.tag, PDP_PACKET_TAG );
+ memset( x->x_previous_frame, 0x00, (x->x_vsize + (x->x_vsize>>1))<<1 );
+}
+
+ /* start emitting */
+static void pdp_o_start(t_pdp_o *x)
+{
+ if ( x->x_emitflag == 1 ) {
+ post("pdp_o : start received but emission is started ... ignored.");
+ return;
+ }
+
+ x->x_emitflag = 1;
+ post("pdp_o : emission started");
+}
+
+ /* stop emitting */
+static void pdp_o_stop(t_pdp_o *x)
+{
+ if ( x->x_emitflag == 0 ) {
+ post("mp3write~: stop received but emission is stopped ... ignored.");
+ return;
+ }
+
+ x->x_emitflag = 0;
+
+ post("pdp_o : emission stopped");
+}
+
+static void pdp_o_process_yv12(t_pdp_o *x)
+{
+ t_pdp *header = pdp_packet_header(x->x_packet0);
+ short int *data = (short int *)pdp_packet_data(x->x_packet0);
+ t_int count, i, ret=0;
+
+ /* setting video track */
+ if ( x->x_emitflag )
+ {
+ if ( ( (int)(header->info.image.width) != x->x_vwidth ) ||
+ ( (int)(header->info.image.height) != x->x_vheight )
+ )
+ {
+ pdp_o_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_o_allocate(x);
+ }
+
+ // smoothe image
+ pdp_o_smoothe(x, data, x->x_vsize );
+
+ for ( i=0; i<x->x_vsize; i++ )
+ {
+ t_int downvalue;
+
+ downvalue = (data[i]>>7);
+ if ( ( downvalue > 128 ) ||
+ ( downvalue < -128 ) )
+ {
+ // post( "pdp_o : y value out of range : %d", downvalue );
+ }
+ if ( data[i] != x->x_previous_frame[i] )
+ {
+ x->x_diff_frame[i] = (char)downvalue;
+ }
+ else
+ {
+ x->x_diff_frame[i] = 0;
+ }
+ }
+ for ( i=x->x_vsize; i<(x->x_vsize+(x->x_vsize>>1)); i++ )
+ {
+ t_int downvalue;
+
+ downvalue = (data[i]>>8);
+ if ( ( downvalue > 128 ) ||
+ ( downvalue < -128 ) )
+ {
+ // post( "pdp_o : y value out of range : %d", downvalue );
+ }
+ if ( data[i] != x->x_previous_frame[i] )
+ {
+ x->x_diff_frame[i] = (char)downvalue;
+ }
+ else
+ {
+ x->x_diff_frame[i] = 0;
+ }
+ }
+
+ x->x_hpacket.width = x->x_vwidth;
+ x->x_hpacket.height = x->x_vheight;
+ if ( gettimeofday(&x->x_hpacket.etime, NULL) == -1)
+ {
+ post("pdp_o : could not set emit time" );
+ }
+ if ( x->x_hpacket.etime.tv_sec != x->x_cursec )
+ {
+ x->x_cursec = x->x_hpacket.etime.tv_sec;
+ x->x_secondcount = 0;
+ x->x_bandwidthcount = 0;
+ }
+
+ // do not send the frame if too many frames
+ // have been sent in the current second
+ if ( x->x_secondcount < x->x_framerate )
+ {
+
+ // try a huffman coding
+ x->x_hpacket.encoding = pdp_o_huffman(x, x->x_diff_frame, x->x_hdata, x->x_vsize+(x->x_vsize>>1), &x->x_hsize );
+
+ x->x_hpacket.clength = (x->x_vsize+(x->x_vsize>>1))*1.01+600;
+ // compress the graphic data
+ if ( ( ret = BZ2_bzBuffToBuffCompress( x->x_cdata,
+ &x->x_hpacket.clength,
+ (char*) x->x_hdata,
+ x->x_hsize,
+ 9, 0, 0 ) ) == BZ_OK )
+ {
+ // post( "pdp_o : bz2 compression (%d)->(%d)", x->x_hsize, x->x_hpacket.clength );
+
+ x->x_secondcount++;
+
+ // memorize last emitted frame
+ memcpy( x->x_previous_frame, data, (x->x_vsize+(x->x_vsize>>1))<<1 );
+
+ // send header
+ count = send(x->x_fd, &x->x_hpacket, sizeof(x->x_hpacket), MSG_NOSIGNAL);
+ if(count < 0)
+ {
+ error("pdp_o : could not send encoded data to the peer (%d)", count);
+ perror( "send" );
+ pdp_o_disconnect(x);
+ }
+ else
+ {
+ if((count > 0)&&(count != sizeof(x->x_hpacket)))
+ {
+ error("pdp_o : %d bytes skipped", sizeof(x->x_hpacket) - count);
+ }
+ x->x_bandwidthcount += count/1024;
+ }
+
+ // send data
+ count = send(x->x_fd, x->x_cdata, x->x_hpacket.clength, MSG_NOSIGNAL);
+ if(count < 0)
+ {
+ error("pdp_o : could not send encoded data to the peer (%d)", count);
+ perror( "send" );
+ pdp_o_disconnect(x);
+ }
+ else
+ {
+ if((count > 0)&&(count != (int)x->x_hpacket.clength))
+ {
+ error("pdp_o : %d bytes skipped", x->x_hpacket.clength - count);
+ }
+ ++x->x_framessent;
+ x->x_bandwidthcount += count/1024;
+ }
+
+ // unless after a refresh, next packets are diffs
+ strcpy( x->x_hpacket.tag, PDP_PACKET_DIFF );
+
+ }
+ else
+ {
+ post( "pdp_o : bz2 compression failed (ret=%d)", ret );
+ }
+ }
+ else
+ {
+ ++x->x_framesdropped;
+ // post( "pdp_o : frames dropped ( framerate limit )" );
+ }
+ }
+
+ return;
+}
+
+static void pdp_o_killpacket(t_pdp_o *x)
+{
+ /* release the packet */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = -1;
+}
+
+static void pdp_o_process(t_pdp_o *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_o_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_o_process_yv12, pdp_o_killpacket, &x->x_queue_id);
+ outlet_float( x->x_framesd, x->x_framesdropped );
+ outlet_float( x->x_frames, x->x_framessent );
+ outlet_float( x->x_bandwidth, x->x_bandwidthcount );
+ 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_o_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_o_input_0(t_pdp_o *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_o_process(x);
+
+ }
+}
+
+static void pdp_o_free(t_pdp_o *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ // close connection if existing
+ pdp_o_disconnect(x);
+}
+
+t_class *pdp_o_class;
+
+void *pdp_o_new(void)
+{
+ int i;
+
+ t_pdp_o *x = (t_pdp_o *)pd_new(pdp_o_class);
+ x->x_connection_status = outlet_new (&x->x_obj, &s_float);
+ x->x_frames = outlet_new (&x->x_obj, &s_float);
+ x->x_framesd = outlet_new (&x->x_obj, &s_float);
+ x->x_bandwidth = outlet_new (&x->x_obj, &s_float);
+
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+
+ x->x_framessent = 0;
+ x->x_framerate = DEFAULT_FRAME_RATE;
+ x->x_smoothing = 0;
+ x->x_secondcount = 0;
+ x->x_bandwidthcount = 0;
+ x->x_cursec = 0;
+ x->x_fd = -1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_o_setup(void)
+{
+ post( pdp_o_version );
+ pdp_o_class = class_new(gensym("pdp_o"), (t_newmethod)pdp_o_new,
+ (t_method)pdp_o_free, sizeof(t_pdp_o), 0, A_NULL);
+
+ class_addmethod(pdp_o_class, (t_method)pdp_o_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_o_class, (t_method)pdp_o_connect, gensym("connect"), A_SYMBOL, A_FLOAT, A_NULL);
+ class_addmethod(pdp_o_class, (t_method)pdp_o_disconnect, gensym("disconnect"), A_NULL);
+ class_addmethod(pdp_o_class, (t_method)pdp_o_start, gensym("start"), A_NULL);
+ class_addmethod(pdp_o_class, (t_method)pdp_o_stop, gensym("stop"), A_NULL);
+ class_addmethod(pdp_o_class, (t_method)pdp_o_refresh, gensym("refresh"), A_NULL);
+ class_addmethod(pdp_o_class, (t_method)pdp_o_framerate, gensym("framerate"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_o_class, (t_method)pdp_o_smoothing, gensym("smoothing"), A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_puzzle.c b/modules/pdp_puzzle.c
new file mode 100644
index 0000000..0c0520f
--- /dev/null
+++ b/modules/pdp_puzzle.c
@@ -0,0 +1,421 @@
+/*
+ * PiDiP module
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 port of puzzle effect from EffecTV
+ * Originally written by Fukuchi Kentaro <nullset@dookie.net>
+ * Pd-fication by Yves Degoyon ( ydegoyon@free.fr )
+ * The origin of PuzzleTV is ``Video Puzzle'' by Suutarou in 1993.
+ * It runs on Fujitsu FM-TOWNS.
+ */
+
+
+#include "pdp.h"
+#include <math.h>
+
+#define DEFAULT_BLOCK_NUMBER 5
+
+static unsigned int fastrand_val;
+#define inline_fastrand() (fastrand_val=fastrand_val*1103515245+12345)
+
+static char *pdp_puzzle_version = "pdp_puzzle: version 0.1, port of puzzle from EffecTV by Fukuchi Kentaro, adapted by ydegoyon@free.fr ";
+
+typedef struct pdp_puzzle_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_packet1;
+ t_int x_dropped;
+ t_int x_queue_id;
+
+ t_outlet *x_outlet0;
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+
+ /* puzzle parameters */
+ t_int *x_blockpos;
+ t_int *x_blockoffset;
+ t_int *x_ublockoffset;
+ t_int *x_vblockoffset;
+ t_int x_nbblocks;
+ t_int x_blockwidth;
+ t_int x_blockheight;
+ t_int x_blockw;
+ t_int x_blockh;
+ t_int x_blocknum;
+ t_int x_spacepos;
+ t_int x_spacex;
+ t_int x_spacey;
+
+} t_pdp_puzzle;
+
+static void pdp_puzzle_init_tables(t_pdp_puzzle *x)
+{
+ t_int i, a, b, c;
+
+ for(i=0; i<x->x_blocknum; i++)
+ {
+ x->x_blockpos[i] = i;
+ }
+ for(i=0; i<20*x->x_blockw; i++)
+ {
+ /* the number of shuffling times is a rule of thumb. */
+ a = inline_fastrand()%(x->x_blocknum-1);
+ b = inline_fastrand()%(x->x_blocknum-1);
+ if(a == b) b = (b+1)%(x->x_blocknum-1);
+ c = x->x_blockpos[a];
+ x->x_blockpos[a] = x->x_blockpos[b];
+ x->x_blockpos[b] = c;
+ }
+ x->x_spacepos = x->x_blocknum-1;
+ x->x_spacex = x->x_blockw-1;
+ x->x_spacey = x->x_blockh-1;
+
+ return;
+}
+
+static void pdp_puzzle_up(t_pdp_puzzle *x )
+{
+ t_int tmp, nextpos=-1;
+
+ if(x->x_spacey>0)
+ {
+ nextpos = x->x_spacepos - x->x_blockw;
+ x->x_spacey--;
+ }
+ if(nextpos>=0)
+ {
+ tmp = x->x_blockpos[x->x_spacepos];
+ x->x_blockpos[x->x_spacepos] = x->x_blockpos[nextpos];
+ x->x_blockpos[nextpos] = tmp;
+ x->x_spacepos = nextpos;
+ }
+}
+
+static void pdp_puzzle_down(t_pdp_puzzle *x )
+{
+ t_int tmp, nextpos=-1;
+
+ if(x->x_spacey<x->x_blockh-1)
+ {
+ nextpos = x->x_spacepos + x->x_blockw;
+ x->x_spacey++;
+ }
+ if(nextpos>=0)
+ {
+ tmp = x->x_blockpos[x->x_spacepos];
+ x->x_blockpos[x->x_spacepos] = x->x_blockpos[nextpos];
+ x->x_blockpos[nextpos] = tmp;
+ x->x_spacepos = nextpos;
+ }
+}
+
+static void pdp_puzzle_left(t_pdp_puzzle *x )
+{
+ t_int tmp, nextpos=-1;
+
+ if(x->x_spacex>0)
+ {
+ nextpos = x->x_spacepos - 1;
+ x->x_spacex--;
+ }
+ if(nextpos>=0)
+ {
+ tmp = x->x_blockpos[x->x_spacepos];
+ x->x_blockpos[x->x_spacepos] = x->x_blockpos[nextpos];
+ x->x_blockpos[nextpos] = tmp;
+ x->x_spacepos = nextpos;
+ }
+}
+
+static void pdp_puzzle_right(t_pdp_puzzle *x )
+{
+ t_int tmp, nextpos=-1;
+
+ if(x->x_spacex<x->x_blockw-1)
+ {
+ nextpos = x->x_spacepos + 1;
+ x->x_spacex++;
+ }
+ if(nextpos>=0)
+ {
+ tmp = x->x_blockpos[x->x_spacepos];
+ x->x_blockpos[x->x_spacepos] = x->x_blockpos[nextpos];
+ x->x_blockpos[nextpos] = tmp;
+ x->x_spacepos = nextpos;
+ }
+}
+
+static void pdp_puzzle_free_ressources(t_pdp_puzzle *x)
+{
+ if ( x->x_blockpos ) freebytes( x->x_blockpos, x->x_blocknum*sizeof(int) );
+ if ( x->x_blockoffset ) freebytes( x->x_blockoffset, x->x_blocknum*sizeof(int) );
+ if ( x->x_ublockoffset ) freebytes( x->x_ublockoffset, x->x_blocknum*sizeof(int) );
+ if ( x->x_vblockoffset ) freebytes( x->x_vblockoffset, x->x_blocknum*sizeof(int) );
+}
+
+static void pdp_puzzle_allocate(t_pdp_puzzle *x)
+{
+ t_int px, py;
+
+ x->x_blockwidth = x->x_vwidth / x->x_nbblocks;
+ x->x_blockheight = x->x_vheight / x->x_nbblocks;
+ x->x_blockw = x->x_nbblocks;
+ x->x_blockh = x->x_nbblocks;
+ x->x_blocknum = x->x_blockw * x->x_blockh;
+
+ x->x_blockpos = (int *) getbytes( x->x_blocknum*sizeof(int) );
+ x->x_blockoffset = (int *) getbytes( x->x_blocknum*sizeof(int) );
+ x->x_ublockoffset = (int *) getbytes( x->x_blocknum*sizeof(int) );
+ x->x_vblockoffset = (int *) getbytes( x->x_blocknum*sizeof(int) );
+ if( x->x_blockpos == NULL || x->x_blockoffset == NULL ||
+ x->x_ublockoffset == NULL || x->x_vblockoffset == NULL )
+ {
+ post( "pdp_puzzle : severe error : cannot allocate buffers !!! ");
+ return;
+ }
+
+ for(py=0; py<x->x_blockh; py++)
+ {
+ for(px=0; px<x->x_blockw; px++)
+ {
+ x->x_blockoffset[py*x->x_blockw+px] = py*x->x_blockheight*x->x_vwidth + px*x->x_blockwidth;
+ x->x_vblockoffset[py*x->x_blockw+px] = x->x_vsize + (py*x->x_blockheight>>1)*(x->x_vwidth>>1) + (px*x->x_blockwidth>>1);
+ x->x_ublockoffset[py*x->x_blockw+px] = x->x_vsize + (x->x_vsize>>2) + (py*x->x_blockheight>>1)*(x->x_vwidth>>1) + (px*x->x_blockwidth>>1);
+ }
+ }
+}
+
+static void pdp_puzzle_nbblocks(t_pdp_puzzle *x, t_floatarg fnbblocks )
+{
+ if ( ( fnbblocks > 1 ) && ( fnbblocks < x->x_vwidth/10 ) )
+ {
+ x->x_nbblocks = fnbblocks;
+ post( "pdp_puzzle : number of blocks set to : %d", x->x_nbblocks );
+ pdp_puzzle_free_ressources(x);
+ pdp_puzzle_allocate(x);
+ pdp_puzzle_init_tables(x);
+ }
+}
+
+static void pdp_puzzle_process_yv12(t_pdp_puzzle *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 px, py, xx, yy, i;
+ short int *pY, *qY, *pU, *pV, *qU, *qV;
+
+ /* allocate all ressources */
+ if ( ((int)header->info.image.width != x->x_vwidth) ||
+ ((int)header->info.image.height != x->x_vheight) )
+ {
+ pdp_puzzle_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_puzzle_allocate(x);
+ post( "pdp_puzzle : reallocated buffers" );
+ pdp_puzzle_init_tables(x);
+ post( "pdp_puzzle : initialized tables" );
+ }
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ i = 0;
+ for(py=0; py<x->x_blockh; py++)
+ {
+ for(px=0; px<x->x_blockw; px++)
+ {
+ pY = &data[x->x_blockoffset[x->x_blockpos[i]]];
+ pU = &data[x->x_ublockoffset[x->x_blockpos[i]]];
+ pV = &data[x->x_vblockoffset[x->x_blockpos[i]]];
+ qY = &newdata[x->x_blockoffset[i]];
+ qU = &newdata[x->x_ublockoffset[i]];
+ qV = &newdata[x->x_vblockoffset[i]];
+ if(x->x_spacepos == i)
+ {
+ for(yy=0; yy<x->x_blockheight; yy++)
+ {
+ for(xx=0; xx<x->x_blockwidth; xx++)
+ {
+ *(qY++) = 0;
+ if ( (xx%2==0) && (yy%2==0) )
+ {
+ *(qU++) = 0;
+ *(qV++) = 0;
+ }
+ }
+ qY+=x->x_vwidth-x->x_blockwidth;
+ if ( yy%2==0 )
+ {
+ qU+=(x->x_vwidth-x->x_blockwidth)>>1;
+ qV+=(x->x_vwidth-x->x_blockwidth)>>1;
+ }
+ }
+ }
+ else
+ {
+ for(yy=0; yy<x->x_blockheight; yy++)
+ {
+ for(xx=0; xx<x->x_blockwidth; xx++)
+ {
+ *(qY++) = *(pY++);
+ if ( (xx%2==0) && (yy%2==0) )
+ {
+ *(qU++) = *(pU++);
+ *(qV++) = *(pV++);
+ }
+ }
+ qY+=x->x_vwidth-x->x_blockwidth;
+ pY+=x->x_vwidth-x->x_blockwidth;
+ if ( yy%2==0 )
+ {
+ qU+=(x->x_vwidth-x->x_blockwidth)>>1;
+ pU+=(x->x_vwidth-x->x_blockwidth)>>1;
+ qV+=(x->x_vwidth-x->x_blockwidth)>>1;
+ pV+=(x->x_vwidth-x->x_blockwidth)>>1;
+ }
+ }
+ }
+ i++;
+ }
+ }
+
+ return;
+}
+
+static void pdp_puzzle_sendpacket(t_pdp_puzzle *x)
+{
+ /* delete source 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_puzzle_process(t_pdp_puzzle *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_puzzle_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_puzzle_process_yv12, pdp_puzzle_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_puzzle_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_puzzle_input_0(t_pdp_puzzle *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_puzzle_process(x);
+
+ }
+
+}
+
+static void pdp_puzzle_free(t_pdp_puzzle *x)
+{
+ int i;
+
+ pdp_puzzle_free_ressources(x);
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_puzzle_class;
+
+void *pdp_puzzle_new(void)
+{
+ int i;
+
+ t_pdp_puzzle *x = (t_pdp_puzzle *)pd_new(pdp_puzzle_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("nbblocks"));
+
+ 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_nbblocks = DEFAULT_BLOCK_NUMBER;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_puzzle_setup(void)
+{
+// post( pdp_puzzle_version );
+ pdp_puzzle_class = class_new(gensym("pdp_puzzle"), (t_newmethod)pdp_puzzle_new,
+ (t_method)pdp_puzzle_free, sizeof(t_pdp_puzzle), 0, A_NULL);
+
+ class_addmethod(pdp_puzzle_class, (t_method)pdp_puzzle_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_puzzle_class, (t_method)pdp_puzzle_up, gensym("up"), A_NULL);
+ class_addmethod(pdp_puzzle_class, (t_method)pdp_puzzle_down, gensym("down"), A_NULL);
+ class_addmethod(pdp_puzzle_class, (t_method)pdp_puzzle_left, gensym("left"), A_NULL);
+ class_addmethod(pdp_puzzle_class, (t_method)pdp_puzzle_right, gensym("right"), A_NULL);
+ class_addmethod(pdp_puzzle_class, (t_method)pdp_puzzle_nbblocks, gensym("nbblocks"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_quark.c b/modules/pdp_quark.c
new file mode 100644
index 0000000..4942ce4
--- /dev/null
+++ b/modules/pdp_quark.c
@@ -0,0 +1,268 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 adaptation of warp effect from effectv
+ * Originally written by Fukuchi Kentaro & others
+ * Pd-fication by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+#define DEFAULT_PLANES 16
+
+static int fastrand_val=0;
+#define inline_fastrand() (fastrand_val=fastrand_val*1103515245+12345)
+
+
+static char *pdp_quark_version = "pdp_quark: version 0.1, port of quark from effectv( Fukuchi Kentaro ) adapted by Yves Degoyon (ydegoyon@free.fr)";
+
+static char* the_wave_table = NULL;
+
+typedef struct pdp_quark_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;
+ short int *x_buffer;
+ short int **x_planetable;
+ t_int x_plane;
+ t_int x_planes;
+ t_int x_tolerance;
+
+} t_pdp_quark;
+
+static void pdp_quark_free_ressources(t_pdp_quark *x)
+{
+ if ( x->x_buffer ) free ( x->x_buffer );
+ if ( x->x_planetable ) free ( x->x_planetable );
+}
+
+static void pdp_quark_allocate(t_pdp_quark *x)
+{
+ int i;
+
+ // allocate space for the frame buffers. A lot of memory is required -
+ // with the default settings, it totals nearly 5 megs.
+ x->x_buffer = (short int *) getbytes ( ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 ) * 2 * x->x_planes);
+ x->x_planetable = (short int**) getbytes( x->x_planes*sizeof( short int* ) );
+
+ // set up the array of pointers to the frame buffers
+ for(i=0;i<x->x_planes;i++)
+ {
+ x->x_planetable[i] = &x->x_buffer[ ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 ) * i];
+ }
+
+ if ( !x->x_buffer )
+ {
+ post( "pdp_quark : severe error : cannot allocate buffers !!! ");
+ return;
+ }
+}
+
+static void pdp_quark_planes(t_pdp_quark *x, t_floatarg fplanes)
+{
+ if ( ( (int)fplanes > 1 ) && ( (int)fplanes < 100 ) )
+ {
+ pdp_quark_free_ressources(x);
+ x->x_planes = (int) fplanes;
+ x->x_plane=x->x_planes-1;
+ pdp_quark_allocate(x);
+ }
+}
+
+static void pdp_quark_tolerance(t_pdp_quark *x, t_floatarg ftolerance)
+{
+ if ( (int)ftolerance > 1 )
+ {
+ x->x_tolerance = (int) ftolerance;
+ }
+}
+
+static void pdp_quark_process_yv12(t_pdp_quark *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, cf, diff;
+
+ /* allocate all ressources */
+ if ( (int)(header->info.image.width*header->info.image.height) != x->x_vsize )
+ {
+ pdp_quark_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;
+ x->x_plane = x->x_planes-1;
+ pdp_quark_allocate(x);
+ post( "pdp_quark : reallocated buffers" );
+ }
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ memcpy(x->x_planetable[x->x_plane], data, (x->x_vsize + (x->x_vsize>>1))<<1 );
+ for(i=0; i<x->x_vsize+(x->x_vsize>>1); i++)
+ {
+ cf = (x->x_plane + (inline_fastrand()>>24))&(x->x_planes-1);
+ if ( i<x->x_vsize )
+ {
+ diff = ((x->x_planetable[cf])[i] - data[i])>>7;
+ }
+ else
+ {
+ diff = (((x->x_planetable[cf])[i] - data[i] )>>8)+128;
+ }
+ if ( abs ( diff ) > x->x_tolerance )
+ {
+ newdata[i] = (x->x_planetable[cf])[i];
+ }
+ else
+ {
+ newdata[i] = data[i];
+ }
+ /* The reason why I use high order 8 bits is written in utils.c
+ (or, 'man rand') */
+ }
+ x->x_plane--;
+ if ( x->x_plane < 0 ) x->x_plane = x->x_planes-1;
+
+ return;
+}
+
+static void pdp_quark_sendpacket(t_pdp_quark *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_quark_process(t_pdp_quark *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_quark_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_quark_process_yv12, pdp_quark_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_quark_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_quark_input_0(t_pdp_quark *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_quark_process(x);
+ }
+}
+
+static void pdp_quark_free(t_pdp_quark *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_quark_free_ressources(x);
+}
+
+t_class *pdp_quark_class;
+
+void *pdp_quark_new(void)
+{
+ int i;
+
+ t_pdp_quark *x = (t_pdp_quark *)pd_new(pdp_quark_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("planes"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("tolerance"));
+
+ 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_planes = DEFAULT_PLANES;
+
+ x->x_buffer = NULL;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_quark_setup(void)
+{
+// post( pdp_quark_version );
+ pdp_quark_class = class_new(gensym("pdp_quark"), (t_newmethod)pdp_quark_new,
+ (t_method)pdp_quark_free, sizeof(t_pdp_quark), 0, A_NULL);
+
+ class_addmethod(pdp_quark_class, (t_method)pdp_quark_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_quark_class, (t_method)pdp_quark_planes, gensym("planes"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_quark_class, (t_method)pdp_quark_tolerance, gensym("tolerance"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_radioactiv.c b/modules/pdp_radioactiv.c
new file mode 100644
index 0000000..c39dd4b
--- /dev/null
+++ b/modules/pdp_radioactiv.c
@@ -0,0 +1,516 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 adaptation of radioactiv effect from effectv
+ * Originally written by Fukuchi Kentaro & others
+ * Pd-fication by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+#define COLORS 32
+#define MAGIC_THRESHOLD 40
+#define RATIO 0.95
+#define DELTA (255/(COLORS/2-1))
+
+#define VIDEO_HWIDTH (x->x_buf_width/2)
+#define VIDEO_HHEIGHT (x->x_buf_height/2)
+
+static char *pdp_radioactiv_version = "pdp_radioactiv: version 0.1, port of radioactiv effect from effectv( Fukuchi Kentaro ) adapted by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_radioactiv_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;
+ unsigned char *x_blurzoombuf;
+ t_int *x_blurzoomx;
+ t_int *x_blurzoomy;
+ t_int x_buf_width_blocks;
+ t_int x_buf_width;
+ t_int x_buf_height;
+ t_int x_buf_area;
+ t_int x_buf_margin_right;
+ t_int x_buf_margin_left;
+ t_int x_palette[COLORS];
+ t_int x_mode; /* 0=normal 1=strobe 2=strobe2 3=trigger */
+ t_int x_snap_time;
+ t_int x_snap_interval;
+ short int *x_snapframe;
+ short int *x_diff;
+ short int *x_bdata;
+ t_int x_snapshot;
+
+} t_pdp_radioactiv;
+
+static void pdp_radioactiv_free_ressources(t_pdp_radioactiv *x)
+{
+ if ( x->x_blurzoombuf ) freebytes ( x->x_blurzoombuf, x->x_buf_area*2 );
+ if ( x->x_blurzoomx ) freebytes ( x->x_blurzoomx, x->x_buf_width*sizeof(t_int) );
+ if ( x->x_blurzoomy ) freebytes ( x->x_blurzoomy, x->x_buf_height*sizeof(t_int) );
+ if ( x->x_snapframe ) freebytes ( x->x_snapframe, ( ( x->x_vsize + x->x_vsize>>1 ) << 1 ) );
+ if ( x->x_diff ) freebytes( x->x_diff, (x->x_vsize + (x->x_vsize>>1))<<1 );
+ if ( x->x_bdata ) freebytes( x->x_bdata, (( x->x_vsize + (x->x_vsize>>1))<<1));
+}
+
+static void pdp_radioactiv_allocate(t_pdp_radioactiv *x)
+{
+ int i;
+
+ x->x_buf_width_blocks = (x->x_vwidth / 32);
+ x->x_buf_width = x->x_buf_width_blocks * 32;
+ x->x_buf_height = x->x_vheight;
+ x->x_buf_area = x->x_buf_width * x->x_buf_height;
+ x->x_buf_margin_left = (x->x_vwidth - x->x_buf_width)/2;
+ x->x_buf_margin_right = x->x_vwidth - x->x_buf_width - x->x_buf_margin_left;
+
+ x->x_blurzoombuf = (unsigned char *) getbytes (x->x_buf_area*2);
+ x->x_blurzoomx = (t_int *) getbytes (x->x_buf_width*sizeof(t_int));
+ x->x_blurzoomy = (t_int *) getbytes (x->x_buf_height*sizeof(t_int));
+ x->x_snapframe = (short int *) getbytes ( ( ( x->x_vsize + x->x_vsize>>1 ) << 1 ) );
+ x->x_diff = (short int*) getbytes((x->x_vsize + (x->x_vsize>>1))<<1);
+ x->x_bdata = (short int *) getbytes((( x->x_vsize + (x->x_vsize>>1))<<1));
+
+ if ( !x->x_blurzoombuf || !x->x_blurzoomx || !x->x_blurzoomy ||
+ !x->x_snapframe || !x->x_diff || !x->x_bdata )
+ {
+ post( "pdp_radioactiv : severe error : cannot allocate buffers !!!" );
+ return;
+ }
+}
+
+/* check if there is a real difference with background image */
+static void pdp_radioactiv_diff(t_pdp_radioactiv *x, short int *src)
+{
+ int i;
+ int Yy=0, Yu=0, Yv=0;
+ int Yby=0, Ybu=0, Ybv=0;
+ short int *p=NULL;
+ short int *pb=NULL;
+ short int *r=NULL;
+ int v;
+
+ p = src;
+ pb = x->x_bdata;
+ r = x->x_diff;
+ for(i=0; i<(x->x_vsize); i++)
+ {
+ Yy = (*p);
+ Yu = (*(p+x->x_vsize+(i>>2)));
+ if ( x->x_vsize+(x->x_vsize>>2)+(i>>2) > x->x_vsize+(x->x_vsize>>1) )
+ {
+ post ("pdp_mosaic : overflow : offset=%d limit=%d", x->x_vsize+(x->x_vsize>>2)+(i>>2),
+ x->x_vsize+(x->x_vsize>>1) );
+ return;
+ }
+ Yv = (*(p+x->x_vsize+(x->x_vsize>>2)+(i>>2)));
+ Yby = (*pb);
+ Ybu = (*(pb+x->x_vsize+(i>>2)));
+ Ybv = (*(pb+x->x_vsize+(x->x_vsize>>2)+(i>>2)));
+ if ( !r ) { post( "pdp_mosaic : hey, buffers are not allocated !!" ); return; };
+ *r = ( (Yy - Yby) + (Yu - Ybu) + (Yv - Ybv) );
+ r++;
+ }
+
+}
+
+static void pdp_radioactiv_make_palette(t_pdp_radioactiv *x)
+{
+ int i;
+
+ for(i=0; i<COLORS/2; i++)
+ {
+ x->x_palette[i] = i*DELTA;
+ }
+ for(i=0; i<COLORS/2; i++)
+ {
+ x->x_palette[i+COLORS/2] = 255 | (i*DELTA)<<16 | (i*DELTA)<<8;
+ }
+ for(i=0; i<COLORS; i++)
+ {
+ x->x_palette[i] = x->x_palette[i] & 0xfefeff;
+ }
+}
+
+/* this table assumes that video_width is times of 32 */
+static void pdp_radioactiv_set_table(t_pdp_radioactiv *x)
+{
+ unsigned int bits;
+ int px, py, tx, ty, xx;
+ int ptr=0, prevptr=0;
+
+ prevptr = (int)(0.5+RATIO*(-VIDEO_HWIDTH)+VIDEO_HWIDTH);
+ for(xx=0; xx<(x->x_buf_width_blocks); xx++)
+ {
+ bits = 0;
+ for(px=0; px<32; px++)
+ {
+ ptr = (int)(0.5+RATIO*((xx*32)+px-VIDEO_HWIDTH)+VIDEO_HWIDTH);
+ bits = bits>>1;
+ if(ptr != prevptr) bits |= 0x80000000;
+ prevptr = ptr;
+ }
+ x->x_blurzoomx[xx] = bits;
+ }
+
+ ty = (int)(0.5+RATIO*(-VIDEO_HHEIGHT)+VIDEO_HHEIGHT);
+ tx = (int)(0.5+RATIO*(-VIDEO_HWIDTH)+VIDEO_HWIDTH);
+ xx=(int)(0.5+RATIO*(x->x_buf_width-1-VIDEO_HWIDTH)+VIDEO_HWIDTH);
+ x->x_blurzoomy[0] = ty * x->x_buf_width + tx;
+ prevptr = ty * x->x_buf_width + xx;
+ for(py=1; py<x->x_buf_height; py++)
+ {
+ ty = (int)(0.5+RATIO*(py-VIDEO_HHEIGHT)+VIDEO_HHEIGHT);
+ x->x_blurzoomy[py] = ty * x->x_buf_width + tx - prevptr;
+ prevptr = ty * x->x_buf_width + xx;
+ }
+}
+
+static void pdp_radioactiv_mode(t_pdp_radioactiv *x, t_floatarg fmode )
+{
+ if ( ( fmode > 0 ) || ( fmode < 4 ) )
+ {
+ x->x_mode = (int)fmode;
+ if(x->x_mode == 3)
+ {
+ x->x_snap_time = 1;
+ }
+ else
+ {
+ x->x_snap_time = 0;
+ }
+ }
+}
+
+static void pdp_radioactiv_snap_time(t_pdp_radioactiv *x, t_floatarg fsnaptime )
+{
+ if ( fsnaptime > 0 )
+ {
+ x->x_snap_time = (t_int) fsnaptime;
+ }
+}
+
+static void pdp_radioactiv_snap_interval(t_pdp_radioactiv *x, t_floatarg fsnapinterval )
+{
+ if ( fsnapinterval > 1 )
+ {
+ x->x_snap_interval = (t_int) fsnapinterval;
+ }
+}
+
+static void pdp_radioactiv_blur(t_pdp_radioactiv *x)
+{
+ int px, py;
+ int width;
+ unsigned char *p, *q;
+ unsigned char v;
+
+ width = x->x_buf_width;
+ p = x->x_blurzoombuf + width + 1;
+ q = p + x->x_buf_area;
+
+ for(py=x->x_buf_height-2; py>0; py--)
+ {
+ for(px=x->x_vwidth-2; px>0; px--)
+ {
+ v = (*(p-width) + *(p-1) + *(p+1) + *(p+width))/4 - 1;
+ if(v == 255) v = 0;
+ *q = v;
+ p++;
+ q++;
+ }
+ p += 2;
+ q += 2;
+ }
+}
+
+static void pdp_radioactiv_zoom(t_pdp_radioactiv *x)
+{
+ int b, px, py;
+ unsigned char *p, *q;
+ int blocks, height;
+ int dx;
+
+ p = x->x_blurzoombuf + x->x_buf_area;
+ q = x->x_blurzoombuf;
+ height = x->x_buf_height;
+ blocks = x->x_buf_width_blocks;
+
+ for(py=0; py<height; py++)
+ {
+ p += x->x_blurzoomy[py];
+ for(b=0; b<blocks; b++)
+ {
+ dx = x->x_blurzoomx[b];
+ for(px=0; px<32; px++)
+ {
+ p += (dx & 1);
+ *q++ = *p;
+ dx = dx>>1;
+ }
+ }
+ }
+}
+
+static void pdp_radioactiv_blurzoom(t_pdp_radioactiv *x)
+{
+ pdp_radioactiv_blur(x);
+ pdp_radioactiv_zoom(x);
+}
+
+static void pdp_radioactiv_process_yv12(t_pdp_radioactiv *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);
+ int i;
+
+ int px, py;
+ short int a, b;
+ unsigned char *p;
+ short int *diff, *src;
+
+ /* allocate all ressources */
+ if ( (int)(header->info.image.width*header->info.image.height) != x->x_vsize )
+ {
+ pdp_radioactiv_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_radioactiv_allocate(x);
+ post( "pdp_radioactiv : reallocating buffers" );
+ pdp_radioactiv_set_table(x);
+ post( "pdp_radioactiv : set table" );
+ }
+
+ 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_bdata && x->x_snapshot )
+ {
+ x->x_snapshot = 0;
+ memcpy( x->x_bdata, data, (x->x_vsize + (x->x_vsize>>1))<<1 );
+ }
+
+ 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);
+
+ if(x->x_mode != 2 || x->x_snap_time <= 0)
+ {
+ pdp_radioactiv_diff(x, data);
+ if(x->x_mode == 0 || x->x_snap_time <= 0)
+ {
+ diff = x->x_diff + x->x_buf_margin_left;
+ p = x->x_blurzoombuf;
+ for(py=0; py<x->x_buf_height; py++)
+ {
+ for(px=0; px<x->x_buf_width; px++)
+ {
+ p[px] |= diff[px] >> 3;
+ }
+ diff += x->x_vwidth;
+ p += x->x_buf_width;
+ }
+ if( ( x->x_mode == 1 ) || ( x->x_mode == 2 ))
+ {
+ memcpy(x->x_snapframe, data, ( ( x->x_vsize + x->x_vsize>>1 ) << 1 ) );
+ }
+ }
+ }
+ pdp_radioactiv_blurzoom(x);
+
+ if( ( x->x_mode == 1 ) || ( x->x_mode == 2 ))
+ {
+ src = x->x_snapframe;
+ }
+ else
+ {
+ src = data;
+ }
+
+ p = x->x_blurzoombuf;
+ for(py=0; py<x->x_vheight; py++)
+ {
+ for(px=0; px<x->x_buf_margin_left; px++)
+ {
+ *newdata++ = *src++;
+ }
+ for(px=0; px<x->x_buf_width; px++)
+ {
+ a = *src++ & 0xfeff;
+ b = x->x_palette[*p++];
+ a += b;
+ b = a & 0x0100;
+ *newdata++ = a | (b - (b >> 8));
+ }
+ for(px=0; px<x->x_buf_margin_right; px++)
+ {
+ *newdata++ = *src++;
+ }
+ }
+
+ if( ( x->x_mode == 1 ) || ( x->x_mode == 2 ) )
+ {
+ x->x_snap_time--;
+ if(x->x_snap_time < 0) {
+ x->x_snap_time = x->x_snap_interval;
+ }
+ }
+
+ return;
+}
+
+static void pdp_radioactiv_sendpacket(t_pdp_radioactiv *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_radioactiv_process(t_pdp_radioactiv *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_radioactiv_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_radioactiv_process_yv12, pdp_radioactiv_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ // pdp_radioactiv_process_packet(x);
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_radioactiv_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_radioactiv_input_0(t_pdp_radioactiv *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_radioactiv_process(x);
+
+ }
+}
+
+static void pdp_radioactiv_free(t_pdp_radioactiv *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_radioactiv_free_ressources(x);
+
+}
+
+t_class *pdp_radioactiv_class;
+
+void *pdp_radioactiv_new(void)
+{
+ int i;
+
+ t_pdp_radioactiv *x = (t_pdp_radioactiv *)pd_new(pdp_radioactiv_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("mode"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("snaptime"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("snapinterval"));
+
+ 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_mode = 0; /* 0=normal/1=strobe/2=strobe2/3=trigger */
+ x->x_blurzoombuf = NULL;
+ x->x_snapframe = NULL;
+ x->x_snap_time = 0;
+ x->x_snap_interval = 3;
+ x->x_blurzoombuf = NULL;
+ x->x_blurzoomx = NULL;
+ x->x_blurzoomy = NULL;
+ x->x_snapframe = NULL;
+ x->x_diff = NULL;
+
+ pdp_radioactiv_make_palette(x);
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_radioactiv_setup(void)
+{
+// post( pdp_radioactiv_version );
+ pdp_radioactiv_class = class_new(gensym("pdp_radioactiv"), (t_newmethod)pdp_radioactiv_new,
+ (t_method)pdp_radioactiv_free, sizeof(t_pdp_radioactiv), 0, A_NULL);
+
+ class_addmethod(pdp_radioactiv_class, (t_method)pdp_radioactiv_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_radioactiv_class, (t_method)pdp_radioactiv_mode, gensym("mode"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_radioactiv_class, (t_method)pdp_radioactiv_snap_time, gensym("snaptime"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_radioactiv_class, (t_method)pdp_radioactiv_snap_interval, gensym("snapinterval"), A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_rec~.c b/modules/pdp_rec~.c
new file mode 100644
index 0000000..7f879d0
--- /dev/null
+++ b/modules/pdp_rec~.c
@@ -0,0 +1,705 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon <ydegoyon@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 recording object
+ * It records its input in quicktime format
+ */
+
+
+#include "pdp.h"
+#include <math.h>
+#include <time.h>
+#include <sys/time.h>
+#include <quicktime/quicktime.h>
+#include <quicktime/colormodels.h>
+
+#define DEFAULT_FRAME_RATE 25
+#define DEFAULT_CHANNELS 2
+#define DEFAULT_BITS 8
+#define DEFAULT_QUALITY 75 // from 1 to 100
+#define MAX_COMP_LENGTH 8
+#define MAX_AUDIO_PACKET_SIZE (128 * 1024)
+
+static char *pdp_rec_version = "pdp_rec~: version 0.1, a video/audio recording object, written by ydegoyon@free.fr";
+
+typedef struct pdp_rec_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;
+
+ quicktime_t *x_qtfile;
+ unsigned char **x_yuvpointers;
+ unsigned char *x_yuvbuffer;
+ t_int x_framerate;
+ t_int x_forced_framerate;
+ t_int x_jpeg_quality;
+ t_int x_newfile;
+ char *x_compressor;
+ t_int x_recflag;
+ t_int x_frameswritten;
+ struct timeval x_tstart;
+ struct timeval x_tstop;
+ struct timeval x_tlastrec;
+
+ /* audio structures */
+ int16_t **x_audio_buf; /* buffer for incoming audio */
+ t_int x_audioin_position; // writing position for incoming audio
+ char *x_acompressor; // audio compressor
+ t_int x_channels; // audio channels
+ t_int x_samplerate; // audio sample rate
+ t_int x_bits; // audio bits
+
+} t_pdp_rec;
+
+static void pdp_rec_free_ressources(t_pdp_rec *x)
+{
+ if ( x->x_yuvpointers ) freebytes ( x->x_yuvpointers, 3*sizeof( unsigned char** ) );
+ if ( x->x_yuvbuffer ) freebytes ( x->x_yuvbuffer, x->x_vsize + (x->x_vsize>>1) );
+
+}
+
+static void pdp_rec_allocate(t_pdp_rec *x)
+{
+ int i;
+
+ x->x_yuvpointers = (unsigned char**) getbytes ( 3*sizeof(unsigned char**) );
+ x->x_yuvbuffer = (unsigned char*) getbytes ( x->x_vsize + (x->x_vsize>>1) );
+ x->x_yuvpointers[0] = &x->x_yuvbuffer[0];
+ x->x_yuvpointers[2] = &x->x_yuvbuffer[x->x_vsize];
+ x->x_yuvpointers[1] = &x->x_yuvbuffer[x->x_vsize + (x->x_vsize>>2)];
+}
+
+ /* set video track whenever width or height is changed */
+static void pdp_rec_set_video(t_pdp_rec *x)
+{
+ t_int ret;
+
+ if ( !x->x_qtfile ) {
+ post( "pdp_rec~ : no video recording file is opened !!");
+ return;
+ }
+
+ if( ( ret = quicktime_set_video(x->x_qtfile, 1, x->x_vwidth, x->x_vheight, x->x_framerate, x->x_compressor) ) != 0) {
+ post( "pdp_rec~ : error setting video track ret=%d", ret );
+ } else {
+ post( "pdp_rec~ : video track set" );
+ }
+
+ quicktime_set_copyright(x->x_qtfile, "");
+ quicktime_set_name(x->x_qtfile, "Pdp output");
+ quicktime_set_info(x->x_qtfile, "File created with PDP/PiDiP");
+
+}
+
+ /* set framerate */
+static void pdp_rec_set_framerate(t_pdp_rec *x)
+{
+ t_int ret;
+
+ if ( !x->x_qtfile ) {
+ post( "pdp_rec~ : no video recording file is opened !!");
+ return;
+ }
+
+ quicktime_set_framerate(x->x_qtfile, (float)x->x_framerate );
+ post( "pdp_rec~ : framerate set to : %d", x->x_framerate );
+
+}
+
+ /* set audio track */
+static void pdp_rec_set_audio(t_pdp_rec *x)
+{
+ t_int ret;
+
+ if ( !x->x_qtfile ) {
+ post( "pdp_rec~ : no video recording file is opened !!");
+ return;
+ }
+
+ if( ( ret = quicktime_set_audio(x->x_qtfile, x->x_channels, x->x_samplerate, x->x_bits, x->x_acompressor ) ) == 0)
+ {
+ post( "pdp_rec~ : error setting audio track ret=%d", ret );
+ post( "pdp_rec~ : params : samplerate=%d : compressor=%s : channels=%d : bits=%d",
+ x->x_samplerate, x->x_acompressor, x->x_channels, x->x_bits );
+ } else {
+ post( "pdp_rec~ : %d audio track(s) allocated.", ret );
+ }
+
+}
+
+ /* set color model : it's hard coded : only one model supported */
+static void pdp_rec_set_cmodel(t_pdp_rec *x)
+{
+ t_int ret;
+
+ if ( !x->x_qtfile ) {
+ post( "pdp_rec~ : no video recording file is opened !!");
+ return;
+ }
+
+ quicktime_set_cmodel(x->x_qtfile, BC_YUV420P );
+ post( "pdp_rec~ : color model set" );
+
+}
+
+static void pdp_rec_set_jpeg(t_pdp_rec *x)
+{
+ if ( !x->x_qtfile )
+ {
+ post( "pdp_rec~ : set jpeg : no video recording file is opened !!");
+ return;
+ }
+
+ if ( strcmp( x->x_compressor, QUICKTIME_JPEG ) )
+ {
+ post( "pdp_rec~ : set jpeg : the codec is not jpeg right now !!");
+ return;
+ }
+ quicktime_set_jpeg( x->x_qtfile, x->x_jpeg_quality, 1 );
+ post( "pdp_rec~ : jpeg quality factor set : %d", x->x_jpeg_quality );
+}
+
+static void pdp_rec_frame_rate(t_pdp_rec *x, t_floatarg frate )
+{
+ if ( frate >= 1 )
+ {
+ x->x_framerate = (int) frate;
+ x->x_forced_framerate = 1;
+ post( "pdp_rec~ : frame rate set to %d : open a new file to activate it", x->x_framerate );
+ }
+}
+
+static void pdp_rec_jpeg(t_pdp_rec *x, t_floatarg fjpeg )
+{
+ if ( ( fjpeg >= 1 ) && ( fjpeg <= 100 ))
+ {
+ x->x_jpeg_quality = (int) fjpeg;
+ post( "pdp_rec~ : jpeg quality set : open a new file to activate it" );
+ }
+}
+
+static void pdp_rec_compressor(t_pdp_rec *x, t_symbol *scompressor )
+{
+ char scomp[ MAX_COMP_LENGTH ];
+
+ // check compressor as defined in quicktime.h
+ if (
+ strcmp( scompressor->s_name, "divx")
+ && strcmp( scompressor->s_name, "dv")
+ && strcmp( scompressor->s_name, "raw")
+ && strcmp( scompressor->s_name, "jpeg")
+ // && strcmp( scompressor->s_name, "png") // crashes with libquicktime 0.9.1
+ // && strcmp( scompressor->s_name, "mjpa") // no output with libquicktime 0.9.1
+ && strcmp( scompressor->s_name, "yuv2")
+ // && strcmp( scompressor->s_name, "yuv4") // crashes with libquicktime 0.9.1
+ )
+ {
+ post( "pdp_rec~ : unsupported codec : %s", scompressor->s_name );
+ return;
+ }
+
+ // map message names to libquicktime names
+ if ( !strcmp( scompressor->s_name, "divx") )
+ {
+ strcpy( scomp, QUICKTIME_DIVX );
+ }
+ if ( !strcmp( scompressor->s_name, "dv") )
+ {
+ strcpy( scomp, QUICKTIME_DV );
+ }
+ if ( !strcmp( scompressor->s_name, "raw") )
+ {
+ strcpy( scomp, QUICKTIME_RAW );
+ }
+ if ( !strcmp( scompressor->s_name, "jpeg") )
+ {
+ strcpy( scomp, QUICKTIME_JPEG );
+ }
+ if ( !strcmp( scompressor->s_name, "png") )
+ {
+ strcpy( scomp, QUICKTIME_PNG );
+ }
+ if ( !strcmp( scompressor->s_name, "mjpa") )
+ {
+ strcpy( scomp, QUICKTIME_MJPA );
+ }
+ if ( !strcmp( scompressor->s_name, "yuv2") )
+ {
+ strcpy( scomp, QUICKTIME_YUV2 );
+ }
+ if ( !strcmp( scompressor->s_name, "yuv4") )
+ {
+ strcpy( scomp, QUICKTIME_YUV4 );
+ }
+
+ if ( x->x_compressor )
+ {
+ freebytes( x->x_compressor, strlen( x->x_compressor )+1 );
+ }
+ x->x_compressor = (char *) getbytes( strlen( scomp ) + 1 );
+ strcpy( x->x_compressor, scomp );
+ post( "pdp_rec~ : compressor set to %s : open a new file to activate it", scomp );
+}
+
+ /* set audio compressor */
+static void pdp_rec_acompressor(t_pdp_rec *x, t_symbol *scompressor )
+{
+ char scomp[ MAX_COMP_LENGTH ];
+
+ // check compressor as defined in quicktime.h
+ if (
+ strcmp( scompressor->s_name, "twos")
+ // && strcmp( scompressor->s_name, "ima4") // produces a lot of errors ( libquicktime 0.9.1 )
+ && strcmp( scompressor->s_name, "raw")
+ // && strcmp( scompressor->s_name, "ulaw") // produces a lot of errors ( libquicktime 0.9.1 )
+ // && strcmp( scompressor->s_name, "ogg") // produces a lot of errors ( libquicktime 0.9.1 )
+ )
+ {
+ post( "pdp_rec~ : unsupported codec : %s", scompressor->s_name );
+ return;
+ }
+
+ // map message names to libquicktime names
+ if ( !strcmp( scompressor->s_name, "raw") )
+ {
+ strcpy( scomp, QUICKTIME_RAW );
+ }
+ if ( !strcmp( scompressor->s_name, "ima4") )
+ {
+ strcpy( scomp, QUICKTIME_IMA4 );
+ }
+ if ( !strcmp( scompressor->s_name, "twos") )
+ {
+ strcpy( scomp, QUICKTIME_TWOS );
+ }
+ if ( !strcmp( scompressor->s_name, "ulaw") )
+ {
+ strcpy( scomp, QUICKTIME_ULAW );
+ }
+ if ( !strcmp( scompressor->s_name, "ogg") )
+ {
+ strcpy( scomp, QUICKTIME_VORBIS );
+ }
+
+ if ( x->x_compressor )
+ {
+ freebytes( x->x_compressor, strlen( x->x_compressor )+1 );
+ }
+ x->x_compressor = (char *) getbytes( strlen( scomp ) + 1 );
+ strcpy( x->x_compressor, scomp );
+ post( "pdp_rec~ : audio compressor set to %s : open a new file to activate it", scomp );
+}
+
+ /* close a video file */
+static void pdp_rec_close(t_pdp_rec *x)
+{
+ int ret;
+
+ if ( x->x_qtfile ) {
+ if( ( ret = quicktime_close(x->x_qtfile) ) != 0 ) {
+ post( "pdp_rec~ : error closing file ret=%d", ret );
+ } else {
+ post( "pdp_rec~ : closed video file" );
+ x->x_qtfile = NULL;
+ }
+ }
+}
+
+ /* open a new video file */
+static void pdp_rec_open(t_pdp_rec *x, t_symbol *sfile)
+{
+ t_int ret=0;
+
+ // close previous video file if existing
+ pdp_rec_close(x);
+
+ if ( x->x_recflag ) {
+ x->x_recflag = 0;
+ }
+
+ if ( ( x->x_qtfile = quicktime_open(sfile->s_name, 0, 1) ) == NULL )
+ {
+ error( "pdp_rec~ : cannot open >%s<", sfile->s_name);
+ error( "pdp_rec~ : ret=%d", ret );
+ x->x_qtfile = NULL;
+ return;
+ } else {
+ x->x_frameswritten = 0;
+ post( "pdp_rec~ : opened >%s<", sfile->s_name);
+ x->x_newfile = 1;
+ }
+
+}
+
+ /* start recording */
+static void pdp_rec_start(t_pdp_rec *x)
+{
+ if ( !x->x_qtfile ) {
+ post("pdp_rec~ : start received but no file has been opened ... ignored.");
+ return;
+ }
+
+ if ( x->x_recflag == 1 ) {
+ post("pdp_rec~ : start received but recording is started ... ignored.");
+ return;
+ }
+
+ if ( gettimeofday(&x->x_tstart, NULL) == -1)
+ {
+ post("pdp_rec~ : could not set start time" );
+ }
+
+ x->x_recflag = 1;
+ post("pdp_rec~ : start recording");
+}
+
+ /* stop recording */
+static void pdp_rec_stop(t_pdp_rec *x)
+{
+ if ( !x->x_qtfile ) {
+ post("pdp_rec~ : stop received but no file has been opened ... ignored.");
+ return;
+ }
+
+ if ( x->x_recflag == 0 ) {
+ post("pdp_rec~ : stop received but recording is stopped ... ignored.");
+ return;
+ }
+
+ if ( gettimeofday(&x->x_tstop, NULL) == -1)
+ {
+ post("pdp_rec~ : could set stop time" );
+ }
+
+ // calculate frame rate if it hasn't been set
+ if ( !x->x_forced_framerate )
+ {
+ if ( ( x->x_tstop.tv_sec - x->x_tstart.tv_sec ) > 0 )
+ {
+ x->x_framerate = x->x_frameswritten / ( x->x_tstop.tv_sec - x->x_tstart.tv_sec );
+ }
+ else
+ {
+ x->x_framerate = DEFAULT_FRAME_RATE;
+ }
+ }
+
+ pdp_rec_set_framerate(x);
+
+ x->x_recflag = 0;
+ pdp_rec_close(x);
+
+ post("pdp_rec~ : stop recording");
+}
+
+ /* store audio data in PCM format in a buffer for now */
+static t_int *pdp_rec_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_rec *x = (t_pdp_rec *)(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; }
+ isample=(short) (32767.0 * fsample);
+ x->x_audio_buf[0][x->x_audioin_position]=isample;
+ fsample=*(in2++);
+ if (fsample > 1.0) { fsample = 1.0; }
+ if (fsample < -1.0) { fsample = -1.0; }
+ isample=(short) (32767.0 * fsample);
+ x->x_audio_buf[1][x->x_audioin_position]=isample;
+ x->x_audioin_position=(x->x_audioin_position+1)%(2*MAX_AUDIO_PACKET_SIZE);
+ if ( x->x_audioin_position == 2*MAX_AUDIO_PACKET_SIZE-1 )
+ {
+ post( "pdp_rec~ : reaching end of audio buffer" );
+ }
+ }
+
+ }
+
+ return (w+5);
+}
+
+static void pdp_rec_dsp(t_pdp_rec *x, t_signal **sp)
+{
+ dsp_add(pdp_rec_perform, 4, sp[0]->s_vec, sp[1]->s_vec, x, sp[0]->s_n);
+}
+
+static void pdp_rec_process_yv12(t_pdp_rec *x)
+{
+ t_pdp *header = pdp_packet_header(x->x_packet0);
+ short int *data = (short int *)pdp_packet_data(x->x_packet0);
+ t_int i, ret;
+ t_int px, py;
+ unsigned short *poy, *pou, *pov;
+ struct timeval trec;
+ t_int nbaudiosamples, nbusecs, nbrecorded;
+ t_float fframerate=0.0;
+
+ x->x_vwidth = header->info.image.width;
+ x->x_vheight = header->info.image.height;
+ x->x_vsize = x->x_vwidth*x->x_vheight;
+
+ /* setting video track */
+ if ( x->x_qtfile && x->x_recflag )
+ {
+ if ( ( (int)(header->info.image.width) != x->x_vwidth ) ||
+ ( (int)(header->info.image.height) != x->x_vheight ) ||
+ ( x->x_newfile ) )
+ {
+ pdp_rec_free_ressources(x);
+ x->x_newfile = 0;
+ if ( x->x_qtfile ) {
+ pdp_rec_set_video(x);
+ pdp_rec_set_audio(x);
+ pdp_rec_set_cmodel(x);
+ if ( !strcmp( x->x_compressor, QUICKTIME_JPEG ) )
+ {
+ pdp_rec_set_jpeg(x);
+ }
+ }
+ pdp_rec_allocate(x);
+ }
+
+ if ( x->x_frameswritten == 0 )
+ {
+ if ( gettimeofday(&x->x_tlastrec, NULL) == -1)
+ {
+ post("pdp_rec~ : could set stop time" );
+ }
+ }
+
+ for (i=0; i<x->x_vsize; i++)
+ {
+ x->x_yuvbuffer[i] = data[i]>>7;
+ }
+ for (i=x->x_vsize; i<(x->x_vsize+(x->x_vsize>>1)); i++)
+ {
+ x->x_yuvbuffer[i] = ((data[i]>>8)+128);
+ }
+
+ if ( ( ret = quicktime_encode_video(x->x_qtfile, x->x_yuvpointers, 0) ) != 0 )
+ {
+ post( "pdp_rec~ : error writing frame : ret=%d", ret );
+ }
+ else
+ {
+ x->x_frameswritten++;
+ }
+
+ // calculate the number of audio samples to output
+ if ( gettimeofday(&trec, NULL) == -1)
+ {
+ post("pdp_rec~ : 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;
+ }
+
+ if ( ( ret = quicktime_encode_audio(x->x_qtfile, x->x_audio_buf, NULL, nbrecorded) ) != 0 )
+ {
+ post( "pdp_rec~ : error writing audio data : ret=%d", ret );
+ }
+ else
+ {
+ memcpy( &x->x_audio_buf[0][0], &x->x_audio_buf[0][nbrecorded], x->x_audioin_position-nbrecorded );
+ memcpy( &x->x_audio_buf[1][0], &x->x_audio_buf[1][nbrecorded], x->x_audioin_position-nbrecorded );
+ x->x_audioin_position -= nbrecorded;
+ // post ( "pdp_rec~ : recorded %d samples.", nbrecorded );
+ }
+ }
+
+ return;
+}
+
+static void pdp_rec_killpacket(t_pdp_rec *x)
+{
+ /* release the packet */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = -1;
+}
+
+static void pdp_rec_process(t_pdp_rec *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_rec_process inputs and write into active inlet */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding)
+ {
+
+ case PDP_IMAGE_YV12:
+ if ( x->x_qtfile && x->x_recflag )
+ {
+ outlet_float( x->x_obj.ob_outlet, x->x_frameswritten );
+ }
+ pdp_queue_add(x, pdp_rec_process_yv12, pdp_rec_killpacket, &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_rec_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_rec_input_0(t_pdp_rec *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_rec_process(x);
+ }
+
+}
+
+static void pdp_rec_free(t_pdp_rec *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ // close video file if existing
+ pdp_rec_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(int16_t) );
+ }
+ if ( x->x_audio_buf ) freebytes( x->x_audio_buf, x->x_channels*sizeof(int16_t*) );
+
+}
+
+t_class *pdp_rec_class;
+
+void *pdp_rec_new(void)
+{
+ t_int i;
+
+ t_pdp_rec *x = (t_pdp_rec *)pd_new(pdp_rec_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_qtfile = NULL;
+ x->x_framerate = DEFAULT_FRAME_RATE;
+ x->x_forced_framerate = 0;
+ x->x_compressor = (char*) getbytes( strlen(QUICKTIME_JPEG)+1 );
+ strcpy( x->x_compressor, QUICKTIME_JPEG );
+
+ /* audio defaults */
+ x->x_acompressor = (char*) getbytes( strlen(QUICKTIME_TWOS)+1 );
+ strcpy( x->x_acompressor, QUICKTIME_TWOS );
+ x->x_samplerate = sys_getsr();
+ x->x_channels = DEFAULT_CHANNELS;
+ x->x_bits = DEFAULT_BITS;
+
+ x->x_audio_buf = (int16_t**) getbytes( x->x_channels*sizeof(int16_t*) );
+ for ( i=0; i<x->x_channels; i++)
+ {
+ x->x_audio_buf[i] = (int16_t*) getbytes( MAX_AUDIO_PACKET_SIZE*sizeof(int16_t) );
+ }
+
+ x->x_newfile = 0;
+ x->x_yuvbuffer = NULL;
+ x->x_yuvpointers = NULL;
+ x->x_jpeg_quality = DEFAULT_QUALITY;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_rec_tilde_setup(void)
+{
+ post( pdp_rec_version );
+ pdp_rec_class = class_new(gensym("pdp_rec~"), (t_newmethod)pdp_rec_new,
+ (t_method)pdp_rec_free, sizeof(t_pdp_rec), 0, A_NULL);
+
+ CLASS_MAINSIGNALIN(pdp_rec_class, t_pdp_rec, x_f );
+ class_addmethod(pdp_rec_class, (t_method)pdp_rec_dsp, gensym("dsp"), 0);
+ class_addmethod(pdp_rec_class, (t_method)pdp_rec_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_rec_class, (t_method)pdp_rec_open, gensym("open"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_rec_class, (t_method)pdp_rec_close, gensym("close"), A_NULL);
+ class_addmethod(pdp_rec_class, (t_method)pdp_rec_frame_rate, gensym("framerate"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_rec_class, (t_method)pdp_rec_compressor, gensym("compressor"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_rec_class, (t_method)pdp_rec_acompressor, gensym("acompressor"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_rec_class, (t_method)pdp_rec_jpeg, gensym("jpeg"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_rec_class, (t_method)pdp_rec_start, gensym("start"), A_NULL);
+ class_addmethod(pdp_rec_class, (t_method)pdp_rec_stop, gensym("stop"), A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_rev.c b/modules/pdp_rev.c
new file mode 100644
index 0000000..58f5753
--- /dev/null
+++ b/modules/pdp_rev.c
@@ -0,0 +1,261 @@
+/*
+ * PiDiP module
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 adaptation of rev effect from effectv
+ * (c)2002 Ed Tannenbaum
+ * Pd-fication by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+static char *pdp_rev_version = "pdp_rev: version 0.1, port of rev from effectv( Fukuchi Kentaro ) adapted by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_rev_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_vgrabtime;
+ t_int x_vgrab;
+ t_int x_linespace;
+ t_int x_vscale;
+ t_int x_vcolor;
+
+} t_pdp_rev;
+
+static void pdp_rev_vgrabtime(t_pdp_rev *x, t_floatarg fvgrabtime )
+{
+ if ( fvgrabtime > 1 )
+ {
+ x->x_vgrabtime = (int)fvgrabtime;
+ }
+}
+
+static void pdp_rev_linespace(t_pdp_rev *x, t_floatarg flinespace )
+{
+ if ( flinespace > 1 )
+ {
+ x->x_linespace = (int)flinespace;
+ }
+}
+
+static void pdp_rev_vscale(t_pdp_rev *x, t_floatarg fvscale )
+{
+ if ( fvscale > 1 )
+ {
+ x->x_vscale = (int)fvscale;
+ }
+}
+
+static void pdp_rev_color(t_pdp_rev *x, t_floatarg fvcolor )
+{
+ if ( ( fvcolor > 0 ) && ( fvcolor < 0xffff ) )
+ {
+ x->x_vcolor = ((int)fvcolor)<<8;
+ }
+}
+
+void pdp_rev_vasulka(t_pdp_rev *x, short int *src, short int *dst, int srcx, int srcy, int dstx, int dsty, int w, int h)
+{
+ short int *cdst=dst+((dsty*x->x_vwidth)+dstx);
+ short int *nsrc, *nusrc, *nvsrc;
+ int py,px,Y,U,V,yval;
+ int offset;
+
+ // draw the offset lines
+ for (py=srcy; py<h+srcy; py+=x->x_linespace)
+ {
+ for(px=srcx; px<=w+srcx; px++)
+ {
+ nsrc=src+(py*x->x_vwidth)+px;
+ nusrc=src+(((py*x->x_vwidth)+px)>>2)+x->x_vsize;
+ nvsrc=src+(((py*x->x_vwidth)+px)>>2)+x->x_vsize+(x->x_vsize>>2);
+ // Calc Y Value for curpix
+ Y = (*nsrc);
+ U = (*nusrc);
+ V = (*nvsrc);
+ yval = py - ((short)(Y + U + V) / x->x_vscale) ;
+ offset = px + yval * x->x_vwidth;
+ if(offset >= 0 && offset < x->x_vsize )
+ {
+ cdst[offset]=x->x_vcolor;
+ cdst[x->x_vsize+(offset>>2)]=x->x_vcolor;
+ cdst[x->x_vsize+(x->x_vsize>>2)+(offset>>2)]=x->x_vcolor;
+ }
+ }
+ }
+}
+
+static void pdp_rev_process_yv12(t_pdp_rev *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);
+ int i;
+
+ unsigned int totalnbpixels;
+
+ totalnbpixels = x->x_vsize;
+
+ x->x_vwidth = header->info.image.width;
+ x->x_vheight = header->info.image.height;
+ x->x_vsize = x->x_vwidth*x->x_vheight;
+
+ 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 );
+
+ x->x_vgrab++;
+ if (x->x_vgrab >= x->x_vgrabtime)
+ {
+ x->x_vgrab=0;
+ pdp_rev_vasulka(x, data, newdata, 0, 0, 0, 0, x->x_vwidth, x->x_vheight);
+ }
+
+ return;
+}
+
+static void pdp_rev_sendpacket(t_pdp_rev *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_rev_process(t_pdp_rev *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_rev_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_rev_process_yv12, pdp_rev_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_rev_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_rev_input_0(t_pdp_rev *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_rev_process(x);
+ }
+}
+
+static void pdp_rev_free(t_pdp_rev *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_rev_class;
+
+void *pdp_rev_new(void)
+{
+ int i;
+
+ t_pdp_rev *x = (t_pdp_rev *)pd_new(pdp_rev_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("vgrabtime"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("linespace"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("vscale"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("color"));
+
+ 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_vgrabtime = 1;
+ x->x_vgrab = 0;
+ x->x_linespace = 6;
+ x->x_vscale = 50;
+ x->x_vcolor = 0xffff;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_rev_setup(void)
+{
+// post( pdp_rev_version );
+ pdp_rev_class = class_new(gensym("pdp_rev"), (t_newmethod)pdp_rev_new,
+ (t_method)pdp_rev_free, sizeof(t_pdp_rev), 0, A_NULL);
+
+ class_addmethod(pdp_rev_class, (t_method)pdp_rev_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_rev_class, (t_method)pdp_rev_vgrabtime, gensym("vgrabtime"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_rev_class, (t_method)pdp_rev_linespace, gensym("linespace"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_rev_class, (t_method)pdp_rev_vscale, gensym("vscale"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_rev_class, (t_method)pdp_rev_color, gensym("color"), A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_ripple.c b/modules/pdp_ripple.c
new file mode 100644
index 0000000..4f54b30
--- /dev/null
+++ b/modules/pdp_ripple.c
@@ -0,0 +1,567 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 adaptation of ripple effect from effectv
+ * Originally written by Fukuchi Kentaro & others
+ * Pd-fication by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+#define MAGIC_THRESHOLD 30
+
+static unsigned int fastrand_val;
+#define inline_fastrand() (fastrand_val=fastrand_val*1103515245+12345)
+
+static int sqrtable[256];
+static int sqrt_init=1;
+static const int point = 16;
+static const int impact = 2;
+static const int decay = 8;
+static const int loopnum = 2;
+static int period = 0;
+static int rain_stat = 0;
+static unsigned int drop_prob = 0;
+static int drop_prob_increment = 0;
+static int drops_per_frame_max = 0;
+static int drops_per_frame = 0;
+static int drop_power = 0;
+
+static char *pdp_ripple_version = "pdp_ripple: version 0.1, port of ripple from effectv( Fukuchi Kentaro ) adapted by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_ripple_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_maph;
+ t_int x_mapw;
+ t_int x_mode;
+ t_int x_threshold;
+ t_int *x_map;
+ t_int *x_map1;
+ t_int *x_map2;
+ t_int *x_map3;
+ signed char *x_vtable;
+ short int *x_diff;
+ short int *x_bdata;
+ t_int x_snapshot;
+
+} t_pdp_ripple;
+
+static void pdp_ripple_mode(t_pdp_ripple *x, t_floatarg fmode )
+{
+ if ( ( fmode == 0 ) || ( fmode == 1 ) )
+ {
+ x->x_mode = (int)fmode;
+ }
+}
+
+static void pdp_ripple_threshold(t_pdp_ripple *x, t_floatarg fthreshold )
+{
+ x->x_threshold = (int)fthreshold;
+}
+
+static void pdp_ripple_increment(t_pdp_ripple *x, t_floatarg fincrement )
+{
+ drop_prob_increment = (int)fincrement;
+}
+
+static void pdp_ripple_background(t_pdp_ripple *x )
+{
+ x->x_snapshot = 1;
+}
+
+static void pdp_ripple_free_ressources(t_pdp_ripple *x)
+{
+ if ( x->x_diff != NULL ) freebytes( x->x_diff, (x->x_vsize + (x->x_vsize>>1))<<1 );
+ if ( x->x_bdata ) freebytes( x->x_bdata, (( x->x_vsize + (x->x_vsize>>1))<<1));
+ if ( x->x_map ) freebytes(x->x_map, x->x_maph*x->x_mapw*3*sizeof(t_int));
+ if ( x->x_vtable ) freebytes(x->x_vtable, x->x_maph*x->x_mapw*2*sizeof(signed char));
+}
+
+static void pdp_ripple_allocate(t_pdp_ripple *x)
+{
+ int i;
+
+ x->x_diff = (short int*) getbytes((x->x_vsize + (x->x_vsize>>1))<<1);
+ x->x_bdata = (short int *)getbytes((( x->x_vsize + (x->x_vsize>>1))<<1));
+ x->x_maph = x->x_vheight / 2 + 1;
+ x->x_mapw = x->x_vwidth / 2 + 1;
+ x->x_map = (int *)getbytes(x->x_maph*x->x_mapw*3*sizeof(t_int));
+ x->x_vtable = (signed char *)getbytes(x->x_maph*x->x_mapw*2*sizeof(signed char));
+ if( !x->x_map || x->x_vtable || !x->x_bdata || ! x->x_diff ) {
+ post( "pdp_ripple : severe error : cannot allocate buffers" );
+ }
+ x->x_map1 = x->x_map;
+ x->x_map2 = x->x_map + x->x_maph * x->x_mapw;
+ x->x_map3 = x->x_map + x->x_mapw * x->x_maph * 2;
+
+}
+
+/* check if there is a real difference with background image */
+short int *pdp_ripple_diff(t_pdp_ripple *x, short int *src)
+{
+ int i;
+ int Y;
+ int Yb;
+ short int *p=NULL;
+ short int *pb=NULL;
+ short int *r=NULL;
+ int v;
+
+ p = src;
+ pb = x->x_bdata;
+ r = x->x_diff;
+ for(i=0; i<(x->x_vsize); i++) {
+ Y = (*p);
+ Yb = (*pb);
+ *r = ( (Yb - Y) > x->x_threshold ) ? (Yb - Y) : 0;
+ p++; pb++;
+ r++;
+ }
+
+ return x->x_diff;
+}
+
+static void pdp_ripple_motion_detect(t_pdp_ripple *x, short int *src)
+{
+ short int *diff;
+ int width;
+ int *p, *q;
+ int px, py, h;
+
+ diff = pdp_ripple_diff(x, src);
+ width = x->x_vwidth;
+ p = x->x_map1+x->x_mapw+1;
+ q = x->x_map2+x->x_mapw+1;
+ diff += width+2;
+
+ for(py=x->x_maph-2; py>0; py--)
+ {
+ for(px=x->x_mapw-2; px>0; px--)
+ {
+ h = (int)*diff;// + (int)*(diff+1) + (int)*(diff+width) + (int)*(diff+width+1);
+ if(h>0) {
+ *p = h<<(point + impact - 8);
+ *q = *p;
+ }
+ p++;
+ q++;
+ diff += 2;
+ }
+ diff += width+2;
+ p+=2;
+ q+=2;
+ }
+}
+
+static inline void pdp_ripple_drop(t_pdp_ripple *x, int power)
+{
+ int px, py;
+ int *p, *q;
+
+ px = inline_fastrand()%(x->x_mapw-4)+2;
+ py = inline_fastrand()%(x->x_maph-4)+2;
+ p = x->x_map1 + py*x->x_mapw + px;
+ q = x->x_map2 + py*x->x_mapw + px;
+ *p = power;
+ *q = power;
+ *(p-x->x_mapw) = *(p-1) = *(p+1) = *(p+x->x_mapw) = power/2;
+ *(p-x->x_mapw-1) = *(p-x->x_mapw+1) = *(p+x->x_mapw-1) = *(p+x->x_mapw+1) = power/4;
+ *(q-x->x_mapw) = *(q-1) = *(q+1) = *(q+x->x_mapw) = power/2;
+ *(q-x->x_mapw-1) = *(q-x->x_mapw+1) = *(q+x->x_mapw-1) = *(p+x->x_mapw+1) = power/4;
+}
+
+static void pdp_ripple_raindrop(t_pdp_ripple *x)
+{
+ int i;
+
+ if(period == 0)
+ {
+ switch(rain_stat)
+ {
+ case 0:
+ period = (inline_fastrand()>>23)+100;
+ drop_prob = 0;
+ drop_prob_increment = 0x00ffffff/period;
+ drop_power = (-(inline_fastrand()>>28)-2)<<point;
+ drops_per_frame_max = 2<<(inline_fastrand()>>30); // 2,4,8 or 16
+ rain_stat = 1;
+ break;
+ case 1:
+ drop_prob = 0x00ffffff;
+ drops_per_frame = 1;
+ drop_prob_increment = 1;
+ period = (drops_per_frame_max - 1) * 16;
+ rain_stat = 2;
+ break;
+ case 2:
+ period = (inline_fastrand()>>22)+1000;
+ drop_prob_increment = 0;
+ rain_stat = 3;
+ break;
+ case 3:
+ period = (drops_per_frame_max - 1) * 16;
+ drop_prob_increment = -1;
+ rain_stat = 4;
+ break;
+ case 4:
+ period = (inline_fastrand()>>24)+60;
+ drop_prob_increment = -(drop_prob/period);
+ rain_stat = 5;
+ break;
+ case 5:
+ default:
+ period = (inline_fastrand()>>23)+500;
+ drop_prob = 0;
+ rain_stat = 0;
+ break;
+ }
+ }
+ switch(rain_stat)
+ {
+ default:
+ case 0:
+ break;
+ case 1:
+ case 5:
+ if((inline_fastrand()>>8)<drop_prob)
+ {
+ pdp_ripple_drop(x, drop_power);
+ }
+ drop_prob += drop_prob_increment;
+ break;
+ case 2:
+ case 3:
+ case 4:
+ for(i=drops_per_frame/16; i>0; i--)
+ {
+ pdp_ripple_drop(x, drop_power);
+ }
+ drops_per_frame += drop_prob_increment;
+ break;
+ }
+ period--;
+}
+
+static void pdp_ripple_process_yv12(t_pdp_ripple *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);
+ int i;
+
+ unsigned int totalnbpixels;
+ unsigned int u_offset;
+ unsigned int v_offset;
+ unsigned int totnbpixels;
+
+ int px, py;
+ int dx, dy;
+ int h, v;
+ int width, height;
+ int *p, *q, *r;
+ signed char *vp;
+
+ /* allocate all ressources */
+ if ( (int)(header->info.image.width*header->info.image.height) != x->x_vsize )
+ {
+ pdp_ripple_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_ripple_allocate(x);
+ post( "pdp_ripple : reallocated buffers" );
+ }
+
+ if ( x->x_bdata && x->x_snapshot )
+ {
+ x->x_snapshot = 0;
+ memcpy( x->x_bdata, data, (x->x_vsize + (x->x_vsize<<1))<<1 );
+ }
+
+ totalnbpixels = x->x_vsize;
+ u_offset = x->x_vsize;
+ v_offset = x->x_vsize + (x->x_vsize>>2);
+ totnbpixels = x->x_vsize + (x->x_vsize>>1);
+
+ 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 );
+
+ if ( x->x_mode )
+ {
+ pdp_ripple_motion_detect(x, data);
+ }
+ else
+ {
+ pdp_ripple_raindrop(x);
+ }
+
+ /* simulate surface wave */
+ width = x->x_mapw;
+ height = x->x_maph;
+
+ /* This function is called only 30 times per second. To increase a speed
+ * of wave, iterates this loop several times. */
+ for(i=loopnum; i>0; i--)
+ {
+ /* wave simulation */
+ p = x->x_map1 + width + 1;
+ q = x->x_map2 + width + 1;
+ r = x->x_map3 + width + 1;
+ for(py=height-2; py>0; py--)
+ {
+ for(px=width-2; px>0; px--)
+ {
+ h = *(p-width-1) + *(p-width+1) + *(p+width-1) + *(p+width+1)
+ + *(p-width) + *(p-1) + *(p+1) + *(p+width) - (*p)*9;
+ h = h >> 3;
+ v = *p - *q;
+ v += h - (v >> decay);
+ *r = v + *p;
+ p++;
+ q++;
+ r++;
+ }
+ p += 2;
+ q += 2;
+ r += 2;
+ }
+
+ /* low pass filter */
+ p = x->x_map3 + width + 1;
+ q = x->x_map2 + width + 1;
+ for(py=height-2; py>0; py--)
+ {
+ for(px=width-2; px>0; px--)
+ {
+ h = *(p-width) + *(p-1) + *(p+1) + *(p+width) + (*p)*60;
+ *q = h >> 6;
+ p++;
+ q++;
+ }
+ p+=2;
+ q+=2;
+ }
+
+ p = x->x_map1;
+ x->x_map1 = x->x_map2;
+ x->x_map2 = p;
+ }
+
+ vp = x->x_vtable;
+ p = x->x_map1;
+ for(py=height-1; py>0; py--)
+ {
+ for(px=width-1; px>0; px--)
+ {
+ /* difference of the height between two voxel. They are twiced to
+ * emphasise the wave. */
+ vp[0] = sqrtable[((p[0] - p[1])>>(point-1))&0xff];
+ vp[1] = sqrtable[((p[0] - p[width])>>(point-1))&0xff];
+ p++;
+ vp+=2;
+ }
+ p++;
+ vp+=2;
+ }
+
+ height = x->x_vheight;
+ width = x->x_vwidth;
+ vp = x->x_vtable;
+
+ /* draw refracted image. The vector table is stretched. */
+ for(py=0; py<height; py+=2)
+ {
+ for(px=0; px<width; px+=2)
+ {
+ h = (int)vp[0];
+ v = (int)vp[1];
+ dx = px + h;
+ dy = py + v;
+ if(dx<0) dx=0;
+ if(dy<0) dy=0;
+ if(dx>=width) dx=width-1;
+ if(dy>=height) dy=height-1;
+ newdata[0] = data[dy*width+dx];
+
+ i = dx;
+
+ dx = px + 1 + (h+(int)vp[2])/2;
+ if(dx<0) dx=0;
+ if(dx>=width) dx=width-1;
+ newdata[1] = data[dy*width+dx];
+
+ dy = py + 1 + (v+(int)vp[x->x_mapw*2+1])/2;
+ if(dy<0) dy=0;
+ if(dy>=height) dy=height-1;
+ newdata[width] = data[dy*width+i];
+
+ newdata[width+1] = data[dy*width+dx];
+ newdata+=2;
+ vp+=2;
+ }
+ newdata += width;
+ vp += 2;
+ }
+
+ return;
+}
+
+static void pdp_ripple_sendpacket(t_pdp_ripple *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_ripple_process(t_pdp_ripple *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_ripple_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_ripple_process_yv12, pdp_ripple_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ // pdp_ripple_process_packet(x);
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_ripple_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_ripple_input_0(t_pdp_ripple *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_ripple_process(x);
+ }
+}
+
+static void pdp_ripple_free(t_pdp_ripple *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_ripple_free_ressources(x);
+}
+
+t_class *pdp_ripple_class;
+
+void *pdp_ripple_new(void)
+{
+ int i;
+
+ t_pdp_ripple *x = (t_pdp_ripple *)pd_new(pdp_ripple_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("mode"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_bang, gensym("background"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("threshold"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("increment"));
+
+ 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_mode = 0;
+ x->x_vsize = -1;
+ x->x_snapshot = 1;
+ x->x_threshold = MAGIC_THRESHOLD;
+
+ if ( sqrt_init )
+ {
+ sqrt_init = 0;
+ for(i=0; i<128; i++) {
+ sqrtable[i] = i*i;
+ }
+ for(i=1; i<=128; i++) {
+ sqrtable[256-i] = -i*i;
+ }
+ }
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_ripple_setup(void)
+{
+// post( pdp_ripple_version );
+ pdp_ripple_class = class_new(gensym("pdp_ripple"), (t_newmethod)pdp_ripple_new,
+ (t_method)pdp_ripple_free, sizeof(t_pdp_ripple), 0, A_NULL);
+
+ class_addmethod(pdp_ripple_class, (t_method)pdp_ripple_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_ripple_class, (t_method)pdp_ripple_mode, gensym("mode"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_ripple_class, (t_method)pdp_ripple_background, gensym("background"), A_NULL);
+ class_addmethod(pdp_ripple_class, (t_method)pdp_ripple_threshold, gensym("threshold"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_ripple_class, (t_method)pdp_ripple_increment, gensym("increment"), A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_segsnd~.c b/modules/pdp_segsnd~.c
new file mode 100644
index 0000000..f593af7
--- /dev/null
+++ b/modules/pdp_segsnd~.c
@@ -0,0 +1,412 @@
+/*
+ * PiDiP module
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 turns an image into sound
+ */
+
+/* Listening to :
+ * The Deviants - Nothing Man
+ * 90 day men - My Trip To Venus
+ */
+
+#include "pdp.h"
+#include "yuv.h"
+#include <math.h>
+#include <ctype.h>
+#include <Imlib2.h> // imlib2 is required
+
+static char *pdp_segsnd_version = "pdp_segsnd~: version 0.1 : turns an image into sound written by ydegoyon@free.fr ";
+
+typedef struct pdp_segsnd_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_x1; // coordinates of fixed segment
+ t_int x_y1;
+ t_int x_x2;
+ t_int x_y2;
+ t_int x_random;
+
+ short int *x_data;
+
+ /* imlib data */
+ Imlib_Image x_image;
+
+} t_pdp_segsnd;
+
+static void pdp_segsnd_x1(t_pdp_segsnd *x, t_floatarg fx )
+{
+ if ( ( fx >= 0 ) && ( fx < x->x_x2 ) )
+ {
+ x->x_x1 = fx;
+ }
+}
+
+static void pdp_segsnd_y1(t_pdp_segsnd *x, t_floatarg fy )
+{
+ if ( ( fy >= 0 ) && ( fy < x->x_y2 ) )
+ {
+ x->x_y1 = fy;
+ }
+}
+
+static void pdp_segsnd_x2(t_pdp_segsnd *x, t_floatarg fx )
+{
+ if ( ( fx >= x->x_x1 ) && ( fx < x->x_vwidth ) )
+ {
+ x->x_x2 = fx;
+ }
+}
+
+static void pdp_segsnd_y2(t_pdp_segsnd *x, t_floatarg fy )
+{
+ if ( ( fy >= x->x_y1 ) && ( fy < x->x_vheight ) )
+ {
+ x->x_y2 = fy;
+ }
+}
+
+static void pdp_segsnd_random(t_pdp_segsnd *x, t_floatarg frand )
+{
+ if ( ( frand == 0 ) || ( frand == 1 ) )
+ {
+ x->x_random = frand;
+ }
+}
+
+static void pdp_segsnd_allocate(t_pdp_segsnd *x)
+{
+ x->x_image = imlib_create_image( x->x_vwidth, x->x_vheight );
+ if ( x->x_image == NULL )
+ {
+ post( "pdp_form : severe error : could not allocate image !!" );
+ }
+ imlib_context_set_image(x->x_image);
+ x->x_data = (short int *)getbytes((( x->x_vsize + (x->x_vsize>>1))<<1));
+}
+
+static void pdp_segsnd_free_ressources(t_pdp_segsnd *x)
+{
+ if ( x->x_image != NULL ) imlib_free_image();
+ x->x_image = NULL;
+ if ( x->x_data ) freebytes( x->x_data, (( x->x_vsize + (x->x_vsize>>1))<<1));
+ x->x_data = NULL;
+}
+
+static void pdp_segsnd_process_yv12(t_pdp_segsnd *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 ti;
+ t_int px, py;
+ unsigned char y, u, v;
+ short int *pY, *pU, *pV;
+ DATA32 *imdata;
+ DATA32 bgcolor;
+
+ if ( ( (int)(header->info.image.width) != x->x_vwidth ) ||
+ ( (int)(header->info.image.height) != x->x_vheight ) )
+ {
+ pdp_segsnd_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_segsnd_allocate(x);
+ }
+
+ 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_data, data, ((x->x_vsize+(x->x_vsize>>1))<<1));
+
+ imlib_image_clear();
+ imlib_context_set_direction(IMLIB_TEXT_TO_ANGLE);
+ imdata = imlib_image_get_data();
+ bgcolor = imdata[0];
+
+ // post( "pdp_segsnd : x1=%d y1=%d x2=%d y2=%d", x->x_x1, x->x_y1, x->x_x2, x->x_y2 );
+ if ( x->x_x1 != -1 )
+ {
+ imlib_context_set_color( 255, 255, 255, 255 );
+ imlib_image_draw_line( x->x_x1, x->x_y1, x->x_x2, x->x_y2, 1);
+
+ pY = newdata;
+ pV = newdata+x->x_vsize;
+ pU = newdata+x->x_vsize+(x->x_vsize>>2);
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ if ( imdata[py*x->x_vwidth+px] != bgcolor )
+ {
+ y = yuv_RGBtoY(imdata[py*x->x_vwidth+px]);
+ u = yuv_RGBtoU(imdata[py*x->x_vwidth+px]);
+ v = yuv_RGBtoV(imdata[py*x->x_vwidth+px]);
+
+ *(pY) = y<<7;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ *(pV) = (v-128)<<8;
+ *(pU) = (u-128)<<8;
+ }
+ }
+ pY++;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ pV++;pU++;
+ }
+ }
+ }
+ if ( x->x_random )
+ {
+ x->x_x2 = ((t_float)rand()/RAND_MAX)*x->x_vwidth;
+ x->x_x1 = ((t_float)rand()/RAND_MAX)*x->x_x2;
+ x->x_y2 = ((t_float)rand()/RAND_MAX)*x->x_vheight;
+ x->x_y1 = ((t_float)rand()/RAND_MAX)*x->x_y2;
+ }
+ }
+
+ return;
+}
+
+static void pdp_segsnd_sendpacket(t_pdp_segsnd *x)
+{
+ /* delete source 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_segsnd_process(t_pdp_segsnd *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_segsnd_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_segsnd_process_yv12, pdp_segsnd_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_segsnd_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_segsnd_input_0(t_pdp_segsnd *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/*") );
+ }
+ // post( "pdp_segsnd : action=%s dropped=%d", s->s_name, x->x_dropped );
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped))
+ {
+
+ /* add the process method and callback to the process queue */
+ pdp_segsnd_process(x);
+
+ }
+
+}
+
+static void pdp_segsnd_free(t_pdp_segsnd *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+static t_int *pdp_segsnd_perform(t_int *w)
+{
+ t_float *out = (t_float *)(w[1]); // audio generated sound
+ t_pdp_segsnd *x = (t_pdp_segsnd *)(w[2]);
+ t_int n = (int)(w[3]);
+ t_int npoints, xi, px, py;
+ t_float a=0;
+
+ // set initial coordinates
+ if ( ( x->x_x1 == -1 ) && (x->x_vwidth != -1 ))
+ {
+ x->x_x1 = 10;
+ x->x_y1 = 10;
+ if ( 10+n > (x->x_vwidth-1) )
+ {
+ x->x_x2 = x->x_vwidth-1;
+ }
+ else
+ {
+ x->x_x2 = 10+n;
+ }
+ if ( 10+n > (x->x_vheight-1) )
+ {
+ x->x_y2 = x->x_vheight-1;
+ }
+ else
+ {
+ x->x_y2 = 10+n;
+ }
+ }
+ // post( "pdp_segsnd : x1=%d y1=%d x2=%d y2=%d", x->x_x1, x->x_y1, x->x_x2, x->x_y2 );
+
+ // output image data
+ if ( x->x_x1 == -1 )
+ {
+ npoints = 0;
+ }
+ else if ( x->x_x2-x->x_x1 > n )
+ {
+ npoints = n;
+ }
+ else
+ {
+ npoints = x->x_x2-x->x_x1;
+ }
+ if ( (x->x_x2-x->x_x1) > 0 )
+ {
+ a = (x->x_y2-x->x_y1)/(x->x_x2-x->x_x1);
+ }
+ // post( "pdp_segsnd : npoints=%d a=%f", npoints, a );
+ // read pixels
+ for (xi=0; xi<npoints; xi++)
+ {
+ px = x->x_x1 + xi;
+ py = x->x_y1 + (int)(a*xi);
+ *out = (((t_float)(x->x_data[py*x->x_vwidth+px]>>7))-127)/128.0; // scaled to -1 ... 1
+ out++;
+ }
+ // fill up with zeros
+ for (xi=npoints; xi<n; xi++)
+ {
+ *out++ = 0.0;
+ }
+
+ return (w+4);
+}
+
+static void pdp_segsnd_dsp(t_pdp_segsnd *x, t_signal **sp)
+{
+ dsp_add(pdp_segsnd_perform, 3, sp[0]->s_vec, x, sp[0]->s_n);
+}
+
+t_class *pdp_segsnd_class;
+
+void *pdp_segsnd_new(void)
+{
+ int i;
+
+ t_pdp_segsnd *x = (t_pdp_segsnd *)pd_new(pdp_segsnd_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("y1"));
+ 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("y2"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("random"));
+
+ // pdp output
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ // sound output
+ outlet_new (&x->x_obj, &s_signal);
+
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_queue_id = -1;
+
+ x->x_vwidth = -1;
+ x->x_vheight = -1;
+
+ x->x_image = NULL;
+ x->x_data = NULL;
+ x->x_x1 = -1;
+ x->x_y1 = -1;
+ x->x_x2 = -1;
+ x->x_y2 = -1;
+ x->x_random = 0;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_segsnd_tilde_setup(void)
+{
+
+ post( pdp_segsnd_version );
+ pdp_segsnd_class = class_new(gensym("pdp_segsnd~"), (t_newmethod)pdp_segsnd_new,
+ (t_method)pdp_segsnd_free, sizeof(t_pdp_segsnd), 0, A_NULL);
+
+ class_addmethod(pdp_segsnd_class, (t_method)pdp_segsnd_dsp, gensym("dsp"), 0);
+ class_addmethod(pdp_segsnd_class, (t_method)pdp_segsnd_input_0, gensym("pdp"),
+ A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_segsnd_class, (t_method)pdp_segsnd_x1, gensym("x1"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_segsnd_class, (t_method)pdp_segsnd_y1, gensym("y1"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_segsnd_class, (t_method)pdp_segsnd_x2, gensym("x2"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_segsnd_class, (t_method)pdp_segsnd_y2, gensym("y2"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_segsnd_class, (t_method)pdp_segsnd_random, gensym("random"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_shagadelic.c b/modules/pdp_shagadelic.c
new file mode 100644
index 0000000..dd24e03
--- /dev/null
+++ b/modules/pdp_shagadelic.c
@@ -0,0 +1,307 @@
+/*
+ * PiDiP module
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 port of shagadelic effect from EffecTV
+ * Originally written by Fukuchi Kentaro
+ * Pd-fication by Yves Degoyon ( ydegoyon@free.fr )
+ */
+
+
+#include "pdp.h"
+#include <math.h>
+
+#define MAX_TABLES 6
+static unsigned int fastrand_val;
+#define inline_fastrand() (fastrand_val=fastrand_val*1103515245+12345)
+
+static char *pdp_shagadelic_version = "pdp_shagadelic: version 0.1, port of cycle from EffecTV by clifford smith, adapted by ydegoyon@free.fr ";
+
+typedef struct pdp_shagadelic_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_packet1;
+ t_int x_dropped;
+ t_int x_queue_id;
+
+ t_outlet *x_outlet0;
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+
+ /* shagadelic parameters */
+ char *x_ripple;
+ char *x_spiral;
+ unsigned char x_phase;
+ t_int x_rx, x_ry;
+ t_int x_bx, x_by;
+ t_int x_rvx, x_rvy;
+ t_int x_bvx, x_bvy;
+ short int x_mask;
+
+} t_pdp_shagadelic;
+
+static void pdp_shagadelic_mask(t_pdp_shagadelic *x, t_floatarg fmask )
+{
+ if ( ( fmask >= 0 ) || ( fmask < 65536 ) )
+ {
+ x->x_mask = fmask;
+ }
+}
+
+static int pdp_shagadelic_map_from_table(t_pdp_shagadelic *x, t_int px, t_int py, t_int t)
+{
+ int xd,yd;
+
+ yd = py + (inline_fastrand() >> 30)-2;
+ xd = px + (inline_fastrand() >> 30)-2;
+ if (xd > x->x_vwidth) {
+ xd-=1;
+ }
+ return (xd+yd*x->x_vwidth);
+}
+
+static void pdp_shagadelic_init_tables(t_pdp_shagadelic *x)
+{
+ t_int px, py, i;
+ double xx, yy;
+
+ i = 0;
+ for(py=0; py<x->x_vheight*2; py++)
+ {
+ yy = py - x->x_vheight;
+ yy *= yy;
+ for(px=0; px<x->x_vwidth*2; px++)
+ {
+ xx = px - x->x_vwidth;
+ x->x_ripple[i++] = ((unsigned int)(sqrt(xx*xx+yy)*8))&255;
+ }
+ }
+ i = 0;
+ for(py=0; py<x->x_vheight; py++)
+ {
+ yy = py - x->x_vheight/2;
+ for(px=0; px<x->x_vwidth; px++)
+ {
+ xx = px - x->x_vwidth/2;
+ x->x_spiral[i++] = ((unsigned int) ((atan2(xx, yy)/M_PI*256*9) + (sqrt(xx*xx+yy*yy)*5)))&255;
+ }
+ }
+
+ x->x_rx = inline_fastrand()%x->x_vwidth;
+ x->x_ry = inline_fastrand()%x->x_vheight;
+ x->x_bx = inline_fastrand()%x->x_vwidth;
+ x->x_by = inline_fastrand()%x->x_vheight;
+}
+
+static void pdp_shagadelic_free_ressources(t_pdp_shagadelic *x)
+{
+ if (x->x_ripple) freebytes( x->x_ripple, x->x_vsize*4 );
+ if (x->x_spiral) freebytes( x->x_spiral, x->x_vsize );
+}
+
+static void pdp_shagadelic_allocate(t_pdp_shagadelic *x)
+{
+ x->x_ripple = (char *) getbytes( x->x_vsize*4 );
+ x->x_spiral = (char *) getbytes( x->x_vsize );
+}
+
+static void pdp_shagadelic_process_yv12(t_pdp_shagadelic *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, py;
+ unsigned char y, u, v;
+ char *p_y, *p_u, *p_v;
+
+
+ /* allocate all ressources */
+ if ( ((int)header->info.image.width != x->x_vwidth) ||
+ ((int)header->info.image.height != x->x_vheight) )
+ {
+ pdp_shagadelic_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_shagadelic_allocate(x);
+ post( "pdp_shagadelic : reallocated buffers" );
+ pdp_shagadelic_init_tables(x);
+ post( "pdp_shagadelic : initialized tables" );
+ }
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ p_y = &x->x_ripple[x->x_ry*x->x_vwidth*2 + x->x_rx];
+ p_u = x->x_spiral;
+ p_v = &x->x_ripple[x->x_by*x->x_vwidth*2 + x->x_bx];
+
+ for(py=0; py<x->x_vheight; py++)
+ {
+ for(px=0; px<x->x_vwidth; px++)
+ {
+ y = (char)(*p_y+x->x_phase*2)>>7;
+ u = (char)(*p_u+x->x_phase*3)>>7;
+ v = (char)(*p_v-x->x_phase)>>7;
+ *(newdata+py*x->x_vwidth+px) = *(data) & (y<<7) & x->x_mask;
+ *(newdata+x->x_vsize+((py*x->x_vwidth+px)>>2)) = *(data) & ((u-128)<<8) & x->x_mask;
+ *(newdata+x->x_vsize+(x->x_vsize>>2)+((py*x->x_vwidth+px)>>2)) = *(data) & ((v-128)<<8) & x->x_mask;
+ p_y++;
+ p_u++;
+ p_v++;
+ data++;
+ }
+ p_y += x->x_vwidth;
+ p_v += x->x_vwidth;
+ }
+
+ x->x_phase -= 8;
+ if((x->x_rx+x->x_rvx)<0 || (x->x_rx+x->x_rvx)>=x->x_vwidth) x->x_rvx =-x->x_rvx;
+ if((x->x_ry+x->x_rvy)<0 || (x->x_ry+x->x_rvy)>=x->x_vheight) x->x_rvy =-x->x_rvy;
+ if((x->x_bx+x->x_bvx)<0 || (x->x_bx+x->x_bvx)>=x->x_vwidth) x->x_bvx =-x->x_bvx;
+ if((x->x_by+x->x_bvy)<0 || (x->x_by+x->x_bvy)>=x->x_vheight) x->x_bvy =-x->x_bvy;
+
+ x->x_rx += x->x_rvx;
+ x->x_ry += x->x_rvy;
+ x->x_bx += x->x_bvx;
+ x->x_by += x->x_bvy;
+
+ return;
+}
+
+static void pdp_shagadelic_sendpacket(t_pdp_shagadelic *x)
+{
+ /* delete source 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_shagadelic_process(t_pdp_shagadelic *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_shagadelic_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_shagadelic_process_yv12, pdp_shagadelic_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_shagadelic_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_shagadelic_input_0(t_pdp_shagadelic *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_shagadelic_process(x);
+
+ }
+
+}
+
+static void pdp_shagadelic_free(t_pdp_shagadelic *x)
+{
+ int i;
+
+ pdp_shagadelic_free_ressources(x);
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_shagadelic_class;
+
+void *pdp_shagadelic_new(void)
+{
+ int i;
+
+ t_pdp_shagadelic *x = (t_pdp_shagadelic *)pd_new(pdp_shagadelic_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("mask"));
+
+ 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_rvx = -2;
+ x->x_rvy = -2;
+ x->x_bvx = 2;
+ x->x_bvy = 2;
+ x->x_phase = 0;
+ x->x_mask = 0xffff;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_shagadelic_setup(void)
+{
+// post( pdp_shagadelic_version );
+ pdp_shagadelic_class = class_new(gensym("pdp_shagadelic"), (t_newmethod)pdp_shagadelic_new,
+ (t_method)pdp_shagadelic_free, sizeof(t_pdp_shagadelic), 0, A_NULL);
+
+ class_addmethod(pdp_shagadelic_class, (t_method)pdp_shagadelic_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_shagadelic_class, (t_method)pdp_shagadelic_mask, gensym("mask"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_simura.c b/modules/pdp_simura.c
new file mode 100644
index 0000000..04fd74b
--- /dev/null
+++ b/modules/pdp_simura.c
@@ -0,0 +1,443 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* This object is an adaptation of simura effect from freej
+ * Originally written by Fukuchi Kentarou
+ * Pd-fication by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+static char *pdp_simura_version = "pdp_simura: version 0.1, port of simura from freej ( Fukuchi Kentarou ), adapted by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_simura_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;
+
+ unsigned short int x_color; /* color for the mask */
+ t_int x_mode; /* mirror mode */
+
+} t_pdp_simura;
+
+static void pdp_simura_process_yv12(t_pdp_simura *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);
+ int newpacket = -1, i;
+
+ unsigned int w = header->info.image.width;
+ unsigned int hw = w/2;
+ unsigned int hhw = w/4;
+ unsigned int h = header->info.image.height;
+ unsigned int hh = h/2;
+ unsigned int hhh = h/4;
+
+ unsigned int size = w*h;
+ unsigned int totalnbpixels = size;
+ unsigned int u_offset = size;
+ unsigned int v_offset = size + (size>>2);
+ unsigned int totnbpixels = size + (size>>1);
+
+ unsigned int px, py;
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = w;
+ newheader->info.image.height = h;
+
+ switch ( x->x_mode )
+ {
+ case 0 :
+ // y component
+ for(py=0; py<h; py++){
+ for(px=0; px<w; px++){
+ newdata[py*w+px] = data[py*w+px];
+ }
+ }
+ // u component
+ for(py=0; py<hh; py++){
+ for(px=0; px<hw; px++){
+ newdata[u_offset+py*hw+px] = data[u_offset+py*hw+px] ^ x->x_color;
+ }
+ }
+ // v component
+ for(py=0; py<hh; py++){
+ for(px=0; px<hw; px++){
+ newdata[v_offset+py*hw+px] = data[v_offset+py*hw+px] ^ x->x_color;
+ }
+ }
+ break;
+ case 1 :
+ // y component
+ for(py=0; py<(hh); py++){
+ for(px=0; px<w; px++){
+ newdata[py*(w)+px] = data[py*(w)+px];
+ newdata[((h)-py-1)*(w)+px] = data[py*(w)+px];
+ }
+ }
+ // u component
+ for(py=0; py<(hhh); py++){
+ for(px=0; px<hw; px++){
+ newdata[u_offset+py*(hw)+px] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ newdata[u_offset+((hh)-py-1)*(hw)+px] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ }
+ }
+ // v component
+ for(py=0; py<(hhh); py++){
+ for(px=0; px<hw; px++){
+ newdata[v_offset+py*(hw)+px] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ newdata[v_offset+((hh)-py-1)*(hw)+px] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ }
+ }
+ break;
+ case 2 :
+ // y component
+ for(py=(hh); py<h; py++){
+ for(px=0; px<w; px++){
+ newdata[py*(w)+px] = data[py*(w)+px];
+ newdata[((h)-py-1)*(w)+px] = data[py*(w)+px];
+ }
+ }
+ // u component
+ for(py=(hhh); py<hh; py++){
+ for(px=0; px<hw; px++){
+ newdata[u_offset+py*(hw)+px] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ newdata[u_offset+((hh)-py-1)*(hw)+px] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ }
+ }
+ // v component
+ for(py=(hhh); py<hh; py++){
+ for(px=0; px<hw; px++){
+ newdata[v_offset+py*(hw)+px] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ newdata[v_offset+((hh)-py-1)*(hw)+px] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ }
+ }
+ break;
+ case 3 :
+ // y component
+ for(py=0; py<h; py++){
+ for(px=0; px<(hw); px++){
+ newdata[py*(w)+px] = data[py*(w)+px];
+ newdata[py*(w)+((w)-px-1)] = data[py*(w)+px];
+ }
+ }
+ // u component
+ for(py=0; py<hh; py++){
+ for(px=0; px<(hhw); px++){
+ newdata[u_offset+py*(hw)+px] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ newdata[u_offset+py*(hw)+((hw)-px-1)] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ }
+ }
+ // v component
+ for(py=0; py<hh; py++){
+ for(px=0; px<(hhw); px++){
+ newdata[v_offset+py*(hw)+px] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ newdata[v_offset+py*(hw)+((hw)-px-1)] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ }
+ }
+ break;
+ case 4 :
+ // y component
+ for(py=0; py<h; py++){
+ for(px=(hw); px<w; px++){
+ newdata[py*(w)+px] = data[py*(w)+px];
+ newdata[py*(w)+((w)-px-1)] = data[py*(w)+px];
+ }
+ }
+ // u component
+ for(py=0; py<hh; py++){
+ for(px=(hhw); px<hw; px++){
+ newdata[u_offset+py*(hw)+px] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ newdata[u_offset+py*(hw)+((hw)-px-1)] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ }
+ }
+ // u component
+ for(py=0; py<hh; py++){
+ for(px=(hhw); px<hw; px++){
+ newdata[u_offset+py*(hw)+px] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ newdata[u_offset+py*(hw)+((hw)-px-1)] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ }
+ }
+ break;
+ case 5 :
+ // y component
+ for(py=0; py<(hh); py++){
+ for(px=0; px<(hw); px++){
+ newdata[py*(w)+px] = data[py*(w)+px];
+ newdata[py*(w)+((w)-px-1)] = data[py*(w)+px];
+ newdata[((h)-py-1)*(w)+px] = data[py*(w)+px];
+ newdata[((h)-py-1)*(w)+((w)-px-1)] = data[py*(w)+px];
+ }
+ }
+ // u component
+ for(py=0; py<(hhh); py++){
+ for(px=0; px<(hhw); px++){
+ newdata[u_offset+py*(hw)+px] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ newdata[u_offset+py*(hw)+((hw)-px-1)] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ newdata[u_offset+((hh)-py-1)*(hw)+px] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ newdata[u_offset+((hh)-py-1)*(w)+((hw)-px-1)] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ }
+ }
+ // v component
+ for(py=0; py<(hhh); py++){
+ for(px=0; px<(hhw); px++){
+ newdata[v_offset+py*(hw)+px] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ newdata[v_offset+py*(hw)+((hw)-px-1)] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ newdata[v_offset+((hh)-py-1)*(hw)+px] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ newdata[v_offset+((hh)-py-1)*(hw)+((hw)-px-1)] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ }
+ }
+ break;
+ case 6 :
+ // y component
+ for(py=0; py<(hh); py++){
+ for(px=(hw); px<w; px++){
+ newdata[py*(w)+px] = data[py*(w)+px];
+ newdata[py*(w)+((w)-px-1)] = data[py*(w)+px];
+ newdata[((h)-py-1)*(w)+px] = data[py*(w)+px];
+ newdata[((h)-py-1)*(w)+((w)-px-1)] = data[py*(w)+px];
+ }
+ }
+ // u component
+ for(py=0; py<(hhh); py++){
+ for(px=(hhw); px<(hw); px++){
+ newdata[u_offset+py*(hw)+px] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ newdata[u_offset+py*(hw)+((hw)-px-1)] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ newdata[u_offset+((hh)-py-1)*(hw)+px] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ newdata[u_offset+((hh)-py-1)*(hw)+((hw)-px-1)] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ }
+ }
+ // v component
+ for(py=0; py<(hhh); py++){
+ for(px=(hhw); px<(hw); px++){
+ newdata[v_offset+py*(hw)+px] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ newdata[v_offset+py*(hw)+((hw)-px-1)] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ newdata[v_offset+((hh)-py-1)*(hw)+px] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ newdata[v_offset+((hh)-py-1)*(hw)+((hw)-px-1)] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ }
+ }
+ break;
+ case 7 :
+ // y component
+ for(py=(hh); py<(h); py++){
+ for(px=0; px<(hw); px++){
+ newdata[py*(w)+px] = data[py*(w)+px];
+ newdata[py*(w)+((w)-px-1)] = data[py*(w)+px];
+ newdata[((h)-py-1)*(w)+px] = data[py*(w)+px];
+ newdata[((h)-py-1)*(w)+((w)-px-1)] = data[py*(w)+px];
+ }
+ }
+ // u component
+ for(py=(hhh); py<(hh); py++){
+ for(px=0; px<(hhw); px++){
+ newdata[u_offset+py*(hw)+px] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ newdata[u_offset+py*(hw)+((hw)-px-1)] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ newdata[u_offset+((hh)-py-1)*(hw)+px] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ newdata[u_offset+((hh)-py-1)*(hw)+((hw)-px-1)] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ }
+ }
+ // v component
+ for(py=(hhh); py<(hh); py++){
+ for(px=0; px<(hhw); px++){
+ newdata[v_offset+py*(hw)+px] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ newdata[v_offset+py*(hw)+((hw)-px-1)] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ newdata[v_offset+((hh)-py-1)*(hw)+px] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ newdata[v_offset+((hh)-py-1)*(hw)+((hw)-px-1)] = data[v_offset+py*(hw)+px]^ x->x_color;
+ }
+ }
+ break;
+ case 8 :
+ // y component
+ for(py=(hh); py<h; py++){
+ for(px=(hw); px<w; px++){
+ newdata[py*(w)+px] = data[py*(w)+px];
+ newdata[py*(w)+((w)-px-1)] = data[py*(w)+px];
+ newdata[((h)-py-1)*(w)+px] = data[py*(w)+px];
+ newdata[((h)-py-1)*(w)+((w)-px-1)] = data[py*(w)+px];
+ }
+ }
+ // u component
+ for(py=(hhh); py<(hh); py++){
+ for(px=(hhw); px<(hw); px++){
+ newdata[u_offset+py*(hw)+px] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ newdata[u_offset+py*(hw)+((hw)-px-1)] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ newdata[u_offset+((hh)-py-1)*(hw)+px] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ newdata[u_offset+((hh)-py-1)*(hw)+((hw)-px-1)] = data[u_offset+py*(hw)+px] ^ x->x_color;
+ }
+ }
+ // v component
+ for(py=(hhh); py<(hh); py++){
+ for(px=(hhw); px<(hw); px++){
+ newdata[v_offset+py*(hw)+px] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ newdata[v_offset+py*(hw)+((hw)-px-1)] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ newdata[v_offset+((hh)-py-1)*(hw)+px] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ newdata[v_offset+((hh)-py-1)*(hw)+((hw)-px-1)] = data[v_offset+py*(hw)+px] ^ x->x_color;
+ }
+ }
+ break;
+ }
+ // post( "pdp_simura : size=%d tsize=%d", size, (int)(size + (size>>1))<<1 );
+
+ /* delete source packet and replace with new packet */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = newpacket;
+ return;
+}
+
+static void pdp_simura_sendpacket(t_pdp_simura *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_simura_process(t_pdp_simura *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_simura_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_simura_process_yv12, pdp_simura_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ // pdp_simura_process_packet(x);
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_simura_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_simura_input_0(t_pdp_simura *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_simura_process(x);
+ }
+}
+
+static void pdp_simura_color(t_pdp_simura *x, t_floatarg fcolor )
+{
+ if ( (int)fcolor >0 && (int)fcolor < 0xFFFF )
+ {
+ x->x_color = (unsigned short int)fcolor;
+ }
+ else
+ {
+ post( "pdp_simura : wrong color %d", (int) fcolor );
+ }
+}
+
+static void pdp_simura_mode(t_pdp_simura *x, t_floatarg fmode )
+{
+ if ( (int)fmode >=0 && (int)fmode <= 8 )
+ {
+ x->x_mode = (int)fmode;
+ }
+ else
+ {
+ post( "pdp_simura : wrong mode : %d : must be 0<=mode<=8", (int)fmode );
+ }
+}
+
+
+static void pdp_simura_free(t_pdp_simura *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_simura_class;
+
+void *pdp_simura_new(void)
+{
+ int i;
+
+ t_pdp_simura *x = (t_pdp_simura *)pd_new(pdp_simura_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("color"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("mode"));
+
+ 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_color = 0;
+ x->x_mode = 0; // no mirror
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_simura_setup(void)
+{
+// post( pdp_simura_version );
+
+ pdp_simura_class = class_new(gensym("pdp_simura"), (t_newmethod)pdp_simura_new,
+ (t_method)pdp_simura_free, sizeof(t_pdp_simura), 0, A_NULL);
+
+ class_addmethod(pdp_simura_class, (t_method)pdp_simura_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_simura_class, (t_method)pdp_simura_color, gensym("color"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_simura_class, (t_method)pdp_simura_mode, gensym("mode"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_smuck.c b/modules/pdp_smuck.c
new file mode 100644
index 0000000..968bea4
--- /dev/null
+++ b/modules/pdp_smuck.c
@@ -0,0 +1,228 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 adaptation of smuck effect from veejay
+ * But it it inspired by effectv's transform ( mode 5 )
+ * Originally written by Niels Elburg
+ * Pd-fication by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+#define MAX_N 100
+
+static int fastrand_val=0;
+#define inline_fastrand() (fastrand_val=fastrand_val*1103515245+12345)
+
+static char *pdp_smuck_version = "pdp_smuck: version 0.1, port of smuck from veejay( Fukuchi Kentaro ) adapted by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_smuck_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_n; // transform number
+
+} t_pdp_smuck;
+
+static void pdp_smuck_free_ressources(t_pdp_smuck *x)
+{
+ // nothing
+}
+
+static void pdp_smuck_allocate(t_pdp_smuck *x)
+{
+ // nothing
+}
+
+static void pdp_smuck_n(t_pdp_smuck *x, t_floatarg fn )
+{
+ if ( ( fn >= 0 ) && ( fn < MAX_N ) )
+ {
+ x->x_n = fn;
+ }
+}
+
+static void pdp_smuck_process_yv12(t_pdp_smuck *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 px, py, pxx, pyy;
+ short int *pnY, *pnU, *pnV;
+
+ /* allocate all ressources */
+ if ( (int)(header->info.image.width*header->info.image.height) != x->x_vsize )
+ {
+ pdp_smuck_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_smuck_allocate(x);
+ post( "pdp_smuck : reallocated buffers" );
+ }
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ pnY = newdata;
+ pnV = newdata+x->x_vsize;
+ pnU = newdata+x->x_vsize+(x->x_vsize>>2);
+
+ for (py = 0; py < x->x_vheight; py++) {
+ for (px = 0; px < x->x_vwidth; px++) {
+ pyy = py + (inline_fastrand() >> x->x_n) - 2;
+ pxx = px + (inline_fastrand() >> x->x_n) - 2;
+ if (pxx > x->x_vwidth)
+ pxx = x->x_vwidth;
+ if ( pxx < 0 ) pxx = 0;
+ if (pyy > x->x_vheight)
+ pyy = x->x_vheight;
+ if ( pyy < 0 ) pyy = 0;
+ *pnY++ = *( data + pyy*x->x_vwidth + pxx );
+ if ( (px%2==0) && (py%2==0) )
+ {
+ *pnU++ = *( data + x->x_vsize + ( (pyy>>1)*(x->x_vwidth>>1) + (pxx>>2) ) );
+ *pnV++ = *( data + x->x_vsize + (x->x_vsize>>2) + ( (pyy>>1)*(x->x_vwidth>>1) + (pxx>>2) ) );
+ }
+ }
+ }
+
+ return;
+}
+
+static void pdp_smuck_sendpacket(t_pdp_smuck *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_smuck_process(t_pdp_smuck *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_smuck_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_smuck_process_yv12, pdp_smuck_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_smuck_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_smuck_input_0(t_pdp_smuck *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_smuck_process(x);
+ }
+}
+
+static void pdp_smuck_free(t_pdp_smuck *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_smuck_free_ressources(x);
+}
+
+t_class *pdp_smuck_class;
+
+void *pdp_smuck_new(void)
+{
+ int i;
+
+ t_pdp_smuck *x = (t_pdp_smuck *)pd_new(pdp_smuck_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("n"));
+
+ 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_n = 30;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_smuck_setup(void)
+{
+// post( pdp_smuck_version );
+ pdp_smuck_class = class_new(gensym("pdp_smuck"), (t_newmethod)pdp_smuck_new,
+ (t_method)pdp_smuck_free, sizeof(t_pdp_smuck), 0, A_NULL);
+
+ class_addmethod(pdp_smuck_class, (t_method)pdp_smuck_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_smuck_class, (t_method)pdp_smuck_n, gensym("n"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_spigot.c b/modules/pdp_spigot.c
new file mode 100644
index 0000000..3b79bb1
--- /dev/null
+++ b/modules/pdp_spigot.c
@@ -0,0 +1,168 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* This object is video packet routing utility
+ * Written by Yves Degoyon ( ydegoyon@free.fr )
+ */
+
+
+#include "pdp.h"
+#include <math.h>
+
+static char *pdp_spigot_version = "pdp_spigot: version 0.1, a video packets routing utility";
+
+typedef struct pdp_spigot_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+ t_outlet *x_outlet1;
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+
+ t_int x_packet0;
+ t_int x_toggle;
+
+} t_pdp_spigot;
+
+static void pdp_spigot_toggle(t_pdp_spigot *x, t_floatarg ftoggle )
+{
+ if ( ( ftoggle == 0 ) || ( ftoggle == 1 ) )
+ {
+ x->x_toggle = ftoggle;
+ }
+}
+
+static void pdp_spigot_process_packet(t_pdp_spigot *x)
+{
+ t_pdp *header = pdp_packet_header(x->x_packet0);
+ short int *data = (short int *)pdp_packet_data(x->x_packet0);
+ t_pdp *newheader = 0;
+ short int *newdata = 0;
+ t_int newpacket = -1, i;
+
+ x->x_vwidth = header->info.image.width;
+ x->x_vheight = header->info.image.height;
+ x->x_vsize = x->x_vwidth*x->x_vheight;
+
+ return;
+}
+
+static void pdp_spigot_process(t_pdp_spigot *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_spigot_process inputs and write into active inlet */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding)
+ {
+
+ case PDP_IMAGE_YV12:
+ pdp_spigot_process_packet(x);
+ 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_spigot_process */
+ break;
+
+ }
+ }
+
+ /* propagate if valid */
+ if(x->x_packet0 != -1){
+ if ( x->x_toggle )
+ {
+ pdp_packet_pass_if_valid(x->x_outlet1, &x->x_packet0);
+ }
+ else
+ {
+ pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet0);
+ }
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = -1;
+ }
+
+}
+
+static void pdp_spigot_input_0(t_pdp_spigot *x, t_symbol *s, t_floatarg f)
+{
+ if (s == gensym("register_rw")){
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = pdp_packet_convert_rw((int)f, pdp_gensym("image/YCrCb/*") );
+ }
+ else if (s == gensym("process")){
+ pdp_spigot_process(x);
+ }
+}
+
+static void pdp_spigot_free(t_pdp_spigot *x)
+{
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_spigot_class;
+
+void *pdp_spigot_new(void)
+{
+ int i;
+
+ t_pdp_spigot *x = (t_pdp_spigot *)pd_new(pdp_spigot_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("toggle"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_spigot_setup(void)
+{
+// post( pdp_spigot_version );
+ pdp_spigot_class = class_new(gensym("pdp_spigot"), (t_newmethod)pdp_spigot_new,
+ (t_method)pdp_spigot_free, sizeof(t_pdp_spigot), 0, A_NULL);
+
+ class_addmethod(pdp_spigot_class, (t_method)pdp_spigot_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_spigot_class, (t_method)pdp_spigot_toggle, gensym("toggle"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_spiral.c b/modules/pdp_spiral.c
new file mode 100644
index 0000000..a97442b
--- /dev/null
+++ b/modules/pdp_spiral.c
@@ -0,0 +1,519 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 adaptation of warp effect from effectv
+ * copyright (c) 2001 Sam Mertens.
+ * Pd-fication by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+#define PLANE_POWER (4) // 2 exp 4 = 16
+#define WAVE_COUNT_POWER (3) // 2 exp 3 = 8
+#define WAVE_LENGTH_POWER (9) // 2 exp 9 = 512
+
+#define PLANES (1 << PLANE_POWER) // 16
+#define PLANE_MASK (PLANES - 1)
+#define PLANE_MAX (PLANES - 1)
+
+#define WAVE_COUNT (1 << WAVE_COUNT_POWER) // 8
+#define WAVE_MASK (WAVE_COUNT - 1)
+#define WAVE_MAX (WAVE_COUNT - 1)
+
+#define WAVE_LENGTH (1 << WAVE_LENGTH_POWER) // 512
+#define WAVE_LENGTH_MASK (WAVE_LENGTH - 1)
+
+
+#define WAVE_CONCENTRIC_A 0
+#define WAVE_SAWTOOTH_UP 1
+#define WAVE_SAWTOOTH_DOWN 2
+#define WAVE_TRIANGLE 3
+
+#define WAVE_SINUS 4
+#define WAVE_CONCENTRIC_B 5
+#define WAVE_LENS 6
+#define WAVE_FLAT 7
+
+/* The *_OFFSET predefines are just precalculations. There shouldn't normally
+** be any need to change them.
+*/
+
+#define WAVE_CONCENTRIC_A_OFFSET (WAVE_CONCENTRIC_A * WAVE_LENGTH)
+#define WAVE_SAW_UP_OFFSET (WAVE_SAWTOOTH_UP * WAVE_LENGTH)
+#define WAVE_SAW_DOWN_OFFSET (WAVE_SAWTOOTH_DOWN * WAVE_LENGTH)
+#define WAVE_TRIANGLE_OFFSET (WAVE_TRIANGLE * WAVE_LENGTH)
+
+#define WAVE_CONCENTRIC_B_OFFSET (WAVE_CONCENTRIC_B * WAVE_LENGTH)
+#define WAVE_LENS_OFFSET (WAVE_LENS * WAVE_LENGTH)
+#define WAVE_SINUS_OFFSET (WAVE_SINUS * WAVE_LENGTH)
+#define WAVE_FLAT_OFFSET (WAVE_FLAT * WAVE_LENGTH)
+
+#define WAVE_ELEMENT_SIZE (sizeof(char))
+#define WAVE_TABLE_SIZE (WAVE_COUNT * WAVE_LENGTH * WAVE_ELEMENT_SIZE)
+
+#define FOCUS_INCREMENT_PRESET (M_PI/2.0)
+
+static char *pdp_spiral_version = "pdp_spiral: version 0.1, port of spiral from effectv( Fukuchi Kentaro ) adapted by Yves Degoyon (ydegoyon@free.fr)";
+
+static char* the_wave_table = NULL;
+
+typedef struct pdp_spiral_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;
+ short int *x_buffer;
+ short int *x_planetable[PLANES];
+ t_int x_plane;
+ t_int *x_depthmap;
+ t_int x_mode;
+ t_int x_focus_x;
+ t_int x_focus_y;
+ t_int x_cursor_state;
+ t_int x_cursor_local;
+ t_int x_toggle_xor;
+ t_int x_animate_focus;
+ t_int x_focus_interval;
+ t_int x_focus_counter;
+ unsigned int x_depth_shift; // Cheesy way to adjust intensity
+ t_int x_focus_radius;
+ double x_focus_degree;
+ double x_focus_increment;
+
+} t_pdp_spiral;
+
+static void pdp_spiral_define_waves(t_pdp_spiral *x)
+{
+ t_int i, w, iw;
+ double sinus_val = M_PI/2.0;
+
+ if (NULL == the_wave_table) return;
+
+ w = ((int)sqrt(x->x_vheight * x->x_vheight + x->x_vwidth * x->x_vwidth));
+ for (i=0; i<WAVE_LENGTH; i++)
+ {
+ the_wave_table[WAVE_FLAT_OFFSET + i] = 0;
+
+ the_wave_table[WAVE_SAW_UP_OFFSET + i] = i & PLANE_MASK;
+ the_wave_table[WAVE_SAW_DOWN_OFFSET + i] = PLANE_MAX - (i & PLANE_MASK);
+ if (i & PLANES)
+ {
+ the_wave_table[WAVE_TRIANGLE_OFFSET + i] = (~i) & PLANE_MASK;
+ }
+ else
+ {
+ the_wave_table[WAVE_TRIANGLE_OFFSET + i] = i & PLANE_MASK;
+ }
+
+ iw = i / (w/(PLANES*2));
+
+ if (iw & PLANES)
+ {
+ the_wave_table[WAVE_CONCENTRIC_A_OFFSET + i] = (~iw) & PLANE_MASK;
+ }
+ else
+ {
+ the_wave_table[WAVE_CONCENTRIC_A_OFFSET + i] = iw & PLANE_MASK;
+ }
+
+ the_wave_table[WAVE_CONCENTRIC_B_OFFSET + i] = (i*PLANES)/w;
+ the_wave_table[WAVE_LENS_OFFSET + i] = i >> 3;
+ the_wave_table[WAVE_SINUS_OFFSET + i] = ((PLANES/2) +
+ (int)((PLANES/2 - 1) * sin(sinus_val))) & PLANE_MASK;
+ sinus_val += M_PI/PLANES;
+ }
+
+}
+
+void pdp_spiral_create_map(t_pdp_spiral *x)
+{
+ t_int px, py, rel_x, rel_y, yy;
+ float x_ratio;
+ float y_ratio;
+ t_int v, i, wave_offset;
+
+ if ( x->x_vsize == -1 )
+ {
+ post( "pdp_spiral : create_map : no video data" );
+ return;
+ }
+
+ /*
+ ** The following code generates the default depth map.
+ */
+ i = 0;
+ wave_offset = x->x_mode * WAVE_LENGTH;
+
+ x_ratio = 320.0 / x->x_vwidth;
+ y_ratio = 240.0 / x->x_vheight;
+
+ for (py=0; py<x->x_vheight; py++)
+ {
+ rel_y = (x->x_focus_y - py) * y_ratio;
+ yy = rel_y * rel_y;
+
+ for(px=0; px<x->x_vwidth; px++)
+ {
+ rel_x = (x->x_focus_x - px) * x_ratio;
+ v = ((int)sqrt(yy + rel_x*rel_x)) & WAVE_LENGTH_MASK;
+ x->x_depthmap[i++] = the_wave_table[wave_offset + v] >> x->x_depth_shift;
+ }
+ }
+
+ return;
+}
+
+static void pdp_spiral_mode(t_pdp_spiral *x, t_floatarg fmode )
+{
+ if ( ( fmode > 0 ) || ( fmode < WAVE_COUNT ) )
+ {
+ x->x_mode = (int)fmode;
+ pdp_spiral_create_map(x);
+ }
+}
+
+static void pdp_spiral_focus_x(t_pdp_spiral *x, t_floatarg ffocusx )
+{
+ if ( ( ffocusx > 0 ) || ( ffocusx < x->x_vwidth ) )
+ {
+ x->x_focus_x = (int)ffocusx;
+ pdp_spiral_create_map(x);
+ }
+}
+
+static void pdp_spiral_focus_y(t_pdp_spiral *x, t_floatarg ffocusy )
+{
+ if ( ( ffocusy > 0 ) || ( ffocusy < x->x_vwidth ) )
+ {
+ x->x_focus_y = (int)ffocusy;
+ pdp_spiral_create_map(x);
+ }
+}
+
+static void pdp_spiral_depth_shift(t_pdp_spiral *x, t_floatarg fdepthshift )
+{
+ if ( ( fdepthshift > 0 ) || ( fdepthshift < 5 ) )
+ {
+ x->x_depth_shift = (int)fdepthshift;
+ pdp_spiral_create_map(x);
+ }
+}
+
+static void pdp_spiral_focus_interval(t_pdp_spiral *x, t_floatarg finterval )
+{
+ if ( ( finterval > 0 ) || ( finterval < 60 ) )
+ {
+ x->x_focus_interval = (int)finterval;
+ }
+}
+
+static void pdp_spiral_focus_increment(t_pdp_spiral *x, t_floatarg fincrement )
+{
+ if ( fincrement > 0 )
+ {
+ x->x_focus_increment = (int)fincrement;
+ }
+}
+
+static void pdp_spiral_toggle_xor(t_pdp_spiral *x, t_floatarg fxor )
+{
+ if ( ( fxor ==0 ) || ( fxor == 1 ) )
+ {
+ x->x_toggle_xor = (int)fxor;
+ }
+}
+
+static void pdp_spiral_animate_focus(t_pdp_spiral *x, t_floatarg fafocus )
+{
+ if ( ( fafocus ==0 ) || ( fafocus == 1 ) )
+ {
+ x->x_animate_focus = (int)fafocus;
+ }
+}
+
+static void pdp_spiral_free_ressources(t_pdp_spiral *x)
+{
+ if ( the_wave_table ) free ( the_wave_table );
+ if ( x->x_buffer ) free ( x->x_buffer );
+ if ( x->x_depthmap ) free ( x->x_depthmap );
+}
+
+static void pdp_spiral_allocate(t_pdp_spiral *x)
+{
+ int i;
+
+ the_wave_table = (char*) malloc (WAVE_TABLE_SIZE);
+ x->x_focus_radius = x->x_vwidth / 2;
+
+ // allocate space for the frame buffers. A lot of memory is required -
+ // with the default settings, it totals nearly 5 megs.
+ x->x_buffer = (short int *) malloc ( ( ( x->x_vsize + x->x_vsize>>1 ) << 1 ) * 2 * PLANES);
+
+ // set up the array of pointers to the frame buffers
+ for(i=0;i<PLANES;i++)
+ {
+ x->x_planetable[i] = &x->x_buffer[ ( ( x->x_vsize + x->x_vsize>>1 ) << 1 ) * i];
+ }
+
+ x->x_depthmap = (t_int*) malloc ( x->x_vsize * sizeof ( t_int ) );
+
+ if ( !the_wave_table || !x->x_buffer || !x->x_depthmap )
+ {
+ post( "pdp_spiral : severe error : cannot allocate buffers !!! ");
+ return;
+ }
+}
+
+static void pdp_spiral_move_focus(t_pdp_spiral *x)
+{
+ x->x_focus_counter++;
+ // We'll only switch maps every X frames.
+ if (x->x_focus_interval <= x->x_focus_counter)
+ {
+ x->x_focus_counter = 0;
+ x->x_focus_x = (x->x_focus_radius * cos(x->x_focus_degree)) + (x->x_vwidth/2);
+ x->x_focus_y = (x->x_focus_radius * sin(x->x_focus_degree*2.0)) + (x->x_vheight/2);
+ pdp_spiral_create_map(x);
+ x->x_focus_degree += x->x_focus_increment;
+ if ((2.0*M_PI) <= x->x_focus_degree)
+ {
+ x->x_focus_degree -= (2.0*M_PI);
+ }
+ }
+}
+
+static void pdp_spiral_process_yv12(t_pdp_spiral *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);
+ int i, iu;
+
+ unsigned int totalnbpixels;
+ unsigned int u_offset;
+ unsigned int v_offset;
+ unsigned int totnbpixels;
+
+ int px, py;
+ int cf;
+
+ /* allocate all ressources */
+ if ( (int)(header->info.image.width*header->info.image.height) != x->x_vsize )
+ {
+ pdp_spiral_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;
+ x->x_focus_x = (x->x_vwidth/2);
+ x->x_focus_y = (x->x_vheight/2);
+ x->x_plane = PLANE_MAX;
+ pdp_spiral_allocate(x);
+ post( "pdp_spiral : reallocated buffers" );
+ pdp_spiral_define_waves( x );
+ pdp_spiral_create_map( x );
+ post( "pdp_spiral : set wave table" );
+ }
+
+ totalnbpixels = x->x_vsize;
+ u_offset = x->x_vsize;
+ v_offset = x->x_vsize + (x->x_vsize>>2);
+ totnbpixels = x->x_vsize + (x->x_vsize>>1);
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ // post( "pdp_spiral : buffer=%x limit=%x dest=%x size=%d data=%x plane=%d",
+ // x->x_buffer, x->x_buffer + ( ( x->x_vsize + x->x_vsize>>1 ) << 1 ) * PLANES - 1,
+ // x->x_planetable[x->x_plane], ( ( x->x_vsize + x->x_vsize>>1) << 1 ), data, x->x_plane );
+ memcpy( x->x_planetable[x->x_plane], data, ( ( x->x_vsize + x->x_vsize>>1 ) << 1 ) );
+
+ if (x->x_animate_focus)
+ {
+ pdp_spiral_move_focus(x);
+ }
+
+ i = 0;
+ iu = 0;
+ for(py = 0; py < x->x_vheight; py++)
+ {
+ for(px = 0; px < x->x_vwidth; px++)
+ {
+ cf = (x->x_plane + x->x_depthmap[i]) & PLANE_MASK;
+ newdata[i] = (x->x_planetable[cf])[i];
+ // u & v are untouched
+ newdata[x->x_vsize+iu] = data[x->x_vsize+iu];
+ newdata[x->x_vsize+(x->x_vsize>>2)+iu] = data[x->x_vsize+(x->x_vsize>>2)+iu];
+ i++;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ iu++;
+ }
+ }
+ }
+
+ x->x_plane--;
+ x->x_plane &= PLANE_MASK;
+
+ return;
+}
+
+static void pdp_spiral_sendpacket(t_pdp_spiral *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_spiral_process(t_pdp_spiral *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_spiral_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_spiral_process_yv12, pdp_spiral_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_spiral_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_spiral_input_0(t_pdp_spiral *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_spiral_process(x);
+ }
+}
+
+static void pdp_spiral_free(t_pdp_spiral *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_spiral_free_ressources(x);
+}
+
+t_class *pdp_spiral_class;
+
+void *pdp_spiral_new(void)
+{
+ int i;
+
+ t_pdp_spiral *x = (t_pdp_spiral *)pd_new(pdp_spiral_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("mode"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("focus_x"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("focus_y"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("depth_shift"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("focus_interval"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("focus_increment"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("toggle_xor"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("animate_focus"));
+
+ 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_mode = 0;
+ x->x_cursor_state = 0;
+ x->x_cursor_local = 0;
+ x->x_toggle_xor = 0;
+ x->x_animate_focus = 0;
+ x->x_focus_interval = 6;
+ x->x_focus_counter = 0;
+ x->x_depth_shift = 0; // Cheesy way to adjust intensity
+ x->x_focus_radius = 100;
+ x->x_focus_degree = 1.0;
+ x->x_focus_increment = FOCUS_INCREMENT_PRESET;
+ x->x_buffer = NULL;
+ x->x_depthmap = NULL;
+ the_wave_table = NULL;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_spiral_setup(void)
+{
+// post( pdp_spiral_version );
+ pdp_spiral_class = class_new(gensym("pdp_spiral"), (t_newmethod)pdp_spiral_new,
+ (t_method)pdp_spiral_free, sizeof(t_pdp_spiral), 0, A_NULL);
+
+ class_addmethod(pdp_spiral_class, (t_method)pdp_spiral_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_spiral_class, (t_method)pdp_spiral_mode, gensym("mode"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_spiral_class, (t_method)pdp_spiral_focus_x, gensym("focus_x"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_spiral_class, (t_method)pdp_spiral_focus_y, gensym("focus_y"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_spiral_class, (t_method)pdp_spiral_depth_shift, gensym("depth_shift"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_spiral_class, (t_method)pdp_spiral_depth_shift, gensym("focus_interval"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_spiral_class, (t_method)pdp_spiral_depth_shift, gensym("focus_increment"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_spiral_class, (t_method)pdp_spiral_depth_shift, gensym("toggle_xor"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_spiral_class, (t_method)pdp_spiral_depth_shift, gensym("animate_focus"), A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_text.c b/modules/pdp_text.c
new file mode 100644
index 0000000..81bd83f
--- /dev/null
+++ b/modules/pdp_text.c
@@ -0,0 +1,630 @@
+/*
+ * PiDiP module
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 text rendering object for PDP
+ * It uses imlib2 for all graphical operations
+ */
+
+/* Listening to :
+ * Deviants - Nothing Man
+ * Monte Cazzaza - Kick That Habit Man
+ */
+
+#include "pdp.h"
+#include "yuv.h"
+#include <math.h>
+#include <ctype.h>
+#include <Imlib2.h> // imlib2 is required
+
+#define DEFAULT_CAPACITY 10
+#define DEFAULT_FONT "helmetr/16"
+
+static char *pdp_text_version = "pdp_text: version 0.2 : text rendering object written by ydegoyon@free.fr";
+
+typedef struct pdp_text_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_packet1;
+ t_int x_dropped;
+ t_int x_queue_id;
+
+ t_outlet *x_outlet0;
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+
+ char **x_text_array;
+ t_int *x_xoffsets;
+ t_int *x_yoffsets;
+ t_int *x_r;
+ t_int *x_g;
+ t_int *x_b;
+ t_float *x_angle;
+ t_int *x_scroll;
+
+ t_int x_nbtexts;
+ t_int x_current;
+ t_int x_capacity;
+
+ /* imlib data */
+ Imlib_Image x_image;
+ Imlib_Font x_font;
+
+} t_pdp_text;
+
+ /* add a new text : syntax : text <my%20text> x y */
+static void pdp_text_add(t_pdp_text *x, t_symbol *s, int argc, t_atom *argv)
+{
+ char *pname;
+ char *pdname;
+
+ if ( x->x_nbtexts >= x->x_capacity )
+ {
+ post( "pdp_text : sorry, maximum capacity has been reached... try resize" );
+ return;
+ }
+
+ if ( argc < 3 )
+ {
+ post( "pdp_text : error in the number of arguments ( minimum is 3 )", argc );
+ return;
+ }
+ if ( argv[0].a_type != A_SYMBOL || argv[1].a_type != A_FLOAT || argv[2].a_type != A_FLOAT ) {
+ post( "pdp_text : add : wrong arguments" );
+ return;
+ }
+
+ // allocate new text area
+ pdname = x->x_text_array[x->x_nbtexts] = (char *) malloc( strlen( argv[0].a_w.w_symbol->s_name ) );
+ pname=argv[0].a_w.w_symbol->s_name;
+ while (*(pname))
+ {
+ if ( (*pname=='%') && ( isdigit(*(pname+1)) || (*(pname+1)=='%') ) )
+ {
+ t_int ivalue;
+ t_int ndigits;
+ char *piname;
+
+ ndigits=0;
+ piname=pname+1;
+ while ( isdigit( *(piname++) ) ) ndigits++;
+
+ ivalue=atoi(pname+1);
+
+ // special case %%
+ if ( ( pname != argv[0].a_w.w_symbol->s_name ) && ( *(pname+1) == '%' ) )
+ {
+ *(pdname++)=*(pname++);
+ pname++;
+ continue;
+ }
+ *(pdname++)=(char)ivalue;
+ pname+=ndigits+1;
+ }
+ else if ( !strncmp( pname, "\"", 1 ) ) // quotes are ignored unless %34
+ {
+ pname++;
+ }
+ else
+ {
+ *(pdname++)=*(pname++);
+ }
+ }
+ *(pdname)='\0';
+ x->x_xoffsets[x->x_nbtexts] = (int)argv[1].a_w.w_float;
+ x->x_yoffsets[x->x_nbtexts] = (int)argv[2].a_w.w_float;
+
+ if ( (argc>=4) && (argv[3].a_type == A_FLOAT) )
+ {
+ x->x_r[x->x_nbtexts] = (int)argv[3].a_w.w_float;
+ }
+ if ( (argc>=5) && (argv[4].a_type == A_FLOAT) )
+ {
+ x->x_g[x->x_nbtexts] = (int)argv[4].a_w.w_float;
+ }
+ if ( (argc>=6) && (argv[5].a_type == A_FLOAT) )
+ {
+ x->x_b[x->x_nbtexts] = (int)argv[5].a_w.w_float;
+ }
+ if ( (argc>=7) && (argv[6].a_type == A_FLOAT) )
+ {
+ x->x_angle[x->x_nbtexts] = argv[6].a_w.w_float;
+ }
+ if ( (argc>=8) && (argv[7].a_type == A_FLOAT) )
+ {
+ x->x_scroll[x->x_nbtexts] = (int)argv[7].a_w.w_float;
+ }
+
+
+ post( "pdp_text : added text >%s< @ %d (r=%d g=%d b=%d)",
+ x->x_text_array[x->x_nbtexts], x->x_nbtexts,
+ x->x_r[x->x_nbtexts], x->x_g[x->x_nbtexts], x->x_b[x->x_nbtexts] );
+
+ if ( x->x_current == -1 ) x->x_current = x->x_nbtexts;
+ x->x_nbtexts++;
+
+}
+
+static void pdp_text_current(t_pdp_text *x, t_floatarg fcurrent )
+{
+ if ( ( fcurrent >= 0 ) && ( fcurrent < x->x_nbtexts ) )
+ {
+ x->x_current = fcurrent;
+ }
+}
+
+static void pdp_text_textx(t_pdp_text *x, t_floatarg fx )
+{
+ if ( ( x->x_current >= 0 ) && ( x->x_current < x->x_nbtexts ) )
+ {
+ x->x_xoffsets[ x->x_current ] = fx;
+ }
+}
+
+static void pdp_text_texty(t_pdp_text *x, t_floatarg fy )
+{
+ if ( ( x->x_current >= 0 ) && ( x->x_current < x->x_nbtexts ) )
+ {
+ x->x_yoffsets[ x->x_current ] = fy;
+ }
+}
+
+static void pdp_text_textr(t_pdp_text *x, t_floatarg fr )
+{
+ if ( ( x->x_current >= 0 ) && ( x->x_current < x->x_nbtexts ) )
+ {
+ x->x_r[ x->x_current ] = fr;
+ }
+}
+
+static void pdp_text_textg(t_pdp_text *x, t_floatarg fg )
+{
+ if ( ( x->x_current >= 0 ) && ( x->x_current < x->x_nbtexts ) )
+ {
+ x->x_g[ x->x_current ] = fg;
+ }
+}
+
+static void pdp_text_textb(t_pdp_text *x, t_floatarg fb )
+{
+ if ( ( x->x_current >= 0 ) && ( x->x_current < x->x_nbtexts ) )
+ {
+ x->x_b[ x->x_current ] = fb;
+ }
+}
+
+static void pdp_text_angle(t_pdp_text *x, t_floatarg fangle )
+{
+ if ( ( x->x_current >= 0 ) && ( x->x_current < x->x_nbtexts ) )
+ {
+ x->x_angle[ x->x_current ] = fangle;
+ }
+}
+
+static void pdp_text_scroll(t_pdp_text *x, t_floatarg fscroll )
+{
+ if ( ( x->x_current >= 0 ) && ( x->x_current < x->x_nbtexts ) )
+ {
+ x->x_scroll[ x->x_current ] = fscroll;
+ }
+}
+
+static void pdp_text_dither(t_pdp_text *x, t_floatarg fdither )
+{
+ imlib_context_set_dither( (char)fdither );
+}
+
+static void pdp_text_blend(t_pdp_text *x, t_floatarg fblend )
+{
+ imlib_context_set_blend( (char)fblend );
+}
+
+static void pdp_text_antialias(t_pdp_text *x, t_floatarg fantialias )
+{
+ imlib_context_set_anti_alias( (char)fantialias );
+}
+
+static void pdp_text_clear(t_pdp_text *x )
+{
+ x->x_nbtexts = 0;
+}
+
+static void pdp_text_delete(t_pdp_text *x, t_floatarg fnum )
+{
+ t_int i;
+ char *lostword;
+
+ if ( ( fnum>0 ) && ( fnum<=x->x_nbtexts ) )
+ {
+ lostword = x->x_text_array[ (int)fnum-1 ];
+ for ( i=(int)fnum; i<x->x_nbtexts; i++ )
+ {
+ x->x_text_array[ i-1 ] = x->x_text_array[ i ];
+ x->x_xoffsets[ i-1 ] = x->x_xoffsets[ i ];
+ x->x_yoffsets[ i-1 ] = x->x_yoffsets[ i ];
+ x->x_r[ i-1 ] = x->x_r[ i ];
+ x->x_g[ i-1 ] = x->x_g[ i ];
+ x->x_b[ i-1 ] = x->x_b[ i ];
+ x->x_angle[ i-1 ] = x->x_angle[ i ];
+ x->x_scroll[ i-1 ] = x->x_scroll[ i ];
+ }
+ x->x_nbtexts--,
+ free( lostword );
+ }
+}
+
+static void pdp_text_resize(t_pdp_text *x, t_floatarg fnewsize )
+{
+ char **text_array;
+ t_int *xoffsets;
+ t_int *yoffsets;
+ t_int *r;
+ t_int *g;
+ t_int *b;
+ t_float *angle;
+ t_int *scroll;
+
+ t_int i, csize;
+
+ if ( (int) fnewsize<=0 ) return;
+
+ // allocate new structures
+ text_array = (char**) getbytes( fnewsize*sizeof(char*) );
+ xoffsets = (t_int*) getbytes( fnewsize*sizeof(t_int) );
+ yoffsets = (t_int*) getbytes( fnewsize*sizeof(t_int) );
+ r = (t_int*) getbytes( fnewsize*sizeof(t_int) );
+ g = (t_int*) getbytes( fnewsize*sizeof(t_int) );
+ b = (t_int*) getbytes( fnewsize*sizeof(t_int) );
+ angle = (t_float*) getbytes( fnewsize*sizeof(t_float) );
+ scroll = (t_int*) getbytes( fnewsize*sizeof(t_int) );
+
+
+ for ( i=0; i<fnewsize; i++ )
+ {
+ r[i] = g[i] = b[i] = 255;
+ }
+
+ if ( fnewsize < x->x_nbtexts )
+ {
+ post( "pdp_text : new size is too small : texts lost !!" );
+ csize = fnewsize;
+ }
+ else
+ {
+ csize = x->x_nbtexts;
+ }
+
+ // copy all values
+ for ( i=0; i<csize; i++ )
+ {
+ text_array[i] = (char*) malloc( strlen( x->x_text_array[i] ) + 1 );
+ strcpy( text_array[i], x->x_text_array[i] );
+ free( x->x_text_array[i] );
+ xoffsets[i] = x->x_xoffsets[i];
+ yoffsets[i] = x->x_yoffsets[i];
+ r[i] = x->x_r[i];
+ g[i] = x->x_g[i];
+ b[i] = x->x_b[i];
+ angle[i] = x->x_angle[i];
+ scroll[i] = x->x_scroll[i];
+ }
+
+ // free old structures
+ if ( x->x_text_array ) freebytes( x->x_text_array, x->x_capacity*sizeof(char*) );
+ if ( x->x_xoffsets ) freebytes( x->x_xoffsets, x->x_capacity*sizeof(t_int) );
+ if ( x->x_yoffsets ) freebytes( x->x_yoffsets, x->x_capacity*sizeof(t_int) );
+ if ( x->x_r ) freebytes( x->x_r, x->x_capacity*sizeof(t_int) );
+ if ( x->x_g ) freebytes( x->x_g, x->x_capacity*sizeof(t_int) );
+ if ( x->x_b ) freebytes( x->x_b, x->x_capacity*sizeof(t_int) );
+ if ( x->x_angle) freebytes( x->x_angle, x->x_capacity*sizeof(t_float) );
+ if ( x->x_scroll) freebytes( x->x_scroll, x->x_capacity*sizeof(t_int) );
+
+ // set new structures
+ x->x_text_array = text_array;
+ x->x_xoffsets = xoffsets;
+ x->x_yoffsets = yoffsets;
+ x->x_r = r;
+ x->x_g = g;
+ x->x_b = b;
+ x->x_angle = angle;
+ x->x_scroll = scroll;
+ x->x_nbtexts = csize;
+ x->x_capacity = csize;
+ if ( x->x_nbtexts > 0 )
+ {
+ x->x_current = 0;
+ }
+ else
+ {
+ x->x_current = -1;
+ }
+}
+
+static void pdp_text_font(t_pdp_text *x, t_symbol *sfont )
+{
+ Imlib_Font font;
+
+ font = imlib_load_font(sfont->s_name);
+ if ( !font )
+ {
+ post( "pdp_text : could not load font : >%s<", sfont->s_name );
+ return;
+ }
+ imlib_context_set_font( font );
+ x->x_font = font;
+}
+
+static void pdp_text_allocate(t_pdp_text *x)
+{
+ x->x_image = imlib_create_image( x->x_vwidth, x->x_vheight );
+ if ( x->x_image == NULL )
+ {
+ post( "pdp_text : severe error : could not allocate image !!" );
+ return;
+ }
+ imlib_context_set_image(x->x_image);
+}
+
+static void pdp_text_free_ressources(t_pdp_text *x)
+{
+ if ( x->x_image != NULL ) imlib_free_image();
+}
+
+static void pdp_text_process_yv12(t_pdp_text *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 ti;
+ t_int px, py;
+ unsigned char y, u, v;
+ DATA32 *imdata;
+ DATA32 bgcolor;
+ short int *pY, *pU, *pV;
+ int text_width, text_height;
+
+ if ( ( (int)(header->info.image.width) != x->x_vwidth ) ||
+ ( (int)(header->info.image.height) != x->x_vheight ) )
+ {
+ pdp_text_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_text_allocate(x);
+ }
+
+ 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 );
+
+ // draw all texts
+ imlib_image_clear();
+ imlib_context_set_direction(IMLIB_TEXT_TO_ANGLE);
+ imdata = imlib_image_get_data();
+ bgcolor = imdata[0];
+
+ for (ti=0; ti<x->x_nbtexts; ti++)
+ {
+ imlib_context_set_angle( x->x_angle[ti] );
+ imlib_context_set_color( x->x_r[ti], x->x_g[ti], x->x_b[ti], 255 );
+
+ imlib_get_text_size( x->x_text_array[ti], &text_width, &text_height);
+
+ imlib_text_draw( x->x_xoffsets[ti] - (0.5*text_width) + (cos(x->x_angle[ti]) * x->x_scroll[ti]), x->x_yoffsets[ti] - (0.5*text_height) + (sin(x->x_angle[ti]) * x->x_scroll[ti]), x->x_text_array[ti] );
+ }
+
+ pY = newdata;
+ pV = newdata+x->x_vsize;
+ pU = newdata+x->x_vsize+(x->x_vsize>>2);
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ if ( imdata[py*x->x_vwidth+px] != bgcolor )
+ {
+ y = yuv_RGBtoY(imdata[py*x->x_vwidth+px]);
+ u = yuv_RGBtoU(imdata[py*x->x_vwidth+px]);
+ v = yuv_RGBtoV(imdata[py*x->x_vwidth+px]);
+
+ *(pY) = y<<7;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ *(pV) = (v-128)<<8;
+ *(pU) = (u-128)<<8;
+ }
+ }
+ pY++;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ pV++;pU++;
+ }
+ }
+ }
+
+ return;
+}
+
+static void pdp_text_sendpacket(t_pdp_text *x)
+{
+ /* delete source 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_text_process(t_pdp_text *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_text_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_text_process_yv12, pdp_text_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_text_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_text_input_0(t_pdp_text *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_text_process(x);
+
+ }
+
+}
+
+static void pdp_text_free(t_pdp_text *x)
+{
+ int i;
+
+ pdp_text_free_ressources(x);
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_text_class;
+
+void *pdp_text_new(void)
+{
+ int i;
+
+ t_pdp_text *x = (t_pdp_text *)pd_new(pdp_text_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("current"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("textx"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("texty"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("textr"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("textg"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("textb"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("angle"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("scroll"));
+
+ 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_image = NULL;
+
+ x->x_font = imlib_context_get_font();
+
+ x->x_capacity = DEFAULT_CAPACITY;
+
+
+ x->x_text_array = (char**) getbytes( x->x_capacity*sizeof(char*) );
+ x->x_xoffsets = (t_int*) getbytes( x->x_capacity*sizeof(t_int) );
+ x->x_yoffsets = (t_int*) getbytes( x->x_capacity*sizeof(t_int) );
+ x->x_r = (t_int*) getbytes( x->x_capacity*sizeof(t_int) );
+ x->x_g = (t_int*) getbytes( x->x_capacity*sizeof(t_int) );
+ x->x_b = (t_int*) getbytes( x->x_capacity*sizeof(t_int) );
+ x->x_angle = (t_float*) getbytes( x->x_capacity*sizeof(t_float) );
+ x->x_scroll = (t_int*) getbytes( x->x_capacity*sizeof(t_int) );
+
+ for ( i=0; i<x->x_capacity; i++ )
+ {
+ x->x_r[i] = x->x_g[i] = x->x_b[i] = 255;
+ }
+
+ x->x_nbtexts = 0;
+ x->x_current = -1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_text_setup(void)
+{
+ Imlib_Font font;
+
+ post( pdp_text_version );
+ pdp_text_class = class_new(gensym("pdp_text"), (t_newmethod)pdp_text_new,
+ (t_method)pdp_text_free, sizeof(t_pdp_text), 0, A_NULL);
+
+ class_addmethod(pdp_text_class, (t_method)pdp_text_input_0, gensym("pdp"),
+ A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_text_class, (t_method)pdp_text_add, gensym("text"), A_GIMME, A_NULL);
+ class_addmethod(pdp_text_class, (t_method)pdp_text_current, gensym("current"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_text_class, (t_method)pdp_text_textx, gensym("textx"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_text_class, (t_method)pdp_text_texty, gensym("texty"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_text_class, (t_method)pdp_text_textr, gensym("textr"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_text_class, (t_method)pdp_text_textg, gensym("textg"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_text_class, (t_method)pdp_text_textb, gensym("textb"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_text_class, (t_method)pdp_text_clear, gensym("clear"), A_NULL);
+ class_addmethod(pdp_text_class, (t_method)pdp_text_delete, gensym("delete"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_text_class, (t_method)pdp_text_resize, gensym("resize"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_text_class, (t_method)pdp_text_font, gensym("font"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_text_class, (t_method)pdp_text_angle, gensym("angle"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_text_class, (t_method)pdp_text_scroll, gensym("scroll"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_text_class, (t_method)pdp_text_dither, gensym("dither"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_text_class, (t_method)pdp_text_blend, gensym("blend"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_text_class, (t_method)pdp_text_antialias, gensym("antialias"), A_DEFFLOAT, A_NULL);
+
+ imlib_add_path_to_font_path("/usr/X11R6/lib/X11/fonts/TTF");
+ font = imlib_load_font(DEFAULT_FONT);
+ if ( !font )
+ {
+ post( "pdp_text : severe error : could not load default font : no rendering !!!" );
+ }
+ imlib_context_set_font( font );
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_transform.c b/modules/pdp_transform.c
new file mode 100644
index 0000000..b69f778
--- /dev/null
+++ b/modules/pdp_transform.c
@@ -0,0 +1,357 @@
+/*
+ * PiDiP module
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 port of transform effect from EffecTV
+ * Originally written by clifford smith <nullset@dookie.net>
+ * Pd-fication by Yves Degoyon ( ydegoyon@free.fr )
+ */
+
+
+#include "pdp.h"
+#include <math.h>
+
+#define MAX_TABLES 6
+static unsigned int fastrand_val;
+#define inline_fastrand() (fastrand_val=fastrand_val*1103515245+12345)
+
+static char *pdp_transform_version = "pdp_transform: version 0.1, port of transform from EffecTV by clifford smith, adapted by ydegoyon@free.fr ";
+
+typedef struct pdp_transform_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_packet1;
+ t_int x_dropped;
+ t_int x_queue_id;
+
+ t_outlet *x_outlet0;
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+
+ t_int **x_table_list; // mapping tables
+ t_int **x_table_list_u; // mapping tables
+ t_int x_table; // current table
+ t_int x_t;
+
+
+} t_pdp_transform;
+
+static void pdp_transform_table(t_pdp_transform *x, t_floatarg ftable )
+{
+ if ( ( ftable >= 0 ) && ( ftable < MAX_TABLES ) )
+ {
+ x->x_table = ftable;
+ }
+}
+
+static int pdp_transform_map_from_table(t_pdp_transform *x, t_int px, t_int py, t_int t)
+{
+ int xd,yd;
+
+ yd = py + (inline_fastrand() >> 30)-2;
+ xd = px + (inline_fastrand() >> 30)-2;
+ if (xd > x->x_vwidth) {
+ xd-=1;
+ }
+ return (xd+yd*x->x_vwidth);
+}
+
+static int pdp_transform_map_from_table_u(t_pdp_transform *x, t_int px, t_int py, t_int t)
+{
+ int xd,yd;
+
+ yd = py + (inline_fastrand() >> 30)-2;
+ xd = px + (inline_fastrand() >> 30)-2;
+ if (xd > x->x_vwidth) {
+ xd-=1;
+ }
+ return ((xd>>1)+(yd>>1)*(x->x_vwidth>>1));
+}
+
+static void pdp_transform_square_table_init(t_pdp_transform *x)
+{
+ const int size = 16;
+ t_int px, py, tx, ty;
+
+ for(py=0; py<x->x_vheight; py++)
+ {
+ ty = py % size - size / 2;
+ if((py/size)%2)
+ {
+ ty = py - ty;
+ }
+ else
+ {
+ ty = py + ty;
+ }
+ if(ty<0) ty = 0;
+ if(ty>=x->x_vheight)
+ {
+ ty = x->x_vheight - 1;
+ }
+ for(px=0; px<x->x_vwidth; px++)
+ {
+ tx = px % size - size / 2;
+ if((px/size)%2)
+ {
+ tx = px - tx;
+ }
+ else
+ {
+ tx = px + tx;
+ }
+ if(tx<0) tx = 0;
+ if(tx>=x->x_vwidth) tx = x->x_vwidth - 1;
+ x->x_table_list[5][px+py*x->x_vwidth] = ty*x->x_vwidth+tx;
+ x->x_table_list_u[5][px+py*x->x_vwidth] = (ty>>1)*(x->x_vwidth>>1)+(tx>>1);
+ }
+ }
+}
+
+static void pdp_transform_init_tables(t_pdp_transform *x)
+{
+ t_int px, py;
+
+ for (py=0;py<x->x_vheight;py++)
+ {
+ for (px=0;px<x->x_vwidth;px++)
+ {
+ x->x_table_list[0][px+py*x->x_vwidth] = px+py*x->x_vwidth;
+ x->x_table_list[1][px+py*x->x_vwidth] = (x->x_vwidth-1-px)+py*x->x_vwidth;
+ x->x_table_list[2][px+py*x->x_vwidth] = px+(x->x_vheight-1-py)*x->x_vwidth;
+ x->x_table_list[3][px+py*x->x_vwidth] = (x->x_vwidth-1-px)+(x->x_vheight-1-py)*x->x_vwidth;
+ x->x_table_list_u[0][px+py*x->x_vwidth]= (px>>1)+((py*x->x_vwidth)>>2);
+ x->x_table_list_u[1][px+py*x->x_vwidth] = (x->x_vwidth>>1)-1-(px>>1)+(py>>1)*(x->x_vwidth>>1);
+ x->x_table_list_u[2][px+py*x->x_vwidth] = (px>>1)+((x->x_vheight>>1)-1-(py>>1))*(x->x_vwidth>>1);
+ x->x_table_list_u[3][px+py*x->x_vwidth] = ((x->x_vwidth-1-px)>>1)+((x->x_vheight-1-py)>>1)*(x->x_vwidth>>1);
+ x->x_table_list[4][px+py*x->x_vwidth] = -2; /* Function */
+ x->x_table_list_u[4][px+py*x->x_vwidth] = -2; /* Function */
+ }
+ }
+ pdp_transform_square_table_init(x);
+}
+
+static void pdp_transform_free_ressources(t_pdp_transform *x)
+{
+ int i;
+
+ // free tables
+ for(i=0;i<MAX_TABLES;i++)
+ {
+ if ( x->x_table_list[i] ) freebytes( x->x_table_list[i], x->x_vsize*sizeof(int) );
+ if ( x->x_table_list_u[i] ) freebytes( x->x_table_list_u[i], x->x_vsize*sizeof(int) );
+ }
+}
+
+static void pdp_transform_allocate(t_pdp_transform *x)
+{
+ int i;
+
+ // allocate tables
+ for(i=0;i<MAX_TABLES;i++)
+ {
+ x->x_table_list[i] = (t_int *) getbytes( x->x_vsize*sizeof(int) );
+ x->x_table_list_u[i] = (t_int *) getbytes( x->x_vsize*sizeof(int) );
+ }
+}
+
+static void pdp_transform_process_yv12(t_pdp_transform *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, iu;
+ t_int px, py;
+ t_int d, o, du=0, ou;
+ short int *pY, *pU, *pV, *pnY, *pnU, *pnV;
+
+ /* allocate all ressources */
+ if ( ((int)header->info.image.width != x->x_vwidth) ||
+ ((int)header->info.image.height != x->x_vheight) )
+ {
+ pdp_transform_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_transform_allocate(x);
+ post( "pdp_transform : reallocated buffers" );
+ pdp_transform_init_tables(x);
+ post( "pdp_transform : initialized tables" );
+ }
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ x->x_t++;
+
+ pnY = newdata;
+ pnV = newdata+x->x_vsize;
+ pnU = newdata+x->x_vsize+(x->x_vsize>>2);
+ iu = 0;
+ for(py=0; py<x->x_vheight; py++)
+ {
+ for(px=0; px<x->x_vwidth; px++)
+ {
+ d = x->x_table_list[x->x_table][py*x->x_vwidth+px];
+ if ( (px%2==0) && (py%2==0) )
+ {
+ du = x->x_table_list_u[x->x_table][py*x->x_vwidth+px];
+ iu++;
+ }
+ if ( d==-2 )
+ {
+ d = pdp_transform_map_from_table( x, px, py, x->x_t );
+ du = pdp_transform_map_from_table_u( x, px, py, x->x_t );
+ }
+ if ( d < 0) {
+ o = 0;
+ ou = 0;
+ } else {
+ o = d;
+ ou = du;
+ }
+ *pnY++ = *(data+o);
+ if ( (px%2==0) && (py%2==0) )
+ {
+ *pnV++ = *(data+x->x_vsize+ou);
+ *pnU++ = *(data+x->x_vsize+(x->x_vsize>>2)+ou);
+ }
+ }
+ }
+
+ return;
+}
+
+static void pdp_transform_sendpacket(t_pdp_transform *x)
+{
+ /* delete source 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_transform_process(t_pdp_transform *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_transform_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_transform_process_yv12, pdp_transform_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_transform_process */
+ break;
+
+ }
+ }
+
+}
+
+static void pdp_transform_input_0(t_pdp_transform *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_transform_process(x);
+
+ }
+
+}
+
+static void pdp_transform_free(t_pdp_transform *x)
+{
+ int i;
+
+ pdp_transform_free_ressources(x);
+ if ( x->x_table_list ) freebytes(x->x_table_list, MAX_TABLES * sizeof(int *));
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_transform_class;
+
+void *pdp_transform_new(void)
+{
+ int i;
+
+ t_pdp_transform *x = (t_pdp_transform *)pd_new(pdp_transform_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("table"));
+
+ 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_table_list = (t_int **) getbytes(MAX_TABLES * sizeof(int *));
+ x->x_table_list_u = (t_int **) getbytes(MAX_TABLES * sizeof(int *));
+ x->x_t = 0;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_transform_setup(void)
+{
+// post( pdp_transform_version );
+ pdp_transform_class = class_new(gensym("pdp_transform"), (t_newmethod)pdp_transform_new,
+ (t_method)pdp_transform_free, sizeof(t_pdp_transform), 0, A_NULL);
+
+ class_addmethod(pdp_transform_class, (t_method)pdp_transform_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_transform_class, (t_method)pdp_transform_table, gensym("table"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_transition.c b/modules/pdp_transition.c
new file mode 100644
index 0000000..d186aa0
--- /dev/null
+++ b/modules/pdp_transition.c
@@ -0,0 +1,787 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 object allowing transitions between two video sources
+ * "circle", "wipe", "random", "melt" and "blend"
+ * Written by Yves Degoyon
+ */
+
+#include "pdp.h"
+#include <math.h>
+
+#define BLEND_MAX 200
+
+static char *pdp_transition_version = "pdp_transition: version 0.1, two sources transition, written by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_transition_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+ t_int x_packet0;
+ t_int x_packet1;
+ t_int x_packet;
+ t_int x_dropped;
+ t_int x_queue_id;
+
+ t_int x_vwidth0;
+ t_int x_vheight0;
+ t_int x_vsize0;
+
+ t_int x_vwidth1;
+ t_int x_vheight1;
+ t_int x_vsize1;
+
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+
+ t_int x_transition_mode; // 1 : "circle"
+ t_int x_transition_pending;
+
+ t_int x_current_source;
+ t_int x_target_source;
+
+ t_int x_pos; // current position for transition
+ t_int x_inc; // increment for various mode
+ t_int x_rand;// randomizing argument
+
+} t_pdp_transition;
+
+static t_int pdp_transition_min( t_int a, t_int b )
+{
+ if ( a == 0 ) return b;
+ if ( b == 0 ) return a;
+ if ( a < b ) return a;
+ else return b;
+}
+
+static void pdp_transition_circle(t_pdp_transition *x, t_floatarg finc )
+{
+ if ( x->x_transition_pending )
+ {
+ post ( "pdp_transition : a transition is already pending, retry later...." );
+ return;
+ }
+ if ( (int) finc > 0 )
+ {
+ x->x_inc = (int)finc;
+ }
+ x->x_transition_mode = 1;
+ x->x_transition_pending = 1;
+}
+
+static void pdp_transition_wipelr(t_pdp_transition *x, t_floatarg finc, t_floatarg frand )
+{
+ if ( x->x_transition_pending )
+ {
+ post ( "pdp_transition : a transition is already pending, retry later...." );
+ return;
+ }
+ if ( (int) finc > 0 )
+ {
+ x->x_inc = (int)finc;
+ }
+ if ( (int) frand >= 0 )
+ {
+ x->x_rand = (int)frand;
+ }
+ x->x_transition_mode = 2;
+ x->x_transition_pending = 1;
+}
+
+static void pdp_transition_wiperl(t_pdp_transition *x, t_floatarg finc, t_floatarg frand )
+{
+ if ( x->x_transition_pending )
+ {
+ post ( "pdp_transition : a transition is already pending, retry later...." );
+ return;
+ }
+ if ( (int) finc > 0 )
+ {
+ x->x_inc = (int)finc;
+ }
+ if ( (int) frand >= 0 )
+ {
+ x->x_rand = (int)frand;
+ }
+ x->x_transition_mode = 3;
+ x->x_transition_pending = 1;
+ x->x_pos = x->x_vwidth;
+}
+
+static void pdp_transition_mwipe(t_pdp_transition *x, t_floatarg finc, t_floatarg frand )
+{
+ if ( x->x_transition_pending )
+ {
+ post ( "pdp_transition : a transition is already pending, retry later...." );
+ return;
+ }
+ if ( (int) finc > 0 )
+ {
+ x->x_inc = (int)finc;
+ }
+ if ( (int) frand >= 0 )
+ {
+ x->x_rand = (int)frand;
+ }
+ x->x_transition_mode = 4;
+ x->x_transition_pending = 1;
+ x->x_pos = 0;
+}
+
+static void pdp_transition_wipetd(t_pdp_transition *x, t_floatarg finc, t_floatarg frand )
+{
+ if ( x->x_transition_pending )
+ {
+ post ( "pdp_transition : a transition is already pending, retry later...." );
+ return;
+ }
+ if ( (int) finc > 0 )
+ {
+ x->x_inc = (int)finc;
+ }
+ if ( (int) frand >= 0 )
+ {
+ x->x_rand = (int)frand;
+ }
+ x->x_transition_mode = 5;
+ x->x_transition_pending = 1;
+ x->x_pos = 0;
+}
+
+static void pdp_transition_wipebu(t_pdp_transition *x, t_floatarg finc, t_floatarg frand )
+{
+ if ( x->x_transition_pending )
+ {
+ post ( "pdp_transition : a transition is already pending, retry later...." );
+ return;
+ }
+ if ( (int) finc > 0 )
+ {
+ x->x_inc = (int)finc;
+ }
+ if ( (int) frand >= 0 )
+ {
+ x->x_rand = (int)frand;
+ }
+ x->x_transition_mode = 6;
+ x->x_transition_pending = 1;
+ x->x_pos = x->x_vheight;
+}
+
+static void pdp_transition_random(t_pdp_transition *x, t_floatarg finc )
+{
+ if ( x->x_transition_pending )
+ {
+ post ( "pdp_transition : a transition is already pending, retry later...." );
+ return;
+ }
+ if ( (int) finc > 0 )
+ {
+ x->x_inc = (int)finc;
+ }
+ x->x_transition_mode = 7;
+ x->x_transition_pending = 1;
+ x->x_rand = x->x_vsize/(x->x_inc*(pdp_transition_min( x->x_vwidth, 100 )));
+}
+
+static void pdp_transition_melt(t_pdp_transition *x, t_floatarg finc )
+{
+ if ( x->x_transition_pending )
+ {
+ post ( "pdp_transition : a transition is already pending, retry later...." );
+ return;
+ }
+ if ( (int) finc > 0 )
+ {
+ x->x_inc = (int)finc;
+ }
+ x->x_transition_mode = 8;
+ x->x_transition_pending = 1;
+ x->x_rand = 20;
+}
+
+static void pdp_transition_blend(t_pdp_transition *x, t_floatarg finc, t_floatarg frand )
+{
+ if ( x->x_transition_pending )
+ {
+ post ( "pdp_transition : a transition is already pending, retry later...." );
+ return;
+ }
+ if ( (int) finc > 0 )
+ {
+ x->x_inc = (int)finc;
+ }
+ if ( (int) frand >= 0 )
+ {
+ x->x_rand = (int)frand;
+ }
+ x->x_transition_mode = 9;
+ x->x_transition_pending = 1;
+ x->x_pos = 0;
+}
+
+static void pdp_transition_process_yv12(t_pdp_transition *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ short int *data0 = (short int *)pdp_packet_data(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ short int *data1 = (short int *)pdp_packet_data(x->x_packet1);
+ t_pdp *header;
+ short int *data;
+ t_int tsource, cx=0, cy=0;
+ t_int px, py, rvalue=0;
+ t_float factor;
+ int i;
+ short int *poY, *poV, *poU, *p0Y, *p0V, *p0U, *p1Y, *p1V, *p1U;
+
+ if ( header0 )
+ {
+ x->x_vwidth0 = header0->info.image.width;
+ x->x_vheight0 = header0->info.image.height;
+ x->x_vsize0 = x->x_vwidth0*x->x_vheight0;
+ }
+ else
+ {
+ x->x_vwidth0 = x->x_vheight0 = x->x_vsize0 = 0;
+ }
+
+ if ( header1 )
+ {
+ x->x_vwidth1 = header1->info.image.width;
+ x->x_vheight1 = header1->info.image.height;
+ x->x_vsize1 = x->x_vwidth1*x->x_vheight1;
+ }
+ else
+ {
+ x->x_vwidth1 = x->x_vheight1 = x->x_vsize1 = 0;
+ }
+
+ x->x_vwidth = pdp_transition_min( x->x_vwidth0 , x->x_vwidth1);
+ x->x_vheight = pdp_transition_min( x->x_vheight0 , x->x_vheight1);
+ x->x_vsize = x->x_vwidth*x->x_vheight;
+ // post( "pdp_transition : resulting frame : %dx%d", x->x_vwidth, x->x_vheight );
+
+ x->x_packet = pdp_packet_new_image_YCrCb( x->x_vwidth, x->x_vheight );
+
+ header = pdp_packet_header(x->x_packet);
+ data = (short int *)pdp_packet_data(x->x_packet);
+
+ header->info.image.encoding = PDP_IMAGE_YV12;
+ header->info.image.width = x->x_vwidth;
+ header->info.image.height = x->x_vheight;
+
+ poY = data;
+ poV = data+x->x_vsize;
+ poU = data+x->x_vsize+(x->x_vsize>>2);
+ if ( x->x_current_source == 0 )
+ {
+ if ( x->x_vsize0 > 0 ) memcpy( data, data0, (x->x_vsize+(x->x_vsize>>1))<<1 );
+ p0Y = data0;
+ p0V = data0+x->x_vsize0;
+ p0U = data0+x->x_vsize0+(x->x_vsize0>>2);
+ p1Y = data1;
+ p1V = data1+x->x_vsize1;
+ p1U = data1+x->x_vsize1+(x->x_vsize1>>2);
+ }
+ else
+ {
+ if ( x->x_vsize1 > 0 ) memcpy( data, data1, (x->x_vsize+(x->x_vsize>>1))<<1 );
+ p0Y = data1;
+ p0V = data1+x->x_vsize0;
+ p0U = data1+x->x_vsize0+(x->x_vsize0>>2);
+ p1Y = data0;
+ p1V = data0+x->x_vsize1;
+ p1U = data0+x->x_vsize1+(x->x_vsize1>>2);
+ }
+ if ( ( x->x_transition_pending ) && ( x->x_vsize0 > 0 ) && ( x->x_vsize1 > 0 ) )
+ {
+ switch ( x->x_transition_mode )
+ {
+ case 1: // circle
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ cx = px-(x->x_vwidth/2);
+ cy = py-(x->x_vheight/2);
+ if ( cx*cx + cy*cy < x->x_pos*x->x_pos )
+ {
+ *(poY) = *(p1Y);
+ *(poU) = *(p1U);
+ *(poV) = *(p1V);
+ }
+ poY++; p1Y++;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ poU++; poV++;
+ p1U++; p1V++;
+ }
+ }
+ }
+ if ( ( x->x_pos > (x->x_vwidth/2) ) && ( x->x_pos > (x->x_vheight/2) ) )
+ {
+ post( "pdp_transition : circle transition finished" );
+ x->x_transition_pending = 0;
+ x->x_transition_mode = 0;
+ tsource = x->x_current_source;
+ x->x_current_source = x->x_target_source;
+ x->x_target_source = tsource;
+ x->x_pos = 0;
+ }
+ x->x_pos += x->x_inc;
+ break;
+
+ case 2: // wipelr
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ rvalue = (int)(((float) x->x_rand )*( (float)random() ) / RAND_MAX);
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ if ( px <= x->x_pos + rvalue )
+ {
+ *(poY) = *(p1Y);
+ *(poU) = *(p1U);
+ *(poV) = *(p1V);
+ }
+ poY++; p1Y++;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ poU++; poV++;
+ p1U++; p1V++;
+ }
+ }
+ }
+ if ( x->x_pos > x->x_vwidth )
+ {
+ post( "pdp_transition : wipelr transition finished" );
+ x->x_transition_pending = 0;
+ x->x_transition_mode = 0;
+ tsource = x->x_current_source;
+ x->x_current_source = x->x_target_source;
+ x->x_target_source = tsource;
+ x->x_pos = 0;
+ }
+ x->x_pos += x->x_inc;
+ break;
+
+ case 3: // wiperl
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ rvalue = (int)(((float) x->x_rand )*( (float)random() ) / RAND_MAX);
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ if ( px >= x->x_pos + rvalue )
+ {
+ *(poY) = *(p1Y);
+ *(poU) = *(p1U);
+ *(poV) = *(p1V);
+ }
+ poY++; p1Y++;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ poU++; poV++;
+ p1U++; p1V++;
+ }
+ }
+ }
+ if ( x->x_pos <= 0 )
+ {
+ post( "pdp_transition : wiperl transition finished" );
+ x->x_transition_pending = 0;
+ x->x_transition_mode = 0;
+ tsource = x->x_current_source;
+ x->x_current_source = x->x_target_source;
+ x->x_target_source = tsource;
+ x->x_pos = 0;
+ }
+ x->x_pos -= x->x_inc;
+ break;
+
+ case 4: // mwipe
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ rvalue = (int)(((float) x->x_rand )*( (float)random() ) / RAND_MAX);
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ if ( py <= x->x_pos + rvalue )
+ {
+ *(poY) = *(p1Y);
+ *(poU) = *(p1U);
+ *(poV) = *(p1V);
+ }
+ poY++; p1Y++;
+ if ( (px%2==0) && (py%2==0) )
+ {
+ poU++; poV++;
+ p1U++; p1V++;
+ }
+ }
+ }
+ if ( x->x_pos >= x->x_vheight )
+ {
+ post( "pdp_transition : mwipe transition finished" );
+ x->x_transition_pending = 0;
+ x->x_transition_mode = 0;
+ tsource = x->x_current_source;
+ x->x_current_source = x->x_target_source;
+ x->x_target_source = tsource;
+ x->x_pos = 0;
+ }
+ x->x_pos += x->x_inc;
+ break;
+
+ case 5: // wipetd
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ rvalue = (int)(((float) x->x_rand )*( (float)random() ) / RAND_MAX);
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ if ( py <= x->x_pos + rvalue )
+ {
+ *(poY+py*x->x_vwidth+px) = *(p1Y+py*x->x_vwidth1+px);
+ *(poU+(py>>1)*(x->x_vwidth>>1)+(px>>1)) =
+ *(p1U+(py>>1)*(x->x_vwidth1>>1)+(px>>1));
+ *(poV+(py>>1)*(x->x_vwidth>>1)+(px>>1)) =
+ *(p1V+(py>>1)*(x->x_vwidth1>>1)+(px>>1));
+ }
+ }
+ }
+ if ( x->x_pos >= x->x_vheight )
+ {
+ post( "pdp_transition : wipetd transition finished" );
+ x->x_transition_pending = 0;
+ x->x_transition_mode = 0;
+ tsource = x->x_current_source;
+ x->x_current_source = x->x_target_source;
+ x->x_target_source = tsource;
+ x->x_pos = 0;
+ }
+ x->x_pos += x->x_inc;
+ break;
+
+ case 6: // wipebu
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ rvalue = (int)(((float) x->x_rand )*( (float)random() ) / RAND_MAX);
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ if ( py >= x->x_pos + rvalue )
+ {
+ *(poY+py*x->x_vwidth+px) = *(p1Y+py*x->x_vwidth1+px);
+ *(poU+(py>>1)*(x->x_vwidth>>1)+(px>>1)) =
+ *(p1U+(py>>1)*(x->x_vwidth1>>1)+(px>>1));
+ *(poV+(py>>1)*(x->x_vwidth>>1)+(px>>1)) =
+ *(p1V+(py>>1)*(x->x_vwidth1>>1)+(px>>1));
+ }
+ }
+ }
+ if ( x->x_pos <= 0 )
+ {
+ post( "pdp_transition : wipebu transition finished" );
+ x->x_transition_pending = 0;
+ x->x_transition_mode = 0;
+ tsource = x->x_current_source;
+ x->x_current_source = x->x_target_source;
+ x->x_target_source = tsource;
+ x->x_pos = 0;
+ }
+ x->x_pos -= x->x_inc;
+ break;
+
+ case 7: // random
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ rvalue = (int)(((float) x->x_rand )*( (float)random() ) / RAND_MAX);
+ if ( rvalue <= x->x_pos )
+ {
+ *(poY+py*x->x_vwidth+px) = *(p1Y+py*x->x_vwidth1+px);
+ *(poU+(py>>1)*(x->x_vwidth>>1)+(px>>1)) =
+ *(p1U+(py>>1)*(x->x_vwidth1>>1)+(px>>1));
+ *(poV+(py>>1)*(x->x_vwidth>>1)+(px>>1)) =
+ *(p1V+(py>>1)*(x->x_vwidth1>>1)+(px>>1));
+ }
+ }
+ }
+ if ( x->x_pos >= x->x_rand )
+ {
+ post( "pdp_transition : wipebu transition finished" );
+ x->x_transition_pending = 0;
+ x->x_transition_mode = 0;
+ tsource = x->x_current_source;
+ x->x_current_source = x->x_target_source;
+ x->x_target_source = tsource;
+ x->x_pos = 0;
+ }
+ x->x_pos += x->x_inc;
+ break;
+
+ case 8: // melt
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ rvalue = (int)(((float) x->x_rand )*( (float)random() ) / RAND_MAX)+(abs(px-x->x_vwidth/2)/5);
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ if ( py <= x->x_pos + rvalue )
+ {
+ *(poY+py*x->x_vwidth+px) = 0;
+ *(poU+(py>>1)*(x->x_vwidth>>1)+(px>>1)) = 0;
+ *(poV+(py>>1)*(x->x_vwidth>>1)+(px>>1)) = 0;
+ }
+ }
+ }
+ if ( x->x_pos >= x->x_vheight )
+ {
+ post( "pdp_transition : melt transition finished" );
+ x->x_transition_pending = 0;
+ x->x_transition_mode = 0;
+ tsource = x->x_current_source;
+ x->x_current_source = x->x_target_source;
+ x->x_target_source = tsource;
+ x->x_pos = 0;
+ }
+ x->x_pos += x->x_inc;
+ break;
+
+ case 9: // blend
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ rvalue = (((float) x->x_rand )*( (float)random() ) / RAND_MAX);
+ factor = ( (float) x->x_pos + rvalue ) / BLEND_MAX;
+ *(poY+py*x->x_vwidth+px) =
+ (int)((1.0-factor)*(*(poY+py*x->x_vwidth+px)) +
+ factor*(*(p1Y+py*x->x_vwidth1+px)));
+ *(poU+(py>>1)*(x->x_vwidth>>1)+(px>>1)) =
+ (int)((1.0-factor)*(*(poU+(py>>1)*(x->x_vwidth>>1)+(px>>1))) +
+ factor*(*(p1U+(py>>1)*(x->x_vwidth1>>1)+(px>>1))));
+ *(poV+(py>>1)*(x->x_vwidth>>1)+(px>>1)) =
+ (int)((1.0-factor)*(*(poV+(py>>1)*(x->x_vwidth>>1)+(px>>1))) +
+ factor*(*(p1V+(py>>1)*(x->x_vwidth1>>1)+(px>>1))));
+ }
+ }
+ if ( x->x_pos >= BLEND_MAX )
+ {
+ post( "pdp_transition : blend transition finished" );
+ x->x_transition_pending = 0;
+ x->x_transition_mode = 0;
+ tsource = x->x_current_source;
+ x->x_current_source = x->x_target_source;
+ x->x_target_source = tsource;
+ x->x_pos = 0;
+ }
+ x->x_pos += x->x_inc;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return;
+}
+
+static void pdp_transition_sendpacket0(t_pdp_transition *x)
+{
+ /* unregister and propagate if valid dest packet */
+ pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet);
+}
+
+static void pdp_transition_sendpacket1(t_pdp_transition *x)
+{
+ /* unregister and propagate if valid dest packet */
+ pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet);
+}
+
+static void pdp_transition_process0(t_pdp_transition *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_transition_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_transition_process_yv12, pdp_transition_sendpacket0, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_transition_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_transition_process1(t_pdp_transition *x)
+{
+ int encoding;
+ t_pdp *header = 0;
+
+ /* check if image data packets are compatible */
+ if ( (header = pdp_packet_header(x->x_packet1))
+ && (PDP_IMAGE == header->type)){
+
+ /* pdp_transition_process inputs and write into active inlet */
+ switch(pdp_packet_header(x->x_packet1)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_queue_add(x, pdp_transition_process_yv12, pdp_transition_sendpacket1, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_transition_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_transition_input_0(t_pdp_transition *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"))
+ {
+ /* release the packet */
+ if ( x->x_packet0 != -1 )
+ {
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = -1;
+ }
+ 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_transition_process0(x);
+
+ }
+}
+
+static void pdp_transition_input_1(t_pdp_transition *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"))
+ {
+ /* release the packet */
+ if ( x->x_packet1 != -1 )
+ {
+ pdp_packet_mark_unused(x->x_packet1);
+ x->x_packet1 = -1;
+ }
+ x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet1, (int)f, pdp_gensym("image/YCrCb/*") );
+ }
+
+ if ((s == gensym("process")) && (-1 != x->x_packet1) && (!x->x_dropped)){
+
+ /* add the process method and callback to the process queue */
+ pdp_transition_process1(x);
+
+ }
+}
+
+static void pdp_transition_free(t_pdp_transition *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+}
+
+t_class *pdp_transition_class;
+
+void *pdp_transition_new(void)
+{
+ int i;
+
+ t_pdp_transition *x = (t_pdp_transition *)pd_new(pdp_transition_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp2"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_packet = -1;
+ x->x_queue_id = -1;
+
+ x->x_transition_mode = 0;
+ x->x_transition_pending = 0;
+
+ x->x_current_source = 0;
+ x->x_target_source = 1;
+
+ x->x_pos = 0;
+ x->x_inc = 1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_transition_setup(void)
+{
+ post( pdp_transition_version );
+ pdp_transition_class = class_new(gensym("pdp_transition"), (t_newmethod)pdp_transition_new,
+ (t_method)pdp_transition_free, sizeof(t_pdp_transition), 0, A_NULL);
+
+ class_addmethod(pdp_transition_class, (t_method)pdp_transition_input_0, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_transition_class, (t_method)pdp_transition_input_1, gensym("pdp2"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_transition_class, (t_method)pdp_transition_circle, gensym("circle"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_transition_class, (t_method)pdp_transition_wipelr, gensym("wipelr"), A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_transition_class, (t_method)pdp_transition_wiperl, gensym("wiperl"), A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_transition_class, (t_method)pdp_transition_mwipe, gensym("mwipe"), A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_transition_class, (t_method)pdp_transition_wipetd, gensym("wipetd"), A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_transition_class, (t_method)pdp_transition_wipebu, gensym("wipebu"), A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_transition_class, (t_method)pdp_transition_random, gensym("random"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_transition_class, (t_method)pdp_transition_melt, gensym("melt"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_transition_class, (t_method)pdp_transition_blend, gensym("blend"), A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_underwatch.c b/modules/pdp_underwatch.c
new file mode 100644
index 0000000..887be29
--- /dev/null
+++ b/modules/pdp_underwatch.c
@@ -0,0 +1,244 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 adaptation of 1d effect from effectv
+ * but i found it funnier to rename it as underwatch
+ * Originally written by Fukuchi Kentaro & others
+ * Pd-fication by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+static char *pdp_underwatch_version = "pdp_underwatch: version 0.1, inspired by 1d from effectv( Fukuchi Kentaro ) adapted by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_underwatch_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_line;
+ t_int x_sline;
+ t_int x_sheight;
+ t_int x_prevline;
+ t_int x_prevsline;
+ t_int x_prevsheight;
+ t_int x_stripsize;
+
+} t_pdp_underwatch;
+
+static void pdp_underwatch_setparams(t_pdp_underwatch *x)
+{
+ int snext;
+
+ x->x_sline = x->x_line;
+ snext = (x->x_line + 1);
+ x->x_sheight = snext - x->x_sline;
+}
+
+static void pdp_underwatch_process_yv12(t_pdp_underwatch *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);
+ short int *p=0, *po=0, *pu=0, *pv=0, *pou=0, *pov=0;
+ int i;
+
+ unsigned int u_offset;
+ unsigned int v_offset;
+ unsigned int totnbpixels;
+ int px, py, pd, t;
+
+ x->x_vwidth = header->info.image.width;
+ x->x_vheight = header->info.image.height;
+ x->x_vsize = x->x_vwidth*x->x_vheight;
+
+ u_offset = x->x_vsize;
+ v_offset = x->x_vsize + (x->x_vsize>>2);
+ totnbpixels = x->x_vsize + (x->x_vsize>>1);
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ /* copy region */
+ for (pd=0; pd<x->x_stripsize; pd++ )
+ {
+ p = newdata+x->x_vwidth*x->x_sline;
+ pu = newdata+((x->x_vwidth*x->x_sline)>>2)+x->x_vsize;
+ pv = newdata+((x->x_vwidth*x->x_sline)>>2)+x->x_vsize+(x->x_vsize>>2);
+ po = data+x->x_vwidth*x->x_line;
+ pou = data+((x->x_vwidth*x->x_line)>>2)+x->x_vsize;
+ pov = data+((x->x_vwidth*x->x_line)>>2)+x->x_vsize+(x->x_vsize>>2);
+ // post("INIT : pov=%x limit=%x", pov, data+x->x_vsize+(x->x_vsize>>1) );
+ for(py=0; py<=x->x_sheight; py++)
+ {
+ for(px=0; px<x->x_vwidth; px++)
+ {
+ if( po < data+x->x_vsize+(x->x_vsize>>1) ) *p = *po;
+ if( pou < data+x->x_vsize+(x->x_vsize>>1) ) *(pu) = *(pou);
+ if( pov < data+x->x_vsize+(x->x_vsize>>1) ) *(pv) = *(pov);
+ p++;
+ po++;
+ if ( ((px+1)%2==0) && ((py+1)%2==0) ) { pu++; pv++; pou++; pov++; };
+ }
+ }
+ x->x_prevline = x->x_line;
+ x->x_prevsline = x->x_sline;
+ x->x_prevsheight = x->x_sheight;
+ x->x_line=(x->x_line+1)%(x->x_vheight);
+ pdp_underwatch_setparams(x);
+ //p = newdata + x->x_vwidth * x->x_sline+1;
+ //for(px=0; px<x->x_vwidth; px++)
+ //{
+ // p[px] = 0xff00;
+ //}
+ }
+
+ return;
+}
+
+static void pdp_underwatch_sendpacket(t_pdp_underwatch *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_underwatch_process(t_pdp_underwatch *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_underwatch_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_underwatch_process_yv12, pdp_underwatch_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ // pdp_underwatch_process_packet(x);
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_underwatch_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_underwatch_stripsize(t_pdp_underwatch *x, t_floatarg fstripsize )
+{
+ if ( fstripsize>0 && fstripsize<x->x_vheight )
+ {
+ x->x_stripsize = (int)fstripsize;
+ }
+}
+
+static void pdp_underwatch_input_0(t_pdp_underwatch *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_underwatch_process(x);
+ }
+}
+
+static void pdp_underwatch_free(t_pdp_underwatch *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_underwatch_class;
+
+void *pdp_underwatch_new(void)
+{
+ int i;
+
+ t_pdp_underwatch *x = (t_pdp_underwatch *)pd_new(pdp_underwatch_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("stripsize"));
+
+ 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_line = 0;
+ pdp_underwatch_setparams(x);
+ x->x_prevline = 0;
+ x->x_prevsline = 0;
+ x->x_prevsheight = 0;
+ x->x_stripsize = 10;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_underwatch_setup(void)
+{
+// post( pdp_underwatch_version );
+ pdp_underwatch_class = class_new(gensym("pdp_underwatch"), (t_newmethod)pdp_underwatch_new,
+ (t_method)pdp_underwatch_free, sizeof(t_pdp_underwatch), 0, A_NULL);
+
+ class_addmethod(pdp_underwatch_class, (t_method)pdp_underwatch_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_underwatch_class, (t_method)pdp_underwatch_stripsize, gensym("stripsize"), A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_vertigo.c b/modules/pdp_vertigo.c
new file mode 100644
index 0000000..b6f4e37
--- /dev/null
+++ b/modules/pdp_vertigo.c
@@ -0,0 +1,349 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 adaptation of lens effect from effectv
+ * Originally written by Fukuchi Kentaro & others
+ * Pd-fication by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+static char *pdp_vertigo_version = "pdp_vertigo: version 0.1, port of vertigo from effectv( Fukuchi Kentaro ) adapted by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_vertigo_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;
+ short int *x_buffer;
+ short int *x_current_buffer;
+ short int *x_alt_buffer;
+ t_int x_dx;
+ t_int x_dy;
+ t_int x_sx;
+ t_int x_sy;
+ double x_phase;
+ double x_phase_increment;
+ double x_zoomrate;
+
+
+} t_pdp_vertigo;
+
+static void pdp_vertigo_increment(t_pdp_vertigo *x, t_floatarg fincrement )
+{
+ x->x_phase_increment = fincrement;
+}
+
+static void pdp_vertigo_zoomrate(t_pdp_vertigo *x, t_floatarg fzoomrate )
+{
+ x->x_zoomrate = (int)fzoomrate;
+}
+
+static void pdp_vertigo_allocate(t_pdp_vertigo *x, t_floatarg fnewsize )
+{
+ t_int nsize = (int) fnewsize;
+
+ if ( x->x_buffer ) freebytes( x->x_buffer, 2*((x->x_vsize + (x->x_vsize>>1))<<1) );
+ x->x_buffer = (short int *) getbytes( 2*(( nsize + (nsize>>1))<<1) );
+ if ( x->x_buffer )
+ {
+ bzero( x->x_buffer, 2*((nsize + (nsize>>1))<<1) );
+ x->x_current_buffer = x->x_buffer;
+ x->x_alt_buffer = x->x_buffer + (nsize + (nsize>>1));
+ }
+ x->x_phase = 0;
+}
+
+static void pdp_vertigo_set_params(t_pdp_vertigo *x)
+{
+ double vx, vy;
+ double t;
+ double X, Y;
+ double dizz;
+
+ dizz = sin(x->x_phase) * 10 + sin(x->x_phase*1.9+5) * 5;
+
+ X = x->x_vwidth / 2;
+ Y = x->x_vheight / 2;
+ t = (X*X + Y*Y) * x->x_zoomrate;
+ if( x->x_vwidth > x->x_vheight )
+ {
+ if(dizz >= 0)
+ {
+ if(dizz > X) dizz = X;
+ vx = (X*(X-dizz) + Y*Y) / t;
+ }
+ else
+ {
+ if(dizz < -X) dizz = -X;
+ vx = (X*(X+dizz) + Y*Y) / t;
+ }
+ vy = (dizz*Y) / t;
+ }
+ else
+ {
+ if(dizz >= 0)
+ {
+ if(dizz > Y) dizz = Y;
+ vx = (X*X + Y*(Y-dizz)) / t;
+ }
+ else
+ {
+ if(dizz < -Y) dizz = -Y;
+ vx = (X*X + Y*(Y+dizz)) / t;
+ }
+ vy = (dizz*X) / t;
+ }
+ x->x_dx = vx * 65536;
+ x->x_dy = vy * 65536;
+ x->x_sx = (-vx * X + vy * Y + X + cos(x->x_phase*5) * 2) * 65536;
+ x->x_sy = (-vx * Y - vy * X + Y + sin(x->x_phase*6) * 2) * 65536;
+
+ x->x_phase += x->x_phase_increment;
+ if(x->x_phase > 5700000) x->x_phase = 0;
+}
+
+
+static void pdp_vertigo_process_yv12(t_pdp_vertigo *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);
+
+ unsigned int totalnbpixels;
+ unsigned int u_offset;
+ unsigned int v_offset;
+ unsigned int totnbpixels;
+ short int *poy, *pou, *pov, *pny, *pnu, *pnv, *pcy, *pcu, *pcv;
+ int px, py;
+ short int v;
+ int ox, oy;
+ int i, ninc;
+
+ /* allocate all ressources */
+ if ( (int)(header->info.image.width*header->info.image.height) != x->x_vsize )
+ {
+ pdp_vertigo_allocate(x, header->info.image.width*header->info.image.height );
+ post( "pdp_vertigo : reallocated buffers" );
+ }
+
+ x->x_vwidth = header->info.image.width;
+ x->x_vheight = header->info.image.height;
+ x->x_vsize = x->x_vwidth*x->x_vheight;
+
+ totalnbpixels = x->x_vsize;
+ u_offset = x->x_vsize;
+ v_offset = x->x_vsize + (x->x_vsize>>2);
+ totnbpixels = x->x_vsize + (x->x_vsize>>1);
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ pdp_vertigo_set_params(x);
+
+ poy = data;
+ pou = data + x->x_vsize;
+ pov = data + x->x_vsize + (x->x_vsize>>2);
+ pcy = x->x_current_buffer;
+ pcu = x->x_current_buffer + x->x_vsize;
+ pcv = x->x_current_buffer + x->x_vsize + (x->x_vsize>>2);
+ pny = x->x_alt_buffer;
+ pnu = x->x_alt_buffer + x->x_vsize;
+ pnv = x->x_alt_buffer + x->x_vsize + (x->x_vsize>>2);
+ ninc=0;
+ for(py=x->x_vheight; py>0; py--)
+ {
+ ox = x->x_sx;
+ oy = x->x_sy;
+ for(px=x->x_vwidth; px>0; px--)
+ {
+ if ( pny >= ( x->x_alt_buffer + x->x_vsize ) )
+ {
+ post( "pdp_vertigo : abnormal pointer position : pny=%x, start=%x, size=%x ninc=%d px=%d py=%d",
+ pny, x->x_alt_buffer , x->x_vsize-1, ninc, px, py );
+ break;
+ }
+ if ( pnu >= ( x->x_alt_buffer + x->x_vsize + (x->x_vsize>>2) ) )
+ {
+ post( "pdp_vertigo : abnormal pointer position : pnu=%x, start=%x, size=%x ninc=%d px=%d py=%d",
+ pnu, x->x_alt_buffer + x->x_vsize, (x->x_vsize>>2)-1, ninc, px, py );
+ break;
+ }
+ if ( pnv >= ( x->x_alt_buffer + x->x_vsize + (x->x_vsize>>1) ) )
+ {
+ post( "pdp_vertigo : abnormal pointer position : pnv=%x, start=%x, size=%x ninc=%d px=%d py=%d",
+ pnv, x->x_alt_buffer + x->x_vsize + (x->x_vsize>>2), (x->x_vsize>>2)-1, ninc, px, py );
+ break;
+ }
+ i = (oy>>16)*x->x_vwidth + (ox>>16);
+ if (i<0) i = 0;
+ if ( i >= (x->x_vsize + (x->x_vsize>>1)) ) i = (x->x_vsize + (x->x_vsize>>1))-1;
+ v = pcy[i] & 0xffff;
+ v = (v * 3) + ((*poy++) & 0xffff);
+ *pny++ = (v>>2);
+ if ( (((px+1)%2)==0) && (((py+1)%2)==0) )
+ {
+ ninc++;
+ v = pcu[(i/4)] & 0xffff;
+ v = (v * 3) + ((*pou++) & 0xffff);
+ *pnu++ = (v>>2);
+ v = pcv[(i/4)] & 0xffff;
+ v = (v * 3) + ((*pov++) & 0xffff);
+ *pnv++ = (v>>2);
+ }
+ ox += x->x_dx;
+ oy += x->x_dy;
+ }
+ x->x_sx -= x->x_dy;
+ x->x_sy += x->x_dx;
+ }
+
+ memcpy(newdata, x->x_alt_buffer, (x->x_vsize + (x->x_vsize>>1))<<1);
+
+ poy = x->x_current_buffer;
+ x->x_current_buffer = x->x_alt_buffer;
+ x->x_alt_buffer = poy;
+
+ return;
+}
+
+static void pdp_vertigo_sendpacket(t_pdp_vertigo *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_vertigo_process(t_pdp_vertigo *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_vertigo_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_vertigo_process_yv12, pdp_vertigo_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ // pdp_vertigo_process_packet(x);
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_vertigo_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_vertigo_input_0(t_pdp_vertigo *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_vertigo_process(x);
+ }
+}
+
+static void pdp_vertigo_free(t_pdp_vertigo *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+
+ if ( x->x_buffer ) freebytes( x->x_buffer, 2*((x->x_vsize + (x->x_vsize>>1))<<1) );
+}
+
+t_class *pdp_vertigo_class;
+
+void *pdp_vertigo_new(void)
+{
+ int i;
+
+ t_pdp_vertigo *x = (t_pdp_vertigo *)pd_new(pdp_vertigo_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("increment"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("zoomrate"));
+
+ 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_phase = 0;
+ x->x_buffer = NULL;
+ x->x_phase_increment = 0.02;
+ x->x_zoomrate = 1.01;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_vertigo_setup(void)
+{
+// post( pdp_vertigo_version );
+ pdp_vertigo_class = class_new(gensym("pdp_vertigo"), (t_newmethod)pdp_vertigo_new,
+ (t_method)pdp_vertigo_free, sizeof(t_pdp_vertigo), 0, A_NULL);
+
+ class_addmethod(pdp_vertigo_class, (t_method)pdp_vertigo_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_vertigo_class, (t_method)pdp_vertigo_increment, gensym("increment"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_vertigo_class, (t_method)pdp_vertigo_zoomrate, gensym("zoomrate"), A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_warhol.c b/modules/pdp_warhol.c
new file mode 100644
index 0000000..8d12f2b
--- /dev/null
+++ b/modules/pdp_warhol.c
@@ -0,0 +1,285 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 adaptation of warhol effect from effectv
+ * Copyright (C) 2002 Jun IIO
+ * Pd-fication by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+#define NBCOLORS 9
+static t_int colortable[NBCOLORS] = {
+ 0x000080, 0x008045, 0x07f0e7,
+ 0x0000f0, 0x00f07f, 0x037a10,
+ 0x0023d9, 0x0080f0, 0x083df0
+};
+
+static char *pdp_warhol_version = "pdp_warhol: version 0.1, port of warhol from effectv( Fukuchi Kentaro ) adapted by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_warhol_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_dividerx;
+ t_int x_dividery;
+ t_int x_colorindex;
+
+} t_pdp_warhol;
+
+static void pdp_warhol_dividerx(t_pdp_warhol *x, t_floatarg fdivider )
+{
+ if ( ( fdivider > 1 ) && ( fdivider < x->x_vwidth ) )
+ {
+ x->x_dividerx = (t_int) fdivider;
+ }
+}
+
+static void pdp_warhol_dividery(t_pdp_warhol *x, t_floatarg fdivider )
+{
+ if ( ( fdivider > 1 ) && ( fdivider < x->x_vwidth ) )
+ {
+ x->x_dividery = (t_int) fdivider;
+ }
+}
+
+static void pdp_warhol_colorindex(t_pdp_warhol *x, t_floatarg findex )
+{
+ if ( ( findex >= 0 ) && ( findex < NBCOLORS ) )
+ {
+ x->x_colorindex = (t_int) findex;
+ }
+}
+
+static void pdp_warhol_v(t_pdp_warhol *x, t_floatarg fv )
+{
+ t_int tc;
+
+ if ( ( fv >= 0 ) && ( fv < 255 ) )
+ {
+ tc = colortable[x->x_colorindex] & 0xffff00;
+ tc = tc | (int) fv;
+ colortable[x->x_colorindex] = tc;
+ }
+}
+
+static void pdp_warhol_u(t_pdp_warhol *x, t_floatarg fu )
+{
+ t_int tc;
+
+ if ( ( fu >= 0 ) && ( fu < 255 ) )
+ {
+ tc = colortable[x->x_colorindex] & 0xff00ff;
+ tc = tc | (((int)fu)<<8);
+ colortable[x->x_colorindex] = tc;
+ }
+}
+
+static void pdp_warhol_y(t_pdp_warhol *x, t_floatarg fy )
+{
+ t_int tc;
+
+ if ( ( fy >= 0 ) && ( fy < 255 ) )
+ {
+ tc = colortable[x->x_colorindex] & 0x00ffff;
+ tc = tc | (((int)fy)<<16);
+ colortable[x->x_colorindex] = tc;
+ }
+}
+
+static void pdp_warhol_process_yv12(t_pdp_warhol *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);
+ short int *pny, *pnu, *pnv;
+ short int *poy, *pou, *pov;
+
+ short int Y, U, V;
+ int p, q, px, py, i;
+
+ x->x_vwidth = header->info.image.width;
+ x->x_vheight = header->info.image.height;
+ x->x_vsize = x->x_vwidth*x->x_vheight;
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ poy = data;
+ pou = data + x->x_vsize;
+ pov = data + x->x_vsize + (x->x_vsize>>2);
+ pny = newdata;
+ pnu = newdata + x->x_vsize;
+ pnv = newdata + x->x_vsize + (x->x_vsize>>2);
+ for (py = 0; py < x->x_vheight; py++)
+ {
+ for (px = 0; px < x->x_vwidth; px++)
+ {
+ p = (px * x->x_dividerx) % x->x_vwidth;
+ q = (py * x->x_dividery) % x->x_vheight;
+ i = ( ((py * x->x_dividery) / x->x_vheight) * x->x_dividery
+ + ((px * x->x_dividerx) / x->x_vwidth) ) % NBCOLORS;
+ Y = (colortable[i] >> 16);
+ U = ( (colortable[i] >> 8) & 0xff );
+ V = ( colortable[i] & 0xff);
+ *pny = ( *(poy + (q*x->x_vwidth+p) ) ) ^ ( Y<<8 );
+ pny++;
+ if ( ( px%2==0 ) && ( py%2==0 ) )
+ {
+ *pnu = ( ( U - 128 << 7 ) );
+ *pnv = ( ( V - 128 << 7 ) );
+ // *pnu = ( *(pou + ((q>>1)*(x->x_vwidth>>1)+(p>>1)) ) ) ^ ( ( U - 128 << 7 ) );
+ // *pnv = ( *(pov + ((q>>1)*(x->x_vwidth>>1)+(p>>1)) ) ) ^ ( ( V - 128 << 7 ) );
+ pnu++; pnv++;
+ }
+ }
+ }
+
+ return;
+}
+
+static void pdp_warhol_sendpacket(t_pdp_warhol *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_warhol_process(t_pdp_warhol *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_warhol_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_warhol_process_yv12, pdp_warhol_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_warhol_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_warhol_input_0(t_pdp_warhol *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_warhol_process(x);
+ }
+}
+
+static void pdp_warhol_free(t_pdp_warhol *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_warhol_class;
+
+void *pdp_warhol_new(void)
+{
+ int i;
+
+ t_pdp_warhol *x = (t_pdp_warhol *)pd_new(pdp_warhol_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("dividerx"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("dividery"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("colorindex"));
+ 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"));
+
+ 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_dividerx = 3;
+ x->x_dividery = 3;
+ x->x_colorindex = 0;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_warhol_setup(void)
+{
+// post( pdp_warhol_version );
+ pdp_warhol_class = class_new(gensym("pdp_warhol"), (t_newmethod)pdp_warhol_new,
+ (t_method)pdp_warhol_free, sizeof(t_pdp_warhol), 0, A_NULL);
+
+ class_addmethod(pdp_warhol_class, (t_method)pdp_warhol_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_warhol_class, (t_method)pdp_warhol_dividerx, gensym("dividerx"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_warhol_class, (t_method)pdp_warhol_dividery, gensym("dividery"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_warhol_class, (t_method)pdp_warhol_colorindex, gensym("colorindex"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_warhol_class, (t_method)pdp_warhol_y, gensym("Y"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_warhol_class, (t_method)pdp_warhol_u, gensym("U"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_warhol_class, (t_method)pdp_warhol_v, gensym("V"), A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_warp.c b/modules/pdp_warp.c
new file mode 100644
index 0000000..e3b4311
--- /dev/null
+++ b/modules/pdp_warp.c
@@ -0,0 +1,352 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@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 adaptation of warp effect from effectv
+ * Originally written by Fukuchi Kentaro & others
+ * Pd-fication by Yves Degoyon
+ */
+
+
+
+#include "pdp.h"
+#include <math.h>
+
+#define CTABLE_SIZE 1024
+
+static t_int sintable[CTABLE_SIZE+256];
+
+static char *pdp_warp_version = "pdp_warp: version 0.1, port of warp from effectv( Fukuchi Kentaro ) adapted by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_warp_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_tval;
+ t_int x_mode;
+ t_int x_ctable[CTABLE_SIZE];
+ t_int *x_disttable;
+ t_int *x_offstable;
+
+} t_pdp_warp;
+
+static void pdp_warp_mode(t_pdp_warp *x, t_floatarg fmode )
+{
+ if ( ( fmode == 0 ) || ( fmode == 1 ) )
+ {
+ x->x_mode = (int)fmode;
+ }
+}
+
+static void pdp_warp_tval(t_pdp_warp *x, t_floatarg ftval )
+{
+ x->x_tval = (int)ftval;
+}
+
+static void pdp_warp_init_sin_table(void)
+{
+ t_int *tptr, *tsinptr;
+ double i;
+
+ tsinptr = tptr = sintable;
+
+ for (i = 0; i < 1024; i++)
+ {
+ *tptr++ = (int) (sin (i*M_PI/512) * 32767);
+ }
+
+ for (i = 0; i < 256; i++)
+ {
+ *tptr++ = *tsinptr++;
+ }
+}
+
+static void pdp_warp_init_offs_table(t_pdp_warp* x)
+{
+ int y;
+
+ for (y = 0; y < x->x_vheight; y++) {
+ x->x_offstable[y] = y * x->x_vwidth;
+ }
+}
+
+static void pdp_warp_init_dist_table(t_pdp_warp *x)
+{
+ t_int halfw, halfh, *distptr;
+ double px,py,m;
+
+ halfw = x->x_vwidth>> 1;
+ halfh = x->x_vheight >> 1;
+
+ distptr = x->x_disttable;
+
+ m = sqrt ((double)(halfw*halfw + halfh*halfh));
+
+ for (py = -halfh; py < halfh; py++)
+ {
+ for (px= -halfw; px < halfw; px++)
+ {
+ *distptr++ = ((int) ( (sqrt (px*px+py*py) * 511.9999) / m)) << 1;
+ }
+ }
+}
+
+
+static void pdp_warp_free_ressources(t_pdp_warp *x)
+{
+ if ( x->x_offstable ) freebytes( x->x_offstable, x->x_vheight * sizeof (t_int) );
+ if ( x->x_disttable ) freebytes( x->x_disttable, x->x_vwidth * x->x_vheight * sizeof (t_int) );
+}
+
+static void pdp_warp_allocate(t_pdp_warp *x)
+{
+ int i;
+
+ x->x_offstable = (t_int*) getbytes ( x->x_vheight * sizeof (t_int) );
+ x->x_disttable = (t_int*) getbytes ( x->x_vwidth * x->x_vheight * sizeof (t_int) );
+ pdp_warp_init_offs_table(x);
+ pdp_warp_init_dist_table(x);
+
+}
+
+void pdp_warp_do_warp(t_pdp_warp *x, short int* src, short int *dest, int xw, int yw, int cw)
+{
+ t_int c, i, px, py, dx, dy, dxu, dyu, maxx, maxy;
+ t_int width, height, skip, *ctptr, *distptr;
+ short int *destptr, *destptru, *destptrv;
+
+ ctptr = x->x_ctable;
+ distptr = x->x_disttable;
+ width = x->x_vwidth;
+ height = x->x_vheight;
+ destptr = dest;
+ destptrv = dest+x->x_vsize;
+ destptru = dest+x->x_vsize+(x->x_vsize>>2);
+ skip = 0 ; /* x->x_vwidth*sizeof(short int)/4 - x->x_vwidth; */
+ c = 0;
+ for (px = 0; px < 512; px++)
+ {
+ i = (c >> 3) & 0x3FE;
+ *ctptr++ = ((sintable[i] * yw) >> 15);
+ *ctptr++ = ((sintable[i+256] * xw) >> 15);
+ c += cw;
+ }
+ maxx = width - 2; maxy = height - 2;
+ for (py = 0; py < height-1; py++)
+ {
+ for (px = 0; px < width; px++)
+ {
+ i = *distptr++;
+ dx = x->x_ctable [i+1] + px;
+ dxu = x->x_ctable [i+1] + (px>>1);
+ dy = x->x_ctable [i] + py;
+ dyu = x->x_ctable [i] + (py>>1);
+
+ if (dx < 0) dx = 0;
+ else if (dx > maxx) dx = maxx;
+ if (dy < 0) dy = 0;
+ else if (dy > maxy) dy = maxy;
+ if (dxu < 0) dxu = 0;
+ else if (dxu > (maxx>>1)) dxu = (maxx>>1);
+ if (dyu < 0) dyu = 0;
+ else if (dyu > (maxy>>1)) dyu = (maxy>>1);
+
+ *destptr++ = src[dy*x->x_vwidth+dx];
+ if ( (py%2==0) && (px%2==0) )
+ {
+ *destptrv++ = src[x->x_vsize+((dyu*x->x_vwidth)>>1)+dxu];
+ *destptru++ = src[x->x_vsize+(x->x_vsize>>2)+((dyu*x->x_vwidth)>>1)+dxu];
+ }
+ }
+ }
+
+}
+
+static void pdp_warp_process_yv12(t_pdp_warp *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);
+ int i;
+
+ unsigned int totalnbpixels;
+ unsigned int u_offset;
+ unsigned int v_offset;
+ unsigned int totnbpixels;
+
+ int px, py;
+ int dx, dy;
+ int h, v;
+ int width, height;
+ int *p, *q, *r;
+ signed char *vp;
+ t_int xw, yw, cw;
+
+ /* allocate all ressources */
+ if ( (int)(header->info.image.width*header->info.image.height) != x->x_vsize )
+ {
+ pdp_warp_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_warp_allocate(x);
+ post( "pdp_warp : reallocated buffers" );
+ }
+
+ totalnbpixels = x->x_vsize;
+ u_offset = x->x_vsize;
+ v_offset = x->x_vsize + (x->x_vsize>>2);
+ totnbpixels = x->x_vsize + (x->x_vsize>>1);
+
+ 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 );
+
+ xw = (int) (sin((x->x_tval+100)*M_PI/128) * 30);
+ yw = (int) (sin((x->x_tval)*M_PI/256) * -35);
+ cw = (int) (sin((x->x_tval-70)*M_PI/64) * 50);
+ xw += (int) (sin((x->x_tval-10)*M_PI/512) * 40);
+ yw += (int) (sin((x->x_tval+30)*M_PI/512) * 40);
+
+ pdp_warp_do_warp( x, data, newdata, xw, yw, cw);
+ if ( x->x_mode ) x->x_tval = (x->x_tval+1) &511;
+
+ return;
+}
+
+static void pdp_warp_sendpacket(t_pdp_warp *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_warp_process(t_pdp_warp *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_warp_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_warp_process_yv12, pdp_warp_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_warp_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_warp_input_0(t_pdp_warp *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_warp_process(x);
+ }
+}
+
+static void pdp_warp_free(t_pdp_warp *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_warp_free_ressources(x);
+}
+
+t_class *pdp_warp_class;
+
+void *pdp_warp_new(void)
+{
+ int i;
+
+ t_pdp_warp *x = (t_pdp_warp *)pd_new(pdp_warp_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("mode"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("tval"));
+
+ 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_mode = 0;
+ x->x_tval = 0;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_warp_setup(void)
+{
+// post( pdp_warp_version );
+ pdp_warp_class = class_new(gensym("pdp_warp"), (t_newmethod)pdp_warp_new,
+ (t_method)pdp_warp_free, sizeof(t_pdp_warp), 0, A_NULL);
+
+ pdp_warp_init_sin_table();
+
+ class_addmethod(pdp_warp_class, (t_method)pdp_warp_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_warp_class, (t_method)pdp_warp_mode, gensym("mode"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_warp_class, (t_method)pdp_warp_tval, gensym("tval"), A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_yqt.c b/modules/pdp_yqt.c
new file mode 100644
index 0000000..5f0ebbe
--- /dev/null
+++ b/modules/pdp_yqt.c
@@ -0,0 +1,444 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+#include "pdp_llconv.h"
+#include <quicktime/lqt.h>
+#include <quicktime/colormodels.h>
+
+#define MIN_AUDIO_INPUT 1024 /* we must have at least n chunks to play a steady sound */
+#define OUTPUT_BUFFER_SIZE 128*1024 /* audio output buffer : 128k */
+#define DECODE_PACKET_SIZE 16*1024 /* size of audio data decoded in one call */
+
+typedef struct pdp_yqt_data
+{
+ short int gain[4];
+} t_pdp_yqt_data;
+
+typedef struct pdp_yqt_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+ t_outlet *x_outlet1;
+ t_outlet *x_outlet2;
+ t_outlet *x_outlet3; /* audio left channel */
+ t_outlet *x_outlet4; /* audio right channel */
+
+ int packet0;
+ bool initialized;
+
+ unsigned int x_vwidth;
+ unsigned int x_vheight;
+
+ bool loop;
+
+ unsigned char * qt_rows[3];
+
+ unsigned char * qt_frame;
+ quicktime_t *qt;
+ int qt_cmodel;
+
+ t_int x_audio; /* indicates the existence of an audio track */
+ t_int x_audio_channels; /* number of audio channels of first track */
+ t_int x_mono; /* indicates a mono audio track */
+ t_int x_audio_rate; /* audio rate */
+ t_int x_resampling_factor; /* resampling factor */
+
+ t_float *x_outbuffer; /* buffer to store audio decoded data */
+ t_int x_outwriteposition;
+ t_int x_outreadposition;
+ t_int x_outunread;
+ t_int x_outbuffersize;
+ t_float *x_outl;
+ t_float *x_outr;
+
+ t_pdp_yqt_data *state_data;
+
+} t_pdp_yqt;
+
+
+
+static void pdp_yqt_close(t_pdp_yqt *x)
+{
+ if (x->initialized){
+ quicktime_close(x->qt);
+ free(x->qt_frame);
+ x->initialized = false;
+ }
+
+}
+
+static void pdp_yqt_open(t_pdp_yqt *x, t_symbol *name)
+{
+ unsigned int size;
+
+ post("pdp_yqt: opening %s", name->s_name);
+
+ pdp_yqt_close(x);
+
+ x->qt = quicktime_open(name->s_name, 1, 0);
+
+ if (!(x->qt)){
+ post("pdp_yqt: error opening qt file");
+ x->initialized = false;
+ return;
+ }
+
+ if (!quicktime_has_video(x->qt)) {
+ post("pdp_yqt: no video stream");
+ quicktime_close(x->qt);
+ x->initialized = false;
+ return;
+
+ }
+ else if (!quicktime_supported_video(x->qt,0)) {
+ post("pdp_yqt: unsupported video codec\n");
+ quicktime_close(x->qt);
+ x->initialized = false;
+ return;
+ }
+ else
+ {
+ x->qt_cmodel = BC_YUV420P;
+ x->x_vwidth = quicktime_video_width(x->qt,0);
+ x->x_vheight = quicktime_video_height(x->qt,0);
+ x->qt_frame = (unsigned char*)malloc(x->x_vwidth*x->x_vheight*4);
+ size = x->x_vwidth * x->x_vheight;
+ x->qt_rows[0] = &x->qt_frame[0];
+ x->qt_rows[2] = &x->qt_frame[size];
+ x->qt_rows[1] = &x->qt_frame[size + (size>>2)];
+
+ quicktime_set_cmodel(x->qt, x->qt_cmodel);
+ x->initialized = true;
+ outlet_float(x->x_outlet2, (float)quicktime_video_length(x->qt,0));
+
+ }
+
+ if (!quicktime_has_audio(x->qt)) {
+ post("pdp_yqt: warning : no audio stream");
+ x->x_audio = 0;
+ return;
+ }
+
+ if ( quicktime_audio_tracks(x->qt) > 1 )
+ {
+ post("pdp_yqt: warning : more that one audio track, using first one");
+ }
+
+ if ( ( x->x_audio_channels = quicktime_track_channels(x->qt, 0) ) != 2 ) {
+ x->x_mono=0;
+ post("pdp_yqt: track 0 has %d channels", x->x_audio_channels );
+ post("pdp_yqt: warning : not a stereo audio track ( audio channels : %d )", x->x_audio_channels );
+ if ( x->x_audio_channels == 1 ) x->x_mono = 1;
+ else x->x_audio_channels = 2;
+ } else {
+ post("pdp_yqt: track 0 has %d channels", x->x_audio_channels );
+ }
+
+ if (!quicktime_supported_audio(x->qt,0)) {
+ post("pdp_yqt: warning : audio not supported" );
+ x->x_audio = 0;
+ } else {
+ x->x_audio = 1;
+ }
+
+ if ( x->x_audio )
+ {
+ post("pdp_yqt: using audio track 0 with %d channels", x->x_audio_channels );
+ post("pdp_yqt: audio data is %d bytes, %d kHz compressed with %s",
+ quicktime_audio_bits(x->qt, 0),
+ x->x_audio_rate = quicktime_sample_rate(x->qt, 0),
+ quicktime_audio_compressor(x->qt, 0) );
+ x->x_resampling_factor = ( sys_getsr() / x->x_audio_rate );
+ }
+
+}
+
+
+static void pdp_yqt_bang(t_pdp_yqt *x)
+{
+ unsigned int w, h, nbpixels, packet_size;
+ int object, length, pos, i, j;
+ short int* data;
+ t_pdp* header;
+
+ static short int gain[4] = {0x7fff, 0x7fff, 0x7fff, 0x7fff};
+
+ if (!(x->initialized)){
+ //post("pdp_yqt: no qt file opened");
+ return;
+ }
+
+ w = x->x_vwidth;
+ h = x->x_vheight;
+ nbpixels = w * h;
+ packet_size = (nbpixels + (nbpixels >> 1)) << 1;
+
+ object = pdp_packet_new_image_YCrCb( x->x_vwidth, x->x_vheight );
+ header = pdp_packet_header(object);
+ data = (short int *) pdp_packet_data(object);
+
+ header->info.image.encoding = PDP_IMAGE_YV12;
+ header->info.image.width = w;
+ header->info.image.height = h;
+
+ length = quicktime_video_length(x->qt,0);
+ pos = quicktime_video_position(x->qt,0);
+ // post("pdp_yqt : video position : %d length =%d", pos, length );
+
+ if (pos >= length){
+ pos = (x->loop) ? 0 : length - 1;
+ // post("pdp_yqt : setting video position to %d", pos);
+ quicktime_set_video_position(x->qt, pos, 0);
+ if (x->loop)
+ {
+ // post("pdp_yqt : resetting audio position");
+ if ( x->x_audio ) quicktime_set_audio_position(x->qt, 0, 0);
+ }
+ }
+
+ lqt_decode_video(x->qt, x->qt_rows, 0);
+
+ switch(x->qt_cmodel){
+ case BC_YUV420P:
+ pdp_llconv(x->qt_frame, RIF_YVU__P411_U8, data, RIF_YVU__P411_S16, x->x_vwidth, x->x_vheight);
+ break;
+
+ case BC_YUV422:
+ pdp_llconv(x->qt_frame, RIF_YUYV_P____U8, data, RIF_YVU__P411_S16, x->x_vwidth, x->x_vheight);
+ break;
+
+ case BC_RGB888:
+ pdp_llconv(x->qt_frame, RIF_RGB__P____U8, data, RIF_YVU__P411_S16, x->x_vwidth, x->x_vheight);
+ break;
+
+ default:
+ post("pdp_yqt : error on decode: unkown colour model");
+ break;
+ }
+
+ outlet_float(x->x_outlet1, (float)pos);
+ pdp_packet_pass_if_valid(x->x_outlet0, &object);
+
+ // fills in the audio buffer with a chunk if necessary
+ if ( x->x_audio && x->x_outunread < MIN_AUDIO_INPUT )
+ {
+ int csize, rsize;
+
+ // watch remaining size
+ rsize = (int ) ( quicktime_audio_length(x->qt, 0) - quicktime_audio_position(x->qt, 0) );
+ csize = ( rsize < DECODE_PACKET_SIZE ) ? rsize : DECODE_PACKET_SIZE;
+
+ // post("pdp_yqt : decode one chunk (size=%d)", csize );
+ if ( ( quicktime_decode_audio(x->qt, NULL, x->x_outl, csize, 1) <0 ) ||
+ ( !x->x_mono && ( quicktime_decode_audio(x->qt, NULL, x->x_outl, csize, 2) <0 ) ) )
+ {
+ post("pdp_yqt : could not decode audio data" );
+ } else {
+ for ( i=0; i<csize; i++ )
+ {
+ if ( x->x_outunread >= x->x_outbuffersize-2 )
+ {
+ post( "pdp_yqt: decode audio : too much input ... ignored" );
+ continue;
+ }
+ for ( j=0; j<x->x_resampling_factor; j++ )
+ {
+ *(x->x_outbuffer+x->x_outwriteposition) = x->x_outl[i];
+ x->x_outwriteposition = (x->x_outwriteposition + 1)%x->x_outbuffersize;
+ *(x->x_outbuffer+x->x_outwriteposition) =
+ ((x->x_mono)? x->x_outl[i] : x->x_outr[i] );
+ x->x_outwriteposition = (x->x_outwriteposition + 1)%x->x_outbuffersize;
+ x->x_outunread+=2;
+ }
+ }
+ }
+ }
+
+}
+
+static void pdp_yqt_loop(t_pdp_yqt *x, t_floatarg loop)
+{
+ int loopi = (int)loop;
+ x->loop = !(loopi == 0);
+}
+
+static void pdp_yqt_frame_cold(t_pdp_yqt *x, t_floatarg frameindex)
+{
+ int frame = (int)frameindex;
+ int length;
+
+
+ if (!(x->initialized)) return;
+
+ length = quicktime_video_length(x->qt,0);
+
+ frame = (frame >= length) ? length-1 : frame;
+ frame = (frame < 0) ? 0 : frame;
+
+ // post("pdp_yqt : frame cold : setting video position to : %d", frame );
+ quicktime_set_video_position(x->qt, frame, 0);
+}
+
+static void pdp_yqt_frame(t_pdp_yqt *x, t_floatarg frameindex)
+{
+ // pdp_yqt_frame_cold(x, frameindex);
+ pdp_yqt_bang(x);
+}
+
+static void pdp_yqt_gain(t_pdp_yqt *x, t_floatarg f)
+{
+ int i;
+ short int g;
+ float bound = (float)0x7fff;
+
+ f *= (float)0x7fff;
+
+ f = (f>bound) ? bound : f;
+ f = (f<-bound) ? -bound : f;
+
+ g = (short int)f;
+
+ for (i=0; i<4; i++) x->state_data->gain[i] = g;
+}
+
+static void pdp_yqt_free(t_pdp_yqt *x)
+{
+
+ free (x->state_data);
+ pdp_yqt_close(x);
+
+ freebytes(x->x_outbuffer, OUTPUT_BUFFER_SIZE*sizeof(t_float));
+ freebytes(x->x_outl, DECODE_PACKET_SIZE*sizeof(t_float));
+ freebytes(x->x_outr, DECODE_PACKET_SIZE*sizeof(t_float));
+}
+
+t_class *pdp_yqt_class;
+
+void *pdp_yqt_new(void)
+{
+ t_pdp_yqt *x = (t_pdp_yqt *)pd_new(pdp_yqt_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("frame_cold"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("gain"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
+
+ x->x_outlet3 = outlet_new(&x->x_obj, &s_signal); /* audio left channel */
+ x->x_outlet4 = outlet_new(&x->x_obj, &s_signal); /* audio right channel */
+
+ x->packet0 = -1;
+
+ x->initialized = false;
+
+ x->loop = false;
+
+ x->state_data = (t_pdp_yqt_data *)malloc(sizeof(t_pdp_yqt_data));
+ pdp_yqt_gain(x, 1.0f);
+
+ // allocate audio buffers
+ x->x_outbuffersize = OUTPUT_BUFFER_SIZE;
+ x->x_outl = (t_float*) getbytes(DECODE_PACKET_SIZE*sizeof(t_float));
+ x->x_outr = (t_float*) getbytes(DECODE_PACKET_SIZE*sizeof(t_float));
+ x->x_outbuffer = (t_float*) getbytes(OUTPUT_BUFFER_SIZE*sizeof(t_float));
+
+ if ( !x->x_outl || !x->x_outr || !x->x_outbuffer )
+ {
+ post( "mp3amp~: could not allocate buffers" );
+ return NULL;
+ }
+ memset( x->x_outl, 0x0, DECODE_PACKET_SIZE*sizeof(t_float) );
+ memset( x->x_outr, 0x0, DECODE_PACKET_SIZE*sizeof(t_float) );
+ memset( x->x_outbuffer, 0x0, OUTPUT_BUFFER_SIZE*sizeof(t_float) );
+
+ x->x_outreadposition = 0;
+ x->x_outwriteposition = 0;
+ x->x_outunread = 0;
+
+ return (void *)x;
+}
+
+static t_int *pdp_yqt_perform(t_int *w)
+{
+ t_pdp_yqt *x = (t_pdp_yqt*) (w[1]);
+ t_float *out1 = (t_float *)(w[2]);
+ t_float *out2 = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ int ret;
+ int i = 0;
+
+ while( n-- )
+ {
+ if ( x->x_audio && x->x_outunread > 0 )
+ {
+ *out1++=*(x->x_outbuffer+x->x_outreadposition);
+ x->x_outreadposition = (x->x_outreadposition + 1)%x->x_outbuffersize;
+ *out2++=*(x->x_outbuffer+x->x_outreadposition);
+ x->x_outreadposition = (x->x_outreadposition + 1)%x->x_outbuffersize;
+ x->x_outunread-=2;
+ }
+ else
+ {
+ *out1++=0.;
+ *out2++=0.;
+ }
+ }
+
+ return (w+5);
+}
+
+static void pdp_yqt_dsp(t_pdp_yqt *x, t_signal **sp)
+{
+ dsp_add(pdp_yqt_perform, 4, x, sp[1]->s_vec, sp[2]->s_vec, sp[1]->s_n);
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_yqt_setup(void)
+{
+ pdp_yqt_class = class_new(gensym("pdp_yqt"), (t_newmethod)pdp_yqt_new,
+ (t_method)pdp_yqt_free, sizeof(t_pdp_yqt), 0, A_NULL);
+
+ class_addmethod(pdp_yqt_class, (t_method)pdp_yqt_bang, gensym("bang"), A_NULL);
+ class_addmethod(pdp_yqt_class, (t_method)pdp_yqt_close, gensym("close"), A_NULL);
+ class_addmethod(pdp_yqt_class, (t_method)pdp_yqt_open, gensym("open"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_yqt_class, (t_method)pdp_yqt_loop, gensym("loop"), A_DEFFLOAT, A_NULL);
+ class_addfloat (pdp_yqt_class, (t_method)pdp_yqt_frame);
+ class_addmethod(pdp_yqt_class, (t_method)pdp_yqt_frame_cold, gensym("frame_cold"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_yqt_class, (t_method)pdp_yqt_gain, gensym("gain"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_yqt_class, nullfn, gensym("signal"), 0);
+ class_addmethod(pdp_yqt_class, (t_method)pdp_yqt_dsp, gensym("dsp"), 0);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_yvu2rgb.c b/modules/pdp_yvu2rgb.c
new file mode 100644
index 0000000..ba22d8b
--- /dev/null
+++ b/modules/pdp_yvu2rgb.c
@@ -0,0 +1,185 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+#include "yuv.h"
+#include <math.h>
+
+
+typedef struct pdp_yvu2rgb_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;
+
+ unsigned int *x_RGBFrame;
+ t_int x_RGBFrameSize;
+
+
+} t_pdp_yvu2rgb;
+
+static void pdp_yvu2rgb_process_yv12(t_pdp_yvu2rgb *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);
+ int i;
+
+ unsigned int w = header->info.image.width;
+ unsigned int h = header->info.image.height;
+
+ unsigned int size = w*h;
+ unsigned int totalnbpixels = size;
+ unsigned int u_offset = size;
+ unsigned int v_offset = size + (size>>2);
+ unsigned int totnbpixels = size + (size>>1);
+
+ unsigned int row, col;
+
+ newheader->info.image.encoding = header->info.image.encoding;
+ newheader->info.image.width = w;
+ newheader->info.image.height = h;
+
+ if ( !x->x_RGBFrame )
+ {
+ x->x_RGBFrame = ( unsigned int* ) getbytes( size*sizeof( unsigned int ) );
+ x->x_RGBFrameSize = size*sizeof( unsigned int );
+ post( "pdp_yvu2rgb : allocated frame size=%d", x->x_RGBFrameSize );
+ }
+ if ( !x->x_RGBFrame )
+ {
+ post( "pdp_yvu2rgb : cannot allocate frame" );
+ return;
+ }
+
+ yuv_Y122RGB( data, x->x_RGBFrame, w, h );
+ // post( "pdp_yvu2rgb : converted to RGB" );
+ yuv_RGB2Y12( x->x_RGBFrame, newdata, w, h );
+ // post( "pdp_yvu2rgb : converted to Y12" );
+
+ return;
+}
+
+static void pdp_yvu2rgb_sendpacket(t_pdp_yvu2rgb *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_yvu2rgb_process(t_pdp_yvu2rgb *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_yvu2rgb_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_yvu2rgb_process_yv12, pdp_yvu2rgb_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ // pdp_yvu2rgb_process_packet(x);
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_yvu2rgb_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_yvu2rgb_input_0(t_pdp_yvu2rgb *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_yvu2rgb_process(x);
+ }
+}
+
+static void pdp_yvu2rgb_free(t_pdp_yvu2rgb *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ if (x->x_RGBFrame ) freebytes( x->x_RGBFrame, x->x_RGBFrameSize );
+}
+
+t_class *pdp_yvu2rgb_class;
+
+void *pdp_yvu2rgb_new(void)
+{
+ int i;
+
+ t_pdp_yvu2rgb *x = (t_pdp_yvu2rgb *)pd_new(pdp_yvu2rgb_class);
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_queue_id = -1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_yvu2rgb_setup(void)
+{
+
+
+ pdp_yvu2rgb_class = class_new(gensym("pdp_yvu2rgb"), (t_newmethod)pdp_yvu2rgb_new,
+ (t_method)pdp_yvu2rgb_free, sizeof(t_pdp_yvu2rgb), 0, A_NULL);
+
+ class_addmethod(pdp_yvu2rgb_class, (t_method)pdp_yvu2rgb_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif