diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/Makefile | 16 | ||||
-rw-r--r-- | modules/README | 33 | ||||
-rw-r--r-- | modules/pdp_add.c | 205 | ||||
-rw-r--r-- | modules/pdp_affine.c | 223 | ||||
-rw-r--r-- | modules/pdp_bq.c | 698 | ||||
-rw-r--r-- | modules/pdp_chrot.c | 201 | ||||
-rw-r--r-- | modules/pdp_conv.c | 325 | ||||
-rw-r--r-- | modules/pdp_del.c | 196 | ||||
-rw-r--r-- | modules/pdp_gain.c | 227 | ||||
-rw-r--r-- | modules/pdp_gradient.c | 331 | ||||
-rw-r--r-- | modules/pdp_grey.c | 168 | ||||
-rw-r--r-- | modules/pdp_mix.c | 279 | ||||
-rw-r--r-- | modules/pdp_mul.c | 205 | ||||
-rw-r--r-- | modules/pdp_noise.c | 230 | ||||
-rw-r--r-- | modules/pdp_qt.c | 941 | ||||
-rw-r--r-- | modules/pdp_randmix.c | 228 | ||||
-rw-r--r-- | modules/pdp_reg.c | 132 | ||||
-rw-r--r-- | modules/pdp_route.c | 129 | ||||
-rw-r--r-- | modules/pdp_scale.c | 267 | ||||
-rw-r--r-- | modules/pdp_scope.c | 312 | ||||
-rw-r--r-- | modules/pdp_snap.c | 146 | ||||
-rw-r--r-- | modules/pdp_trigger.c | 105 | ||||
-rw-r--r-- | modules/pdp_v4l.c | 734 | ||||
-rw-r--r-- | modules/pdp_xv.c | 534 | ||||
-rw-r--r-- | modules/pdp_zoom.c | 264 |
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 |