aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorTom Schouten <doelie@users.sourceforge.net>2003-01-21 10:27:33 +0000
committerTom Schouten <doelie@users.sourceforge.net>2003-01-21 10:27:33 +0000
commit9b8745d5250c9d0b60c9aa5a77f58a3fcddf1076 (patch)
tree8372b6a414a7124cec57efc9c80845e2bc1b157d /modules
This commit was generated by cvs2svn to compensate for changes in r352,svn2git-root
which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/pdp/; revision=353
Diffstat (limited to 'modules')
-rw-r--r--modules/Makefile16
-rw-r--r--modules/README33
-rw-r--r--modules/pdp_add.c205
-rw-r--r--modules/pdp_affine.c223
-rw-r--r--modules/pdp_bq.c698
-rw-r--r--modules/pdp_chrot.c201
-rw-r--r--modules/pdp_conv.c325
-rw-r--r--modules/pdp_del.c196
-rw-r--r--modules/pdp_gain.c227
-rw-r--r--modules/pdp_gradient.c331
-rw-r--r--modules/pdp_grey.c168
-rw-r--r--modules/pdp_mix.c279
-rw-r--r--modules/pdp_mul.c205
-rw-r--r--modules/pdp_noise.c230
-rw-r--r--modules/pdp_qt.c941
-rw-r--r--modules/pdp_randmix.c228
-rw-r--r--modules/pdp_reg.c132
-rw-r--r--modules/pdp_route.c129
-rw-r--r--modules/pdp_scale.c267
-rw-r--r--modules/pdp_scope.c312
-rw-r--r--modules/pdp_snap.c146
-rw-r--r--modules/pdp_trigger.c105
-rw-r--r--modules/pdp_v4l.c734
-rw-r--r--modules/pdp_xv.c534
-rw-r--r--modules/pdp_zoom.c264
25 files changed, 7129 insertions, 0 deletions
diff --git a/modules/Makefile b/modules/Makefile
new file mode 100644
index 0000000..3b5d402
--- /dev/null
+++ b/modules/Makefile
@@ -0,0 +1,16 @@
+current: all_modules
+
+include ../Makefile.config
+
+OBJECTS = pdp_xv.o pdp_qt.o pdp_add.o pdp_reg.o pdp_conv.o \
+ pdp_mix.o pdp_v4l.o pdp_affine.o pdp_del.o pdp_mul.o pdp_randmix.o \
+ pdp_snap.o pdp_trigger.o pdp_bq.o pdp_noise.o pdp_gradient.o \
+ pdp_route.o pdp_gain.o pdp_grey.o pdp_chrot.o pdp_scope.o \
+ pdp_scale.o pdp_zoom.o
+
+all_modules: $(OBJECTS)
+
+clean:
+ rm -f *~
+ rm -f *.o
+
diff --git a/modules/README b/modules/README
new file mode 100644
index 0000000..537ff2d
--- /dev/null
+++ b/modules/README
@@ -0,0 +1,33 @@
+This file describes the protocol used for communicating packets.
+See include/pdp.h and the sources in this directory for more info.
+
+There are 3 kinds of pdp messages:
+
+[pdp register_ro <packet_id>]
+[pdp register_rw <packet_id>]
+[pdp process]
+
+An object can receive a packet by catching the 3 kinds of messages:
+
+When a register_ro message is received, the object can call
+pdp_packet_copy_ro(packet) to reseve a read only copy for itself.
+The only operations on the packet at that time are read only
+operations.
+
+The same goes for handling the register_rw message. You can
+reserve a read/write copy by using pdp_packet_copy_rw(packet)
+
+When a process message is received, the object is allowed to start
+processing the data.
+
+In the register_ro or register_rw phases, the object can inspect
+the packet to see if it wants to register it (using pdp_packet_header
+and pdp_packet_data operations) but it is not allowed to allocate other objects
+in that phase. This is only allowed in the process phase. (or after
+the receiving packet is registerd.)
+
+An object can send out a pdp message using the outlet_pdp(outlet, packet)
+function. This sends out these 3 messages in sequence. It is best to
+unregister a packet using pdp_packet_mark_unused(packet) before sending it out,
+if it is no longer used by the sending object. This eliminates one extra
+copy operation on the data.
diff --git a/modules/pdp_add.c b/modules/pdp_add.c
new file mode 100644
index 0000000..9bf8c13
--- /dev/null
+++ b/modules/pdp_add.c
@@ -0,0 +1,205 @@
+/*
+ * 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"
+
+typedef struct pdp_add_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0; // packet outlet
+
+ int x_packet0; // current hot packet (left inlet)
+ int x_packet1; // current cold packet (right inlet)
+ int x_packet1next; // next cold packet (right inlet)
+ int x_queue_id; // task id in process queue (for callback cancelling)
+ int x_dropped; // indicate if a packet was dropped during register_rw cycle
+
+} t_pdp_add;
+
+
+
+static void pdp_add_process_yv12(t_pdp_add *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+
+ // set hight so it includes the chroma frames
+ h = h + (h>>1);
+
+ pdp_imageproc_add_process((short int*)data0, (short int*)data1, w, h);
+
+
+ return;
+}
+
+static void pdp_add_process_grey(t_pdp_add *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ pdp_imageproc_add_process((short int*)data0, (short int*)data1, w, h);
+
+
+ return;
+}
+
+static void pdp_add_process(t_pdp_add *x)
+{
+ int encoding;
+
+ /* check if image data packets are compatible */
+ if (pdp_type_compat_image(x->x_packet0, x->x_packet1)){
+
+ /* dispatch to process thread */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_add_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_add_process_grey(x);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont process */
+
+ }
+ }
+}
+
+/* this method is called after the thread has finished processing */
+static void pdp_add_sendpacket(t_pdp_add *x)
+{
+
+ /* unregister (mark unused) packet and propagate if packet is valid */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+
+}
+
+static void pdp_add_input_0(t_pdp_add *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* if a cold packet was received in the meantime
+ swap it in, else keep the old one */
+
+ pdp_replace_if_valid(&x->x_packet1, &x->x_packet1next);
+
+
+ /* add the process method and callback to the process queue */
+
+ pdp_queue_add(x, pdp_add_process, pdp_add_sendpacket, &x->x_queue_id);
+ }
+}
+
+static void pdp_add_input_1(t_pdp_add *x, t_symbol *s, t_floatarg f)
+{
+ /* store the packet and trow away
+ the old one, if there is any */
+
+ int p = (int)f;
+
+ if(s == gensym("register_ro")) pdp_packet_copy_ro_or_drop(&x->x_packet1next, p);
+
+}
+
+
+
+
+
+static void pdp_add_free(t_pdp_add *x)
+{
+ /* remove process method from queue before deleting data */
+ pdp_queue_finish(x->x_queue_id);
+
+ /* delete stuff */
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+ pdp_packet_mark_unused(x->x_packet1next);
+
+}
+
+t_class *pdp_add_class;
+
+
+
+void *pdp_add_new(void)
+{
+ t_pdp_add *x = (t_pdp_add *)pd_new(pdp_add_class);
+
+ /* init in/out */
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ /* init pdp vars */
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_packet1next = -1;
+ x->x_queue_id = -1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_add_setup(void)
+{
+
+
+ pdp_add_class = class_new(gensym("pdp_add"), (t_newmethod)pdp_add_new,
+ (t_method)pdp_add_free, sizeof(t_pdp_add), 0, A_NULL);
+
+
+ class_addmethod(pdp_add_class, (t_method)pdp_add_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_add_class, (t_method)pdp_add_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_affine.c b/modules/pdp_affine.c
new file mode 100644
index 0000000..06d41ac
--- /dev/null
+++ b/modules/pdp_affine.c
@@ -0,0 +1,223 @@
+/*
+ * 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_mmx.h"
+
+
+typedef struct pdp_affine_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ int x_packet0;
+ int x_queue_id;
+ int x_dropped; // indicate if a packet was dropped during register_rw cycle
+
+ int x_channel;
+
+ void *x_affine;
+
+} t_pdp_affine;
+
+
+
+static void pdp_affine_process_yv12(t_pdp_affine *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data (x->x_packet0);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ unsigned int size = w*h;
+ unsigned int v_offset = size;
+ unsigned int u_offset = size + (size >> 2) ;
+ unsigned int i,j;
+
+ short int * idata = (short int *)data0;
+ int ch = x->x_channel;
+
+ if((ch == 0) || (ch==1)) pdp_imageproc_affine_process(x->x_affine, &idata[0], w, h);
+ if((ch == 0) || (ch==2)) pdp_imageproc_affine_process(x->x_affine, &idata[v_offset], w>>1, h>>1);
+ if((ch == 0) || (ch==3)) pdp_imageproc_affine_process(x->x_affine, &idata[u_offset], w>>1, h>>1);
+
+ return;
+
+
+}
+
+static void pdp_affine_process_grey(t_pdp_affine *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data (x->x_packet0);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ short int * idata = (short int *)data0;
+ int ch = x->x_channel;
+
+ if((ch == 0) || (ch==1)) pdp_imageproc_affine_process(x->x_affine, &idata[0], w, h);
+
+ return;
+
+
+}
+
+static void pdp_affine_process(t_pdp_affine *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+
+ /* check data packets */
+
+ if ((header0) && (PDP_IMAGE == header0->type)){
+
+ /* pdp_affine_process inputs and write into active inlet */
+ switch(header0->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_affine_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_affine_process_grey(x);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont pdp_affine_process */
+
+ }
+ }
+
+}
+
+static void pdp_affine_sendpacket(t_pdp_affine *x)
+{
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_affine_input_0(t_pdp_affine *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+
+ /* add the process method and callback to the process queue */
+
+ pdp_queue_add(x, pdp_affine_process, pdp_affine_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+
+
+static void pdp_affine_gain(t_pdp_affine *x, t_floatarg f)
+{
+ pdp_imageproc_affine_setgain(x->x_affine, f);
+
+}
+
+static void pdp_affine_offset(t_pdp_affine *x, t_floatarg f)
+{
+ pdp_imageproc_affine_setoffset(x->x_affine, f);
+}
+
+static void pdp_affine_channel(t_pdp_affine *x, t_floatarg f)
+{
+ int ch = (int)f;
+
+
+ if ((ch < 1) || (ch > 3)) ch = 0;
+
+ x->x_channel = ch;
+
+
+}
+static void pdp_affine_free(t_pdp_affine *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_imageproc_affine_delete(x->x_affine);
+ pdp_packet_mark_unused(x->x_packet0);
+
+}
+
+t_class *pdp_affine_class;
+
+
+
+void *pdp_affine_new(t_floatarg f)
+{
+ t_pdp_affine *x = (t_pdp_affine *)pd_new(pdp_affine_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("gain"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("offset"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+
+ x->x_affine = pdp_imageproc_affine_new();
+
+ pdp_affine_gain(x, 1.0f);
+ pdp_affine_offset(x, 0.0f);
+ pdp_affine_channel(x, f);
+
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_affine_setup(void)
+{
+
+
+ pdp_affine_class = class_new(gensym("pdp_affine"), (t_newmethod)pdp_affine_new,
+ (t_method)pdp_affine_free, sizeof(t_pdp_affine), 0, A_DEFFLOAT, A_NULL);
+
+
+ class_addmethod(pdp_affine_class, (t_method)pdp_affine_gain, gensym("gain"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_affine_class, (t_method)pdp_affine_offset, gensym("offset"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_affine_class, (t_method)pdp_affine_channel, gensym("chan"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_affine_class, (t_method)pdp_affine_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_bq.c b/modules/pdp_bq.c
new file mode 100644
index 0000000..b7c33c2
--- /dev/null
+++ b/modules/pdp_bq.c
@@ -0,0 +1,698 @@
+/*
+ * 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_mmx.h"
+#include <math.h>
+
+/* computes a transfer function:
+ *
+ * b0 + b1 z^(-1) + b2 z^(-2)
+ * T(z) = --------------------------
+ * 1 + a1 z^(-1) + a2 z^(-2)
+ *
+ * TODO: think about scaling.
+ */
+
+
+/*
+ * TODO:
+ * add another time processing class
+ * add methods for separate horizontal/vertical filters
+ */
+
+
+typedef struct pdp_bq_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+ //_outlet *x_outlet1;
+ //t_outlet *x_outlet2;
+
+ /* pass through packet */
+ int x_packet0;
+
+ /* state packets for bqt */
+ int x_packet1;
+ int x_packet2;
+
+ int x_dropped;
+ int x_queue_id;
+
+ unsigned int x_nbpasses;
+
+ /* single direction */
+ unsigned int x_direction;
+
+ bool x_reset_on_formatchange;
+
+
+ void *x_biquad;
+
+ float x_coefs_a[3]; // a0, -a1, -a2
+ float x_coefs_b[3]; // b0, b1, b2
+ float x_state_u[2]; // u0, u1
+ float x_state_u_save[2]; // u0, u1 (for reset)
+
+} t_pdp_bq;
+
+
+/************************* COEFFICIENT METHODS ****************************/
+
+static void pdp_bq_a0(t_pdp_bq *x, t_floatarg f){x->x_coefs_a[0] = f;}
+static void pdp_bq_a1(t_pdp_bq *x, t_floatarg f){x->x_coefs_a[1] = -f;}
+static void pdp_bq_a2(t_pdp_bq *x, t_floatarg f){x->x_coefs_a[2] = -f;}
+
+static void pdp_bq_b0(t_pdp_bq *x, t_floatarg f){x->x_coefs_b[0] = f;}
+static void pdp_bq_b1(t_pdp_bq *x, t_floatarg f){x->x_coefs_b[1] = f;}
+static void pdp_bq_b2(t_pdp_bq *x, t_floatarg f){x->x_coefs_b[2] = f;}
+
+static void pdp_bq_u0(t_pdp_bq *x, t_floatarg f){x->x_state_u_save[0] = f;}
+static void pdp_bq_u1(t_pdp_bq *x, t_floatarg f){x->x_state_u_save[1] = f;}
+
+
+static void pdp_bq_setcoefs(t_pdp_bq *x,
+ float a0, float a1, float a2,
+ float b0, float b1, float b2)
+{
+ pdp_bq_a0(x,a0);
+ pdp_bq_a1(x,a1);
+ pdp_bq_a2(x,a2);
+ pdp_bq_b0(x,b0);
+ pdp_bq_b1(x,b1);
+ pdp_bq_b2(x,b2);
+ pdp_imageproc_bq_setcoef(x->x_biquad, x->x_coefs_a);
+}
+
+static void pdp_bq_setstate(t_pdp_bq *x, float u0, float u1)
+{
+ pdp_bq_u0(x,u0);
+ pdp_bq_u1(x,u1);
+ pdp_imageproc_bq_setcoef(x->x_biquad, x->x_coefs_a);
+}
+
+
+
+/* reso lowpass */
+static void pdp_bq_lpf(t_pdp_bq *x, t_floatarg f, t_floatarg Q)
+{
+ float a0, a1, a2, b0, b1, b2, cs, sn, w, alpha;
+ w = 2.0 * M_PI * f;
+ cs = cos(w);
+ sn = sin(w);
+
+ alpha = sn*sinh(1.0f/(2.0f*Q));
+ b0 = (1.0 - cs)/2.0;
+ b1 = 1.0 - cs;
+ b2 = (1.0 - cs)/2.0;
+ a0 = (1.0 + alpha);
+ a1 = -2.0*cs;
+ a2 = 1.0 - alpha;
+
+ pdp_bq_setcoefs(x, a0, a1, a2, b0, b1, b2);
+
+}
+
+/* reso highpass */
+static void pdp_bq_hpf(t_pdp_bq *x, t_floatarg f, t_floatarg Q)
+{
+ float a0, a1, a2, b0, b1, b2, cs, sn, w, alpha;
+ w = 2.0 * M_PI * f;
+ cs = cos(w);
+ sn = sin(w);
+
+ alpha = sn*sinh(1.0f/(2.0f*Q));
+
+ b0 = (1.0 + cs)/2.0;
+ b1 = -1.0 - cs;
+ b2 = (1.0 + cs)/2.0;
+ a0 = (1.0 + alpha);
+ a1 = -2.0*cs;
+ a2 = 1.0 - alpha;
+
+ pdp_bq_setcoefs(x, a0, a1, a2, b0, b1, b2);
+
+}
+
+
+/* reso allpass */
+static void pdp_bq_apf(t_pdp_bq *x, t_floatarg f, t_floatarg Q)
+{
+ float a0, a1, a2, b0, b1, b2, cs, sn, w, alpha;
+ w = 2.0 * M_PI * f;
+ cs = cos(w);
+ sn = sin(w);
+
+ alpha = sn*sinh(1.0f/(2.0f*Q));
+
+ b0 = (1.0 - alpha);
+ b1 = -2.0 * cs;
+ b2 = (1.0 + alpha);
+ a0 = (1.0 + alpha);
+ a1 = -2.0*cs;
+ a2 = 1.0 - alpha;
+
+ pdp_bq_setcoefs(x, a0, a1, a2, b0, b1, b2);
+}
+
+/* reso band stop (notch) */
+static void pdp_bq_bsf(t_pdp_bq *x, t_floatarg f, t_floatarg Q)
+{
+ float a0, a1, a2, b0, b1, b2, cs, sn, w, alpha;
+ w = 2.0 * M_PI * f;
+ cs = cos(w);
+ sn = sin(w);
+
+ alpha = sn*sinh(1.0f/(2.0f*Q));
+
+ b0 = 1.0;
+ b1 = -2.0 * cs;
+ b2 = 1.0;
+ a0 = (1.0 + alpha);
+ a1 = -2.0*cs;
+ a2 = 1.0 - alpha;
+
+ pdp_bq_setcoefs(x, a0, a1, a2, b0, b1, b2);
+
+}
+
+static void pdp_bq_onep(t_pdp_bq *x, t_floatarg f)
+{
+ float a0,a1,a2,b0,b1,b2;
+
+ if (f>1.0f) f = 1.0f;
+ if (f<0.0f) f = 0.0f;
+
+ a0 = 1.0f;
+ a1 = -(1.0f - f);
+ a2 = 0.0f;
+ b0 = f;
+ b1 = 0.0f;
+ b2 = 0.0f;
+ pdp_bq_setcoefs(x, a0, a1, a2, b0, b1, b2);
+}
+
+static void pdp_bq_twop(t_pdp_bq *x, t_floatarg f)
+{
+ float f1;
+ float a0,a1,a2,b0,b1,b2;
+
+ if (f>1.0) f = 1.0;
+ if (f<0.0) f = 0.0;
+
+ f1 = 1.0 - f;
+
+ a0 = 1.0f;
+ a1 = -2.0f*f1;
+ a2 = f1*f1;
+ b0 = f*f;
+ b1 = 0.0f;
+ b2 = 0.0f;
+
+ pdp_bq_setcoefs(x, a0, a1, a2, b0, b1, b2);
+}
+
+
+
+
+
+/************************* PROCESS METHODS ****************************/
+
+
+static void pdp_bqt_process_yv12(t_pdp_bq *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ t_pdp *header2 = pdp_packet_header(x->x_packet2);
+
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+ void *data2 = pdp_packet_data (x->x_packet2);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ h = h + (h>>1);
+
+ pdp_imageproc_bqt_process(x->x_biquad, (short int*)data0, (short int*)data1, (short int *)data2, w, h);
+
+ return;
+}
+
+
+
+static void pdp_bqt_process_grey(t_pdp_bq *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ t_pdp *header2 = pdp_packet_header(x->x_packet2);
+
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+ void *data2 = pdp_packet_data (x->x_packet2);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ pdp_imageproc_bqt_process(x->x_biquad, (short int*)data0, (short int*)data1, (short int *)data2, w, h);
+
+ return;
+}
+
+
+
+
+static void pdp_bq_process_yv12(t_pdp_bq *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data (x->x_packet0);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ unsigned int size = w*h;
+ unsigned int v_offset = size;
+ unsigned int u_offset = size + (size >> 2);
+
+ unsigned int nbp = x->x_nbpasses;
+
+ short int * idata = (short int *)data0;
+
+ pdp_imageproc_bq_process(x->x_biquad, idata, w, h, x->x_direction, nbp);
+ pdp_imageproc_bq_process(x->x_biquad, idata + v_offset, w>>1, h>>1, x->x_direction, nbp);
+ pdp_imageproc_bq_process(x->x_biquad, idata + u_offset, w>>1, h>>1, x->x_direction, nbp);
+
+ return;
+}
+
+
+static void pdp_bq_process_grey(t_pdp_bq *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data (x->x_packet0);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ unsigned int nbp = x->x_nbpasses;
+
+ short int * idata = (short int *)data0;
+ pdp_imageproc_bq_process(x->x_biquad, idata, w, h, x->x_direction, nbp);
+
+ return;
+
+}
+
+
+static void pdp_bqt_process(t_pdp_bq *x)
+{
+ int encoding;
+
+ /* image data packets are compatible, this is ensured in the pdp method */
+ /* when the hot packet is received */
+
+ /* process inputs and write into active inlet */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_bqt_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_bqt_process_grey(x);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont process */
+
+ }
+
+}
+
+
+static void pdp_bq_process(t_pdp_bq *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+
+ /* check data packets */
+
+ if ((header0) && (PDP_IMAGE == header0->type)){
+
+ /* process inputs and write into active inlet */
+ switch(header0->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_bq_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_bq_process_grey(x);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont process */
+
+ }
+ }
+
+}
+
+
+static void pdp_bqt_reset(t_pdp_bq *x)
+{
+ t_pdp* header1 = pdp_packet_header(x->x_packet1);
+ t_pdp* header2 = pdp_packet_header(x->x_packet2);
+ void *data1 = pdp_packet_data(x->x_packet1);
+ void *data2 = pdp_packet_data(x->x_packet1);
+ unsigned int w,h,nbpixels,count;
+
+ if (!(header1 && header2)) return;
+ if (header1->type != PDP_IMAGE) return;
+
+ w = header1->info.image.width;
+ h = header1->info.image.height;
+ nbpixels = w*h;
+
+ post("pdp_bqt: resetting state");
+ switch (header1->info.image.encoding){
+ case PDP_IMAGE_YV12:
+ count = (nbpixels + nbpixels >> 1) << 1;
+ bzero(data1, count);
+ bzero(data2, count);
+ break;
+ case PDP_IMAGE_GREY:
+ count = (nbpixels) << 1;
+ bzero(data1, count);
+ bzero(data2, count);
+ break;
+ default:
+ break;
+ }
+
+}
+
+
+
+/************************* INPUT HANDLERS ****************************/
+
+static void pdp_bq_sendpacket(t_pdp_bq *x)
+{
+
+ /* output state packets for those that are interested */
+ //if(x->x_packet2 != -1) outlet_pdp(x->x_outlet2, x->x_packet2);
+ //if(x->x_packet1 != -1) outlet_pdp(x->x_outlet1, x->x_packet1);
+
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_bq_input_0(t_pdp_bq *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+ int passes, i;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* add the process method and callback to the process queue */
+ pdp_queue_add(x, pdp_bq_process, pdp_bq_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+
+
+static void pdp_bqt_input_0(t_pdp_bq *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+ int passes, i;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* check if state packets are compatible */
+ if (!( (pdp_type_compat_image(x->x_packet0, x->x_packet1))
+ && (pdp_packet_header(x->x_packet0)->info.image.encoding
+ == pdp_packet_header(x->x_packet1)->info.image.encoding))){
+
+
+ /* if not, create new state packets by copying the input packets */
+ post("pdp_bqt: created new state packets");
+ pdp_packet_mark_unused(x->x_packet1);
+ pdp_packet_mark_unused(x->x_packet2);
+ x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
+ x->x_packet2 = pdp_packet_clone_rw(x->x_packet0);
+
+ /* reset */
+ if (x->x_reset_on_formatchange) pdp_bqt_reset(x);
+ }
+
+ /* add the process method and callback to the process queue */
+ pdp_queue_add(x, pdp_bqt_process, pdp_bq_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+
+
+/************************* CONFIG METHODS ****************************/
+
+
+static void pdp_bq_passes(t_pdp_bq *x, t_floatarg f)
+{
+ int passes = (int)f;
+ passes = passes < 0 ? 0 : passes;
+ x->x_nbpasses = passes;
+
+}
+
+static void pdp_bq_lr(t_pdp_bq *x, t_floatarg f)
+{
+ if (f == 1.0f) x->x_direction |= PDP_IMAGEPROC_BIQUAD_LEFT2RIGHT;
+ if (f == 0.0f) x->x_direction &= ~PDP_IMAGEPROC_BIQUAD_LEFT2RIGHT;
+}
+
+static void pdp_bq_rl(t_pdp_bq *x, t_floatarg f)
+{
+ if (f == 1.0f) x->x_direction |= PDP_IMAGEPROC_BIQUAD_RIGHT2LEFT;
+ if (f == 0.0f) x->x_direction &= ~PDP_IMAGEPROC_BIQUAD_RIGHT2LEFT;
+}
+static void pdp_bq_tb(t_pdp_bq *x, t_floatarg f)
+{
+ if (f == 1.0f) x->x_direction |= PDP_IMAGEPROC_BIQUAD_TOP2BOTTOM;
+ if (f == 0.0f) x->x_direction &= ~PDP_IMAGEPROC_BIQUAD_TOP2BOTTOM;
+}
+
+static void pdp_bq_bt(t_pdp_bq *x, t_floatarg f)
+{
+ if (f == 1.0f) x->x_direction |= PDP_IMAGEPROC_BIQUAD_BOTTOM2TOP;
+ if (f == 0.0f) x->x_direction &= ~PDP_IMAGEPROC_BIQUAD_BOTTOM2TOP;
+}
+
+
+static void pdp_bq_hor(t_pdp_bq *x, t_floatarg f)
+{
+ pdp_bq_lr(x, f);
+ pdp_bq_rl(x, f);
+}
+static void pdp_bq_ver(t_pdp_bq *x, t_floatarg f)
+{
+ pdp_bq_tb(x, f);
+ pdp_bq_bt(x, f);
+}
+
+
+
+/************************* DES/CONSTRUCTORS ****************************/
+
+static void pdp_bq_free(t_pdp_bq *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_imageproc_bq_delete(x->x_biquad);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+ pdp_packet_mark_unused(x->x_packet2);
+
+}
+
+
+void pdp_bq_init(t_pdp_bq *x)
+{
+
+
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_packet2 = -1;
+
+ x->x_queue_id = -1;
+
+ x->x_nbpasses = 1;
+ x->x_reset_on_formatchange = true;
+
+ x->x_biquad = pdp_imageproc_bq_new();
+
+
+ pdp_bq_setstate(x, 0.0f, 0.0f);
+ pdp_bq_onep(x, 0.1f);
+
+}
+
+
+
+/* class pointers */
+
+t_class *pdp_bq_class; /* biquad spacial processing */
+t_class *pdp_bqt_class; /* biquad time processing */
+
+void *pdp_bq_new(void)
+{
+ t_pdp_bq *x = (t_pdp_bq *)pd_new(pdp_bq_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("passes"));
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ pdp_bq_init(x);
+ return (void *)x;
+}
+
+void *pdp_bqt_new(void)
+{
+ t_pdp_bq *x = (t_pdp_bq *)pd_new(pdp_bqt_class);
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ //x->x_outlet1 = outlet_new(&x->x_obj, &s_anything);
+ //x->x_outlet2 = outlet_new(&x->x_obj, &s_anything);
+ pdp_bq_init(x);
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+
+
+
+/************************* CLASS CONSTRUCTORS ****************************/
+
+
+void pdp_bq_setup(void)
+{
+
+ /* setup spatial processing class */
+
+ pdp_bq_class = class_new(gensym("pdp_bq"), (t_newmethod)pdp_bq_new,
+ (t_method)pdp_bq_free, sizeof(t_pdp_bq), 0, A_NULL);
+
+
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_passes, gensym("passes"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_hor, gensym("hor"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_ver, gensym("ver"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_tb, gensym("tb"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_bt, gensym("bt"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_lr, gensym("lr"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_rl, gensym("rl"), A_FLOAT, A_NULL);
+
+
+
+ /* raw coefficient methods */
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_a1, gensym("a1"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_a2, gensym("a2"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_b0, gensym("b0"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_b1, gensym("b1"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_b2, gensym("b2"), A_FLOAT, A_NULL);
+ //class_addmethod(pdp_bq_class, (t_method)pdp_bq_u1, gensym("u1"), A_FLOAT, A_NULL);
+ //class_addmethod(pdp_bq_class, (t_method)pdp_bq_u2, gensym("u2"), A_FLOAT, A_NULL);
+
+ /* real pole filters */
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_onep, gensym("onep"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_twop, gensym("twop"), A_FLOAT, A_NULL);
+
+ /* resonnant pole filters */
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_lpf, gensym("lpf"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_hpf, gensym("hpf"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_apf, gensym("apf"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_bsf, gensym("bsf"), A_FLOAT, A_FLOAT, A_NULL);
+
+
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+
+
+
+
+
+
+ /* setup time processing class */
+ pdp_bqt_class = class_new(gensym("pdp_bqt"), (t_newmethod)pdp_bqt_new,
+ (t_method)pdp_bq_free, sizeof(t_pdp_bq), 0, A_NULL);
+
+
+ /* raw coefficient methods */
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_a1, gensym("a1"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_a2, gensym("a2"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_b0, gensym("b0"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_b1, gensym("b1"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_b2, gensym("b2"), A_FLOAT, A_NULL);
+ //class_addmethod(pdp_bqt_class, (t_method)pdp_bq_u1, gensym("u1"), A_FLOAT, A_NULL);
+ //class_addmethod(pdp_bqt_class, (t_method)pdp_bq_u2, gensym("u2"), A_FLOAT, A_NULL);
+
+ /* real pole filters */
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_onep, gensym("onep"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_twop, gensym("twop"), A_FLOAT, A_NULL);
+
+ /* resonnant pole filters */
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_lpf, gensym("lpf"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_hpf, gensym("hpf"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_apf, gensym("apf"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_bsf, gensym("bsf"), A_FLOAT, A_FLOAT, A_NULL);
+
+ /* control */
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bqt_reset, gensym("reset"), A_NULL);
+
+
+
+ /* pdp */
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bqt_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+
+
+
+
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_chrot.c b/modules/pdp_chrot.c
new file mode 100644
index 0000000..5181195
--- /dev/null
+++ b/modules/pdp_chrot.c
@@ -0,0 +1,201 @@
+/*
+ * 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_mmx.h"
+#include <math.h>
+
+
+typedef struct pdp_chrot_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ int x_packet0;
+ int x_queue_id;
+ int x_dropped; // indicate if a packet was dropped during register_rw cycle
+
+ int x_channel;
+
+ float x_matrix[4];
+
+ void *x_crot2d;
+
+} t_pdp_chrot;
+
+
+
+static void pdp_chrot_process_yv12(t_pdp_chrot *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data (x->x_packet0);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ unsigned int size = w*h;
+ unsigned int v_offset = size;
+
+ short int * idata = (short int *)data0;
+
+
+ /* color rotation for 2 colour planes */
+ pdp_imageproc_crot2d_process(x->x_crot2d, idata + v_offset, w>>1, h>>1);
+
+
+ return;
+
+
+}
+
+static void pdp_chrot_process(t_pdp_chrot *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+
+ /* check data packets */
+
+ if ((header0) && (PDP_IMAGE == header0->type)){
+
+ /* pdp_chrot_process inputs and write into active inlet */
+ switch(header0->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_chrot_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont pdp_chrot_process */
+
+ }
+ }
+
+}
+
+static void pdp_chrot_sendpacket(t_pdp_chrot *x)
+{
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_chrot_input_0(t_pdp_chrot *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+
+ /* add the process method and callback to the process queue */
+
+ pdp_queue_add(x, pdp_chrot_process, pdp_chrot_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+
+static void pdp_chrot_setelement(t_pdp_chrot *x, int element, float f)
+{
+ x->x_matrix[element] = f;
+
+}
+
+static void pdp_chrot_angle_radians(t_pdp_chrot *x, t_floatarg angle)
+{
+ float c = cos(angle);
+ float s = sin(angle);
+
+ pdp_chrot_setelement(x, 0, c);
+ pdp_chrot_setelement(x, 1, s);
+ pdp_chrot_setelement(x, 2, -s);
+ pdp_chrot_setelement(x, 3, c);
+
+ pdp_imageproc_crot2d_setmatrix(x->x_crot2d, x->x_matrix);
+}
+
+static void pdp_chrot_angle_degrees(t_pdp_chrot *x, t_floatarg angle)
+{
+ pdp_chrot_angle_radians(x, (angle * (M_PI / 180.f)));
+
+}
+
+static void pdp_chrot_free(t_pdp_chrot *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_imageproc_crot2d_delete(x->x_crot2d);
+ pdp_packet_mark_unused(x->x_packet0);
+
+}
+
+t_class *pdp_chrot_class;
+
+
+
+void *pdp_chrot_new(t_floatarg f)
+{
+ t_pdp_chrot *x = (t_pdp_chrot *)pd_new(pdp_chrot_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("angle"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+
+ x->x_crot2d = pdp_imageproc_crot2d_new();
+ pdp_chrot_angle_radians(x, 0.0f);
+
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_chrot_setup(void)
+{
+
+
+ pdp_chrot_class = class_new(gensym("pdp_chrot"), (t_newmethod)pdp_chrot_new,
+ (t_method)pdp_chrot_free, sizeof(t_pdp_chrot), 0, A_DEFFLOAT, A_NULL);
+
+
+ class_addmethod(pdp_chrot_class, (t_method)pdp_chrot_angle_degrees, gensym("angle"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_chrot_class, (t_method)pdp_chrot_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_conv.c b/modules/pdp_conv.c
new file mode 100644
index 0000000..885b86b
--- /dev/null
+++ b/modules/pdp_conv.c
@@ -0,0 +1,325 @@
+/*
+ * 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_mmx.h"
+
+
+typedef struct pdp_conv_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+
+ int x_packet0;
+ int x_dropped;
+ int x_queue_id;
+
+ unsigned int x_nbpasses;
+ bool x_horizontal;
+ bool x_vertical;
+
+ void *x_convolver_hor;
+ void *x_convolver_ver;
+
+} t_pdp_conv;
+
+
+
+static void pdp_conv_process_yv12(t_pdp_conv *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data (x->x_packet0);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ unsigned int size = w*h;
+ unsigned int v_offset = size;
+ unsigned int u_offset = size + (size >> 2) ;
+
+
+ unsigned int i,j;
+ unsigned int nbpasses = x->x_nbpasses;
+
+ short int * idata = (short int *)data0;
+
+ int orient;
+
+
+
+
+ orient = PDP_IMAGEPROC_CONV_VERTICAL;
+ if (x->x_vertical){
+ pdp_imageproc_conv_process(x->x_convolver_ver, idata, w, h, orient, nbpasses);
+ pdp_imageproc_conv_process(x->x_convolver_ver, idata+v_offset, w>>1, h>>1, orient, nbpasses);
+ pdp_imageproc_conv_process(x->x_convolver_ver, idata+u_offset, w>>1, h>>1, orient, nbpasses);
+ }
+
+
+
+ orient = PDP_IMAGEPROC_CONV_HORIZONTAL;
+ if (x->x_horizontal){
+ pdp_imageproc_conv_process(x->x_convolver_hor, idata, w, h, orient, nbpasses);
+ pdp_imageproc_conv_process(x->x_convolver_hor, idata+v_offset, w>>1, h>>1, orient, nbpasses);
+ pdp_imageproc_conv_process(x->x_convolver_hor, idata+u_offset, w>>1, h>>1, orient, nbpasses);
+ }
+
+
+ return;
+
+
+}
+static void pdp_conv_process_grey(t_pdp_conv *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data (x->x_packet0);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ unsigned int size = w*h;
+
+
+ unsigned int i,j;
+ unsigned int nbpasses = x->x_nbpasses;
+
+ short int * idata = (short int *)data0;
+
+ int orient;
+
+ if (x->x_vertical){
+ orient = PDP_IMAGEPROC_CONV_VERTICAL;
+ pdp_imageproc_conv_process(x->x_convolver_ver, idata, w, h, orient, nbpasses);
+ }
+
+ if (x->x_horizontal){
+ orient = PDP_IMAGEPROC_CONV_HORIZONTAL;
+ pdp_imageproc_conv_process(x->x_convolver_hor, idata, w, h, orient, nbpasses);
+ }
+
+
+}
+
+static void pdp_conv_process(t_pdp_conv *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+
+ /* check data packets */
+
+ if ((header0) && (PDP_IMAGE == header0->type)){
+
+ /* pdp_conv_process inputs and write into active inlet */
+ switch(header0->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_conv_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_conv_process_grey(x);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont process */
+
+ }
+ }
+
+}
+
+
+static void pdp_conv_sendpacket(t_pdp_conv *x)
+{
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_conv_input_0(t_pdp_conv *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+ int passes, i;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* add the process method and callback to the process queue */
+
+ pdp_queue_add(x, pdp_conv_process, pdp_conv_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+
+
+
+static void pdp_conv_passes(t_pdp_conv *x, t_floatarg f)
+{
+ int passes = (int)f;
+ passes = passes < 0 ? 0 : passes;
+ x->x_nbpasses = passes;
+
+}
+static void pdp_conv_hor(t_pdp_conv *x, t_floatarg f)
+{
+ int hor = (int)f;
+ x->x_horizontal = (hor != 0);
+
+}
+static void pdp_conv_ver(t_pdp_conv *x, t_floatarg f)
+{
+ int ver = (int)f;
+ x->x_vertical = (ver != 0);
+}
+static void pdp_conv_free(t_pdp_conv *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_imageproc_conv_delete(x->x_convolver_hor);
+ pdp_imageproc_conv_delete(x->x_convolver_ver);
+ pdp_packet_mark_unused(x->x_packet0);
+
+}
+
+/* setup hmask */
+
+static void pdp_conv_hleft(t_pdp_conv *x, t_floatarg f)
+{
+ pdp_imageproc_conv_setmin1(x->x_convolver_hor, f);
+
+}
+static void pdp_conv_hmiddle(t_pdp_conv *x, t_floatarg f)
+{
+ pdp_imageproc_conv_setzero(x->x_convolver_hor, f);
+}
+static void pdp_conv_hright(t_pdp_conv *x, t_floatarg f)
+{
+ pdp_imageproc_conv_setplus1(x->x_convolver_hor, f);
+}
+
+static void pdp_conv_hmask(t_pdp_conv *x, t_floatarg l, t_floatarg m, t_floatarg r)
+{
+ pdp_conv_hleft(x, l);
+ pdp_conv_hmiddle(x, m);
+ pdp_conv_hright(x, r);
+}
+
+static void pdp_conv_vtop(t_pdp_conv *x, t_floatarg f)
+{
+ pdp_imageproc_conv_setmin1(x->x_convolver_ver, f);
+}
+static void pdp_conv_vmiddle(t_pdp_conv *x, t_floatarg f)
+{
+ pdp_imageproc_conv_setzero(x->x_convolver_ver, f);
+
+}
+static void pdp_conv_vbottom(t_pdp_conv *x, t_floatarg f)
+{
+ pdp_imageproc_conv_setplus1(x->x_convolver_ver, f);
+}
+
+static void pdp_conv_vmask(t_pdp_conv *x, t_floatarg l, t_floatarg m, t_floatarg r)
+{
+ pdp_conv_vtop(x, l);
+ pdp_conv_vmiddle(x, m);
+ pdp_conv_vbottom(x, r);
+}
+
+
+static void pdp_conv_mask(t_pdp_conv *x, t_floatarg l, t_floatarg m, t_floatarg r)
+{
+ pdp_conv_hmask(x, l, m, r);
+ pdp_conv_vmask(x, l, m, r);
+}
+
+t_class *pdp_conv_class;
+
+
+
+void *pdp_conv_new(void)
+{
+ t_pdp_conv *x = (t_pdp_conv *)pd_new(pdp_conv_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("passes"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+ x->x_nbpasses = 1;
+ x->x_horizontal = true;
+ x->x_vertical = true;
+
+ x->x_convolver_hor = pdp_imageproc_conv_new();
+ x->x_convolver_ver = pdp_imageproc_conv_new();
+
+ pdp_imageproc_conv_setbordercolor(x->x_convolver_hor, 0);
+ pdp_imageproc_conv_setbordercolor(x->x_convolver_ver, 0);
+
+ pdp_conv_mask(x, .25,.5,.25);
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_conv_setup(void)
+{
+
+
+ pdp_conv_class = class_new(gensym("pdp_conv"), (t_newmethod)pdp_conv_new,
+ (t_method)pdp_conv_free, sizeof(t_pdp_conv), 0, A_NULL);
+
+
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_passes, gensym("passes"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_hor, gensym("hor"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_ver, gensym("ver"), A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_hleft, gensym("hleft"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_hmiddle, gensym("hmiddle"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_hright, gensym("hright"), A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_vtop, gensym("vtop"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_vmiddle, gensym("vmiddle"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_vbottom, gensym("vbottom"), A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_vmask, gensym("vmask"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_hmask, gensym("hmask"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_mask, gensym("mask"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_del.c b/modules/pdp_del.c
new file mode 100644
index 0000000..97e47fd
--- /dev/null
+++ b/modules/pdp_del.c
@@ -0,0 +1,196 @@
+/*
+ * 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"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef struct pdp_del_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ int *x_packet;
+ int x_order;
+ int x_head;
+ int x_delay;
+} t_pdp_del;
+
+
+
+
+
+static void pdp_del_input_0(t_pdp_del *x, t_symbol *s, t_floatarg f)
+{
+ int in;
+ int out;
+ int packet;
+
+
+ /* if this is a register_ro message or register_rw message, register with packet factory */
+ /* if this is a process message, start the processing + propagate stuff to outputs */
+
+ if (s == gensym("register_ro")){
+ in = (x->x_head & (x->x_order-1));
+ //post("pdp_del: marking unused packed id=%d on loc %d", x->x_packet[0], in);
+ pdp_packet_mark_unused(x->x_packet[in]);
+ packet = pdp_packet_copy_ro((int)f);
+ x->x_packet[in] = packet;
+ //post("pdp_del: writing packed id=%d on loc %d", packet, in);
+ }
+ else if (s == gensym("process")){
+ out = ((x->x_head + x->x_delay) & (x->x_order-1));
+ packet = x->x_packet[out];
+
+ if (-1 != packet){
+ //post("pdp_del: packet %d has id %d", out, packet);
+ pdp_packet_mark_unused(packet);
+ outlet_pdp(x->x_outlet0, packet);
+ x->x_packet[out] = -1;
+ }
+ else {
+ //post("pdp_del: packet %d is empty", out);
+ }
+ x->x_head--;
+ }
+
+
+}
+
+
+
+
+
+static void pdp_del_delay(t_pdp_del *x, t_floatarg fdel)
+{
+ int del = (int)fdel;
+ if (del < 0) del = 0;
+ if (del >= x->x_order) del = x->x_order - 1;
+
+ x->x_delay = del;
+
+}
+
+static void pdp_del_reset(t_pdp_del *x)
+{
+ int i;
+ for (i=0; i<x->x_order; i++) {
+ pdp_packet_mark_unused(x->x_packet[i]);
+ x->x_packet[i] = -1;
+ }
+ x->x_head = 0;
+
+}
+
+static void pdp_del_free(t_pdp_del *x)
+{
+ pdp_del_reset(x);
+ free (x->x_packet);
+}
+
+t_class *pdp_del_class;
+
+
+
+void *pdp_del_new(t_floatarg forder, t_floatarg fdel)
+{
+ int order = (int)forder;
+ int del;
+ int logorder;
+ int i;
+ t_pdp_del *x = (t_pdp_del *)pd_new(pdp_del_class);
+
+
+ del = order;
+ order++;
+
+ if (del < 0) del = 0;
+
+
+ if (order <= 2) order = 2;
+ else {
+
+ order--;
+ logorder = 1;
+
+
+ while ((order | 1) != 1) {
+ order >>= 1;
+ logorder++;
+ }
+
+ order = 1 << logorder;
+ }
+
+ post("pdp_del: order = %d", order);
+
+ x->x_order = order;
+ x->x_packet = (int *)malloc(sizeof(int)*order);
+ for(i=0; i<order; i++) x->x_packet[i] = -1;
+
+ x->x_delay = del;
+
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("delay"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_del_setup(void)
+{
+
+
+ pdp_del_class = class_new(gensym("pdp_del"), (t_newmethod)pdp_del_new,
+ (t_method)pdp_del_free, sizeof(t_pdp_del), 0, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_del_class, (t_method)pdp_del_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_del_class, (t_method)pdp_del_delay, gensym("delay"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_del_class, (t_method)pdp_del_reset, gensym("reset"), A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_gain.c b/modules/pdp_gain.c
new file mode 100644
index 0000000..a334656
--- /dev/null
+++ b/modules/pdp_gain.c
@@ -0,0 +1,227 @@
+/*
+ * 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"
+
+
+
+typedef struct pdp_gain_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+
+ int x_packet0;
+ int x_dropped;
+ int x_queue_id;
+
+ void *x_gain_y;
+ void *x_gain_v;
+ void *x_gain_u;
+
+} t_pdp_gain;
+
+
+
+static void pdp_gain_process_yv12(t_pdp_gain *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data (x->x_packet0);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ short int * idata = (short int *)data0;
+ unsigned int size = w*h;
+
+ pdp_imageproc_gain_process(x->x_gain_y, idata, w, h);
+ pdp_imageproc_gain_process(x->x_gain_u, idata + size, w>>1, h>>1);
+ pdp_imageproc_gain_process(x->x_gain_v, idata + size + (size>>2) , w>>1, h>>1);
+
+
+ return;
+
+
+}
+static void pdp_gain_process_grey(t_pdp_gain *x)
+{
+
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data (x->x_packet0);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ unsigned int size = w*h;
+ short int * idata = (short int *)data0;
+
+ pdp_imageproc_gain_process(x->x_gain_y, idata, w, h);
+
+ return;
+
+
+}
+
+static void pdp_gain_process(t_pdp_gain *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+
+ /* check data packets */
+
+ if ((header0) && (PDP_IMAGE == header0->type)){
+
+ /* pdp_gain_process inputs and write into active inlet */
+ switch(header0->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_gain_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_gain_process_grey(x);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont process */
+
+ }
+ }
+
+}
+
+
+static void pdp_gain_sendpacket(t_pdp_gain *x)
+{
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_gain_input_0(t_pdp_gain *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+ int passes, i;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* add the process method and callback to the process queue */
+
+ pdp_queue_add(x, pdp_gain_process, pdp_gain_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+
+
+
+static void pdp_gain_gainy(t_pdp_gain *x, t_floatarg f)
+{
+ pdp_imageproc_gain_setgain(x->x_gain_y, f);
+}
+
+static void pdp_gain_gainv(t_pdp_gain *x, t_floatarg f)
+{
+ pdp_imageproc_gain_setgain(x->x_gain_v, f);
+}
+
+static void pdp_gain_gainu(t_pdp_gain *x, t_floatarg f)
+{
+ pdp_imageproc_gain_setgain(x->x_gain_u, f);
+}
+
+static void pdp_gain_gain(t_pdp_gain *x, t_floatarg f)
+{
+ pdp_gain_gainy(x, f);
+ pdp_gain_gainv(x, f);
+ pdp_gain_gainu(x, f);
+
+}
+
+
+
+t_class *pdp_gain_class;
+
+
+
+void pdp_gain_free(t_pdp_gain *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_imageproc_gain_delete(x->x_gain_y);
+ pdp_imageproc_gain_delete(x->x_gain_u);
+ pdp_imageproc_gain_delete(x->x_gain_v);
+}
+
+void *pdp_gain_new(t_floatarg f)
+{
+ t_pdp_gain *x = (t_pdp_gain *)pd_new(pdp_gain_class);
+
+
+ /* no arg, or zero -> gain = 1 */
+ if (f==0.0f) f = 1.0f;
+
+ 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_packet0 = -1;
+ x->x_queue_id = -1;
+
+ x->x_gain_y = pdp_imageproc_gain_new();
+ x->x_gain_u = pdp_imageproc_gain_new();
+ x->x_gain_v = pdp_imageproc_gain_new();
+ pdp_gain_gain(x, f);
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_gain_setup(void)
+{
+
+
+ pdp_gain_class = class_new(gensym("pdp_gain"), (t_newmethod)pdp_gain_new,
+ (t_method)pdp_gain_free, sizeof(t_pdp_gain), 0, A_DEFFLOAT, A_NULL);
+
+
+ class_addmethod(pdp_gain_class, (t_method)pdp_gain_gain, gensym("gain"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_gain_class, (t_method)pdp_gain_gainy, gensym("y"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_gain_class, (t_method)pdp_gain_gainu, gensym("v"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_gain_class, (t_method)pdp_gain_gainv, gensym("u"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_gain_class, (t_method)pdp_gain_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_gradient.c b/modules/pdp_gradient.c
new file mode 100644
index 0000000..5c92e12
--- /dev/null
+++ b/modules/pdp_gradient.c
@@ -0,0 +1,331 @@
+/*
+ * 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"
+
+
+typedef struct yv12_palette_struct
+{
+ short int y;
+ short int u;
+ short int v;
+} t_yv12_palette;
+
+typedef struct pdp_gradient_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ int x_packet0;
+ int x_dropped;
+ int x_queue_id;
+
+ t_yv12_palette x_palette[512];
+
+} t_pdp_gradient;
+
+
+unsigned int float2fixed(float f)
+{
+ f *= 0x8000;
+ if(f>0x7fff) f = 0x7fff;
+ if(f<-0x7fff) f = -0x7fff;
+ return (short int)f;
+}
+
+static void pdp_gradient_yuv_index(t_pdp_gradient *x,
+ t_floatarg index,
+ t_floatarg y,
+ t_floatarg u,
+ t_floatarg v)
+{
+ int i = ((int)index) & 511;
+ x->x_palette[i].y = float2fixed(y);
+ x->x_palette[i].u = float2fixed(u);
+ x->x_palette[i].v = float2fixed(v);
+}
+
+static void pdp_gradient_yuv(t_pdp_gradient *x,
+ t_floatarg y,
+ t_floatarg u,
+ t_floatarg v)
+{
+ int i;
+ float inc = 1.0f / 256.0f;
+ float frac = -1.0f;
+ for(i=-256; i<256; i++) {
+ pdp_gradient_yuv_index(x, i, frac*y, frac*u, frac*v);
+ frac += inc;
+ }
+}
+
+static void pdp_gradient_rgb_index(t_pdp_gradient *x,
+ t_floatarg index,
+ t_floatarg r,
+ t_floatarg g,
+ t_floatarg b)
+{
+ float y,u,v;
+
+
+ y = 0.299f * r + 0.587f * g + 0.114f * b;
+ u = (r-y) * 0.713f;
+ v = (b-y) * 0.565f;
+
+ pdp_gradient_yuv_index(x, index, y,u,v);
+}
+
+static void pdp_gradient_rgb(t_pdp_gradient *x,
+ t_floatarg r,
+ t_floatarg g,
+ t_floatarg b)
+{
+ int i;
+ float inc = 1.0f / 256.0f;
+ float frac = -1.0f;
+ for(i=-256; i<256; i++) {
+ pdp_gradient_rgb_index(x, i, frac*r, frac*g, frac*b);
+ frac += inc;
+ }
+}
+
+/*
+static void pdp_gradient_hsv_index(t_pdp_gradient *x,
+ t_floatarg index,
+ t_floatarg h,
+ t_floatarg s,
+ t_floatarg v)
+{
+ float r,g,b;
+
+ r = h;
+ g = s;
+ b = v;
+
+ pdp_gradient_rgb_index(x, index, r,g,b);
+}
+
+static void pdp_gradient_hsv(t_pdp_gradient *x,
+ t_floatarg h,
+ t_floatarg s,
+ t_floatarg v)
+{
+ int i;
+ float inc = 1.0f / 256.0f;
+ float frac = -1.0f;
+ for(i=-256; i<256; i++) {
+ pdp_gradient_hsv_index(x, i, h, s, frac*v);
+ frac += inc;
+ }
+}
+*/
+
+static void pdp_gradient_process_grey(t_pdp_gradient *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;
+ int newpacket = -1;
+
+ 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 row, col;
+
+ newpacket = pdp_packet_new(PDP_IMAGE, (size + (size>>1))<<1);
+ newheader = pdp_packet_header(newpacket);
+ newdata = (short int *)pdp_packet_data(newpacket);
+
+ newheader->info.image.encoding = PDP_IMAGE_YV12;
+ newheader->info.image.width = w;
+ newheader->info.image.height = h;
+
+ /* convert every pixel according to palette */
+ for(row=0; row < size; row += (w<<1)){
+ for(col=0; col < w; col += 2){
+ short int u_acc, v_acc;
+ short int grey;
+
+ /* top left pixel */
+ grey = ((data[row+col])>>7) & 511;
+ newdata[row+col] = x->x_palette[grey].y;
+ u_acc = (x->x_palette[grey].u)>>2;
+ v_acc = (x->x_palette[grey].v)>>2;
+
+ /* top right pixel */
+ grey = ((data[row+col+1])>>7) & 511;
+ newdata[row+col+1] = x->x_palette[grey].y;
+ u_acc += (x->x_palette[grey].u)>>2;
+ v_acc += (x->x_palette[grey].v)>>2;
+
+ /* bottom left pixel */
+ grey = ((data[row+col+w])>>7) & 511;
+ newdata[row+col+w] = x->x_palette[grey].y;
+ u_acc += (x->x_palette[grey].u)>>2;
+ v_acc += (x->x_palette[grey].v)>>2;
+
+ /* bottom right pixel */
+ grey = ((data[row+col+w+1])>>7) & 511;
+ newdata[row+col+w+1] = x->x_palette[grey].y;
+ u_acc += (x->x_palette[grey].u)>>2;
+ v_acc += (x->x_palette[grey].v)>>2;
+
+ /* store uv comp */
+ newdata[u_offset + (row>>2) + (col>>1)] = u_acc;
+ newdata[v_offset + (row>>2) + (col>>1)] = v_acc;
+ }
+ }
+
+
+
+ /* delete source packet and replace with new packet */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = newpacket;
+ return;
+}
+
+static void pdp_gradient_process_yv12(t_pdp_gradient *x)
+{
+ /* pdp_gradient_process only the luminance channel */
+ pdp_gradient_process_grey(x);
+}
+
+
+
+static void pdp_gradient_process(t_pdp_gradient *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_gradient_process inputs and write into active inlet */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_gradient_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_gradient_process_grey(x);
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_gradient_process */
+
+ break;
+ }
+ }
+}
+
+static void pdp_gradient_sendpacket(t_pdp_gradient *x)
+{
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_gradient_input_0(t_pdp_gradient *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+
+ /* add the process method and callback to the process queue */
+
+ pdp_queue_add(x, pdp_gradient_process, pdp_gradient_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+
+
+static void pdp_gradient_free(t_pdp_gradient *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+
+}
+
+t_class *pdp_gradient_class;
+
+
+
+void *pdp_gradient_new(void)
+{
+ int i;
+
+ t_pdp_gradient *x = (t_pdp_gradient *)pd_new(pdp_gradient_class);
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+
+ for (i=-256; i<256; i++){
+ x->x_palette[i&511].y = i << 7;
+ x->x_palette[i&511].u = (-i) << 6;
+ x->x_palette[i&511].v = (i) << 5;
+ }
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_gradient_setup(void)
+{
+
+
+ pdp_gradient_class = class_new(gensym("pdp_gradient"), (t_newmethod)pdp_gradient_new,
+ (t_method)pdp_gradient_free, sizeof(t_pdp_gradient), 0, A_NULL);
+
+
+ class_addmethod(pdp_gradient_class, (t_method)pdp_gradient_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_gradient_class, (t_method)pdp_gradient_yuv, gensym("yuv"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_gradient_class, (t_method)pdp_gradient_rgb, gensym("rgb"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ // class_addmethod(pdp_gradient_class, (t_method)pdp_gradient_hsv, gensym("hsv"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_grey.c b/modules/pdp_grey.c
new file mode 100644
index 0000000..0626ea9
--- /dev/null
+++ b/modules/pdp_grey.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.
+ *
+ */
+
+
+
+#include "pdp.h"
+
+
+typedef struct pdp_grey_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+
+ int x_packet0;
+
+} t_pdp_grey;
+
+
+
+static void pdp_grey_process(t_pdp_grey *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *headernew;
+ int newpacket;
+ int w;
+ int h;
+
+ /* check data packets */
+
+ if ((header0) && (PDP_IMAGE == header0->type)){
+
+ /* pdp_grey_process inputs and write into active inlet */
+ switch(header0->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ w = header0->info.image.width;
+ h = header0->info.image.height;
+ newpacket = pdp_packet_new(PDP_IMAGE, w*h*2);
+ headernew = pdp_packet_header(newpacket);
+ headernew->info.image.encoding = PDP_IMAGE_GREY;
+ headernew->info.image.width = w;
+ headernew->info.image.height = h;
+ memcpy(pdp_packet_data(newpacket), pdp_packet_data(x->x_packet0), 2*w*h);
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = newpacket;
+ break;
+
+ case PDP_IMAGE_GREY:
+ /* just pass along */
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont process */
+
+ }
+ }
+
+}
+
+
+static void pdp_grey_sendpacket(t_pdp_grey *x)
+{
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_grey_input_0(t_pdp_grey *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+ int passes, i;
+
+ if (s== gensym("register_rw")) pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0)){
+
+ pdp_grey_process(x);
+ pdp_grey_sendpacket(x);
+ }
+
+}
+
+
+
+
+short int pdp_grey_fixedpoint(float f)
+{
+
+ float min = (float)-0x7fff;
+ float max = (float)0x7fff;
+ f *= (float)0x100;
+ if (f>max) f = max;
+ if (f<min) f = min;
+
+ return (short int)f;
+
+}
+
+
+t_class *pdp_grey_class;
+
+
+
+void pdp_grey_free(t_pdp_grey *x)
+{
+}
+
+void *pdp_grey_new(t_floatarg f)
+{
+ t_pdp_grey *x = (t_pdp_grey *)pd_new(pdp_grey_class);
+
+
+ /* no arg, or zero -> gain = 1 */
+ if (f==0.0f) f = 1.0f;
+
+ 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_packet0 = -1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_grey_setup(void)
+{
+
+
+ pdp_grey_class = class_new(gensym("pdp_grey"), (t_newmethod)pdp_grey_new,
+ (t_method)pdp_grey_free, sizeof(t_pdp_grey), 0, A_DEFFLOAT, A_NULL);
+
+
+ class_addmethod(pdp_grey_class, (t_method)pdp_grey_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_mix.c b/modules/pdp_mix.c
new file mode 100644
index 0000000..9602c4b
--- /dev/null
+++ b/modules/pdp_mix.c
@@ -0,0 +1,279 @@
+/*
+ * 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"
+
+
+typedef struct pdp_mix_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+ t_outlet *x_outlet1;
+
+ int x_packet0; // hot packet
+ int x_packet1; // cold packet
+ int x_packet1next; // next cold packet
+ int x_dropped;
+
+ int x_queue_id; // identifier of method in the processing queue
+
+ void *x_mixer;
+
+ int x_extrapolate;
+
+} t_pdp_mix;
+
+
+
+static void pdp_mix_process_yv12(t_pdp_mix *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+
+ h = h + (h>>1);
+ pdp_imageproc_mix_process(x->x_mixer,(short int*)data0, (short int*)data1, w, h);
+
+ return;
+
+
+
+}
+
+static void pdp_mix_process_grey(t_pdp_mix *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ pdp_imageproc_mix_process(x->x_mixer,(short int*)data0, (short int*)data1, w, h);
+
+ return;
+
+
+
+}
+
+static void pdp_mix_process(t_pdp_mix *x)
+{
+ int encoding;
+
+ /* check if image data packets are compatible */
+ if (pdp_type_compat_image(x->x_packet0, x->x_packet1)){
+
+ /* dispatch to process thread */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_mix_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_mix_process_grey(x);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont pdp_mix_process */
+
+ }
+ }
+
+}
+
+static void pdp_mix_sendpacket(t_pdp_mix *x)
+{
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_mix_input_0(t_pdp_mix *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* if a cold packet was received in the meantime
+ swap it in, else keep the old one */
+
+ pdp_replace_if_valid(&x->x_packet1, &x->x_packet1next);
+
+
+ /* add the process method and callback to the process queue */
+
+ pdp_queue_add(x, pdp_mix_process, pdp_mix_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+static void pdp_mix_input_1(t_pdp_mix *x, t_symbol *s, t_floatarg f)
+{
+ /* store the packet and drop
+ the old one, if there is any */
+
+ if(s == gensym("register_ro")) pdp_packet_copy_ro_or_drop(&x->x_packet1next, (int)f);
+
+}
+
+
+
+static void pdp_mix_mix(t_pdp_mix *x, t_floatarg f)
+{
+ float f2;
+ if (!x->x_extrapolate){
+ if (f < 0.0f) f = 0.0f;
+ if (f > 1.0f) f = 1.0f;
+ }
+
+ f2 = (1.0f - f);
+ pdp_imageproc_mix_setleftgain(x->x_mixer, f2);
+ pdp_imageproc_mix_setrightgain(x->x_mixer, f);
+
+}
+
+static void pdp_mix_mix1(t_pdp_mix *x, t_floatarg f)
+{
+ pdp_imageproc_mix_setleftgain(x->x_mixer, f);
+
+}
+static void pdp_mix_mix2(t_pdp_mix *x, t_floatarg f2)
+{
+ pdp_imageproc_mix_setrightgain(x->x_mixer, f2);
+}
+
+static void pdp_mix_extrapolate(t_pdp_mix *x, t_floatarg f)
+{
+ if (f == 0.0f) x->x_extrapolate = 0;
+ if (f == 1.0f) x->x_extrapolate = 1;
+}
+
+
+static void pdp_mix_free(t_pdp_mix *x)
+{
+ /* remove the method from the queue before deleting stuff */
+ pdp_queue_finish(x->x_queue_id);
+
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+ pdp_packet_mark_unused(x->x_packet1next);
+
+ pdp_imageproc_mix_delete(x->x_mixer);
+}
+
+t_class *pdp_mix_class;
+t_class *pdp_mix2_class;
+
+
+void *pdp_mix_common_init(t_pdp_mix *x)
+{
+ int i;
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_packet1next = -1;
+ x->x_queue_id = -1;
+ x->x_extrapolate = 0;
+
+
+ x->x_mixer = pdp_imageproc_mix_new();
+ pdp_mix_mix(x, 0.0f);
+
+
+ return (void *)x;
+}
+
+
+void *pdp_mix_new(t_floatarg mix)
+{
+ t_pdp_mix *x = (t_pdp_mix *)pd_new(pdp_mix_class);
+ pdp_mix_common_init(x);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("mix"));
+ if (mix == 0.0f) mix = 0.5f;
+ pdp_mix_mix(x, mix);
+ return (void *)x;
+}
+
+void *pdp_mix2_new(t_floatarg mix1, t_floatarg mix2)
+{
+ t_pdp_mix *x = (t_pdp_mix *)pd_new(pdp_mix2_class);
+ pdp_mix_common_init(x);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("mix1"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("mix2"));
+ if ((mix1 == 0.0f) && (mix2 == 0.0f)) mix1 = mix2 = 0.5f;
+ pdp_mix_mix1(x, mix1);
+ pdp_mix_mix2(x, mix2);
+ return (void *)x;
+}
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+void pdp_mix_setup(void)
+{
+
+
+ pdp_mix_class = class_new(gensym("pdp_mix"), (t_newmethod)pdp_mix_new,
+ (t_method)pdp_mix_free, sizeof(t_pdp_mix), 0, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_mix_class, (t_method)pdp_mix_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mix_class, (t_method)pdp_mix_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mix_class, (t_method)pdp_mix_mix, gensym("mix"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mix_class, (t_method)pdp_mix_extrapolate, gensym("extrapolate"), A_DEFFLOAT, A_NULL);
+
+ pdp_mix2_class = class_new(gensym("pdp_mix2"), (t_newmethod)pdp_mix2_new,
+ (t_method)pdp_mix_free, sizeof(t_pdp_mix), 0, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_mix2_class, (t_method)pdp_mix_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mix2_class, (t_method)pdp_mix_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mix2_class, (t_method)pdp_mix_mix1, gensym("mix1"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mix2_class, (t_method)pdp_mix_mix2, gensym("mix2"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mix2_class, (t_method)pdp_mix_extrapolate, gensym("extrapolate"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_mul.c b/modules/pdp_mul.c
new file mode 100644
index 0000000..8c06087
--- /dev/null
+++ b/modules/pdp_mul.c
@@ -0,0 +1,205 @@
+/*
+ * 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"
+
+
+typedef struct pdp_mul_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+ t_outlet *x_outlet1;
+
+ int x_packet0;
+ int x_packet1;
+ int x_packet1next;
+ int x_queue_id;
+ int x_dropped;
+
+} t_pdp_mul;
+
+
+static void pdp_mul_process_yv12(t_pdp_mul *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ // set hight so it includes the chroma frames
+ h = h + (h>>1);
+
+ pdp_imageproc_mul_process((short int*)data0, (short int*)data1, w, h);
+
+ return;
+
+
+
+}
+static void pdp_mul_process_grey(t_pdp_mul *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ // set hight so it includes the chroma frames
+ h = h + (h>>1);
+
+ pdp_imageproc_mul_process((short int*)data0, (short int*)data1, w, h);
+
+ return;
+
+
+
+}
+
+static void pdp_mul_process(t_pdp_mul *x)
+{
+ int encoding;
+
+ /* check if image data packets are compatible */
+ if (pdp_type_compat_image(x->x_packet0, x->x_packet1)){
+
+ /* pdp_mul_process inputs and write into active inlet */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_mul_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_mul_process_grey(x);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont pdp_mul_process */
+
+ }
+ }
+}
+
+static void pdp_mul_sendpacket(t_pdp_mul *x)
+{
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_mul_input_0(t_pdp_mul *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* if a cold packet was received in the meantime
+ swap it in, else keep the old one */
+
+ pdp_replace_if_valid(&x->x_packet1, &x->x_packet1next);
+
+
+ /* add the process method and callback to the process queue */
+
+ pdp_queue_add(x, pdp_mul_process, pdp_mul_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+static void pdp_mul_input_1(t_pdp_mul *x, t_symbol *s, t_floatarg f)
+{
+ /* store the packet and drop
+ the old one, if there is any */
+
+ if(s == gensym("register_ro")) pdp_packet_copy_ro_or_drop(&x->x_packet1next, (int)f);
+
+}
+
+
+
+
+
+
+
+static void pdp_mul_free(t_pdp_mul *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+
+}
+
+t_class *pdp_mul_class;
+
+
+
+void *pdp_mul_new(void)
+{
+ t_pdp_mul *x = (t_pdp_mul *)pd_new(pdp_mul_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_packet1next = -1;
+ x->x_queue_id = -1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_mul_setup(void)
+{
+
+
+ pdp_mul_class = class_new(gensym("pdp_mul"), (t_newmethod)pdp_mul_new,
+ (t_method)pdp_mul_free, sizeof(t_pdp_mul), 0, A_NULL);
+
+
+
+ class_addmethod(pdp_mul_class, (t_method)pdp_mul_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mul_class, (t_method)pdp_mul_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_noise.c b/modules/pdp_noise.c
new file mode 100644
index 0000000..f1a4661
--- /dev/null
+++ b/modules/pdp_noise.c
@@ -0,0 +1,230 @@
+/*
+ * 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"
+
+
+
+typedef struct pdp_noise_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ void *x_noisegen;
+
+ int x_packet0;
+ int x_queue_id;
+
+ int x_pdp_image_type;
+
+ unsigned int x_width;
+ unsigned int x_height;
+
+} t_pdp_noise;
+
+
+
+void pdp_noise_type(t_pdp_noise *x, t_symbol *s)
+{
+ if (gensym("yv12") == s) {x->x_pdp_image_type = PDP_IMAGE_YV12; return;}
+ if (gensym("grey") == s) {x->x_pdp_image_type = PDP_IMAGE_GREY; return;}
+
+ x->x_pdp_image_type = -1;
+
+}
+
+
+void pdp_noise_random(t_pdp_noise *x, t_floatarg seed)
+{
+ if (seed == 0.0f) seed = (float)random();
+ pdp_imageproc_random_setseed(x->x_noisegen, seed);
+
+}
+
+
+
+static void pdp_noise_createpacket_yv12(t_pdp_noise *x)
+{
+ /* create new packet */
+ x->x_packet0 = pdp_packet_new_image_yv12(x->x_width, x->x_height);
+
+ /* seed the 16 bit rng with a new random number from the clib */
+ pdp_noise_random(x, 0.0f);
+}
+
+static void pdp_noise_generate_yv12(t_pdp_noise *x)
+{
+ short int *data;
+ unsigned int w = x->x_width;
+ unsigned int h = x->x_height;
+
+ h = h + (h>>1);
+
+ data = (short int *) pdp_packet_data(x->x_packet0);
+
+ pdp_noise_random(x, 0.0f);
+ pdp_imageproc_random_process(x->x_noisegen, data, w, h);
+
+ return;
+
+}
+
+static void pdp_noise_createpacket_grey(t_pdp_noise *x)
+{
+ /* create new packet */
+ x->x_packet0 = pdp_packet_new_image_grey(x->x_width, x->x_height);
+
+ /* seed the 16 bit rng with a new random number from the clib */
+ pdp_noise_random(x, 0.0f);
+}
+
+static void pdp_noise_generate_grey(t_pdp_noise *x)
+{
+ unsigned int w = x->x_width;
+ unsigned int h = x->x_height;
+ short int *data = (short int *) pdp_packet_data(x->x_packet0);
+
+ data = (short int *) pdp_packet_data(x->x_packet0);
+
+ pdp_noise_random(x, 0.0f);
+ pdp_imageproc_random_process(x->x_noisegen, data, w, h);
+
+
+ return;
+}
+
+static void pdp_noise_sendpacket(t_pdp_noise *x, t_floatarg w, t_floatarg h)
+{
+ /* propagate if valid */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+
+static void pdp_noise_bang(t_pdp_noise *x)
+{
+
+ int encoding;
+
+ /* if we have an active packet, don't do anything */
+ if (-1 != x->x_packet0) return;
+
+ switch(x->x_pdp_image_type){
+
+ case PDP_IMAGE_YV12:
+ pdp_noise_createpacket_yv12(x); // don't create inside thread!!!
+ pdp_queue_add(x, pdp_noise_generate_yv12, pdp_noise_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_noise_createpacket_grey(x); // don't create inside thread!!!
+ pdp_queue_add(x, pdp_noise_generate_grey, pdp_noise_sendpacket, &x->x_queue_id);
+ break;
+
+ default:
+ break;
+
+ }
+
+
+ /* release the packet */
+
+}
+
+
+static void pdp_noise_dim(t_pdp_noise *x, t_floatarg w, t_floatarg h)
+{
+ if (w<32.0f) w = 32.0f;
+ if (h<32.0f) h = 32.0f;
+
+ x->x_width = (unsigned int)w;
+ x->x_height = (unsigned int)h;
+}
+
+
+static void pdp_noise_free(t_pdp_noise *x)
+{
+
+ /* remove callback from process queue */
+ pdp_queue_finish(x->x_queue_id);
+
+
+ /* tidy up */
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_imageproc_random_delete(x->x_noisegen);
+
+}
+
+t_class *pdp_noise_class;
+
+
+
+
+void *pdp_noise_new(void)
+{
+ int i;
+
+ t_pdp_noise *x = (t_pdp_noise *)pd_new(pdp_noise_class);
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+ x->x_width = 320;
+ x->x_height = 240;
+
+ x->x_noisegen = pdp_imageproc_random_new();
+
+ pdp_noise_random(x, 0.0f);
+
+ pdp_noise_type(x, gensym("yv12"));
+
+ return (void *)x;
+}
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+void pdp_noise_setup(void)
+{
+
+
+ pdp_noise_class = class_new(gensym("pdp_noise"), (t_newmethod)pdp_noise_new,
+ (t_method)pdp_noise_free, sizeof(t_pdp_noise), 0, A_NULL);
+
+ class_addmethod(pdp_noise_class, (t_method)pdp_noise_random, gensym("seed"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_noise_class, (t_method)pdp_noise_type, gensym("type"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_noise_class, (t_method)pdp_noise_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_noise_class, (t_method)pdp_noise_bang, gensym("bang"), A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_qt.c b/modules/pdp_qt.c
new file mode 100644
index 0000000..1c778d5
--- /dev/null
+++ b/modules/pdp_qt.c
@@ -0,0 +1,941 @@
+/*
+ * 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(x,y) ((x<y)?(x):(y))
+
+
+
+#define FREE(x) {if (x) {free(x); x=0;} else post("free null pointer");}
+
+
+/* debug macro */
+//#define DEBUG_MSG_ENABLED
+
+#ifdef DEBUG_MSG_ENABLED
+
+#define DEBUG_MSG(EXP)\
+fprintf (stderr, "mark start: [" #EXP "], on line %d\n", __LINE__);\
+ EXP \
+fprintf (stderr, "mark end: [" #EXP "], on line %d\n", __LINE__);
+
+#else
+#define DEBUG_MSG(EXP) EXP
+#endif
+
+typedef struct pdp_qt_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ float x_gain;
+
+
+ t_symbol *x_name; // this is our name
+ int x_istilde; // 0==pdp_qt / 1==pdp_qt~
+ int x_syncaudio;
+
+
+ /* clock object */
+ t_clock *x_clock;
+ int x_counter;
+ int x_queue_id;
+
+ /* audio outlets */
+ t_outlet *x_outleft;
+ t_outlet *x_outright;
+
+ /* message outlets */
+ t_outlet *x_outlet0;
+ t_outlet *x_outlet1;
+ t_outlet *x_outlet2;
+
+ /* pdp data */
+ int x_packet0;
+
+ /* toggles */
+ int x_loop;
+ int x_autoplay;
+
+ /* qt data */
+ unsigned char ** x_qt_rows; // pointer array to rows / colour planes
+ float ** x_qt_audiochans; // pointer array to audio channel buffers
+ unsigned char * x_qt_frame;
+ quicktime_t *x_qt;
+ int x_qt_cmodel;
+
+ //t_pdp_qt_data *x_state_data;
+
+ /* audio data */
+ int x_chunk_current;
+ float *x_chunk_buf;
+ float *x_chunk[2][2];
+ int x_chunk_used[2]; // marks if chunk is used or not
+ int x_chunk_size;
+ int x_chunk_pos;
+
+ /* global state */
+ int x_initialized;
+ int x_frame;
+ int x_frame_thread;
+ int x_process_in_thread;
+
+
+ /* audio info */
+ int x_audio_tracks; // ==0 means audio not available
+ int x_audio_channels;
+ long x_audio_samplerate;
+ long x_audio_length;
+
+ /* video info */
+ int x_video_tracks; // ==0 means video not available
+ float x_video_framerate;
+ long x_video_length;
+ unsigned int x_video_width;
+ unsigned int x_video_height;
+
+
+} t_pdp_qt;
+
+
+static void pdp_qt_bang(t_pdp_qt *x);
+
+static void pdp_qt_close(t_pdp_qt *x)
+{
+ /* disable clock */
+ clock_unset(x->x_clock);
+ pdp_queue_finish(x->x_queue_id);
+
+ if (x->x_initialized){
+ /* close file */
+ quicktime_close(x->x_qt);
+ x->x_initialized = 0;
+
+
+ /* free video data */
+ if (x->x_video_tracks){
+ FREE(x->x_qt_frame);
+ FREE(x->x_qt_rows);
+ x->x_video_tracks = 0;
+ //x->x_qt_rows = 0;
+ //x->x_qt_frame = 0;
+ }
+
+ /* free audio data */
+ if (x->x_audio_tracks){
+ x->x_chunk_used[0] = 0;
+ x->x_chunk_used[1] = 0;
+ FREE(x->x_chunk_buf);
+ FREE(x->x_qt_audiochans);
+ x->x_audio_tracks = 0;
+ //x->x_qt_audiochans = 0;
+ //x->x_chunk_buf = 0;
+ x->x_chunk[0][0] = 0;
+ x->x_chunk[0][1] = 0;
+ x->x_chunk[1][0] = 0;
+ x->x_chunk[1][1] = 0;
+ }
+
+
+ }
+
+
+}
+
+void pdp_qt_create_pdp_packet(t_pdp_qt *x)
+{
+ t_pdp *header;
+ int nbpixels = x->x_video_width * x->x_video_height;
+ //int packet_size = (x->x_qt_cmodel == BC_RGB888) ? (nbpixels << 1) : (nbpixels + (nbpixels >> 1)) << 1;
+ int packet_size = (nbpixels + (nbpixels >> 1)) << 1;
+
+
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = pdp_packet_new(PDP_IMAGE, packet_size);
+ header = pdp_packet_header(x->x_packet0);
+
+ //header->info.image.encoding = (x->x_qt_cmodel == BC_RGB888) ? PDP_IMAGE_GREY : PDP_IMAGE_YV12;
+ header->info.image.encoding = PDP_IMAGE_YV12;
+ header->info.image.width = x->x_video_width;
+ header->info.image.height = x->x_video_height;
+}
+
+
+
+
+static void pdp_qt_open(t_pdp_qt *x, t_symbol *name)
+{
+ unsigned int size;
+ unsigned int i;
+ unsigned int chunk_bytesize;
+
+ post("%s: opening %s", x->x_name->s_name, name->s_name);
+
+
+ /* close previous one */
+ pdp_qt_close(x);
+
+
+ /* check if qt file */
+ if(0 == quicktime_check_sig(name->s_name)){
+ post("%s: ERROR: not a quicktime file", x->x_name->s_name);
+ goto exit;
+ }
+
+ /* open */
+ DEBUG_MSG(x->x_qt = quicktime_open(name->s_name, 1, 0);)
+ if (!(x->x_qt)){
+ post("%s: ERROR: can't open file", x->x_name->s_name);
+ goto exit;
+ }
+
+ /* check video */
+ x->x_video_tracks = 0;
+ if (quicktime_has_video(x->x_qt)) {
+ x->x_video_framerate = quicktime_frame_rate (x->x_qt, 0);
+ x->x_video_length = quicktime_video_length (x->x_qt, 0);
+ x->x_video_width = quicktime_video_width (x->x_qt, 0);
+ x->x_video_height = quicktime_video_height (x->x_qt, 0);
+ post("%s: video stream found (%dx%d pixels, %0.00f fps, %d frames, %s codec)",
+ x->x_name->s_name, x->x_video_width, x->x_video_height, x->x_video_framerate,
+ x->x_video_length, quicktime_video_compressor(x->x_qt, 0));
+ x->x_video_tracks = quicktime_video_tracks(x->x_qt);
+
+ }
+
+
+ /* check audior */
+ x->x_audio_tracks = 0;
+ if (quicktime_has_audio(x->x_qt)) {
+ x->x_audio_tracks = quicktime_audio_tracks (x->x_qt);
+ //x->x_audio_channels = quicktime_track_channels (x->x_qt, 0);
+ x->x_audio_channels = lqt_total_channels (x->x_qt);
+ x->x_audio_samplerate = quicktime_sample_rate (x->x_qt, 0);
+ x->x_audio_length = quicktime_audio_length (x->x_qt, 0);
+ x->x_chunk_size = (int)((float)x->x_audio_samplerate / x->x_video_framerate);
+ post("%s: audio stream found (%d channels, %d Hz, %d samples, chunksize %d)",
+ x->x_name->s_name, x->x_audio_channels, x->x_audio_samplerate, x->x_audio_length, x->x_chunk_size);
+ }
+
+ /* check if video codec is supported */
+ if (x->x_video_tracks){
+ if (!quicktime_supported_video(x->x_qt,0)) {
+ post("%s: WARNING: unsupported video codec",x->x_name->s_name);
+ x->x_video_tracks = 0;
+ }
+ }
+
+ /* check if audio codec is supported */
+ if (x->x_audio_tracks){
+ if (!quicktime_supported_audio(x->x_qt,0)) {
+ post("%s: WARNING: unsupported audio codec", x->x_name->s_name);
+ x->x_audio_tracks = 0;
+ }
+ }
+
+
+
+ /* check which colormodel to use */
+ if (x->x_video_tracks){
+
+ if (quicktime_reads_cmodel(x->x_qt,BC_YUV420P,0)){
+ post("%s: using colormodel YUV420P", x->x_name->s_name);
+ x->x_qt_cmodel = BC_YUV420P;
+ }
+ else if (quicktime_reads_cmodel(x->x_qt,BC_YUV422,0)){
+ post("%s: using colormodel YUV422", x->x_name->s_name);
+ x->x_qt_cmodel = BC_YUV422;
+ }
+ else if (quicktime_reads_cmodel(x->x_qt,BC_RGB888,0)){
+ post("%s: using colormodel RGB888", x->x_name->s_name);
+ x->x_qt_cmodel = BC_RGB888;
+ }
+ else {
+ post("%s: WARNING: can't find a usable colour model", x->x_name->s_name);
+ x->x_video_tracks = 0;
+ }
+
+ }
+
+
+
+ /* no video == errors */
+ if (!x->x_video_tracks) {
+ post("%s: ERROR: no usable video stream found.", x->x_name->s_name);
+ goto exit_close;
+ }
+
+
+ /* initialize video data structures */
+ if (x->x_video_tracks){
+
+ /* allocate enough space for all supported colormodels (24bpp)*/
+ x->x_frame = 0;
+ x->x_qt_frame = (unsigned char*)malloc(x->x_video_width * x->x_video_height * 3);
+ x->x_qt_rows = (unsigned char **)malloc(sizeof(unsigned char *) * x->x_video_height);
+ size = x->x_video_width * x->x_video_height;
+
+ switch(x->x_qt_cmodel){
+ case BC_YUV420P:
+ /* planar with u&v 2x2 subsampled */
+ x->x_qt_rows[0] = &x->x_qt_frame[0];
+ x->x_qt_rows[2] = &x->x_qt_frame[size];
+ x->x_qt_rows[1] = &x->x_qt_frame[size + (size>>2)];
+ break;
+
+ case BC_YUV422:
+ /* packed with u&v 2x subsampled (lines) */
+ /* later on we will convert this to planar */
+ for(i=0; i< x->x_video_height; i++) x->x_qt_rows[i] = &x->x_qt_frame[i * x->x_video_width * 2];
+ break;
+
+ case BC_RGB888:
+ /* packed rgb */
+ /* later on we will convert this to planar */
+ for(i=0; i< x->x_video_height; i++) x->x_qt_rows[i] = &x->x_qt_frame[i * x->x_video_width * 3];
+ break;
+
+ default:
+ post("%s: error on init: unkown colour model",x->x_name->s_name);
+ break;
+ }
+
+ DEBUG_MSG(quicktime_set_cmodel(x->x_qt, x->x_qt_cmodel);)
+ pdp_qt_create_pdp_packet(x);
+ outlet_float(x->x_outlet2, (float)quicktime_video_length(x->x_qt,0));
+
+ }
+
+ /* initialize audio data structures */
+ if (x->x_audio_tracks){
+ x->x_chunk_pos = 0;
+ x->x_chunk_current = 0;
+
+ chunk_bytesize = sizeof(float)*x->x_chunk_size;
+ x->x_chunk_buf = (float *)malloc(chunk_bytesize * 4);
+ memset(x->x_chunk_buf, 0, chunk_bytesize * 4);
+ x->x_chunk[0][0] = x->x_chunk_buf;
+ x->x_chunk[0][1] = x->x_chunk_buf + x->x_chunk_size ;
+ x->x_chunk[1][0] = x->x_chunk_buf + x->x_chunk_size * 2;
+ x->x_chunk[1][1] = x->x_chunk_buf + x->x_chunk_size * 3;
+ x->x_chunk_used[0] = 0;
+ x->x_chunk_used[1] = 0;
+ x->x_syncaudio = x->x_istilde; //sync on audio if this is a tilde object
+
+ DEBUG_MSG(if (x->x_audio_channels == 0) exit(1);)
+ x->x_qt_audiochans = (float **)malloc(x->x_audio_channels * sizeof(float **));
+ memset(x->x_qt_audiochans, 0, x->x_audio_channels * sizeof(float **));
+ }
+ else {
+ x->x_syncaudio = 0;
+ }
+
+
+ /* everything went well */
+ x->x_initialized = 1;
+
+ /* start playback if outplay is on */
+ if(x->x_autoplay) clock_delay(x->x_clock, 1000.0L / (double)x->x_video_framerate);
+
+ /* brag about success */
+ post("%s: %s opened", x->x_name->s_name, name->s_name);
+
+ return;
+
+ /* error exits */
+
+ exit_close:
+ DEBUG_MSG(quicktime_close(x->x_qt);)
+
+ exit:
+ x->x_initialized = 0;
+ x->x_audio_tracks = 0;
+ x->x_video_tracks = 0;
+ return;
+
+}
+
+
+//static void pdp_qt_setposition(t_pdp_qt *x, int pos)
+//{
+// x->x_frame = pos;
+// DEBUG_MSG(if(x->x_video_tracks) quicktime_set_video_position(x->x_qt, pos, 0);)
+// DEBUG_MSG(if(x->x_audio_tracks) quicktime_set_audio_position(x->x_qt, pos * x->x_chunk_size, 0);)
+//
+//}
+
+
+static void pdp_qt_bangaudio(t_pdp_qt *x)
+{
+ int lefterr=0;
+ int righterr=0;
+ int err=0;
+ int sample = 0;
+ int remaining = 0;
+ int readamount = 0;
+
+
+
+ if (!x->x_initialized){
+ //post("pdp_qt: no qt file opened");
+ return;
+ }
+
+
+ if (!x->x_audio_tracks){
+ //post("pdp_qt: no audio stream present");
+ return;
+ }
+
+
+
+ //DEBUG_MSG(sample = quicktime_audio_position(x->x_qt,0);)
+
+
+ // if the active chunk is unused, clear it and mark it used
+ if (!x->x_chunk_used[x->x_chunk_current]){
+ //post("%s: clearing unused active chunk",x->x_name->s_name);
+
+
+
+ //probably this is the !@#%&*(*)&!$() bug
+ //memset(x->x_chunk[0][x->x_chunk_current], 0, sizeof(float)*2*x->x_chunk_size);
+ //memset(x->x_chunk[1][x->x_chunk_current], 0, sizeof(float)*2*x->x_chunk_size);
+
+ memset(x->x_chunk[0][x->x_chunk_current], 0, sizeof(float) * x->x_chunk_size);
+ memset(x->x_chunk[1][x->x_chunk_current], 0, sizeof(float) * x->x_chunk_size);
+
+
+
+
+ x->x_chunk_used[x->x_chunk_current] = 1;
+ }
+
+ // compute the remaining time
+ DEBUG_MSG(remaining = (int ) ( quicktime_audio_length(x->x_qt, 0) - quicktime_audio_position(x->x_qt, 0) );)
+ readamount = min(remaining, x->x_chunk_size);
+ if (!readamount) return;
+
+
+ // if the inactive chunk is unused, fill it with the current frame's audio data and mark it used
+ if (!x->x_chunk_used[!x->x_chunk_current]){
+ switch(x->x_audio_channels){
+ case 1:
+ x->x_qt_audiochans[0] = x->x_chunk[0][!x->x_chunk_current];
+ x->x_qt_audiochans[1] = 0;
+ DEBUG_MSG(err = lqt_decode_audio(x->x_qt, NULL, x->x_qt_audiochans, readamount);)
+ break;
+ default:
+ x->x_qt_audiochans[0] = x->x_chunk[0][!x->x_chunk_current];
+ x->x_qt_audiochans[1] = x->x_chunk[1][!x->x_chunk_current];
+ DEBUG_MSG(err = lqt_decode_audio(x->x_qt, NULL, x->x_qt_audiochans, readamount);)
+ break;
+ }
+ x->x_chunk_used[!x->x_chunk_current] = 1;
+ }
+ // if it is used, something went wrong with sync
+ else{
+ //post("%s: dropping audio chunk %d.",x->x_name->s_name, x->x_frame_thread);
+ }
+
+
+ if (err) post("%s: error decoding audio",x->x_name->s_name, x->x_frame_thread);
+
+ // ensure audio pointer points to next frame's data
+ //DEBUG_MSG(quicktime_set_audio_position(x->x_qt, sample + readamount, 0);)
+
+}
+
+
+
+
+static void pdp_qt_bangvideo(t_pdp_qt *x)
+{
+ unsigned int w, h, nbpixels, packet_size, i,j;
+ unsigned int *source, *dest;
+ unsigned int uoffset, voffset;
+ short int* data;
+ t_pdp* header;
+
+ // check if we want greyscale output or not
+ //int grey = (x->x_qt_cmodel == BC_RGB888);
+
+ static short int gain[4] = {0x7fff, 0x7fff, 0x7fff, 0x7fff};
+
+ if ((!x->x_initialized) || (!x->x_video_tracks)){
+ //post("pdp_qt: no qt file opened");
+ return;
+ }
+
+ w = x->x_video_width;
+ h = x->x_video_height;
+ nbpixels = x->x_video_width * x->x_video_height;
+
+ header = pdp_packet_header(x->x_packet0);
+ data = (short int *) pdp_packet_data(x->x_packet0);
+
+
+ DEBUG_MSG(lqt_decode_video(x->x_qt, x->x_qt_rows, 0);)
+
+
+ switch(x->x_qt_cmodel){
+ case BC_YUV420P:
+ pdp_llconv(x->x_qt_frame, RIF_YVU__P411_U8, data, RIF_YVU__P411_S16, x->x_video_width, x->x_video_height);
+ break;
+
+ case BC_YUV422:
+ pdp_llconv(x->x_qt_frame, RIF_YUYV_P____U8, data, RIF_YVU__P411_S16, x->x_video_width, x->x_video_height);
+ break;
+
+ case BC_RGB888:
+ pdp_llconv(x->x_qt_frame, RIF_RGB__P____U8, data, RIF_YVU__P411_S16, x->x_video_width, x->x_video_height);
+ break;
+
+ default:
+ post("%s: error on decode: unkown colour model",x->x_name->s_name);
+ break;
+ }
+
+
+
+}
+
+static void pdp_qt_sendpacket(t_pdp_qt *x)
+{
+ if (x->x_packet0 != -1){
+ //pdp_packet_mark_unused(x->x_packet0);
+ outlet_pdp(x->x_outlet0, x->x_packet0);
+ //x->x_packet0 = -1;
+ }
+}
+
+
+static void pdp_qt_thread_bang(t_pdp_qt *x)
+{
+ // set audio position
+ if(x->x_video_tracks) quicktime_set_video_position(x->x_qt, x->x_frame_thread, 0);
+
+ // bang video
+ pdp_qt_bangvideo(x);
+
+ // if it's a tilde object, bang audio
+ if (x->x_istilde && x->x_audio_tracks){
+ quicktime_set_audio_position(x->x_qt, x->x_frame_thread * x->x_chunk_size, 0);
+ pdp_qt_bangaudio(x);
+ }
+
+}
+
+
+static void pdp_qt_bang(t_pdp_qt *x)
+{
+ int length, pos;
+
+ /* return if not initialized */
+ if (!x->x_initialized) return;
+
+ //length = quicktime_video_length(x->x_qt,0);
+ //pos = quicktime_video_position(x->x_qt,0);
+ length = x->x_video_length;
+ pos = x->x_frame;
+
+
+ /* check bounds */
+ if (x->x_loop){
+ pos = x->x_frame % length;
+ if (pos < 0) pos += length;
+ }
+ else{
+ if (pos < 0) pos = 0;
+ if (pos >= length) pos = length - 1;
+ }
+
+ /* store next frame for access in thread */
+ x->x_frame_thread = pos;
+
+
+ // if autoplay is on and we do not have audio synchro
+ // set clock to play next frame
+ if (x->x_autoplay && !x->x_syncaudio) clock_delay(x->x_clock, 1000.0L / (double)x->x_video_framerate);
+
+
+ // make sure prev decode is finished don't drop frames in this one
+ pdp_queue_finish(x->x_queue_id);
+ x->x_queue_id = -1;
+
+ /* only decode new stuff if previous is done */
+ if (-1 == x->x_queue_id){
+ // send the current frame number to outlet
+ outlet_float(x->x_outlet1, (float)pos);
+
+ //pdp_qt_setposition(x, pos);
+
+ // start process method
+ if (x->x_process_in_thread) pdp_queue_add(x, pdp_qt_thread_bang, pdp_qt_sendpacket, &x->x_queue_id);
+ else {
+ pdp_qt_thread_bang(x);
+ pdp_qt_sendpacket(x);
+ }
+ }
+ // advance frame
+ x->x_frame = pos + 1;
+
+
+ // send the packet
+ //pdp_qt_sendpacket(x);
+}
+
+
+
+//static void pdp_qt_getaudiochunk(t_pdp_qt *x, int channel)
+//{
+// if (!x->x_audio_tracks) return;
+// quicktime_decode_audio(x->x_qt, NULL, x->x_chunk[channel][x->x_chunk_current], x->x_chunk_size<<1, channel);
+//
+//}
+
+static void pdp_qt_loop(t_pdp_qt *x, t_floatarg loop)
+{
+ int loopi = (int)loop;
+ x->x_loop = !(loopi == 0);
+}
+
+static void pdp_qt_autoplay(t_pdp_qt *x, t_floatarg play)
+{
+ int playi = (int)play;
+ x->x_autoplay = !(playi == 0);
+
+
+ // reset clock if autoplay is off
+ if (!x->x_autoplay) clock_unset(x->x_clock);
+
+
+}
+
+
+
+static void pdp_qt_frame_cold(t_pdp_qt *x, t_floatarg frameindex)
+{
+ int frame = (int)frameindex;
+ //int length;
+
+
+ x->x_frame = frame;
+
+ //if (!(x->x_initialized)) return;
+
+ //length = quicktime_video_length(x->x_qt,0);
+
+ //frame = (frame >= length) ? length-1 : frame;
+ //frame = (frame < 0) ? 0 : frame;
+
+ //pdp_qt_setposition(x, frame);
+}
+
+static void pdp_qt_frame(t_pdp_qt *x, t_floatarg frameindex)
+{
+ pdp_qt_frame_cold(x, frameindex);
+ pdp_qt_bang(x);
+}
+
+static void pdp_qt_stop(t_pdp_qt *x)
+{
+ pdp_qt_autoplay(x, 0);
+}
+
+static void pdp_qt_continue(t_pdp_qt *x)
+{
+ pdp_qt_autoplay(x, 1);
+ pdp_qt_bang(x);
+}
+
+
+static void pdp_qt_play(t_pdp_qt *x){
+ pdp_qt_frame_cold(x, 0);
+ pdp_qt_continue(x);
+}
+
+
+
+
+static void pdp_qt_importaudio(t_pdp_qt *x, t_symbol *array, t_floatarg channel)
+{
+ int c = (int)channel;
+ t_garray *g;
+ int vecsize;
+ int sample;
+ float *f;
+ int i;
+
+ /* if there's no audio, there's nothing to export */
+ if (!x->x_audio_tracks) return;
+
+ /* check audio channel */
+ if ((c < 0) || (c >= x->x_audio_channels)) return;
+
+ /* check if array exists */
+ if (!(g = (t_garray *)pd_findbyclass(array, garray_class))){
+ pd_error(x, "%s: no such table", array->s_name);
+ return;
+ }
+
+ post("%s: importing audio channel %d into array %s", x->x_name->s_name, c, array->s_name);
+
+
+ // make sure decode is finished
+ pdp_queue_finish(x->x_queue_id);
+ x->x_queue_id = -1;
+
+
+ /* resize array */
+ garray_resize(g, x->x_audio_length);
+
+ /* for sanity's sake let's clear the save-in-patch flag here */
+ garray_setsaveit(g, 0);
+ garray_getfloatarray(g, &vecsize, &f);
+
+ /* if the resize failed, garray_resize reported the error */
+ if (vecsize != x->x_audio_length){
+ pd_error(x, "array resize failed");
+ return;
+ }
+
+ /* save pointer in file */
+ DEBUG_MSG(sample = quicktime_audio_position(x->x_qt, 0);)
+ DEBUG_MSG(quicktime_set_audio_position(x->x_qt, 0, 0);)
+
+ /* transfer the audio file to the end of the array */
+ DEBUG_MSG(quicktime_decode_audio(x->x_qt, NULL, f, vecsize, c);)
+
+ /* restore pointer in file */
+ DEBUG_MSG(quicktime_set_audio_position(x->x_qt, sample, 0);)
+
+
+}
+
+
+
+static t_int *pdp_qt_perform(t_int *w)
+{
+ t_pdp_qt *x = (t_pdp_qt *)w[1];
+ t_float *out0 = (t_float *)w[2];
+ t_float *out1 = (t_float *)w[3];
+ t_int n = (t_int)w[4];
+
+ t_int xfer_samples;
+ if (!x->x_initialized || !x->x_audio_tracks) goto zero;
+
+ while(1){
+ // check current chunk
+ if (!x->x_chunk_used[x->x_chunk_current]) goto zero;
+
+
+ // transfer from chunk to output
+ xfer_samples = min(n, x->x_chunk_size - x->x_chunk_pos);
+
+ //x->x_audio_channels = 1;
+
+ if (x->x_audio_channels == 1){
+ memcpy(out0, x->x_chunk[0][x->x_chunk_current] + x->x_chunk_pos, sizeof(float)*xfer_samples);
+ memcpy(out1, x->x_chunk[0][x->x_chunk_current] + x->x_chunk_pos, sizeof(float)*xfer_samples);
+ }
+ else {
+ memcpy(out0, x->x_chunk[0][x->x_chunk_current] + x->x_chunk_pos, sizeof(float)*xfer_samples);
+ memcpy(out1, x->x_chunk[1][x->x_chunk_current] + x->x_chunk_pos, sizeof(float)*xfer_samples);
+ }
+ out0 += xfer_samples;
+ out1 += xfer_samples;
+ n -= xfer_samples;
+ x->x_chunk_pos += xfer_samples;
+
+
+ // check if chunk is finished, if so mark unused, swap buffers and set clock
+ if (x->x_chunk_size == x->x_chunk_pos){
+ x->x_chunk_used[x->x_chunk_current] = 0;
+ x->x_chunk_pos = 0;
+ x->x_chunk_current ^= 1;
+ if (x->x_autoplay) clock_delay(x->x_clock, 0L);
+ }
+
+ // if chunk is not finished, the output buffer is full
+ else{
+ goto exit;
+ }
+
+ }
+
+
+ zero:
+ // fill the rest of the output with zeros
+ memset(out0, 0, sizeof(float)*n);
+ memset(out1, 0, sizeof(float)*n);
+
+ exit:
+ return(w+5);
+}
+
+static void pdp_qt_dsp(t_pdp_qt *x, t_signal **sp)
+{
+ dsp_add(pdp_qt_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+
+}
+
+static void pdp_qt_process_in_thread(t_pdp_qt *x, t_float f)
+{
+
+ int t = (f != 0.0f);
+
+ x->x_process_in_thread = t;
+
+ post("pdp_qt: thread processing switched %d", t ? "on" : "off");
+
+}
+
+static void pdp_qt_tick(t_pdp_qt *x)
+{
+
+ // bang audio/video
+ pdp_qt_bang(x);
+}
+
+static void pdp_qt_free(t_pdp_qt *x)
+{
+ clock_unset(x->x_clock);
+ pdp_qt_close(x);
+ clock_free(x->x_clock);
+ //free (x->x_state_data);
+
+}
+
+
+
+t_class *pdp_qt_class;
+t_class *pdp_qt_tilde_class;
+
+
+void pdp_qt_init_common(t_pdp_qt *x)
+{
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("frame_cold"));
+
+ /* add common outlets */
+ 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);
+
+ /* init */
+ x->x_gain = 1.0f;
+ x->x_process_in_thread = 0;
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+ x->x_initialized = 0;
+ x->x_audio_tracks = 0;
+ x->x_video_tracks = 0;
+ x->x_loop = 0;
+ x->x_autoplay = 0;
+ x->x_chunk[0][0] = 0;
+ x->x_chunk[0][1] = 0;
+ x->x_chunk[1][0] = 0;
+ x->x_chunk[1][1] = 0;
+
+ /* initialize clock object */
+ x->x_clock = clock_new(x, (t_method)pdp_qt_tick);
+
+
+
+
+}
+
+void *pdp_qt_new(void)
+{
+ t_pdp_qt *x = (t_pdp_qt *)pd_new(pdp_qt_class);
+ x->x_name = gensym("pdp_qt");
+ x->x_istilde = 0;
+ pdp_qt_init_common(x);
+ return (void *)x;
+}
+
+void *pdp_qt_tilde_new(void)
+{
+ t_pdp_qt *x = (t_pdp_qt *)pd_new(pdp_qt_tilde_class);
+ x->x_name = gensym("pdp_qt");
+ x->x_istilde = 1;
+
+ pdp_qt_init_common(x);
+
+ /* add outlets to the right so pdp_qt~ can replace pdp_qt without breaking a patch */
+ x->x_outleft = outlet_new(&x->x_obj, &s_signal);
+ x->x_outright = outlet_new(&x->x_obj, &s_signal);
+
+ return (void *)x;
+}
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_qt_setup_common(t_class *class)
+{
+ class_addmethod(class, (t_method)pdp_qt_bang, gensym("bang"), A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_close, gensym("close"), A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_open, gensym("open"), A_SYMBOL, A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_autoplay, gensym("autoplay"), A_DEFFLOAT, A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_stop, gensym("stop"), A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_play, gensym("play"), A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_continue, gensym("cont"), A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_loop, gensym("loop"), A_DEFFLOAT, A_NULL);
+ class_addfloat (class, (t_method)pdp_qt_frame);
+ class_addmethod(class, (t_method)pdp_qt_frame_cold, gensym("frame_cold"), A_FLOAT, A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_process_in_thread, gensym("thread"), A_FLOAT, A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_importaudio, gensym("importaudio"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_importaudio, gensym("dump"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+}
+
+void pdp_qt_setup(void)
+{
+
+ /* plain class */
+ pdp_qt_class = class_new(gensym("pdp_qt"), (t_newmethod)pdp_qt_new,
+ (t_method)pdp_qt_free, sizeof(t_pdp_qt), 0, A_NULL);
+ pdp_qt_setup_common(pdp_qt_class);
+
+
+ /* tilde class */
+ pdp_qt_tilde_class = class_new(gensym("pdp_qt~"), (t_newmethod)pdp_qt_tilde_new,
+ (t_method)pdp_qt_free, sizeof(t_pdp_qt), 0, A_NULL);
+ pdp_qt_setup_common(pdp_qt_tilde_class);
+
+ class_addmethod(pdp_qt_tilde_class, (t_method)pdp_qt_dsp, gensym("dsp"), 0);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_randmix.c b/modules/pdp_randmix.c
new file mode 100644
index 0000000..3ffea27
--- /dev/null
+++ b/modules/pdp_randmix.c
@@ -0,0 +1,228 @@
+/*
+ * 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"
+
+
+typedef struct pdp_randmix_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ int x_packet0;
+ int x_packet1;
+ int x_packet1next;
+ int x_queue_id;
+ int x_dropped;
+
+ void *x_randmixer;
+
+} t_pdp_randmix;
+
+
+void pdp_randmix_random(t_pdp_randmix *x, t_floatarg seed)
+{
+ pdp_imageproc_randmix_setseed(x->x_randmixer, seed);
+}
+
+
+
+static void pdp_randmix_process_yv12(t_pdp_randmix *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ h = h + (h>>1);
+
+ pdp_imageproc_randmix_process(x->x_randmixer, (short int*)data0, (short int*)data1, w, h);
+
+ return;
+
+
+
+}
+
+static void pdp_randmix_process_grey(t_pdp_randmix *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ pdp_imageproc_randmix_process(x->x_randmixer, (short int*)data0, (short int*)data1, w, h);
+
+ return;
+
+}
+
+static void pdp_randmix_process(t_pdp_randmix *x)
+{
+
+ int encoding;
+
+ /* check if image data packets are compatible */
+ if (pdp_type_compat_image(x->x_packet0, x->x_packet1)){
+
+ /* pdp_randmix_process inputs and write into active inlet */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_randmix_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_randmix_process_grey(x);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont pdp_randmix_process */
+
+ }
+ }
+
+}
+
+static void pdp_randmix_sendpacket(t_pdp_randmix *x)
+{
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_randmix_input_0(t_pdp_randmix *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* if a cold packet was received in the meantime
+ swap it in, else keep the old one */
+
+ pdp_replace_if_valid(&x->x_packet1, &x->x_packet1next);
+
+
+ /* add the process method and callback to the process queue */
+
+ pdp_queue_add(x, pdp_randmix_process, pdp_randmix_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+static void pdp_randmix_input_1(t_pdp_randmix *x, t_symbol *s, t_floatarg f)
+{
+ /* store the packet and drop
+ the old one, if there is any */
+
+ if(s == gensym("register_ro")) pdp_packet_copy_ro_or_drop(&x->x_packet1next, (int)f);
+
+}
+
+
+
+
+
+static void pdp_randmix_threshold(t_pdp_randmix *x, t_floatarg f)
+{
+ pdp_imageproc_randmix_setthreshold(x->x_randmixer, f);
+
+}
+
+
+
+static void pdp_randmix_free(t_pdp_randmix *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+
+ pdp_imageproc_randmix_delete(x->x_randmixer);
+
+}
+
+t_class *pdp_randmix_class;
+
+
+void *pdp_randmix_new(void)
+{
+ int i;
+
+ t_pdp_randmix *x = (t_pdp_randmix *)pd_new(pdp_randmix_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("float"), gensym("threshold"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_packet1next = -1;
+ x->x_queue_id = -1;
+
+ x->x_randmixer = pdp_imageproc_randmix_new();
+
+ pdp_randmix_threshold(x, 0.5f);
+ pdp_randmix_random(x, 0.0f);
+
+ return (void *)x;
+}
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+void pdp_randmix_setup(void)
+{
+
+
+ pdp_randmix_class = class_new(gensym("pdp_randmix"), (t_newmethod)pdp_randmix_new,
+ (t_method)pdp_randmix_free, sizeof(t_pdp_randmix), 0, A_NULL);
+
+ class_addmethod(pdp_randmix_class, (t_method)pdp_randmix_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_randmix_class, (t_method)pdp_randmix_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_randmix_class, (t_method)pdp_randmix_threshold, gensym("threshold"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_randmix_class, (t_method)pdp_randmix_random, gensym("seed"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_reg.c b/modules/pdp_reg.c
new file mode 100644
index 0000000..e3aa721
--- /dev/null
+++ b/modules/pdp_reg.c
@@ -0,0 +1,132 @@
+/*
+ * 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"
+
+
+typedef struct pdp_reg_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ int x_packet0;
+
+} t_pdp_reg;
+
+
+static void pdp_reg_bang(t_pdp_reg *x)
+{
+
+ if (-1 != x->x_packet0) outlet_pdp(x->x_outlet0, x->x_packet0);
+
+}
+
+
+
+static void pdp_reg_input_0(t_pdp_reg *x, t_symbol *s, t_floatarg f)
+{
+
+ /* if this is a register_ro message or register_rw message, register with packet factory */
+
+ /* if this is a process message, start the processing + propagate stuff to outputs */
+
+ if (s == gensym("register_ro")){
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = pdp_packet_copy_ro((int)f);
+ //post("in0ro: requested %d, got %d", (int)f, x->x_packet0);
+ }
+ else if (s == gensym("process")){
+ pdp_reg_bang(x);
+
+ }
+
+
+}
+
+
+static void pdp_reg_input_1(t_pdp_reg *x, t_symbol *s, t_floatarg f)
+{
+
+ /* if this is a register_ro message or register_rw message, register with packet factory */
+
+ /* if this is a process message, start the processing + propagate stuff to outputs */
+
+ if (s == gensym("register_ro")){
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = pdp_packet_copy_ro((int)f);
+ //post("in0ro: requested %d, got %d", (int)f, x->x_packet0);
+ }
+
+}
+
+
+
+static void pdp_reg_free(t_pdp_reg *x)
+{
+ pdp_packet_mark_unused(x->x_packet0);
+
+}
+
+t_class *pdp_reg_class;
+
+
+
+void *pdp_reg_new(void)
+{
+ t_pdp_reg *x = (t_pdp_reg *)pd_new(pdp_reg_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_reg_setup(void)
+{
+
+
+ pdp_reg_class = class_new(gensym("pdp_reg"), (t_newmethod)pdp_reg_new,
+ (t_method)pdp_reg_free, sizeof(t_pdp_reg), 0, A_NULL);
+
+
+ class_addmethod(pdp_reg_class, (t_method)pdp_reg_bang, gensym("bang"), A_NULL);
+
+ class_addmethod(pdp_reg_class, (t_method)pdp_reg_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_reg_class, (t_method)pdp_reg_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_route.c b/modules/pdp_route.c
new file mode 100644
index 0000000..7b0a0a9
--- /dev/null
+++ b/modules/pdp_route.c
@@ -0,0 +1,129 @@
+/*
+ * 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"
+
+// dynamic ????
+#define PDP_ROUTE_MAX_NB_OUTLETS 100
+
+typedef struct pdp_route_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet[PDP_ROUTE_MAX_NB_OUTLETS];
+
+ int x_nb_outlets;
+ int x_route;
+ int x_route_next;
+
+
+} t_pdp_route;
+
+
+static void pdp_route_input_0(t_pdp_route *x, t_symbol *s, t_floatarg f)
+{
+ t_atom atom[2];
+ t_symbol *pdp = gensym("pdp");
+
+
+ /* trigger on register_ro */
+ if (s == gensym("register_ro")){
+ x->x_route = x->x_route_next;
+ }
+
+ /* propagate the pdp message */
+ SETSYMBOL(atom+0, s);
+ SETFLOAT(atom+1, f);
+ outlet_anything(x->x_outlet[x->x_route], pdp, 2, atom);
+
+}
+
+static void pdp_route_route(t_pdp_route *x, t_floatarg f)
+{
+ int route = (int)f;
+
+ if (route < 0) route = 0;
+ if (route >= x->x_nb_outlets) route = x->x_nb_outlets - 1;
+
+ x->x_route_next = route;
+
+}
+
+
+
+static void pdp_route_free(t_pdp_route *x)
+{
+
+}
+
+t_class *pdp_route_class;
+
+
+
+void *pdp_route_new(t_floatarg f)
+{
+ int nboutlets = (int)f;
+ int i;
+
+ t_pdp_route *x = (t_pdp_route *)pd_new(pdp_route_class);
+
+
+ if (nboutlets < 2) nboutlets = 2;
+ if (nboutlets >= PDP_ROUTE_MAX_NB_OUTLETS) nboutlets = PDP_ROUTE_MAX_NB_OUTLETS - 1;
+
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("route"));
+
+ x->x_nb_outlets = nboutlets;
+ x->x_route = 0;
+ x->x_route_next = 0;
+
+ for (i=0; i<nboutlets; i++)
+ x->x_outlet[i] = outlet_new(&x->x_obj, &s_anything);
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_route_setup(void)
+{
+
+
+ pdp_route_class = class_new(gensym("pdp_route"), (t_newmethod)pdp_route_new,
+ (t_method)pdp_route_free, sizeof(t_pdp_route), 0, A_FLOAT, A_NULL);
+
+
+ class_addmethod(pdp_route_class, (t_method)pdp_route_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_route_class, (t_method)pdp_route_route, gensym("route"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_scale.c b/modules/pdp_scale.c
new file mode 100644
index 0000000..82c5257
--- /dev/null
+++ b/modules/pdp_scale.c
@@ -0,0 +1,267 @@
+/*
+ * 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_resample.h"
+
+
+
+typedef struct pdp_scale_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+
+ int x_packet0;
+ int x_packet1;
+ int x_dropped;
+ int x_queue_id;
+
+ unsigned int x_width;
+ unsigned int x_height;
+ int x_quality;
+
+
+} t_pdp_scale;
+
+
+static void pdp_scale_process_yv12(t_pdp_scale *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int src_w = header0->info.image.width;
+ unsigned int src_h = header0->info.image.height;
+
+ unsigned int dst_w = header1->info.image.width;
+ unsigned int dst_h = header1->info.image.height;
+
+ short int *src_image = (short int *)data0;
+ short int *dst_image = (short int *)data1;
+
+ unsigned int src_size = src_w*src_h;
+ unsigned int src_voffset = src_size;
+ unsigned int src_uoffset = src_size + (src_size>>2);
+
+ unsigned int dst_size = dst_w*dst_h;
+ unsigned int dst_voffset = dst_size;
+ unsigned int dst_uoffset = dst_size + (dst_size>>2);
+
+ if (x->x_quality){
+ pdp_resample_scale_bilin(src_image, dst_image, src_w, src_h, dst_w, dst_h);
+ pdp_resample_scale_bilin(src_image+src_voffset, dst_image+dst_voffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1);
+ pdp_resample_scale_bilin(src_image+src_uoffset, dst_image+dst_uoffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1);
+ }
+ else{
+ pdp_resample_scale_nn(src_image, dst_image, src_w, src_h, dst_w, dst_h);
+ pdp_resample_scale_nn(src_image+src_voffset, dst_image+dst_voffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1);
+ pdp_resample_scale_nn(src_image+src_uoffset, dst_image+dst_uoffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1);
+ }
+
+ return;
+}
+
+static void pdp_scale_process_grey(t_pdp_scale *x)
+{
+
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int src_w = header0->info.image.width;
+ unsigned int src_h = header0->info.image.height;
+
+ unsigned int dst_w = header1->info.image.width;
+ unsigned int dst_h = header1->info.image.height;
+
+ short int *src_image = (short int *)data0;
+ short int *dst_image = (short int *)data1;
+
+ if (x->x_quality) pdp_resample_scale_bilin(src_image, dst_image, src_w, src_h, dst_w, dst_h);
+ else pdp_resample_scale_nn(src_image, dst_image, src_w, src_h, dst_w, dst_h);
+
+ return;
+
+
+}
+
+static void pdp_scale_sendpacket(t_pdp_scale *x)
+{
+ /* delete source packet */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = -1;
+
+ /* unregister and propagate if valid dest packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet1);
+}
+
+static void pdp_scale_process(t_pdp_scale *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+
+ /* check data packets */
+
+ if ((header0) && (PDP_IMAGE == header0->type)){
+
+ /* if dims are equal, just send the packet */
+ if ((header0->info.image.width == x->x_width)
+ && (header0->info.image.height == x->x_height)){
+ x->x_packet1 = x->x_packet0;
+ x->x_packet0 = -1;
+ pdp_scale_sendpacket(x);
+ return;
+ }
+
+ /* type hub */
+ switch(header0->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ x->x_packet1 = pdp_packet_new_image_yv12(x->x_width, x->x_height);
+ pdp_queue_add(x, pdp_scale_process_yv12, pdp_scale_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ x->x_packet1 = pdp_packet_new_image_grey(x->x_width, x->x_height);
+ pdp_queue_add(x, pdp_scale_process_grey, pdp_scale_sendpacket, &x->x_queue_id);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont process */
+
+ }
+ }
+
+}
+
+
+
+
+static void pdp_scale_input_0(t_pdp_scale *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+ int passes, i;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_ro_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* add the process method and callback to the process queue */
+ pdp_scale_process(x);
+
+ }
+
+}
+
+
+
+
+static void pdp_scale_width(t_pdp_scale *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i < 32) i = 32;
+ x->x_width = i;
+}
+
+static void pdp_scale_height(t_pdp_scale *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i < 32) i = 32;
+ x->x_height = i;
+}
+
+
+static void pdp_scale_dim(t_pdp_scale *x, t_floatarg w, t_floatarg h)
+{
+ pdp_scale_width(x, w);
+ pdp_scale_height(x, h);
+}
+
+static void pdp_scale_quality(t_pdp_scale *x, t_floatarg f)
+{
+ if (f==0) x->x_quality = 0;
+ if (f==1) x->x_quality = 1;
+}
+
+
+t_class *pdp_scale_class;
+
+
+
+void pdp_scale_free(t_pdp_scale *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+}
+
+void *pdp_scale_new(t_floatarg fw, t_floatarg fh)
+{
+ t_pdp_scale *x = (t_pdp_scale *)pd_new(pdp_scale_class);
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_queue_id = -1;
+
+ if ((fw != 0.0f) && (fh != 0.0f)) pdp_scale_dim(x, fw, fh);
+ else pdp_scale_dim(x, 320, 240);
+
+ pdp_scale_quality(x, 1);
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_scale_setup(void)
+{
+
+
+ pdp_scale_class = class_new(gensym("pdp_scale"), (t_newmethod)pdp_scale_new,
+ (t_method)pdp_scale_free, sizeof(t_pdp_scale), 0, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+
+ class_addmethod(pdp_scale_class, (t_method)pdp_scale_quality, gensym("quality"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_scale_class, (t_method)pdp_scale_width, gensym("width"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_scale_class, (t_method)pdp_scale_height, gensym("height"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_scale_class, (t_method)pdp_scale_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_scale_class, (t_method)pdp_scale_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_scope.c b/modules/pdp_scope.c
new file mode 100644
index 0000000..6c0f5c0
--- /dev/null
+++ b/modules/pdp_scope.c
@@ -0,0 +1,312 @@
+/*
+ * 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 <string.h>
+
+#define BUFSIZE 2048
+
+typedef struct pdp_scope_data
+{
+ short int random_seed[4];
+
+}t_pdp_scope_data;
+
+typedef struct pdp_scope_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ t_pdp_scope_data *x_data;
+ int x_packet0;
+ int x_queue_id;
+
+ int x_pdp_image_type;
+
+ unsigned int x_width;
+ unsigned int x_height;
+
+ float *x_buffer;
+ int x_needle;
+
+
+} t_pdp_scope;
+
+
+
+void pdp_scope_type(t_pdp_scope *x, t_symbol *s)
+{
+ if (gensym("yv12") == s) {x->x_pdp_image_type = PDP_IMAGE_YV12; return;}
+ if (gensym("grey") == s) {x->x_pdp_image_type = PDP_IMAGE_GREY; return;}
+
+ x->x_pdp_image_type = -1;
+
+}
+
+
+
+
+
+static void pdp_scope_createpacket_yv12(t_pdp_scope *x)
+{
+ t_pdp *header;
+
+ unsigned int w = x->x_width;
+ unsigned int h = x->x_height;
+
+ unsigned int size = w*h;
+ unsigned int totalnbpixels = size + (size >> 1);
+ unsigned int packet_size = totalnbpixels << 1;
+
+ x->x_packet0 = pdp_packet_new(PDP_IMAGE, packet_size);
+ header = pdp_packet_header(x->x_packet0);
+
+ header->info.image.encoding = PDP_IMAGE_YV12;
+ header->info.image.width = w;
+ header->info.image.height = h;
+
+ memset(pdp_packet_data(x->x_packet0), 0, packet_size);
+
+}
+
+static void pdp_scope_generate_yv12(t_pdp_scope *x)
+{
+ unsigned int w = x->x_width;
+ unsigned int h = x->x_height;
+ unsigned int size = w*h;
+ unsigned int totalnbpixels = size + (size >> 1);
+ short int *data = (short int *) pdp_packet_data(x->x_packet0);
+
+ unsigned int i;
+ int offset = x->x_needle;
+ int val;
+ unsigned int y;
+ float fh2 = (float)(h/2);
+
+ for (i=0; i<w; i++){
+ y = (h/2) + (int)(fh2 * -x->x_buffer[(offset - w + i) & (BUFSIZE - 1)]);
+ if (y>=h) y = h-1;
+
+ data[i + y*w] = 0x7fff;
+ }
+
+ return;
+
+}
+
+static void pdp_scope_createpacket_grey(t_pdp_scope *x)
+{
+ t_pdp *header;
+ short int *data;
+
+ unsigned int w = x->x_width;
+ unsigned int h = x->x_height;
+
+ unsigned int size = w*h;
+ unsigned int totalnbpixels = size;
+ unsigned int packet_size = totalnbpixels << 1;
+
+ /* create new packet */
+ x->x_packet0 = pdp_packet_new(PDP_IMAGE, packet_size);
+
+
+ header = pdp_packet_header(x->x_packet0);
+ data = (short int *) pdp_packet_data(x->x_packet0);
+
+ header->info.image.encoding = PDP_IMAGE_GREY;
+ header->info.image.width = w;
+ header->info.image.height = h;
+
+ memset(pdp_packet_data(x->x_packet0), 0, packet_size);
+
+}
+
+static void pdp_scope_generate_grey(t_pdp_scope *x)
+{
+ unsigned int w = x->x_width;
+ unsigned int h = x->x_height;
+ unsigned int totalnbpixels = x->x_width * x->x_height;
+ short int *data = (short int *) pdp_packet_data(x->x_packet0);
+
+ unsigned int i;
+ int offset = x->x_needle;
+ int val;
+ unsigned int y;
+ float fh2 = (float)(h/2);
+
+ for (i=0; i<w; i++){
+ y = (h/2) + (int)(fh2 * -x->x_buffer[(offset - w + i) & (BUFSIZE - 1)]);
+ if (y>=h) y = h-1;
+
+ data[i + y*w] = 0x7fff;
+ }
+
+ return;
+}
+
+static void pdp_scope_sendpacket(t_pdp_scope *x)
+{
+ /* propagate if valid */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+
+static void pdp_scope_bang(t_pdp_scope *x)
+{
+
+ int encoding;
+
+ /* if we have an active packet, don't do anything */
+ if (-1 != x->x_packet0) return;
+
+ switch(x->x_pdp_image_type){
+
+ case PDP_IMAGE_YV12:
+ pdp_scope_createpacket_yv12(x); // don't create inside thread!!!
+ pdp_scope_generate_yv12(x);
+ pdp_scope_sendpacket(x);
+ //pdp_queue_add(x, pdp_scope_generate_yv12, pdp_scope_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_scope_createpacket_grey(x); // don't create inside thread!!!
+ pdp_scope_generate_grey(x);
+ pdp_scope_sendpacket(x);
+ //pdp_queue_add(x, pdp_scope_generate_grey, pdp_scope_sendpacket, &x->x_queue_id);
+ break;
+
+ default:
+ break;
+
+ }
+
+
+ /* release the packet */
+
+}
+
+
+static void pdp_scope_dim(t_pdp_scope *x, t_floatarg w, t_floatarg h)
+{
+ if (w<32.0f) w = 32.0f;
+ if (h<32.0f) h = 32.0f;
+
+ x->x_width = (unsigned int)w;
+ x->x_height = (unsigned int)h;
+}
+
+
+static void pdp_scope_free(t_pdp_scope *x)
+{
+
+ /* remove callback from process queue */
+ pdp_queue_finish(x->x_queue_id);
+
+
+ /* tidy up */
+ pdp_packet_mark_unused(x->x_packet0);
+ free(x->x_data);
+
+}
+static t_int *pdp_scope_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_pdp_scope *x = (t_pdp_scope *)(w[1]);
+ t_int n = (t_int)(w[2]);
+ t_int i;
+
+ t_int offset = x->x_needle;
+
+ for (i=0; i<n; i++)
+ x->x_buffer[(offset+i)&(BUFSIZE-1)] = in[i];
+
+ x->x_needle = (offset + n ) & (BUFSIZE - 1);
+
+ return (w+4);
+
+}
+static void pdp_scope_dsp(t_pdp_scope *x, t_signal **sp)
+{
+ dsp_add(pdp_scope_perform, 3, x, sp[0]->s_n, sp[0]->s_vec);
+
+}
+
+t_class *pdp_scope_class;
+
+
+
+
+void *pdp_scope_new(void)
+{
+ int i;
+
+ t_pdp_scope *x = (t_pdp_scope *)pd_new(pdp_scope_class);
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+ x->x_width = 320;
+ x->x_height = 240;
+ x->x_f = 0.0;
+
+ x->x_data = (t_pdp_scope_data *)malloc(sizeof(t_pdp_scope_data));
+
+ pdp_scope_type(x, gensym("yv12"));
+
+ x->x_buffer = (float *)malloc(sizeof(float) * BUFSIZE);
+ x->x_needle = 0;
+
+ return (void *)x;
+}
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+void pdp_scope_setup(void)
+{
+
+
+ pdp_scope_class = class_new(gensym("pdp_scope~"), (t_newmethod)pdp_scope_new,
+ (t_method)pdp_scope_free, sizeof(t_pdp_scope), 0, A_NULL);
+
+ CLASS_MAINSIGNALIN(pdp_scope_class, t_pdp_scope, x_f);
+
+ class_addmethod(pdp_scope_class, (t_method)pdp_scope_type, gensym("type"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_scope_class, (t_method)pdp_scope_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_scope_class, (t_method)pdp_scope_bang, gensym("bang"), A_NULL);
+ class_addmethod(pdp_scope_class, (t_method)pdp_scope_dsp, gensym("dsp"), 0);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_snap.c b/modules/pdp_snap.c
new file mode 100644
index 0000000..3ed0da2
--- /dev/null
+++ b/modules/pdp_snap.c
@@ -0,0 +1,146 @@
+/*
+ * 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"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef struct pdp_snap_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ int x_packet0;
+ bool x_snapnext;
+
+} t_pdp_snap;
+
+
+static void pdp_snap_bang(t_pdp_snap *x)
+{
+
+ if (-1 != x->x_packet0)
+ outlet_pdp(x->x_outlet0, x->x_packet0);
+
+}
+
+
+
+
+static void pdp_snap_input_1(t_pdp_snap *x, t_symbol *s, t_floatarg f)
+{
+
+ /* if this is a register_ro message or register_rw message, register with packet factory */
+
+ /* if this is a process message, start the processing + propagate stuff to outputs */
+
+ if (s == gensym("register_ro")){
+ if(x->x_snapnext) {
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = pdp_packet_copy_ro((int)f);
+ x->x_snapnext = false;
+ }
+ }
+
+}
+
+static void pdp_snap_snap(t_pdp_snap *x)
+{
+ x->x_snapnext = true;
+}
+
+static void pdp_snap_free(t_pdp_snap *x)
+{
+ pdp_packet_mark_unused(x->x_packet0);
+
+}
+
+t_class *pdp_snap_class;
+
+
+
+void *pdp_snap_new(void)
+{
+ t_pdp_snap *x = (t_pdp_snap *)pd_new(pdp_snap_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_snapnext = false;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_snap_setup(void)
+{
+
+
+ pdp_snap_class = class_new(gensym("pdp_snap"), (t_newmethod)pdp_snap_new,
+ (t_method)pdp_snap_free, sizeof(t_pdp_snap), 0, A_NULL);
+
+
+ class_addmethod(pdp_snap_class, (t_method)pdp_snap_bang, gensym("bang"), A_NULL);
+ class_addmethod(pdp_snap_class, (t_method)pdp_snap_snap, gensym("snap"), A_NULL);
+
+ class_addmethod(pdp_snap_class, (t_method)pdp_snap_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_trigger.c b/modules/pdp_trigger.c
new file mode 100644
index 0000000..e131438
--- /dev/null
+++ b/modules/pdp_trigger.c
@@ -0,0 +1,105 @@
+/*
+ * 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"
+
+
+
+
+
+typedef struct pdp_trigger_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+ t_outlet *x_outlet1;
+ int x_packet;
+
+
+} t_pdp_trigger;
+
+
+
+
+static void pdp_trigger_input_0(t_pdp_trigger *x, t_symbol *s, t_floatarg f)
+{
+ t_atom atom[2];
+ t_symbol *pdp = gensym("pdp");
+
+
+ /* trigger on register_ro */
+ if (s == gensym("register_ro")){
+ outlet_bang(x->x_outlet1);
+
+ }
+
+ /* propagate the pdp message */
+ SETSYMBOL(atom+0, s);
+ SETFLOAT(atom+1, f);
+ outlet_anything(x->x_outlet0, pdp, 2, atom);
+
+}
+
+
+
+static void pdp_trigger_free(t_pdp_trigger *x)
+{
+
+}
+
+t_class *pdp_trigger_class;
+
+
+
+void *pdp_trigger_new(void)
+{
+ t_pdp_trigger *x = (t_pdp_trigger *)pd_new(pdp_trigger_class);
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_bang);
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_trigger_setup(void)
+{
+
+
+ pdp_trigger_class = class_new(gensym("pdp_trigger"), (t_newmethod)pdp_trigger_new,
+ (t_method)pdp_trigger_free, sizeof(t_pdp_trigger), 0, A_NULL);
+
+ class_addmethod(pdp_trigger_class, (t_method)pdp_trigger_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_v4l.c b/modules/pdp_v4l.c
new file mode 100644
index 0000000..e4dbff9
--- /dev/null
+++ b/modules/pdp_v4l.c
@@ -0,0 +1,734 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <linux/types.h>
+#include <linux/videodev.h>
+#include <sys/mman.h>
+#include <sched.h>
+#include <pthread.h>
+
+// dont open any more after a set number
+// of failed attempts
+// this is to prevent locks on auto-open
+// is reset when manually opened or closed
+#define PDP_XV_RETRIES 10
+
+//uncomment this for additional philips webcam control
+//#define HAVE_V4LPWC
+#ifdef HAVE_V4LPWC
+#include "pwc-ioctl.h"
+#endif
+
+
+#define DEVICENO 0
+#define NBUF 2
+#define COMPOSITEIN 1
+
+
+
+
+typedef struct pdp_v4l_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ bool x_initialized;
+ bool x_auto_open;
+
+ unsigned int x_width;
+ unsigned int x_height;
+ int x_channel;
+ unsigned int x_norm;
+ int x_freq;
+
+ unsigned int x_framerate;
+
+ struct video_tuner x_vtuner;
+ struct video_picture x_vpicture;
+ struct video_buffer x_vbuffer;
+ struct video_capability x_vcap;
+ struct video_channel x_vchannel;
+ struct video_audio x_vaudio;
+ struct video_mbuf x_vmbuf;
+ struct video_mmap x_vmmap[NBUF];
+ struct video_window x_vwin;
+ int x_tvfd;
+ int x_frame;
+ unsigned char *x_videobuf;
+ int x_skipnext;
+ int x_mytopmargin, x_mybottommargin;
+ int x_myleftmargin, x_myrightmargin;
+
+ t_symbol *x_device;
+ t_symbol *x_image_type;
+ //int x_pdp_image_type;
+ int x_v4l_palette;
+
+ pthread_t x_thread_id;
+ int x_continue_thread;
+ int x_frame_ready;
+ int x_only_new_frames;
+ int x_last_frame;
+
+
+ int x_open_retry;
+
+
+} t_pdp_v4l;
+
+
+
+
+
+static void pdp_v4l_close(t_pdp_v4l *x)
+{
+ /* close the v4l device and dealloc buffer */
+
+ void *dummy;
+
+ /* terminate thread if there is one */
+ if(x->x_continue_thread){
+ x->x_continue_thread = 0;
+ pthread_join (x->x_thread_id, &dummy);
+ }
+
+
+ if (x->x_tvfd >= 0)
+ {
+ close(x->x_tvfd);
+ x->x_tvfd = -1;
+ }
+
+ if (x->x_initialized){
+ munmap(x->x_videobuf, x->x_vmbuf.size);
+ x->x_initialized = false;
+ }
+
+}
+
+static void pdp_v4l_close_manual(t_pdp_v4l *x)
+{
+ x->x_open_retry = PDP_XV_RETRIES;
+ pdp_v4l_close(x);
+
+}
+
+static void pdp_v4l_close_error(t_pdp_v4l *x)
+{
+ pdp_v4l_close(x);
+ if(x->x_open_retry) x->x_open_retry--;
+}
+
+
+static void pdp_v4l_pwc_init(t_pdp_v4l *x)
+{
+ /* todo add detection code for pwc */
+
+#ifdef HAVE_V4LPWC
+
+ if(ioctl(x->x_tvfd, VIDIOCPWCRUSER)){
+ perror("pdp_v4l: pwc: VIDIOCPWCRUSER");
+ goto closit;
+ }
+
+ if (ioctl(x->x_tvfd, VIDIOCGWIN, &x->x_vwin)){
+ perror("pdp_v4l: pwc: VIDIOCGWIN");
+ goto closit;
+ }
+
+
+
+ if (x->x_vwin.flags & PWC_FPS_MASK){
+ post("pdp_v4l: pwc: framerate: %d", (x->x_vwin.flags & PWC_FPS_MASK) >> PWC_FPS_SHIFT);
+ post("pdp_v4l: pwc: setting framerate to %d", x->x_framerate);
+ x->x_vwin.flags &= PWC_FPS_MASK;
+ x->x_vwin.flags |= (x->x_framerate << PWC_FPS_SHIFT);
+ if (ioctl(x->x_tvfd, VIDIOCSWIN, &x->x_vwin)){
+ perror("pdp_v4l: pwc: VIDIOCSWIN");
+ goto closit;
+ }
+ if (ioctl(x->x_tvfd, VIDIOCGWIN, &x->x_vwin)){
+ perror("pdp_v4l: pwc: VIDIOCGWIN");
+ goto closit;
+ }
+ post("pdp_v4l: pwc: framerate: %d", (x->x_vwin.flags & PWC_FPS_MASK) >> PWC_FPS_SHIFT);
+
+ }
+
+
+ return;
+
+
+
+ closit:
+ pdp_v4l_close_error(x);
+ return;
+
+#else
+ post("pdp_v4l: additional pwc support disabled");
+ return;
+#endif
+}
+
+static void pdp_v4l_sync_frame(t_pdp_v4l* x){
+ /* grab frame */
+ if (ioctl(x->x_tvfd, VIDIOCSYNC, &x->x_vmmap[x->x_frame].frame) < 0){
+ perror("pdp_v4l: VIDIOCSYNC");
+ pdp_v4l_close(x);
+ return;
+ }
+}
+
+static void pdp_v4l_capture_frame(t_pdp_v4l* x){
+ if (ioctl(x->x_tvfd, VIDIOCMCAPTURE, &x->x_vmmap[x->x_frame]) < 0){
+ if (errno == EAGAIN)
+ post("pdp_v4l: can't sync (no video source?)\n");
+ else
+ perror("pdp_v4l: VIDIOCMCAPTURE");
+ if (ioctl(x->x_tvfd, VIDIOCMCAPTURE, &x->x_vmmap[x->x_frame]) < 0)
+ perror("pdp_v4l: VIDIOCMCAPTURE2");
+
+ post("pdp_v4l: frame %d %d, format %d, width %d, height %d",
+ x->x_frame, x->x_vmmap[x->x_frame].frame, x->x_vmmap[x->x_frame].format,
+ x->x_vmmap[x->x_frame].width, x->x_vmmap[x->x_frame].height);
+
+ pdp_v4l_close(x);
+ return;
+ }
+}
+
+
+static void *pdp_v4l_thread(void *voidx)
+{
+ t_pdp_v4l *x = ((t_pdp_v4l *)voidx);
+
+
+ /* flip buffers */
+ x->x_frame ^= 0x1;
+
+ /* capture with a double buffering scheme */
+ while (x->x_continue_thread){
+
+ /* schedule capture command for next frame */
+ pdp_v4l_capture_frame(x);
+
+ /* wait until previous capture is ready */
+ x->x_frame ^= 0x1;
+ pdp_v4l_sync_frame(x);
+
+ /* setup pointers for main thread */
+ x->x_frame_ready = 1;
+ x->x_last_frame = x->x_frame;
+
+ }
+
+ return 0;
+}
+
+
+static void pdp_v4l_open(t_pdp_v4l *x, t_symbol *name)
+{
+ /* open a v4l device and allocate a buffer */
+
+ unsigned int size;
+ int i;
+
+ unsigned int width, height;
+
+
+ /* if already opened -> close */
+ if (x->x_initialized) pdp_v4l_close(x);
+
+
+ /* exit if retried too much */
+ if (!x->x_open_retry){
+ post("pdp_v4l: retry count reached zero for %s", name->s_name);
+ post("pdp_v4l: try to open manually");
+ return;
+ }
+
+ post("pdp_v4l: opening %s", name->s_name);
+
+ x->x_device = name;
+
+ if ((x->x_tvfd = open(name->s_name, O_RDWR)) < 0)
+ {
+ post("pdp_v4l: error:");
+ perror(name->s_name);
+ goto closit;
+ }
+
+
+ if (ioctl(x->x_tvfd, VIDIOCGCAP, &x->x_vcap) < 0)
+ {
+ perror("get capabilities");
+ goto closit;
+ }
+
+ post("pdp_v4l: cap: name %s type %d channels %d maxw %d maxh %d minw %d minh %d",
+ x->x_vcap.name, x->x_vcap.type, x->x_vcap.channels, x->x_vcap.maxwidth, x->x_vcap.maxheight,
+ x->x_vcap.minwidth, x->x_vcap.minheight);
+
+ if (ioctl(x->x_tvfd, VIDIOCGPICT, &x->x_vpicture) < 0)
+ {
+ perror("VIDIOCGCAP");
+ goto closit;
+ }
+
+ post("pdp_v4l: picture: brightness %d depth %d palette %d",
+ x->x_vpicture.brightness, x->x_vpicture.depth, x->x_vpicture.palette);
+
+ /* get channel info */
+ for (i = 0; i < x->x_vcap.channels; i++)
+ {
+ x->x_vchannel.channel = i;
+ if (ioctl(x->x_tvfd, VIDIOCGCHAN, &x->x_vchannel) < 0)
+ {
+ perror("VDIOCGCHAN");
+ goto closit;
+ }
+ post("pdp_v4l: channel %d name %s type %d flags %d",
+ x->x_vchannel.channel, x->x_vchannel.name,
+ x->x_vchannel.type, x->x_vchannel.flags);
+ }
+
+ /* switch to the desired channel */
+ if (x->x_channel < 0) x->x_channel = 0;
+ if (x->x_channel >= x->x_vcap.channels) x->x_channel = x->x_vcap.channels - 1;
+
+ x->x_vchannel.channel = x->x_channel;
+ if (ioctl(x->x_tvfd, VIDIOCGCHAN, &x->x_vchannel) < 0)
+ {
+ perror("pdp_v4l: warning: VDIOCGCHAN");
+ post("pdp_v4l: cant change to channel %d",x->x_channel);
+
+ // ignore error
+ // goto closit;
+ }
+ else{
+ post("pdp_v4l: switched to channel %d", x->x_channel);
+ }
+
+ x->x_vchannel.norm = x->x_norm;
+ if (ioctl(x->x_tvfd, VIDIOCSCHAN, &x->x_vchannel) < 0)
+ {
+ perror("pdp_v4l: warning: VDIOCSCHAN");
+ post("pdp_v4l: cant change to norm %d",x->x_norm);
+
+ // ignore error
+ // goto closit;
+ }
+
+ if (x->x_freq > 0){
+ if (ioctl(x->x_tvfd, VIDIOCSFREQ, &x->x_freq) < 0)
+ perror ("couldn't set frequency :");
+ }
+
+
+
+
+ /* get mmap numbers */
+ if (ioctl(x->x_tvfd, VIDIOCGMBUF, &x->x_vmbuf) < 0)
+ {
+ perror("pdp_v4l: VIDIOCGMBUF");
+ goto closit;
+ }
+ post("pdp_v4l: buffer size %d, frames %d, offset %d %d", x->x_vmbuf.size,
+ x->x_vmbuf.frames, x->x_vmbuf.offsets[0], x->x_vmbuf.offsets[1]);
+ if (!(x->x_videobuf = (unsigned char *)
+ mmap(0, x->x_vmbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, x->x_tvfd, 0)))
+ {
+ perror("pdp_v4l: mmap");
+ goto closit;
+ }
+
+ width = (x->x_width > (unsigned int)x->x_vcap.minwidth) ? x->x_width : (unsigned int)x->x_vcap.minwidth;
+ width = (width > (unsigned int)x->x_vcap.maxwidth) ?(unsigned int) x->x_vcap.maxwidth : width;
+ height = (x->x_height > (unsigned int)x->x_vcap.minheight) ? x->x_height :(unsigned int) x->x_vcap.minheight;
+ height = (height > (unsigned int)x->x_vcap.maxheight) ? (unsigned int)x->x_vcap.maxheight : height;
+
+ for (i = 0; i < NBUF; i++)
+ {
+ //x->x_vmmap[i].format = VIDEO_PALETTE_YUV420P;
+ //x->x_vmmap[i].format = VIDEO_PALETTE_UYVY;
+ x->x_vmmap[i].width = width;
+ x->x_vmmap[i].height = height;
+ x->x_vmmap[i].frame = i;
+ }
+
+
+ //goto test;
+
+ //try yuv planar format
+ x->x_v4l_palette = VIDEO_PALETTE_YUV420P;
+ for (i = 0; i < NBUF; i++) x->x_vmmap[i].format = x->x_v4l_palette;
+ if (ioctl(x->x_tvfd, VIDIOCMCAPTURE, &x->x_vmmap[x->x_frame]) < 0)
+ {
+ if (errno == EAGAIN)
+ post("pdp_v4l: can't sync (no video source?)");
+ }
+ else{
+ post("pdp_v4l: using VIDEO_PALETTE_YUV420P");
+ goto capture_ok;
+ }
+
+
+ //try VIDEO_PALETTE_YUV422 format
+ x->x_v4l_palette = VIDEO_PALETTE_YUV422;
+ for (i = 0; i < NBUF; i++) x->x_vmmap[i].format = x->x_v4l_palette;
+ if (ioctl(x->x_tvfd, VIDIOCMCAPTURE, &x->x_vmmap[x->x_frame]) < 0)
+ {
+ if (errno == EAGAIN)
+ post("pdp_v4l: can't sync (no video source?)");
+ }
+ else{
+ post("pdp_v4l: using VIDEO_PALETTE_YUV422");
+ goto capture_ok;
+ }
+
+
+ test:
+
+ //try rgb packed format
+ x->x_v4l_palette = VIDEO_PALETTE_RGB24;
+ for (i = 0; i < NBUF; i++) x->x_vmmap[i].format = x->x_v4l_palette;
+ if (ioctl(x->x_tvfd, VIDIOCMCAPTURE, &x->x_vmmap[x->x_frame]) < 0)
+ {
+ if (errno == EAGAIN)
+ post("pdp_v4l: can't sync (no video source?)");
+ }
+ else{
+ post("pdp_v4l: using VIDEO_PALETTE_RGB24");
+ goto capture_ok;
+ }
+
+
+ // none of the formats are supported
+ perror("pdp_v4l: VIDIOCMCAPTURE: format not supported");
+ goto closit;
+
+
+ capture_ok:
+
+ post("pdp_v4l: frame %d %d, format %d, width %d, height %d",
+ x->x_frame, x->x_vmmap[x->x_frame].frame, x->x_vmmap[x->x_frame].format,
+ x->x_vmmap[x->x_frame].width, x->x_vmmap[x->x_frame].height);
+
+ x->x_width = width;
+ x->x_height = height;
+
+ post("pdp_v4l: Opened video connection (%dx%d)",x->x_width,x->x_height);
+
+
+ /* do some pwc specific inits */
+ pdp_v4l_pwc_init(x);
+
+
+ x->x_initialized = true;
+
+ /* create thread */
+ x->x_continue_thread = 1;
+ x->x_frame_ready = 0;
+ pthread_create(&x->x_thread_id, 0, pdp_v4l_thread, x);
+
+ return;
+ closit:
+ pdp_v4l_close_error(x);
+
+}
+
+static void pdp_v4l_open_manual(t_pdp_v4l *x, t_symbol *name)
+{
+ x->x_open_retry = PDP_XV_RETRIES;
+ pdp_v4l_open(x, name);
+}
+
+
+static void pdp_v4l_channel(t_pdp_v4l *x, t_float f)
+{
+ int channel = (float)f;
+
+ if (x->x_initialized){
+ pdp_v4l_close(x);
+ x->x_channel = channel;
+ pdp_v4l_open(x, x->x_device);
+ }
+ else
+ x->x_channel = channel;
+}
+
+
+static void pdp_v4l_freq(t_pdp_v4l *x, t_float f)
+{
+ int freq = (int)f;
+
+ x->x_freq = freq;
+ if (x->x_freq > 0){
+ if (ioctl(x->x_tvfd, VIDIOCSFREQ, &x->x_freq) < 0)
+ perror ("couldn't set frequency :");
+ else {post("pdp_v4l: tuner frequency: %f MHz", f / 16.0f);}
+ }
+
+}
+
+static void pdp_v4l_freqMHz(t_pdp_v4l *x, t_float f)
+{
+ pdp_v4l_freq(x, f*16.0f);
+}
+
+
+static void pdp_v4l_bang(t_pdp_v4l *x)
+{
+
+ /* if initialized, grab a frame and output it */
+
+ unsigned int w,h,nbpixels,packet_size,plane1,plane2;
+ unsigned char *newimage;
+ int object,length,pos,i,encoding;
+ t_pdp* header;
+ short int * data;
+
+
+ static short int gain[4] = {0x7fff, 0x7fff, 0x7fff, 0x7fff};
+
+ if (!(x->x_initialized)){
+ post("pdp_v4l: no device opened");
+
+ if (x->x_auto_open){
+ post("pdp_v4l: attempting auto open");
+ pdp_v4l_open(x, x->x_device);
+ if (!(x->x_initialized)){
+ post("pdp_v4l: auto open failed");
+ return;
+ }
+ }
+
+ else return;
+ }
+
+
+ /* do nothing if there is no frame ready */
+ if((!x->x_frame_ready) && (x->x_only_new_frames)) return;
+ x->x_frame_ready = 0;
+
+ /* get the address of the "other" frame */
+ newimage = x->x_videobuf + x->x_vmbuf.offsets[x->x_last_frame];
+
+ /* create new packet */
+ w = x->x_width;
+ h = x->x_height;
+
+ nbpixels = w * h;
+
+/*
+ switch(x->x_pdp_image_type){
+ case PDP_IMAGE_GREY:
+ packet_size = nbpixels << 1;
+ break;
+ case PDP_IMAGE_YV12:
+ packet_size = (nbpixels + (nbpixels >> 1)) << 1;
+ break;
+ default:
+ packet_size = 0;
+ post("pdp_v4l: internal error");
+ }
+*/
+
+ packet_size = (nbpixels + (nbpixels >> 1)) << 1;
+
+
+ plane1 = nbpixels;
+ plane2 = nbpixels + (nbpixels>>2);
+
+ object = pdp_packet_new(PDP_IMAGE, packet_size);
+ header = pdp_packet_header(object);
+ data = (short int *) pdp_packet_data(object);
+
+ //header->info.image.encoding = x->x_pdp_image_type;
+ header->info.image.encoding = PDP_IMAGE_YV12;
+ header->info.image.width = w;
+ header->info.image.height = h;
+
+ /* read from the "other" frame */
+ newimage = x->x_videobuf + x->x_vmbuf.offsets[x->x_frame ^ 0x1];
+
+
+ /* convert data to pdp packet */
+
+ switch(x->x_v4l_palette){
+ case VIDEO_PALETTE_YUV420P:
+ pdp_llconv(newimage, RIF_YUV__P411_U8, data, RIF_YVU__P411_S16, w, h);
+ break;
+
+ case VIDEO_PALETTE_RGB24:
+ pdp_llconv(newimage, RIF_RGB__P____U8, data, RIF_YVU__P411_S16, w, h);
+ break;
+
+ case VIDEO_PALETTE_YUV422:
+ pdp_llconv(newimage, RIF_YUYV_P____U8, data, RIF_YVU__P411_S16, w, h);
+ break;
+
+
+ default:
+ post("pdp_v4l: unsupported palette");
+ break;
+ }
+
+/*
+ if (PDP_IMAGE_YV12 == x->x_pdp_image_type){
+ pixel_unpack_u8s16_y(&newimage[0], data, nbpixels>>3, x->x_state_data->gain);
+ pixel_unpack_u8s16_uv(&newimage[plane1], &data[plane2], nbpixels>>5, x->x_state_data->gain);
+ pixel_unpack_u8s16_uv(&newimage[plane2], &data[plane1], nbpixels>>5, x->x_state_data->gain);
+ }
+*/
+ //x->x_v4l_palette = VIDEO_PALETTE_YUV420P;
+ //x->x_v4l_palette = VIDEO_PALETTE_RGB24;
+
+/*
+
+ else if(PDP_IMAGE_GREY == x->x_pdp_image_type){
+ pixel_unpack_u8s16_y(&newimage[0], data, nbpixels>>3, x->x_state_data->gain);
+ }
+*/
+ //post("pdp_v4l: mark unused %d", object);
+
+ pdp_packet_mark_unused(object);
+ outlet_pdp(x->x_outlet0, object);
+
+
+}
+
+
+static void pdp_v4l_dim(t_pdp_v4l *x, t_floatarg xx, t_floatarg yy)
+{
+ unsigned int w,h;
+
+ xx = (xx < 0.0f) ? 0.0f : xx;
+ yy = (yy < 0.0f) ? 0.0f : yy;
+
+ w = (unsigned int)xx;
+ h = (unsigned int)yy;
+
+
+ if (x->x_initialized){
+ pdp_v4l_close(x);
+ x->x_width = w;
+ x->x_height = h;
+ pdp_v4l_open(x, x->x_device);
+
+ }
+ else{
+ x->x_width = w;
+ x->x_height = h;
+ }
+}
+
+
+static void pdp_v4l_free(t_pdp_v4l *x)
+{
+ pdp_v4l_close(x);
+}
+
+t_class *pdp_v4l_class;
+
+
+
+void *pdp_v4l_new(void)
+{
+ t_pdp_v4l *x = (t_pdp_v4l *)pd_new(pdp_v4l_class);
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_initialized = false;
+
+
+ x->x_tvfd = -1;
+ x->x_frame = 0;
+ x->x_last_frame = 0;
+
+ x->x_framerate = 27;
+
+ x->x_auto_open = true;
+ x->x_device = gensym("/dev/video0");
+
+ x->x_continue_thread = 0;
+ x->x_only_new_frames = 1;
+
+ x->x_width = 320;
+ x->x_height = 240;
+
+// pdp_v4l_type(x, gensym("yv12"));
+
+
+ x->x_open_retry = PDP_XV_RETRIES;
+
+ x->x_channel = 0;
+ x->x_freq = -1; //don't set freq by default
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_v4l_setup(void)
+{
+
+
+ pdp_v4l_class = class_new(gensym("pdp_v4l"), (t_newmethod)pdp_v4l_new,
+ (t_method)pdp_v4l_free, sizeof(t_pdp_v4l), 0, A_NULL);
+
+
+ class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_bang, gensym("bang"), A_NULL);
+ class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_close_manual, gensym("close"), A_NULL);
+ class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_open_manual, gensym("open"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_channel, gensym("channel"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_freq, gensym("freq"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_freqMHz, gensym("freqMHz"), A_FLOAT, A_NULL);
+
+
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_xv.c b/modules/pdp_xv.c
new file mode 100644
index 0000000..c859a40
--- /dev/null
+++ b/modules/pdp_xv.c
@@ -0,0 +1,534 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+
+pdp xvideo output
+
+*/
+
+
+// x stuff
+#include <X11/Xlib.h>
+#include <X11/extensions/Xv.h>
+#include <X11/extensions/Xvlib.h>
+
+// image formats for communication with the X Server
+#define FOURCC_YV12 0x32315659 /* YV12 YUV420P */
+#define FOURCC_YUV2 0x32595559 /* YUV2 YUV422 */
+#define FOURCC_I420 0x30323449 /* I420 Intel Indeo 4 */
+
+// pdp stuff
+#include "pdp.h"
+#include "pdp_llconv.h"
+
+
+/* initial image dimensions */
+#define PDP_XV_W 320
+#define PDP_XV_H 240
+
+#define PDP_XV_AUTOCREATE_RETRY 10
+
+
+typedef struct pdp_xv_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ int x_packet0;
+ int x_queue_id;
+ t_symbol *x_display;
+
+ Display *x_dpy;
+ int x_screen;
+ Window x_win;
+ GC x_gc;
+
+ int x_xv_format;
+ int x_xv_port;
+
+ int x_winwidth;
+ int x_winheight;
+
+ XvImage *x_xvi;
+ unsigned char *x_data;
+ unsigned int x_width;
+ unsigned int x_height;
+ int x_last_encoding;
+
+ int x_initialized;
+ int x_autocreate;
+
+ float x_cursor;
+
+
+} t_pdp_xv;
+
+
+static int xv_init(t_pdp_xv *x)
+{
+ unsigned int ver, rel, req, ev, err, i, j;
+ unsigned int adaptors;
+ int formats;
+ XvAdaptorInfo *ai;
+
+ if (Success != XvQueryExtension(x->x_dpy,&ver,&rel,&req,&ev,&err)) return 0;
+
+ /* find + lock port */
+ if (Success != XvQueryAdaptors(x->x_dpy,DefaultRootWindow(x->x_dpy),&adaptors,&ai))
+ return 0;
+ for (i = 0; i < adaptors; i++) {
+ if ((ai[i].type & XvInputMask) && (ai[i].type & XvImageMask)) {
+ for (j=0; j < ai[i].num_ports; j++){
+ if (Success != XvGrabPort(x->x_dpy,ai[i].base_id+j,CurrentTime)) {
+ //fprintf(stderr,"INFO: Xvideo port %ld on adapter %d: is busy, skipping\n",ai[i].base_id+j, i);
+ }
+ else {
+ x->x_xv_port = ai[i].base_id + j;
+ goto breakout;
+ }
+ }
+ }
+ }
+
+
+ breakout:
+
+ XFree(ai);
+ if (0 == x->x_xv_port) return 0;
+ post("pdp_xv: grabbed port %d on adaptor %d", x->x_xv_port, i);
+ return 1;
+}
+
+
+void pdp_xv_create_xvimage(t_pdp_xv *x)
+{
+
+ long size = (x->x_width * x->x_height + (((x->x_width>>1)*(x->x_height>>1))<<1));
+ x->x_data = (unsigned char *)malloc(size);
+ x->x_xvi = XvCreateImage(x->x_dpy, x->x_xv_port, x->x_xv_format, (char *)x->x_data, x->x_width, x->x_height);
+ x->x_last_encoding = -1;
+ if (!(x->x_xvi) || (!x->x_data)) post ("ERROR CREATING XVIMAGE");
+
+}
+
+void pdp_xv_destroy_xvimage(t_pdp_xv *x)
+{
+ if(x->x_data) free(x->x_data);
+ if (x->x_xvi) XFree(x->x_xvi);
+ x->x_xvi = 0;
+ x->x_data = 0;
+}
+
+
+static void pdp_xv_cursor(t_pdp_xv *x, t_floatarg f)
+{
+ if (!x->x_initialized) return;
+
+ if (f == 0) {
+ static char data[1] = {0};
+
+ Cursor cursor;
+ Pixmap blank;
+ XColor dummy;
+
+ blank = XCreateBitmapFromData(x->x_dpy, x->x_win, data, 1, 1);
+ cursor = XCreatePixmapCursor(x->x_dpy, blank, blank, &dummy,
+ &dummy, 0, 0);
+ XFreePixmap(x->x_dpy, blank);
+ XDefineCursor(x->x_dpy, x->x_win,cursor);
+ }
+ else
+ XUndefineCursor(x->x_dpy, x->x_win);
+
+ x->x_cursor = f;
+}
+
+
+static void pdp_xv_destroy(t_pdp_xv* x)
+{
+ XEvent e;
+
+ if (x->x_initialized){
+ XFreeGC(x->x_dpy, x->x_gc);
+ XDestroyWindow(x->x_dpy, x->x_win);
+ while(XPending(x->x_dpy)) XNextEvent(x->x_dpy, &e);
+ XvUngrabPort(x->x_dpy, x->x_xv_port, CurrentTime);
+ pdp_xv_destroy_xvimage(x);
+ XCloseDisplay(x->x_dpy);
+ x->x_initialized = false;
+
+ }
+
+}
+
+static void pdp_xv_resize(t_pdp_xv* x, t_floatarg width, t_floatarg height)
+{
+ if (x->x_initialized && (width>0) && (height>0)){
+ XResizeWindow(x->x_dpy, x->x_win, (unsigned int)width, (unsigned int)height);
+ XFlush(x->x_dpy);
+ }
+}
+
+static void pdp_xv_create(t_pdp_xv* x)
+{
+ unsigned int *uintdata = (unsigned int *)(x->x_data);
+ XEvent e;
+ unsigned int i;
+
+ if( x->x_initialized ){
+ //post("pdp_xv: window already created");
+ return;
+ }
+
+ if (NULL == (x->x_dpy = XOpenDisplay(x->x_display->s_name))){
+ post("pdp_xv: cant open display %s\n",x->x_display->s_name);
+ x->x_initialized = false;
+ return;
+ }
+
+ /* init xvideo */
+ if (xv_init(x)){
+
+ pdp_xv_create_xvimage(x);
+
+ }
+
+ else {
+ /* clean up mess */
+ post("pdp_xv: ERROR: no xv port available. closing display.");
+ XCloseDisplay(x->x_dpy);
+ x->x_initialized = false;
+ return;
+ }
+
+
+ /* create a window */
+ x->x_screen = DefaultScreen(x->x_dpy);
+
+
+ x->x_win = XCreateSimpleWindow(
+ x->x_dpy,
+ RootWindow(x->x_dpy, x->x_screen), 0, 0, x->x_winwidth, x->x_winheight, 0,
+ BlackPixel(x->x_dpy, x->x_screen),
+ BlackPixel(x->x_dpy, x->x_screen));
+
+ if(!(x->x_win)){
+ /* clean up mess */
+ post("pdp_xv: could not create window\n");
+ post("pdp_xv: unlocking xv port");
+ XvUngrabPort(x->x_dpy, x->x_xv_port, CurrentTime);
+ post("pdp_xv: freeing xvimage");
+ pdp_xv_destroy_xvimage(x);
+ post("pdp_xv: closing display");
+ XCloseDisplay(x->x_dpy);
+ x->x_initialized = false;
+ return;
+ }
+
+ XSelectInput(x->x_dpy, x->x_win, StructureNotifyMask);
+
+ XMapWindow(x->x_dpy, x->x_win);
+
+ x->x_gc = XCreateGC(x->x_dpy, x->x_win, 0, 0);
+
+ for(;;){
+ XNextEvent(x->x_dpy, &e);
+ if (e.type == MapNotify) break;
+ }
+
+
+ x->x_initialized = true;
+ pdp_xv_cursor(x, x->x_cursor);
+
+}
+
+void pdp_xv_copy_xvimage(t_pdp_xv *x, t_image *image, short int* data)
+{
+ unsigned int width = image->width;
+ unsigned int height = image->height;
+ int encoding = image->encoding;
+ unsigned int* uintdata;
+ int i;
+
+
+ /* 8bit y fulscale and 8bit u,v 2x2 subsampled */
+ //static short int gain[4] = {0x0100, 0x0100, 0x0100, 0x0100};
+ long size = (width * height + (((width>>1)*(height>>1))<<1));
+ int nbpixels = width * height;
+
+ /* check if xvimage needs to be recreated */
+ if ((width != x->x_width) || (height != x->x_height)){
+ //post("pdp_xv: replace image");
+ x->x_width = width;
+ x->x_height = height;
+ pdp_xv_destroy_xvimage(x);
+ pdp_xv_create_xvimage(x);
+ }
+
+
+ /* data holds a 16bit version of a the xvimage, so it needs to be converted */
+
+
+
+ if (data) {
+ /* convert 16bit -> 8bit */
+ if(PDP_IMAGE_YV12 == encoding){
+ pdp_llconv(data,RIF_YVU__P411_S16, x->x_data, RIF_YVU__P411_U8, x->x_width, x->x_height);
+ x->x_last_encoding = PDP_IMAGE_YV12;
+ }
+ if(PDP_IMAGE_GREY == encoding){
+ pdp_llconv(data,RIF_GREY______S16, x->x_data, RIF_GREY______U8, x->x_width, x->x_height);
+ if (PDP_IMAGE_GREY != x->x_last_encoding) {
+ post("pdp_xv: switching to greyscale");
+ /* clear u&v planes if necessary */
+ uintdata = (unsigned int *)&x->x_data[nbpixels];
+ for(i=0; i < nbpixels>>3; i++) uintdata[i]=0x80808080;
+ }
+ x->x_last_encoding = PDP_IMAGE_GREY;
+
+ }
+ }
+ else bzero(x->x_data, size);
+
+
+
+}
+
+static int pdp_xv_try_autocreate(t_pdp_xv *x)
+{
+
+ if (x->x_autocreate){
+ post("pdp_xv: autocreate window");
+ pdp_xv_create(x);
+ if (!(x->x_initialized)){
+ x->x_autocreate--;
+ if (!x->x_autocreate){
+ post ("pdp_xv: autocreate failed %d times: disabled", PDP_XV_AUTOCREATE_RETRY);
+ post ("pdp_xv: send [autocreate 1] message to re-enable");
+ return 0;
+ }
+ }
+ else return 1;
+
+ }
+ return 0;
+}
+
+static void pdp_xv_bang(t_pdp_xv *x);
+
+static void pdp_xv_process(t_pdp_xv *x)
+{
+ t_pdp *header = pdp_packet_header(x->x_packet0);
+ void *data = pdp_packet_data (x->x_packet0);
+
+
+ if (-1 != x->x_queue_id) return;
+
+ /* check if window is initialized */
+ if (!(x->x_initialized)){
+ if (!pdp_xv_try_autocreate(x)) return;
+ }
+
+ /* check data packet */
+ if (!(header)) {
+ post("pdp_xv: invalid packet header");
+ return;
+ }
+ if (PDP_IMAGE != header->type) {
+ post("pdp_xv: packet is not a PDP_IMAGE");
+ return;
+ }
+ if ((PDP_IMAGE_YV12 != header->info.image.encoding)
+ && (PDP_IMAGE_GREY != header->info.image.encoding)) {
+ post("pdp_xv: packet is not a PDP_IMAGE_YV12/GREY");
+ return;
+ }
+
+ /* copy the packet to the xvimage */
+ pdp_xv_copy_xvimage(x, &header->info.image, (short int *)data);
+
+
+ /* display the new image */
+ pdp_xv_bang(x);
+
+
+}
+
+
+static void pdp_xv_random(t_pdp_xv *x)
+{
+ unsigned int i;
+ long *intdata = (long *)(x->x_data);
+ for(i=0; i<x->x_width*x->x_height/4; i++) intdata[i]=random();
+}
+
+/* redisplays image */
+static void pdp_xv_bang_thread(t_pdp_xv *x)
+{
+
+ XEvent e;
+ unsigned int i;
+
+ //while (XEventsQueued(x->x_dpy, QueuedAlready)){
+ while (XPending(x->x_dpy)){
+ //post("pdp_xv: waiting for event");
+ XNextEvent(x->x_dpy, &e);
+ //post("pdp_xv: XEvent %d", e.type);
+ if(e.type == ConfigureNotify){
+ XConfigureEvent *ce = (XConfigureEvent *)&e;
+ x->x_winwidth = ce->width;
+ x->x_winheight = ce->height;
+
+ }
+ //post("pdp_xv: received event");
+
+ }
+
+ XvPutImage(x->x_dpy,x->x_xv_port,x->x_win,x->x_gc,x->x_xvi,
+ 0,0,x->x_width,x->x_height, 0,0,x->x_winwidth,x->x_winheight);
+ XFlush(x->x_dpy);
+}
+
+static void pdp_xv_bang_callback(t_pdp_xv *x)
+{
+ /* release the packet if there is one */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = -1;}
+
+static void pdp_xv_bang(t_pdp_xv *x)
+{
+
+
+ /* if previous queued method returned
+ schedule a new one, else ignore */
+ if (-1 == x->x_queue_id) {
+ pdp_queue_add(x, pdp_xv_bang_thread, pdp_xv_bang_callback, &x->x_queue_id);
+ }
+
+}
+
+static void pdp_xv_input_0(t_pdp_xv *x, t_symbol *s, t_floatarg f)
+{
+
+ if (s == gensym("register_ro")) pdp_packet_copy_ro_or_drop(&x->x_packet0, (int)f);
+ if (s == gensym("process")) pdp_xv_process(x);
+
+}
+
+
+static void pdp_xv_autocreate(t_pdp_xv *x, t_floatarg f)
+{
+ if (f != 0.0f) x->x_autocreate = PDP_XV_AUTOCREATE_RETRY;
+ else x->x_autocreate = 0;
+}
+
+static void pdp_xv_display(t_pdp_xv *x, t_symbol *s)
+{
+ pdp_queue_finish(x->x_queue_id);
+ x->x_queue_id = -1;
+ x->x_display = s;
+ if (x->x_initialized){
+ pdp_xv_destroy(x);
+ pdp_xv_create(x);
+ }
+}
+
+
+
+static void pdp_xv_free(t_pdp_xv *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+
+ pdp_xv_destroy(x);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_xv_class;
+
+
+
+void *pdp_xv_new(void)
+{
+ t_pdp_xv *x = (t_pdp_xv *)pd_new(pdp_xv_class);
+
+
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+ x->x_display = gensym(":0");
+
+
+ x->x_dpy = 0;
+ x->x_screen = -1;
+
+ x->x_xv_format = FOURCC_YV12;
+ x->x_xv_port = 0;
+
+ x->x_winwidth = PDP_XV_W;
+ x->x_winheight = PDP_XV_H;
+
+ x->x_width = PDP_XV_W;
+ x->x_height = PDP_XV_H;
+
+ x->x_data = 0;
+ x->x_xvi = 0;
+
+ x->x_initialized = 0;
+ pdp_xv_autocreate(x,1);
+ x->x_last_encoding = -1;
+
+ x->x_cursor = 0;
+
+ return (void *)x;
+}
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_xv_setup(void)
+{
+
+
+ pdp_xv_class = class_new(gensym("pdp_xv"), (t_newmethod)pdp_xv_new,
+ (t_method)pdp_xv_free, sizeof(t_pdp_xv), 0, A_NULL);
+
+
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_bang, gensym("bang"), A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_random, gensym("random"), A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_create, gensym("create"), A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_autocreate, gensym("autocreate"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_destroy, gensym("destroy"), A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_destroy, gensym("close"), A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_resize, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_resize, gensym("size"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_display, gensym("display"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_cursor, gensym("cursor"), A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_zoom.c b/modules/pdp_zoom.c
new file mode 100644
index 0000000..33207ce
--- /dev/null
+++ b/modules/pdp_zoom.c
@@ -0,0 +1,264 @@
+/*
+ * 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_resample.h"
+
+
+
+typedef struct pdp_zoom_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+
+ int x_packet0;
+ int x_packet1;
+ int x_dropped;
+ int x_queue_id;
+
+ float x_zoom_x;
+ float x_zoom_y;
+
+ float x_center_x;
+ float x_center_y;
+
+ int x_quality; //not used
+
+
+} t_pdp_zoom;
+
+
+static void pdp_zoom_process_yv12(t_pdp_zoom *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ short int *src_image = (short int *)data0;
+ short int *dst_image = (short int *)data1;
+
+ unsigned int size = w * h;
+ unsigned int voffset = size;
+ unsigned int uoffset = size + (size>>2);
+
+
+ pdp_resample_zoom_tiled_bilin(src_image, dst_image, w, h, x->x_zoom_x, x->x_zoom_y, x->x_center_x, x->x_center_y);
+ pdp_resample_zoom_tiled_bilin(src_image+voffset, dst_image+voffset, w>>1, h>>1, x->x_zoom_x, x->x_zoom_y, x->x_center_x, x->x_center_y);
+ pdp_resample_zoom_tiled_bilin(src_image+uoffset, dst_image+uoffset, w>>1, h>>1, x->x_zoom_x, x->x_zoom_y, x->x_center_x, x->x_center_y);
+
+ return;
+}
+
+static void pdp_zoom_process_grey(t_pdp_zoom *x)
+{
+
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ short int *src_image = (short int *)data0;
+ short int *dst_image = (short int *)data1;
+
+ pdp_resample_zoom_tiled_bilin(src_image, dst_image, w, h, x->x_zoom_x, x->x_zoom_y, x->x_center_x, x->x_center_y);
+
+ return;
+
+}
+
+static void pdp_zoom_sendpacket(t_pdp_zoom *x)
+{
+ /* delete source packet */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = -1;
+
+ /* unregister and propagate if valid dest packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet1);
+}
+
+static void pdp_zoom_process(t_pdp_zoom *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+
+ /* check data packets */
+
+ if ((header0) && (PDP_IMAGE == header0->type)){
+
+
+ /* type hub */
+ switch(header0->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
+ pdp_queue_add(x, pdp_zoom_process_yv12, pdp_zoom_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
+ pdp_queue_add(x, pdp_zoom_process_grey, pdp_zoom_sendpacket, &x->x_queue_id);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont process */
+
+ }
+ }
+
+}
+
+
+
+
+static void pdp_zoom_input_0(t_pdp_zoom *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+ int passes, i;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_ro_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* add the process method and callback to the process queue */
+ pdp_zoom_process(x);
+
+ }
+
+}
+
+
+
+
+static void pdp_zoom_x(t_pdp_zoom *x, t_floatarg f)
+{
+ x->x_zoom_x = f;
+}
+
+static void pdp_zoom_y(t_pdp_zoom *x, t_floatarg f)
+{
+ x->x_zoom_y = f;
+}
+
+static void pdp_zoom(t_pdp_zoom *x, t_floatarg f)
+{
+ pdp_zoom_x(x, f);
+ pdp_zoom_y(x, f);
+}
+
+static void pdp_zoom_center_x(t_pdp_zoom *x, t_floatarg f)
+{
+ x->x_center_x = (f + 0.5f);
+}
+
+static void pdp_zoom_center_y(t_pdp_zoom *x, t_floatarg f)
+{
+ x->x_center_y = (f + 0.5f);
+}
+static void pdp_zoom_center(t_pdp_zoom *x, t_floatarg fx, t_floatarg fy)
+{
+ pdp_zoom_center_x(x, fx);
+ pdp_zoom_center_y(x, fy);
+}
+
+static void pdp_zoom_quality(t_pdp_zoom *x, t_floatarg f)
+{
+ if (f==0) x->x_quality = 0;
+ if (f==1) x->x_quality = 1;
+}
+
+
+t_class *pdp_zoom_class;
+
+
+
+void pdp_zoom_free(t_pdp_zoom *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+}
+
+void *pdp_zoom_new(t_floatarg fw, t_floatarg zoom)
+{
+ t_pdp_zoom *x = (t_pdp_zoom *)pd_new(pdp_zoom_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("zoom"));
+
+
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_queue_id = -1;
+
+ pdp_zoom_quality(x, 1);
+ pdp_zoom_center_x(x, 0);
+ pdp_zoom_center_y(x, 0);
+
+ if (zoom = 0.0f) zoom = 1.0f;
+ pdp_zoom(x, zoom);
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_zoom_setup(void)
+{
+
+
+ pdp_zoom_class = class_new(gensym("pdp_zoom"), (t_newmethod)pdp_zoom_new,
+ (t_method)pdp_zoom_free, sizeof(t_pdp_zoom), 0, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+
+ class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_quality, gensym("quality"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_center_x, gensym("centerx"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_center_y, gensym("centery"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_center, gensym("center"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_x, gensym("zoomx"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_y, gensym("zoomy"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_zoom_class, (t_method)pdp_zoom, gensym("zoom"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif