diff options
author | N.N. <sevyves@users.sourceforge.net> | 2004-11-14 23:05:44 +0000 |
---|---|---|
committer | N.N. <sevyves@users.sourceforge.net> | 2004-11-14 23:05:44 +0000 |
commit | a9cfc5852d75ca1c62e4c97e3334c99ee2f2f9a8 (patch) | |
tree | 6f6e19f6504a051015b0a18506c52f7197223dd5 | |
parent | bf6d0609625714ed52acf19a007a378645de2faa (diff) |
PiDiP 0.12.17
svn path=/trunk/externals/pidip/; revision=2273
27 files changed, 5741 insertions, 0 deletions
diff --git a/doc/help-pdp_background.pd b/doc/help-pdp_background.pd new file mode 100644 index 0000000..62112cd --- /dev/null +++ b/doc/help-pdp_background.pd @@ -0,0 +1,41 @@ +#N canvas 237 21 712 664 10; +#X obj 212 155 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 173 154 stop; +#X obj 201 189 metro 70; +#X obj 410 486 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 410 538 pdp_control; +#X msg 410 511 thread \$1; +#X floatatom 410 599 5 0 0 0 - - -; +#X obj 410 570 route pdp_drop; +#X obj 247 263 pdp_background; +#X obj 218 304 pdp_convert image/YCrCb/*; +#X msg 143 189 bang; +#X floatatom 273 229 5 0 0 0 - - -; +#X text 280 214 Red; +#X floatatom 321 228 5 0 0 0 - - -; +#X floatatom 373 228 5 0 0 0 - - -; +#X text 321 213 Green; +#X text 375 212 Blue; +#X obj 308 96 pdp_colorgrid pdp_colorgrid1 256 0 256 50 0 50 0 1 1 +10 10 409 121; +#X text 258 392 pdp_background : a simple background generator; +#X text 259 409 written by Yves Degoyon ( ydegoyon@free.fr ); +#X obj 218 339 pdp_xv; +#X connect 0 0 2 0; +#X connect 1 0 2 0; +#X connect 2 0 8 0; +#X connect 3 0 5 0; +#X connect 4 0 7 0; +#X connect 5 0 4 0; +#X connect 7 0 6 0; +#X connect 8 0 9 0; +#X connect 9 0 20 0; +#X connect 10 0 8 0; +#X connect 11 0 8 1; +#X connect 13 0 8 2; +#X connect 14 0 8 3; +#X connect 17 0 11 0; +#X connect 17 1 13 0; +#X connect 17 2 14 0; diff --git a/doc/help-pdp_binary.pd b/doc/help-pdp_binary.pd new file mode 100644 index 0000000..f74c13c --- /dev/null +++ b/doc/help-pdp_binary.pd @@ -0,0 +1,97 @@ +#N canvas 416 0 781 666 10; +#X obj 342 90 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 197 162 loop \$1; +#X obj 198 140 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 +1; +#X msg 444 70 open \$1; +#X obj 443 46 openpanel; +#X obj 428 29 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X floatatom 390 125 5 0 0 0 - - -; +#X msg 299 91 stop; +#X obj 397 94 hsl 300 15 0 1000 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X obj 331 161 metro 70; +#X obj 326 193 pdp_yqt; +#X obj 26 263 pdp_v4l; +#X obj 35 232 metro 70; +#X obj 80 198 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 37 199 stop; +#X msg 122 230 open /dev/video; +#X floatatom 303 338 5 0 0 0 - - -; +#X floatatom 312 359 5 0 0 0 - - -; +#X floatatom 329 380 5 0 0 0 - - -; +#X floatatom 334 402 5 0 0 0 - - -; +#X text 296 631 written by Yves Degoyon ( ydegoyon@free.fr ); +#X floatatom 343 427 5 0 0 0 - - -; +#X text 382 401 X coordinate of cursor ( pick ); +#X text 391 426 Y coordinate of cursor ( pick ); +#X msg 89 341 pick; +#X text 57 323 Pick up the color; +#X floatatom 356 450 5 0 0 0 - - -; +#X obj 594 197 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 594 249 pdp_control; +#X msg 594 222 thread \$1; +#X floatatom 594 310 5 0 0 0 - - -; +#X obj 594 281 route pdp_drop; +#X msg 118 379 setcur \$1 \$2; +#X text 6 378 Set the cursor; +#X floatatom 155 524 5 0 0 0 - - -; +#X floatatom 205 525 5 0 0 0 - - -; +#X floatatom 252 524 5 0 0 0 - - -; +#X text 297 614 pdp_binary : image binarizer; +#X text 122 554 Components of selected color; +#X text 167 542 Y; +#X text 218 542 U; +#X text 262 542 V; +#X text 402 449 Tolerance ( default = 55 ); +#X text 350 337 Y component ( default : 200 ); +#X text 357 358 U component ( default : -1 ); +#X text 374 379 V component ( default : -1 ); +#X obj 110 459 pdp_binary ----; +#X obj 312 264 pdp_glx; +#X obj 311 290 route press drag release; +#X msg 335 234 cursor 1; +#X obj 78 504 pdp_glx; +#X connect 0 0 9 0; +#X connect 1 0 10 0; +#X connect 2 0 1 0; +#X connect 3 0 10 0; +#X connect 4 0 3 0; +#X connect 5 0 4 0; +#X connect 6 0 9 1; +#X connect 7 0 9 0; +#X connect 8 0 6 0; +#X connect 9 0 10 0; +#X connect 10 0 46 0; +#X connect 10 0 47 0; +#X connect 10 0 49 0; +#X connect 11 0 46 0; +#X connect 11 0 47 0; +#X connect 12 0 11 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 11 0; +#X connect 16 0 46 1; +#X connect 17 0 46 2; +#X connect 18 0 46 3; +#X connect 19 0 46 4; +#X connect 21 0 46 5; +#X connect 24 0 46 0; +#X connect 26 0 46 6; +#X connect 27 0 29 0; +#X connect 28 0 31 0; +#X connect 29 0 28 0; +#X connect 31 0 30 0; +#X connect 32 0 24 0; +#X connect 32 0 46 0; +#X connect 46 0 50 0; +#X connect 46 1 34 0; +#X connect 46 2 35 0; +#X connect 46 3 36 0; +#X connect 47 0 48 0; +#X connect 48 0 32 0; +#X connect 49 0 47 0; diff --git a/doc/help-pdp_cropper.pd b/doc/help-pdp_cropper.pd new file mode 100644 index 0000000..7088b9c --- /dev/null +++ b/doc/help-pdp_cropper.pd @@ -0,0 +1,64 @@ +#N canvas 237 21 712 664 10; +#X obj 217 367 pdp_xv; +#X obj 268 64 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 123 136 loop \$1; +#X obj 124 114 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 +1; +#X msg 150 62 open \$1; +#X obj 149 38 openpanel; +#X obj 134 21 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X floatatom 316 99 5 0 0 0 - - -; +#X msg 225 65 stop; +#X obj 257 135 metro 70; +#X obj 252 167 pdp_yqt; +#X obj 369 162 pdp_v4l; +#X obj 378 131 metro 70; +#X obj 423 97 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 380 98 stop; +#X msg 465 129 open /dev/video; +#X obj 414 352 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 414 404 pdp_control; +#X msg 414 377 thread \$1; +#X floatatom 414 465 5 0 0 0 - - -; +#X obj 414 436 route pdp_drop; +#X obj 217 299 pdp_cropper; +#X text 187 505 pdp_cropper : crop a video; +#X text 185 520 ( useful for cut and paste : see the cutandpaste.pd +patch ); +#X text 186 534 written by Yves Degoyon ( ydegoyon@free.fr ); +#X floatatom 378 218 5 0 0 0 - - -; +#X text 387 201 X1; +#X floatatom 423 217 5 0 0 0 - - -; +#X text 432 200 X2; +#X floatatom 337 239 5 0 0 0 - - -; +#X text 315 239 Y1; +#X floatatom 338 259 5 0 0 0 - - -; +#X text 316 259 Y2; +#X connect 1 0 9 0; +#X connect 2 0 10 0; +#X connect 3 0 2 0; +#X connect 4 0 10 0; +#X connect 5 0 4 0; +#X connect 6 0 5 0; +#X connect 7 0 9 1; +#X connect 8 0 9 0; +#X connect 9 0 10 0; +#X connect 10 0 21 0; +#X connect 11 0 21 0; +#X connect 12 0 11 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 11 0; +#X connect 16 0 18 0; +#X connect 17 0 20 0; +#X connect 18 0 17 0; +#X connect 20 0 19 0; +#X connect 21 0 0 0; +#X connect 25 0 21 1; +#X connect 27 0 21 2; +#X connect 29 0 21 3; +#X connect 31 0 21 4; diff --git a/doc/help-pdp_dilate.pd b/doc/help-pdp_dilate.pd new file mode 100644 index 0000000..2f5a0a2 --- /dev/null +++ b/doc/help-pdp_dilate.pd @@ -0,0 +1,91 @@ +#N canvas 381 0 781 666 10; +#X obj 341 20 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 196 92 loop \$1; +#X obj 197 70 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 1 +; +#X msg 453 93 open \$1; +#X obj 452 69 openpanel; +#X obj 437 52 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X floatatom 389 55 5 0 0 0 - - -; +#X msg 298 21 stop; +#X obj 396 24 hsl 300 15 0 1000 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X obj 330 91 metro 70; +#X obj 325 123 pdp_yqt; +#X obj 25 193 pdp_v4l; +#X obj 34 162 metro 70; +#X obj 79 128 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 36 129 stop; +#X msg 121 160 open /dev/video; +#X text 296 540 written by Yves Degoyon ( ydegoyon@free.fr ); +#X msg 31 236 pick; +#X floatatom 248 262 5 0 0 0 - - -; +#X obj 594 197 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 594 249 pdp_control; +#X msg 594 222 thread \$1; +#X floatatom 594 310 5 0 0 0 - - -; +#X obj 594 281 route pdp_drop; +#X msg 72 237 setcur \$1 \$2; +#X floatatom 174 328 5 0 0 0 - - -; +#X floatatom 224 329 5 0 0 0 - - -; +#X floatatom 271 328 5 0 0 0 - - -; +#X text 294 261 Tolerance ( default = 55 ); +#X obj 138 289 pdp_binary ----; +#X obj 41 369 route press drag release; +#X msg 42 311 cursor 1; +#X obj 148 476 pdp_glx; +#X floatatom 250 370 5 0 0 0 - - -; +#X text 296 369 Number of passes ( default = 1 ); +#X obj 41 342 pdp_glx; +#X floatatom 271 396 5 0 0 0 - - -; +#X floatatom 292 420 5 0 0 0 - - -; +#X text 317 395 Kernel width ( default = 3 ); +#X text 338 418 Kernel height ( default = 3 ); +#X obj 149 437 pdp_dilate ----; +#X text 297 523 pdp_dilate : morphology : dilation; +#X obj 54 478 pdp_xor; +#X obj 55 508 pdp_glx; +#X connect 0 0 9 0; +#X connect 1 0 10 0; +#X connect 2 0 1 0; +#X connect 3 0 10 0; +#X connect 4 0 3 0; +#X connect 5 0 4 0; +#X connect 6 0 9 1; +#X connect 7 0 9 0; +#X connect 8 0 6 0; +#X connect 9 0 10 0; +#X connect 10 0 29 0; +#X connect 11 0 29 0; +#X connect 12 0 11 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 11 0; +#X connect 17 0 29 0; +#X connect 18 0 29 6; +#X connect 19 0 21 0; +#X connect 20 0 23 0; +#X connect 21 0 20 0; +#X connect 23 0 22 0; +#X connect 24 0 17 0; +#X connect 24 0 29 0; +#X connect 29 0 35 0; +#X connect 29 0 31 0; +#X connect 29 0 40 0; +#X connect 29 0 42 0; +#X connect 29 1 25 0; +#X connect 29 2 26 0; +#X connect 29 3 27 0; +#X connect 30 0 24 0; +#X connect 31 0 35 0; +#X connect 33 0 40 1; +#X connect 35 0 30 0; +#X connect 36 0 40 2; +#X connect 37 0 40 3; +#X connect 40 0 32 0; +#X connect 40 0 42 1; +#X connect 42 0 43 0; diff --git a/doc/help-pdp_disintegration.pd b/doc/help-pdp_disintegration.pd new file mode 100644 index 0000000..b58d0a2 --- /dev/null +++ b/doc/help-pdp_disintegration.pd @@ -0,0 +1,61 @@ +#N canvas 381 0 781 666 10; +#X obj 341 20 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 196 92 loop \$1; +#X obj 197 70 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 1 +; +#X msg 453 93 open \$1; +#X obj 452 69 openpanel; +#X obj 437 52 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X floatatom 389 55 5 0 0 0 - - -; +#X msg 298 21 stop; +#X obj 396 24 hsl 300 15 0 1000 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X obj 330 91 metro 70; +#X obj 325 123 pdp_yqt; +#X obj 25 193 pdp_v4l; +#X obj 34 162 metro 70; +#X obj 79 128 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 36 129 stop; +#X msg 121 160 open /dev/video; +#X text 296 540 written by Yves Degoyon ( ydegoyon@free.fr ); +#X obj 594 197 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 594 249 pdp_control; +#X msg 594 222 thread \$1; +#X floatatom 594 310 5 0 0 0 - - -; +#X obj 594 281 route pdp_drop; +#X floatatom 239 270 5 0 0 0 - - -; +#X floatatom 287 311 5 0 0 0 - - -; +#X text 297 522 pdp_disintegration : piksels summing-up and averaging +; +#X obj 138 337 pdp_disintegration ----; +#X text 285 267 Number of passes ( default = 3 ); +#X text 333 310 Reduction factor ( default = 5 ); +#X text 281 282 ( disintegration is here ); +#X obj 137 376 pdp_xv; +#X connect 0 0 9 0; +#X connect 1 0 10 0; +#X connect 2 0 1 0; +#X connect 3 0 10 0; +#X connect 4 0 3 0; +#X connect 5 0 4 0; +#X connect 6 0 9 1; +#X connect 7 0 9 0; +#X connect 8 0 6 0; +#X connect 9 0 10 0; +#X connect 10 0 25 0; +#X connect 11 0 25 0; +#X connect 12 0 11 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 11 0; +#X connect 17 0 19 0; +#X connect 18 0 21 0; +#X connect 19 0 18 0; +#X connect 21 0 20 0; +#X connect 22 0 25 1; +#X connect 23 0 25 2; +#X connect 25 0 29 0; diff --git a/doc/help-pdp_distance.pd b/doc/help-pdp_distance.pd new file mode 100644 index 0000000..3451c85 --- /dev/null +++ b/doc/help-pdp_distance.pd @@ -0,0 +1,72 @@ +#N canvas 375 16 781 666 10; +#X obj 341 20 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 196 92 loop \$1; +#X obj 197 70 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 1 +; +#X msg 453 93 open \$1; +#X obj 452 69 openpanel; +#X obj 437 52 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X floatatom 389 55 5 0 0 0 - - -; +#X msg 298 21 stop; +#X obj 396 24 hsl 300 15 0 1000 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X obj 330 91 metro 70; +#X obj 325 123 pdp_yqt; +#X obj 25 193 pdp_v4l; +#X obj 34 162 metro 70; +#X obj 79 128 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 36 129 stop; +#X msg 121 160 open /dev/video; +#X obj 594 197 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 594 249 pdp_control; +#X msg 594 222 thread \$1; +#X floatatom 594 310 5 0 0 0 - - -; +#X obj 594 281 route pdp_drop; +#X text 297 554 http://www.cs.cf.ac.uk/User/Paul.Rosin/resources/sdt/ +; +#X text 296 538 inspired by Paul Rosin; +#X text 297 570 PD-fication by Yves Degoyon ( ydegoyon@free.fr ); +#X text 297 521 pdp_distance : chamfer34 distance transform; +#X obj 108 400 pdp_distance ----; +#X obj 31 328 pdp_glx; +#X floatatom 211 317 5 0 0 0 - - -; +#X text 254 315 Coefficient 1; +#X floatatom 237 337 5 0 0 0 - - -; +#X floatatom 264 359 5 0 0 0 - - -; +#X floatatom 281 382 5 0 0 0 - - -; +#X text 280 335 Coefficient 2; +#X text 307 357 Coefficient 3; +#X text 324 380 Coefficient 4; +#X obj 108 441 pdp_glx; +#X obj 113 289 pdp_grey ----; +#X connect 0 0 9 0; +#X connect 1 0 10 0; +#X connect 2 0 1 0; +#X connect 3 0 10 0; +#X connect 4 0 3 0; +#X connect 5 0 4 0; +#X connect 6 0 9 1; +#X connect 7 0 9 0; +#X connect 8 0 6 0; +#X connect 9 0 10 0; +#X connect 10 0 36 0; +#X connect 11 0 36 0; +#X connect 12 0 11 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 11 0; +#X connect 16 0 18 0; +#X connect 17 0 20 0; +#X connect 18 0 17 0; +#X connect 20 0 19 0; +#X connect 25 0 35 0; +#X connect 27 0 25 1; +#X connect 29 0 25 2; +#X connect 30 0 25 3; +#X connect 31 0 25 4; +#X connect 36 0 25 0; +#X connect 36 0 26 0; diff --git a/doc/help-pdp_erode.pd b/doc/help-pdp_erode.pd new file mode 100644 index 0000000..c2ad22e --- /dev/null +++ b/doc/help-pdp_erode.pd @@ -0,0 +1,91 @@ +#N canvas 381 0 781 666 10; +#X obj 341 20 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 196 92 loop \$1; +#X obj 197 70 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 1 +; +#X msg 453 93 open \$1; +#X obj 452 69 openpanel; +#X obj 437 52 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X floatatom 389 55 5 0 0 0 - - -; +#X msg 298 21 stop; +#X obj 396 24 hsl 300 15 0 1000 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X obj 330 91 metro 70; +#X obj 325 123 pdp_yqt; +#X obj 25 193 pdp_v4l; +#X obj 34 162 metro 70; +#X obj 79 128 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 36 129 stop; +#X msg 121 160 open /dev/video; +#X text 296 540 written by Yves Degoyon ( ydegoyon@free.fr ); +#X msg 31 236 pick; +#X floatatom 248 262 5 0 0 0 - - -; +#X obj 594 197 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 594 249 pdp_control; +#X msg 594 222 thread \$1; +#X floatatom 594 310 5 0 0 0 - - -; +#X obj 594 281 route pdp_drop; +#X msg 72 237 setcur \$1 \$2; +#X floatatom 174 328 5 0 0 0 - - -; +#X floatatom 224 329 5 0 0 0 - - -; +#X floatatom 271 328 5 0 0 0 - - -; +#X text 294 261 Tolerance ( default = 55 ); +#X obj 138 289 pdp_binary ----; +#X obj 41 369 route press drag release; +#X msg 42 311 cursor 1; +#X text 297 523 pdp_erode : morphology : erosion; +#X obj 148 476 pdp_glx; +#X floatatom 250 370 5 0 0 0 - - -; +#X text 296 369 Number of passes ( default = 1 ); +#X obj 41 342 pdp_glx; +#X floatatom 271 396 5 0 0 0 - - -; +#X floatatom 292 420 5 0 0 0 - - -; +#X text 317 395 Kernel width ( default = 3 ); +#X text 338 418 Kernel height ( default = 3 ); +#X obj 148 437 pdp_erode ----; +#X obj 63 477 pdp_xor; +#X obj 64 509 pdp_glx; +#X connect 0 0 9 0; +#X connect 1 0 10 0; +#X connect 2 0 1 0; +#X connect 3 0 10 0; +#X connect 4 0 3 0; +#X connect 5 0 4 0; +#X connect 6 0 9 1; +#X connect 7 0 9 0; +#X connect 8 0 6 0; +#X connect 9 0 10 0; +#X connect 10 0 29 0; +#X connect 11 0 29 0; +#X connect 12 0 11 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 11 0; +#X connect 17 0 29 0; +#X connect 18 0 29 6; +#X connect 19 0 21 0; +#X connect 20 0 23 0; +#X connect 21 0 20 0; +#X connect 23 0 22 0; +#X connect 24 0 17 0; +#X connect 24 0 29 0; +#X connect 29 0 36 0; +#X connect 29 0 31 0; +#X connect 29 0 41 0; +#X connect 29 0 42 0; +#X connect 29 1 25 0; +#X connect 29 2 26 0; +#X connect 29 3 27 0; +#X connect 30 0 24 0; +#X connect 31 0 36 0; +#X connect 34 0 41 1; +#X connect 36 0 30 0; +#X connect 37 0 41 2; +#X connect 38 0 41 3; +#X connect 41 0 33 0; +#X connect 41 0 42 1; +#X connect 42 0 43 0; diff --git a/doc/help-pdp_hitandmiss.pd b/doc/help-pdp_hitandmiss.pd new file mode 100644 index 0000000..5b54cce --- /dev/null +++ b/doc/help-pdp_hitandmiss.pd @@ -0,0 +1,97 @@ +#N canvas 381 0 781 666 10; +#X obj 341 20 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 196 92 loop \$1; +#X obj 197 70 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 1 +; +#X msg 453 93 open \$1; +#X obj 452 69 openpanel; +#X obj 437 52 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X floatatom 389 55 5 0 0 0 - - -; +#X msg 298 21 stop; +#X obj 396 24 hsl 300 15 0 1000 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X obj 330 91 metro 70; +#X obj 325 123 pdp_yqt; +#X obj 25 193 pdp_v4l; +#X obj 34 162 metro 70; +#X obj 79 128 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 36 129 stop; +#X msg 121 160 open /dev/video; +#X text 306 611 written by Yves Degoyon ( ydegoyon@free.fr ); +#X msg 31 236 pick; +#X floatatom 248 262 5 0 0 0 - - -; +#X obj 594 197 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 594 249 pdp_control; +#X msg 594 222 thread \$1; +#X floatatom 594 310 5 0 0 0 - - -; +#X obj 594 281 route pdp_drop; +#X msg 72 237 setcur \$1 \$2; +#X floatatom 174 328 5 0 0 0 - - -; +#X floatatom 224 329 5 0 0 0 - - -; +#X floatatom 271 328 5 0 0 0 - - -; +#X text 294 261 Tolerance ( default = 55 ); +#X obj 138 289 pdp_binary ----; +#X obj 41 369 route press drag release; +#X msg 42 311 cursor 1; +#X floatatom 250 370 5 0 0 0 - - -; +#X text 296 369 Number of passes ( default = 1 ); +#X floatatom 271 396 5 0 0 0 - - -; +#X floatatom 292 420 5 0 0 0 - - -; +#X text 317 395 Kernel width ( default = 3 ); +#X text 338 418 Kernel height ( default = 3 ); +#X obj 143 501 pdp_hitandmiss ----; +#X text 307 594 pdp_hitandmiss : morphology : hit and miss; +#X msg 307 456 kernel 1 1 1 1 1 1 1 1 1; +#X text 515 454 Change the kernel; +#X text 514 468 ( this one is equivalent to erosion ); +#X text 515 485 The default one is :; +#X text 570 501 -1 1 -1; +#X text 578 516 0 1 1; +#X text 578 529 0 0 -1; +#X text 517 547 ( -1 here means unused ); +#X obj 41 342 pdp_glx; +#X msg 308 484 kernel -1 1 -1 0 1 1 0 0 -1; +#X obj 143 540 pdp_glx; +#X connect 0 0 9 0; +#X connect 1 0 10 0; +#X connect 2 0 1 0; +#X connect 3 0 10 0; +#X connect 4 0 3 0; +#X connect 5 0 4 0; +#X connect 6 0 9 1; +#X connect 7 0 9 0; +#X connect 8 0 6 0; +#X connect 9 0 10 0; +#X connect 10 0 29 0; +#X connect 11 0 29 0; +#X connect 12 0 11 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 11 0; +#X connect 17 0 29 0; +#X connect 18 0 29 6; +#X connect 19 0 21 0; +#X connect 20 0 23 0; +#X connect 21 0 20 0; +#X connect 23 0 22 0; +#X connect 24 0 17 0; +#X connect 24 0 29 0; +#X connect 29 0 31 0; +#X connect 29 0 38 0; +#X connect 29 0 48 0; +#X connect 29 1 25 0; +#X connect 29 2 26 0; +#X connect 29 3 27 0; +#X connect 30 0 24 0; +#X connect 31 0 48 0; +#X connect 32 0 38 1; +#X connect 34 0 38 2; +#X connect 35 0 38 3; +#X connect 38 0 50 0; +#X connect 40 0 38 0; +#X connect 48 0 30 0; +#X connect 49 0 38 0; diff --git a/doc/help-pdp_theorin~.pd b/doc/help-pdp_theorin~.pd new file mode 100644 index 0000000..19d133a --- /dev/null +++ b/doc/help-pdp_theorin~.pd @@ -0,0 +1,14 @@ +#N canvas 259 178 509 391 10; +#X obj 156 158 dac~; +#X text 51 309 written by Yves Degoyon (ydegoyon@free.fr); +#X text 236 112 <-- everything is in this box; +#X text 265 127 where the block size is redefined; +#X text 265 141 this is necessary for an; +#X text 266 154 ( acceptable? ) audio decoding; +#X obj 395 221 loadbang; +#X msg 395 251 \; pd dsp 1; +#X text 51 295 pdp_theorin~ : theora threaded file reader; +#X obj 128 113 rs_pdp_theorin~; +#X connect 6 0 7 0; +#X connect 9 0 0 0; +#X connect 9 1 0 1; diff --git a/doc/help-pdp_theorout~.pd b/doc/help-pdp_theorout~.pd new file mode 100644 index 0000000..0fe1b31 --- /dev/null +++ b/doc/help-pdp_theorout~.pd @@ -0,0 +1,118 @@ +#N canvas 5 16 986 661 10; +#X obj 255 34 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 117 65 loop \$1; +#X obj 117 40 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 1 +; +#X msg 278 48 open \$1; +#X obj 278 24 openpanel; +#X obj 278 3 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X floatatom 293 75 5 0 0 0 - - -; +#X msg 212 35 stop; +#X obj 215 91 metro 70; +#X obj 18 191 pdp_v4l; +#X obj 27 160 metro 70; +#X obj 72 126 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 29 127 stop; +#X msg 92 161 open /dev/video; +#X text 112 622 written by Yves Degoyon ( ydegoyon@free.fr ); +#X msg 383 294 stop; +#X msg 382 268 start; +#X text 424 269 Start recording; +#X floatatom 159 534 5 0 0 0 - - -; +#X obj 213 124 pdp_yqt; +#X text 424 296 Stop recording; +#X obj 832 499 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 832 551 pdp_control; +#X msg 832 524 thread \$1; +#X floatatom 832 612 5 0 0 0 - - -; +#X obj 832 583 route pdp_drop; +#X obj 119 300 adc~; +#X text 326 197 <---- audio connections; +#X text 383 224 ==== ACTIONS ========; +#X text 384 327 ==== VIDEOS SETTINGS ========; +#X text 383 403 ==== AUDIO SETTINGS ========; +#X obj 142 200 pdp_xv; +#X obj 36 255 pdp_affine; +#X floatatom 68 229 5 0 0 0 - - -; +#X obj 36 287 pdp_xv; +#X text 113 605 pdp_theorout~ : records a/v theora encoded file; +#X msg 382 242 open /tmp/output.ogg; +#X text 534 244 Open a theora/vorbis file before any operations; +#X obj 308 124 pdp_theorin~; +#X obj 378 32 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 378 82 open \$1; +#X obj 378 54 openpanel; +#X obj 357 167 dac~; +#X text 612 296 Warning : change audio and video settings; +#X msg 386 347 videoquality \$1; +#X msg 387 375 videobitrate \$1; +#X text 560 377 Video bitrate ( kbps ) : [45 \, 2000]; +#X text 558 350 Video quality : [0 \, 63] \, default 16; +#X text 727 392 default 96; +#X msg 385 424 audioquality \$1; +#X msg 386 452 audiobitrate \$1; +#X text 729 468 default 32; +#X text 563 453 Audio bitrate ( kbps ) : [8 \, 2000]; +#X text 562 426 Audio quality : [-0.1 \, 1.0] \, default 0.5; +#X floatatom 504 349 5 0 0 0 - - -; +#X floatatom 505 376 5 0 0 0 - - -; +#X floatatom 506 424 5 0 0 0 - - -; +#X floatatom 506 453 5 0 0 0 - - -; +#X text 682 310 before starting the recording; +#X text 682 324 ( or restart it ); +#X obj 159 504 pdp_theorout~; +#X connect 0 0 8 0; +#X connect 1 0 19 0; +#X connect 2 0 1 0; +#X connect 3 0 19 0; +#X connect 4 0 3 0; +#X connect 5 0 4 0; +#X connect 6 0 8 1; +#X connect 7 0 8 0; +#X connect 8 0 19 0; +#X connect 9 0 32 0; +#X connect 10 0 9 0; +#X connect 11 0 10 0; +#X connect 12 0 10 0; +#X connect 13 0 9 0; +#X connect 15 0 60 0; +#X connect 16 0 60 0; +#X connect 19 0 31 0; +#X connect 19 0 60 0; +#X connect 19 4 42 0; +#X connect 19 4 60 0; +#X connect 19 5 42 1; +#X connect 19 5 60 1; +#X connect 21 0 23 0; +#X connect 22 0 25 0; +#X connect 23 0 22 0; +#X connect 25 0 24 0; +#X connect 26 0 60 0; +#X connect 26 1 60 1; +#X connect 32 0 34 0; +#X connect 32 0 60 0; +#X connect 33 0 32 1; +#X connect 36 0 60 0; +#X connect 38 0 31 0; +#X connect 38 0 60 0; +#X connect 38 1 42 0; +#X connect 38 1 60 0; +#X connect 38 2 42 1; +#X connect 38 2 60 1; +#X connect 39 0 41 0; +#X connect 40 0 38 0; +#X connect 41 0 40 0; +#X connect 44 0 60 0; +#X connect 45 0 60 0; +#X connect 49 0 60 0; +#X connect 50 0 60 0; +#X connect 54 0 44 0; +#X connect 55 0 45 0; +#X connect 56 0 49 0; +#X connect 57 0 50 0; +#X connect 60 0 18 0; diff --git a/doc/rs_pdp_theorin~.pd b/doc/rs_pdp_theorin~.pd new file mode 100644 index 0000000..cc1a74b --- /dev/null +++ b/doc/rs_pdp_theorin~.pd @@ -0,0 +1,115 @@ +#N canvas 127 47 872 636 10; +#X text 452 600 written by Yves Degoyon (ydegoyon@free.fr); +#X floatatom 240 549 5 0 0 0 - - -; +#X text 289 550 Number of video frames decoded; +#X msg 250 409 priority \$1; +#X floatatom 339 410 5 0 0 0 - - -; +#X text 385 433 ( optional \, if you know what you're doing ); +#X obj 134 543 outlet~; +#X text 390 405 Set the priority of decoding thread; +#X obj 247 143 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 250 379 audio \$1; +#X obj 319 381 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X obj 322 350 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X msg 248 350 thread \$1; +#X obj 378 350 loadbang; +#X msg 343 350 1; +#X text 446 350 Activate threading ( default : on ); +#X floatatom 256 526 5 0 0 0 - - -; +#X floatatom 280 506 5 0 0 0 - - -; +#X obj 339 257 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X obj 395 255 loadbang; +#X msg 360 255 1; +#X msg 248 256 autoplay \$1; +#X text 463 255 Activate auto play mode ( default : on ); +#X msg 248 287 bang; +#X msg 388 289 bang; +#X floatatom 429 290 5 0 0 0 - - -; +#X text 481 288 In manual mode \, read next frame ( autoplay = off +); +#X obj 324 289 metro 70; +#X msg 249 318 loop \$1; +#X obj 311 319 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X obj 367 317 loadbang; +#X msg 332 317 1; +#X text 435 317 Activate loop mode for files ( default : on ); +#X msg 285 288 stop; +#X obj 111 430 pdp_theorin~; +#X msg 248 222 close; +#X text 326 224 Close the current file; +#X text 325 164 Open a theora video file; +#X msg 247 193 open \$1; +#X text 303 528 File framerate; +#X text 327 507 End of file reached; +#X text 452 586 pdp_theorin~ : threaded theora file reader; +#X text 11 163 Seek file ( in kilobytes ); +#X obj 72 543 outlet~; +#X text 387 418 ([0 \, 20 ] default : 1 ); +#X obj 247 165 openpanel; +#X text 444 380 Activate decoding of audio ( default : on ); +#X obj 377 380 loadbang; +#X msg 342 380 1; +#X obj 67 60 block~ 512; +#X text 12 179 warning : there's a big delay; +#X text 11 192 and risks of desynchronisation; +#X text 25 220 seekable for now ); +#X text 11 207 ( sorry \, theora is not really; +#X floatatom 309 455 5 0 0 0 - - -; +#X text 354 455 File size ( in kbs ); +#X obj 39 496 pdp_xv; +#X obj 78 259 vsl 15 128 0 2083 0 0 empty filesize empty 0 -8 0 8 -262144 +-1 -1 0 1; +#X msg 310 473 \; filesize range 0 \$1; +#X floatatom 59 411 5 0 0 0 - - -; +#X obj 691 39 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 691 91 pdp_control; +#X msg 691 64 thread \$1; +#X floatatom 691 152 5 0 0 0 - - -; +#X obj 691 123 route pdp_drop; +#X connect 3 0 34 0; +#X connect 4 0 3 0; +#X connect 8 0 45 0; +#X connect 9 0 34 0; +#X connect 10 0 9 0; +#X connect 11 0 12 0; +#X connect 12 0 34 0; +#X connect 13 0 14 0; +#X connect 14 0 11 0; +#X connect 18 0 21 0; +#X connect 19 0 20 0; +#X connect 20 0 18 0; +#X connect 21 0 34 0; +#X connect 23 0 34 0; +#X connect 24 0 27 0; +#X connect 25 0 27 1; +#X connect 27 0 34 0; +#X connect 28 0 34 0; +#X connect 29 0 28 0; +#X connect 30 0 31 0; +#X connect 31 0 29 0; +#X connect 33 0 27 0; +#X connect 34 0 56 0; +#X connect 34 1 43 0; +#X connect 34 2 6 0; +#X connect 34 3 1 0; +#X connect 34 4 16 0; +#X connect 34 5 17 0; +#X connect 34 6 54 0; +#X connect 35 0 34 0; +#X connect 38 0 34 0; +#X connect 45 0 38 0; +#X connect 47 0 48 0; +#X connect 48 0 10 0; +#X connect 54 0 58 0; +#X connect 57 0 34 1; +#X connect 57 0 59 0; +#X connect 60 0 62 0; +#X connect 61 0 64 0; +#X connect 62 0 61 0; +#X connect 64 0 63 0; diff --git a/modules/pdp_background.c b/modules/pdp_background.c new file mode 100644 index 0000000..130253d --- /dev/null +++ b/modules/pdp_background.c @@ -0,0 +1,188 @@ +/* + * PiDiP module. + * Copyright (c) by Yves Degoyon (ydegoyon@free.fr) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + + +#include "pdp.h" +#include "yuv.h" +#include "time.h" +#include "sys/time.h" + +#define DEFAULT_RED_VALUE 255 +#define DEFAULT_GREEN_VALUE 255 +#define DEFAULT_BLUE_VALUE 255 +#define DEFAULT_WIDTH 320 +#define DEFAULT_HEIGHT 240 + +typedef struct pdp_background_struct +{ + t_object x_obj; + + t_outlet *x_outlet0; + + t_int x_packet0; + + t_int x_colorR; + t_int x_colorG; + t_int x_colorB; + t_int x_colorY; + t_int x_colorU; + t_int x_colorV; + + t_int x_width; + t_int x_height; + +} t_pdp_background; + +static void pdp_background_bang(t_pdp_background *x) +{ + + t_pdp *header; + unsigned char *data; + unsigned char *pY, *pU, *pV; + t_int px, py; + + x->x_packet0 = pdp_packet_new_bitmap_yv12( x->x_width, x->x_height ); + + data = (char *)pdp_packet_data(x->x_packet0); + pY = data; + pV = data+(x->x_width*x->x_height); + pU = data+(x->x_width*x->x_height)+((x->x_width*x->x_height)>>2); + + memset( pY, (unsigned char)x->x_colorY, x->x_width*x->x_height ); + memset( pV, (unsigned char)x->x_colorV, (x->x_width*x->x_height>>2) ); + memset( pU, (unsigned char)x->x_colorU, (x->x_width*x->x_height>>2) ); + + pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet0); + +} + +static void pdp_background_dim(t_pdp_background *x, t_floatarg fwidth, t_floatarg fheight) +{ + if ( ( (t_int)fwidth>0 ) && ( (t_int) fheight>0 ) ) + { + if ( ((t_int)fwidth)%8 == 0 ) + { + x->x_width = (t_int)fwidth; + } + else + { + x->x_width = (t_int)fwidth + (8-((t_int)fwidth)%8); // align on 8 + } + if ( ((t_int)fheight)%8 == 0 ) + { + x->x_height = (t_int)fheight; + } + else + { + x->x_height = (t_int)fheight + (8-((t_int)fheight)%8); // align on 8 + } + } +} + +static void pdp_background_red(t_pdp_background *x, t_floatarg fred) +{ + if ( ( (t_int)fred>=0 ) && ( (t_int) fred <= 255 ) ) + { + x->x_colorR = (t_int) fred; + x->x_colorY = yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ); + x->x_colorU = yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ); + x->x_colorV = yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ); + } +} + +static void pdp_background_green(t_pdp_background *x, t_floatarg fgreen) +{ + if ( ( (t_int)fgreen>=0 ) && ( (t_int) fgreen <= 255 ) ) + { + x->x_colorG = (t_int) fgreen; + x->x_colorY = yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ); + x->x_colorU = yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ); + x->x_colorV = yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ); + } +} + +static void pdp_background_blue(t_pdp_background *x, t_floatarg fblue) +{ + if ( ( (t_int)fblue>=0 ) && ( (t_int) fblue <= 255 ) ) + { + x->x_colorB = (t_int) fblue; + x->x_colorY = yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ); + x->x_colorU = yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ); + x->x_colorV = yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ); + } +} + +static void pdp_background_free(t_pdp_background *x) +{ + // nothing to do +} + +t_class *pdp_background_class; + +void *pdp_background_new(void) +{ + t_pdp_background *x = (t_pdp_background *)pd_new(pdp_background_class); + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("red")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("green")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("blue")); + + x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + + x->x_colorR = DEFAULT_RED_VALUE; + x->x_colorG = DEFAULT_GREEN_VALUE; + x->x_colorB = DEFAULT_BLUE_VALUE; + + x->x_colorY = yuv_RGBtoY( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ); + x->x_colorU = yuv_RGBtoU( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ); + x->x_colorV = yuv_RGBtoV( (x->x_colorR << 16) + (x->x_colorG << 8) + x->x_colorB ); + + x->x_width = DEFAULT_WIDTH; + x->x_height = DEFAULT_HEIGHT; + + x->x_packet0 = -1; + + return (void *)x; +} + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_background_setup(void) +{ + pdp_background_class = class_new(gensym("pdp_background"), (t_newmethod)pdp_background_new, + (t_method)pdp_background_free, sizeof(t_pdp_background), 0, A_NULL); + + class_addmethod(pdp_background_class, (t_method)pdp_background_bang, gensym("bang"), A_NULL); + class_addmethod(pdp_background_class, (t_method)pdp_background_red, gensym("red"), A_FLOAT, A_NULL); + class_addmethod(pdp_background_class, (t_method)pdp_background_green, gensym("green"), A_FLOAT, A_NULL); + class_addmethod(pdp_background_class, (t_method)pdp_background_blue, gensym("blue"), A_FLOAT, A_NULL); + class_addmethod(pdp_background_class, (t_method)pdp_background_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL); + class_sethelpsymbol( pdp_background_class, gensym("pdp_background.pd") ); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/pdp_binary.c b/modules/pdp_binary.c new file mode 100644 index 0000000..5ce943c --- /dev/null +++ b/modules/pdp_binary.c @@ -0,0 +1,364 @@ +/* + * PiDiP module + * Copyright (c) by Yves Degoyon ( ydegoyon@free.fr ) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* This object is an image binarizer, based on some (y,u,v) setting + */ + +#include "pdp.h" +#include "yuv.h" +#include <math.h> +#include <stdio.h> + +static char *pdp_binary_version = "pdp_binary: a image binarizer version 0.1 written by Yves Degoyon (ydegoyon@free.fr)"; + +typedef struct pdp_binary_struct +{ + t_object x_obj; + + t_int x_packet0; + t_int x_packet1; + t_int x_queue_id; + t_int x_dropped; + + t_int x_vwidth; + t_int x_vheight; + t_int x_vsize; + t_int x_colorY; // YUV components of binary mask + t_int x_colorU; + t_int x_colorV; + t_int x_cursX; // X position of the cursor + t_int x_cursY; // Y position of the cursor + t_int x_tolerance; // tolerance + short int *x_frame; // keep a copy of current frame for picking color + + t_outlet *x_pdp_output; // output packets + t_outlet *x_Y; // output Y component of selected color + t_outlet *x_U; // output U component of selected color + t_outlet *x_V; // output V component of selected color + +} t_pdp_binary; + +static void pdp_binary_setcur(t_pdp_binary *x, t_floatarg fpx, t_floatarg fpy ) +{ + if ( (fpx>=0.0) && (fpx<=1.0) && (fpy>=0.0) && (fpy<=1.0) ) + { + x->x_cursX = fpx*(t_float)x->x_vwidth; + x->x_cursY = fpy*(t_float)x->x_vheight; + } +} + +static void pdp_binary_y(t_pdp_binary *x, t_floatarg fy ) +{ + if ( fy <= 255. ) + { + x->x_colorY = (t_int)fy; + outlet_float( x->x_Y, x->x_colorY ); + } +} + +static void pdp_binary_u(t_pdp_binary *x, t_floatarg fu ) +{ + if ( fu <= 255. ) + { + x->x_colorU = (t_int)fu; + outlet_float( x->x_U, x->x_colorU ); + } +} + +static void pdp_binary_v(t_pdp_binary *x, t_floatarg fv ) +{ + if ( fv < 255 ) + { + x->x_colorV = (t_int)fv; + outlet_float( x->x_V, x->x_colorV ); + } +} + +static void pdp_binary_cursx(t_pdp_binary *x, t_floatarg fx ) +{ + if ( ( fx >= 0 ) && ( fx < x->x_vwidth) ) + { + x->x_cursX = (int)fx; + } +} + +static void pdp_binary_cursy(t_pdp_binary *x, t_floatarg fy ) +{ + if ( ( fy >= 0 ) && ( fy < x->x_vheight) ) + { + x->x_cursY = (int)fy; + } +} + +static void pdp_binary_tolerance(t_pdp_binary *x, t_floatarg ftolerance ) +{ + if ( ftolerance >= 0 ) + { + x->x_tolerance = (int)ftolerance; + } +} + +static void pdp_binary_pick(t_pdp_binary *x) +{ + if ( x->x_frame && ( x->x_cursX > 0 ) && ( x->x_cursX < x->x_vwidth ) + && ( x->x_cursY > 0 ) && ( x->x_cursY < x->x_vheight ) ) + { + // post( "pdp_binary : picking up color : x=%d y=%d", x->x_cursX, x->x_cursY ); + x->x_colorY = x->x_frame[ x->x_cursY*x->x_vwidth+x->x_cursX ]; + x->x_colorV = x->x_frame[ x->x_vsize + (x->x_cursY>>1)*(x->x_vwidth>>1)+(x->x_cursX>>1) ]; + x->x_colorU = x->x_frame[ x->x_vsize + (x->x_vsize>>2) + (x->x_cursY>>1)*(x->x_vwidth>>1)+(x->x_cursX>>1) ]; + x->x_colorY = (x->x_colorY)>>7; + x->x_colorV = (x->x_colorV>>8)+128; + x->x_colorU = (x->x_colorU>>8)+128; + outlet_float( x->x_Y, x->x_colorY ); + outlet_float( x->x_V, x->x_colorV ); + outlet_float( x->x_U, x->x_colorU ); + } +} + +static void pdp_binary_allocate(t_pdp_binary *x) +{ + x->x_frame = (short int *) getbytes ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 ); + + if ( !x->x_frame ) + { + post( "pdp_binary : severe error : cannot allocate buffer !!! "); + return; + } +} + +static void pdp_binary_free_ressources(t_pdp_binary *x) +{ + if ( x->x_frame ) freebytes ( x->x_frame, ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 ); +} + +static void pdp_binary_process_yv12(t_pdp_binary *x) +{ + t_pdp *header = pdp_packet_header(x->x_packet0); + short int *data = (short int *)pdp_packet_data(x->x_packet0); + t_pdp *newheader = pdp_packet_header(x->x_packet1); + short int *newdata = (short int *)pdp_packet_data(x->x_packet1); + t_int i; + t_int px=0, py=0; + t_int y=0, u=0, v=0; + short int *pfY, *pfU, *pfV; + t_int diff; + + /* allocate all ressources */ + if ( ( (int)header->info.image.width != x->x_vwidth ) || + ( (int)header->info.image.height != x->x_vheight ) ) + { + pdp_binary_free_ressources( x ); + x->x_vwidth = header->info.image.width; + x->x_vheight = header->info.image.height; + x->x_vsize = x->x_vwidth*x->x_vheight; + pdp_binary_allocate( x ); + post( "pdp_binary : reallocated buffers" ); + } + + memcpy(x->x_frame, data, (x->x_vsize + (x->x_vsize>>1))<<1 ); + + // post( "pdp_binary : newheader:%x", newheader ); + + newheader->info.image.encoding = header->info.image.encoding; + newheader->info.image.width = x->x_vwidth; + newheader->info.image.height = x->x_vheight; + + // binarize + pfY = data; + pfV = data+x->x_vsize; + pfU = data+x->x_vsize+(x->x_vsize>>2); + for ( py=0; py<x->x_vheight; py++ ) + { + for ( px=0; px<x->x_vwidth; px++ ) + { + y = (*pfY)>>7; + v = ((*pfV)>>8)+128; + u = ((*pfU)>>8)+128; + + // post( "pdp_binary : y=%d, u=%d, v=%d", y, u, v ); + + diff = 0; + if ( x->x_colorY >= 0 ) + { + diff += abs(y-x->x_colorY ); + } + if ( x->x_colorV >= 0 ) + { + diff += abs(v-x->x_colorV ); + } + if ( x->x_colorU >=0 ) + { + diff += abs(u-x->x_colorU ); + } + + if ( diff <= x->x_tolerance ) + { + *(newdata+(py*x->x_vwidth+px)) = 0xff<<7; + } + else + { + *(newdata+(py*x->x_vwidth+px)) = 0; + } + + pfY++; + if ( (px%2==0) && (py%2==0) ) + { + pfU++;pfV++; + } + } + } + + memset( newdata+x->x_vsize, 0x0, (x->x_vsize>>1)<<1 ); + + return; +} + +static void pdp_binary_sendpacket(t_pdp_binary *x) +{ + /* release the packet */ + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = -1; + + /* unregister and propagate if valid dest packet */ + pdp_packet_pass_if_valid(x->x_pdp_output, &x->x_packet1); +} + +static void pdp_binary_process(t_pdp_binary *x) +{ + int encoding; + t_pdp *header = 0; + + /* check if image data packets are compatible */ + if ( (header = pdp_packet_header(x->x_packet0)) + && (PDP_IMAGE == header->type)){ + + /* pdp_binary_process inputs and write into active inlet */ + switch(pdp_packet_header(x->x_packet0)->info.image.encoding) + { + + case PDP_IMAGE_YV12: + x->x_packet1 = pdp_packet_clone_rw(x->x_packet0); + pdp_queue_add(x, pdp_binary_process_yv12, pdp_binary_sendpacket, &x->x_queue_id); + break; + + case PDP_IMAGE_GREY: + // should write something to handle these one day + // but i don't use this mode + break; + + default: + /* don't know the type, so dont pdp_binary_process */ + break; + + } + } + +} + +static void pdp_binary_input_0(t_pdp_binary *x, t_symbol *s, t_floatarg f) +{ + /* if this is a register_ro message or register_rw message, register with packet factory */ + + if (s== gensym("register_rw")) + { + x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("image/YCrCb/*") ); + } + + if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)) + { + pdp_binary_process(x); + } +} + +static void pdp_binary_free(t_pdp_binary *x) +{ + int i; + + pdp_packet_mark_unused(x->x_packet0); + pdp_binary_free_ressources( x ); +} + +t_class *pdp_binary_class; + +void *pdp_binary_new(void) +{ + int i; + + t_pdp_binary *x = (t_pdp_binary *)pd_new(pdp_binary_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("Y")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("U")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("V")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("cursx")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("cursy")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("tolerance")); + + x->x_pdp_output = outlet_new(&x->x_obj, &s_anything); + x->x_Y = outlet_new(&x->x_obj, &s_float); + x->x_U = outlet_new(&x->x_obj, &s_float); + x->x_V = outlet_new(&x->x_obj, &s_float); + + x->x_colorY = 200; + x->x_colorU = -1; + x->x_colorV = -1; + + x->x_packet0 = -1; + x->x_packet1 = -1; + + x->x_cursX = -1; + x->x_cursY = -1; + x->x_tolerance = 55; + + x->x_vwidth = -1; + x->x_vheight = -1; + x->x_vsize = -1; + x->x_frame = NULL; + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_binary_setup(void) +{ + // post( pdp_binary_version ); + pdp_binary_class = class_new(gensym("pdp_binary"), (t_newmethod)pdp_binary_new, + (t_method)pdp_binary_free, sizeof(t_pdp_binary), 0, A_NULL); + + class_addmethod(pdp_binary_class, (t_method)pdp_binary_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_binary_class, (t_method)pdp_binary_y, gensym("Y"), A_FLOAT, A_NULL); + class_addmethod(pdp_binary_class, (t_method)pdp_binary_u, gensym("U"), A_FLOAT, A_NULL); + class_addmethod(pdp_binary_class, (t_method)pdp_binary_v, gensym("V"), A_FLOAT, A_NULL); + class_addmethod(pdp_binary_class, (t_method)pdp_binary_cursx, gensym("cursx"), A_FLOAT, A_NULL); + class_addmethod(pdp_binary_class, (t_method)pdp_binary_cursy, gensym("cursy"), A_FLOAT, A_NULL); + class_addmethod(pdp_binary_class, (t_method)pdp_binary_pick, gensym("pick"), A_NULL); + class_addmethod(pdp_binary_class, (t_method)pdp_binary_tolerance, gensym("tolerance"), A_FLOAT, A_NULL); + class_addmethod(pdp_binary_class, (t_method)pdp_binary_setcur, gensym("setcur"), A_DEFFLOAT, A_DEFFLOAT, A_NULL); + class_sethelpsymbol( pdp_binary_class, gensym("pdp_binary.pd") ); +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/pdp_cropper.c b/modules/pdp_cropper.c new file mode 100644 index 0000000..f1c3004 --- /dev/null +++ b/modules/pdp_cropper.c @@ -0,0 +1,291 @@ +/* + * PiDiP module. + * Copyright (c) by Yves Degoyon (ydegoyon@free.fr) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* This object is a video cropper + * Written by Yves Degoyon + */ + + + +#include "pdp.h" +#include <math.h> + +static char *pdp_cropper_version = "pdp_cropper: a video cropper, version 0.1, written by Yves Degoyon (ydegoyon@free.fr)"; + +typedef struct pdp_cropper_struct +{ + t_object x_obj; + t_float x_f; + + t_outlet *x_outlet0; + t_int x_packet0; + t_int x_packet1; + t_int x_dropped; + t_int x_queue_id; + + t_int x_vwidth; + t_int x_vheight; + t_int x_vsize; + t_int x_csizex; + t_int x_csizey; + t_int x_csizev; + unsigned int x_encoding; + + int x_cropx1; + int x_cropx2; + int x_cropy1; + int x_cropy2; + +} t_pdp_cropper; + +static void pdp_cropper_cropx1(t_pdp_cropper *x, t_floatarg fcropx1 ) +{ + if ( ( fcropx1>=0 ) && ( fcropx1<x->x_vwidth ) ) + { + x->x_cropx1 = (t_int)fcropx1; + } +} + +static void pdp_cropper_cropx2(t_pdp_cropper *x, t_floatarg fcropx2 ) +{ + if ( ( fcropx2>=0 ) && ( fcropx2<x->x_vwidth ) ) + { + x->x_cropx2 = (t_int)fcropx2; + } +} + +static void pdp_cropper_cropy1(t_pdp_cropper *x, t_floatarg fcropy1 ) +{ + if ( ( fcropy1>=0 ) && ( fcropy1<x->x_vheight ) ) + { + x->x_cropy1 = (t_int)fcropy1; + } +} + +static void pdp_cropper_cropy2(t_pdp_cropper *x, t_floatarg fcropy2 ) +{ + if ( ( fcropy2>=0 ) && ( fcropy2<x->x_vheight ) ) + { + x->x_cropy2 = (t_int)fcropy2; + } +} + +static void pdp_cropper_process_yv12(t_pdp_cropper *x) +{ + t_pdp *header = pdp_packet_header(x->x_packet0); + short int *data = (short int *)pdp_packet_data(x->x_packet0); + t_pdp *newheader = NULL; + short int *newdata = NULL; + int i; + + int px, py; + short int *pY, *pU, *pV; + short int *pnY, *pnU, *pnV; + int minx, maxx; + int miny, maxy; + + /* allocate all ressources */ + if ( ( (t_int)header->info.image.width != x->x_vwidth ) || + ( (t_int)header->info.image.height != x->x_vheight ) ) + { + x->x_vwidth = header->info.image.width; + x->x_vheight = header->info.image.height; + x->x_vsize = x->x_vwidth*x->x_vheight; + if ( ( x->x_cropx1 <0 ) || ( x->x_cropx1 >= x->x_vwidth ) ) x->x_cropx1 = 0; + if ( ( x->x_cropx2 <0 ) || ( x->x_cropx2 >= x->x_vwidth ) ) x->x_cropx2 = x->x_vwidth-1; + if ( ( x->x_cropy1 <0 ) || ( x->x_cropy1 >= x->x_vheight ) ) x->x_cropy1 = 0; + if ( ( x->x_cropy2 <0 ) || ( x->x_cropy2 >= x->x_vheight ) ) x->x_cropy2 = x->x_vheight-1; + } + + x->x_csizex = abs ( x->x_cropx2 - x->x_cropx1 ); + if ( x->x_csizex%8 != 0 ) x->x_csizex = x->x_csizex + (8-(x->x_csizex%8)); // align on 8 + x->x_csizey = abs ( x->x_cropy2 - x->x_cropy1 ); + if ( x->x_csizey%8 != 0 ) x->x_csizey = x->x_csizey + (8-(x->x_csizey%8)); // align on 8 + if ( x->x_csizex == 0 ) x->x_csizex = 8; + if ( x->x_csizey == 0 ) x->x_csizey = 8; + // post( "pdp_cropper : new image %dx%d", x->x_csizex, x->x_csizey ); + + x->x_csizev = x->x_csizex*x->x_csizey; + x->x_packet1 = pdp_packet_new_image_YCrCb( x->x_csizex, x->x_csizey ); + newheader = pdp_packet_header(x->x_packet1); + newdata = (short int *)pdp_packet_data(x->x_packet1); + + newheader->info.image.encoding = header->info.image.encoding; + newheader->info.image.width = x->x_csizex; + newheader->info.image.height = x->x_csizey; + + pY = data; + pU = (data+x->x_vsize); + pV = (data+x->x_vsize+(x->x_vsize>>2)); + pnY = newdata; + pnU = (newdata+x->x_csizev); + pnV = (newdata+x->x_csizev+(x->x_csizev>>2)); + + if ( x->x_cropx1<x->x_cropx2 ) + { + minx = x->x_cropx1; + maxx = x->x_cropx2; + } + else + { + minx = x->x_cropx2; + maxx = x->x_cropx1; + } + + if ( x->x_cropy1<x->x_cropy2 ) + { + miny = x->x_cropy1; + maxy = x->x_cropy2; + } + else + { + miny = x->x_cropy2; + maxy = x->x_cropy1; + } + + for(py=miny; py<maxy; py++) + { + for(px=minx; px<maxx; px++) + { + *(pnY+(py-miny)*x->x_csizex+(px-minx)) = *(pY+py*x->x_vwidth+px); + if ( (py%2==0) && (px%2==0) ) + { + *(pnU+((py-miny)>>1)*(x->x_csizex>>1)+((px-minx)>>1)) = *(pU+(py>>1)*(x->x_vwidth>>1)+(px>>1)); + *(pnV+((py-miny)>>1)*(x->x_csizex>>1)+((px-minx)>>1)) = *(pV+(py>>1)*(x->x_vwidth>>1)+(px>>1)); + } + } + } + + return; +} + +static void pdp_cropper_sendpacket(t_pdp_cropper *x) +{ + /* release the packet */ + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = -1; + + /* unregister and propagate if valid dest packet */ + pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet1); +} + +static void pdp_cropper_process(t_pdp_cropper *x) +{ + int encoding; + t_pdp *header = 0; + + /* check if image data packets are compatible */ + if ( (header = pdp_packet_header(x->x_packet0)) + && (PDP_IMAGE == header->type)){ + + /* pdp_cropper_process inputs and write into active inlet */ + switch(pdp_packet_header(x->x_packet0)->info.image.encoding){ + + case PDP_IMAGE_YV12: + pdp_queue_add(x, pdp_cropper_process_yv12, pdp_cropper_sendpacket, &x->x_queue_id); + break; + + case PDP_IMAGE_GREY: + // pdp_cropper_process_packet(x); + break; + + default: + /* don't know the type, so dont pdp_cropper_process */ + break; + + } + } +} + +static void pdp_cropper_input_0(t_pdp_cropper *x, t_symbol *s, t_floatarg f) +{ + /* if this is a register_ro message or register_rw message, register with packet factory */ + + if (s== gensym("register_rw")) + { + x->x_dropped = + pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("image/YCrCb/*") ); + } + + if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)) + { + /* add the process method and callback to the process queue */ + pdp_cropper_process(x); + } +} + +static void pdp_cropper_free(t_pdp_cropper *x) +{ + int i; + + pdp_queue_finish(x->x_queue_id); + pdp_packet_mark_unused(x->x_packet0); +} + +t_class *pdp_cropper_class; + +void *pdp_cropper_new(void) +{ + int i; + + t_pdp_cropper *x = (t_pdp_cropper *)pd_new(pdp_cropper_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("x1")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("x2")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("y1")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("y2")); + + x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + + x->x_packet0 = -1; + x->x_packet1 = -1; + x->x_queue_id = -1; + + x->x_cropx1=-1; + x->x_cropx2=-1; + x->x_cropy1=-1; + x->x_cropy2=-1; + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_cropper_setup(void) +{ +// post( pdp_cropper_version ); + pdp_cropper_class = class_new(gensym("pdp_cropper"), (t_newmethod)pdp_cropper_new, + (t_method)pdp_cropper_free, sizeof(t_pdp_cropper), 0, A_NULL); + + class_addmethod(pdp_cropper_class, (t_method)pdp_cropper_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_cropper_class, (t_method)pdp_cropper_cropx1, gensym("x1"), A_FLOAT, A_NULL); + class_addmethod(pdp_cropper_class, (t_method)pdp_cropper_cropx2, gensym("x2"), A_FLOAT, A_NULL); + class_addmethod(pdp_cropper_class, (t_method)pdp_cropper_cropy1, gensym("y1"), A_FLOAT, A_NULL); + class_addmethod(pdp_cropper_class, (t_method)pdp_cropper_cropy2, gensym("y2"), A_FLOAT, A_NULL); + class_sethelpsymbol( pdp_cropper_class, gensym("pdp_cropper.pd") ); +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/pdp_dilate.c b/modules/pdp_dilate.c new file mode 100644 index 0000000..062f452 --- /dev/null +++ b/modules/pdp_dilate.c @@ -0,0 +1,281 @@ +/* + * PiDiP module + * Copyright (c) by Yves Degoyon ( ydegoyon@free.fr ) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* This object is a morphological operator for dilation using as a structuring element a WxH square + */ + +#include "pdp.h" +#include "yuv.h" +#include <math.h> +#include <stdio.h> + +static char *pdp_dilate_version = "pdp_dilate: morphology : dilation version 0.1 written by Yves Degoyon (ydegoyon@free.fr)"; + +typedef struct pdp_dilate_struct +{ + t_object x_obj; + + t_int x_packet0; + t_int x_packet1; + t_int x_queue_id; + t_int x_dropped; + + t_int x_vwidth; + t_int x_vheight; + t_int x_vsize; + t_int x_kernelw; // width of the (square) kernel + t_int x_kernelh; // height of the square kernel + t_int x_nbpasses; // number of passes + short int *x_frame; // keep a copy of current frame for transformations + + t_outlet *x_pdp_output; // output packets + +} t_pdp_dilate; + +static void pdp_dilate_nbpasses(t_pdp_dilate *x, t_floatarg fpasses ) +{ + if ( fpasses>=1.) + { + x->x_nbpasses = (t_int)fpasses; + } +} + +static void pdp_dilate_kernelw(t_pdp_dilate *x, t_floatarg fkernelw ) +{ + if ( fkernelw>=0.) + { + x->x_kernelw = (t_int)fkernelw; + } +} + +static void pdp_dilate_kernelh(t_pdp_dilate *x, t_floatarg fkernelh ) +{ + if ( fkernelh>=0.) + { + x->x_kernelh = (t_int)fkernelh; + } +} + +static void pdp_dilate_allocate(t_pdp_dilate *x) +{ + x->x_frame = (short int *) getbytes ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 ); + + if ( !x->x_frame ) + { + post( "pdp_dilate : severe error : cannot allocate buffer !!! "); + return; + } +} + +static void pdp_dilate_free_ressources(t_pdp_dilate *x) +{ + if ( x->x_frame ) freebytes ( x->x_frame, ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 ); +} + +static void pdp_dilate_process_yv12(t_pdp_dilate *x) +{ + t_pdp *header = pdp_packet_header(x->x_packet0); + short int *data = (short int *)pdp_packet_data(x->x_packet0); + t_pdp *newheader = pdp_packet_header(x->x_packet1); + short int *newdata = (short int *)pdp_packet_data(x->x_packet1); + t_int i; + t_int px=0, py=0; + short int *pfY, *pfU, *pfV; + t_int ppx, ppy, ix, iy, pn, kx, ky; + + // allocate all ressources + if ( ( (int)header->info.image.width != x->x_vwidth ) || + ( (int)header->info.image.height != x->x_vheight ) ) + { + pdp_dilate_free_ressources( x ); + x->x_vwidth = header->info.image.width; + x->x_vheight = header->info.image.height; + x->x_vsize = x->x_vwidth*x->x_vheight; + pdp_dilate_allocate( x ); + post( "pdp_dilate : reallocated buffers" ); + } + + // post( "pdp_dilate : newheader:%x", newheader ); + + newheader->info.image.encoding = header->info.image.encoding; + newheader->info.image.width = x->x_vwidth; + newheader->info.image.height = x->x_vheight; + + memcpy( newdata, data, x->x_vsize+(x->x_vsize>>1)<<1 ); + memcpy( x->x_frame, data, x->x_vsize+(x->x_vsize>>1)<<1 ); + + // dilate (supposedly) binary image by using a 3x3 square as a structuring element + pfY = x->x_frame; + pfV = x->x_frame+x->x_vsize; + pfU = x->x_frame+x->x_vsize+(x->x_vsize>>2); + kx = (x->x_kernelw/2); + ky = (x->x_kernelh/2); + for ( pn=0; pn<x->x_nbpasses; pn++ ) + { + memcpy( x->x_frame, newdata, x->x_vsize+(x->x_vsize>>1)<<1 ); + for ( py=0; py<x->x_vheight; py++ ) + { + for ( px=0; px<x->x_vwidth; px++ ) + { + if ( *(pfY+py*x->x_vwidth+px) == 0 ) + { + for (ix=-kx; ix<=kx; ix++) + { + ppx=px+ix; + if ( (ppx>=0) && (ppx<x->x_vwidth) ) + { + for (iy=-ky; iy<=ky; iy++) + { + ppy=py+iy; + if ( (ppy>=0) && (ppy<x->x_vheight) ) + { + if( *(pfY+ppy*x->x_vwidth+ppx) == ((255)<<7) ) + { + *(newdata+py*x->x_vwidth+px) = ((255)<<7); + break; + } + } + } + if ( *(newdata+py*x->x_vwidth+px) == ((255)<<7) ) break; + } + } + } + } + } + } + + return; +} + +static void pdp_dilate_sendpacket(t_pdp_dilate *x) +{ + /* release the packet */ + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = -1; + + /* unregister and propagate if valid dest packet */ + pdp_packet_pass_if_valid(x->x_pdp_output, &x->x_packet1); +} + +static void pdp_dilate_process(t_pdp_dilate *x) +{ + int encoding; + t_pdp *header = 0; + + /* check if image data packets are compatible */ + if ( (header = pdp_packet_header(x->x_packet0)) + && (PDP_IMAGE == header->type)){ + + /* pdp_dilate_process inputs and write into active inlet */ + switch(pdp_packet_header(x->x_packet0)->info.image.encoding) + { + + case PDP_IMAGE_YV12: + x->x_packet1 = pdp_packet_clone_rw(x->x_packet0); + pdp_queue_add(x, pdp_dilate_process_yv12, pdp_dilate_sendpacket, &x->x_queue_id); + break; + + case PDP_IMAGE_GREY: + // should write something to handle these one day + // but i don't use this mode + break; + + default: + /* don't know the type, so dont pdp_dilate_process */ + break; + + } + } + +} + +static void pdp_dilate_input_0(t_pdp_dilate *x, t_symbol *s, t_floatarg f) +{ + /* if this is a register_ro message or register_rw message, register with packet factory */ + + if (s== gensym("register_rw")) + { + x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("image/YCrCb/*") ); + } + + if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)) + { + pdp_dilate_process(x); + } +} + +static void pdp_dilate_free(t_pdp_dilate *x) +{ + int i; + + pdp_packet_mark_unused(x->x_packet0); + pdp_dilate_free_ressources( x ); +} + +t_class *pdp_dilate_class; + +void *pdp_dilate_new(void) +{ + int i; + + t_pdp_dilate *x = (t_pdp_dilate *)pd_new(pdp_dilate_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("nbpasses")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("kernelw")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("kernelh")); + + x->x_pdp_output = outlet_new(&x->x_obj, &s_anything); + + x->x_packet0 = -1; + x->x_packet1 = -1; + x->x_vwidth = -1; + x->x_vheight = -1; + x->x_vsize = -1; + x->x_frame = NULL; + x->x_kernelw = 3; + x->x_kernelh = 3; + + x->x_nbpasses = 1; + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_dilate_setup(void) +{ + // post( pdp_dilate_version ); + pdp_dilate_class = class_new(gensym("pdp_dilate"), (t_newmethod)pdp_dilate_new, + (t_method)pdp_dilate_free, sizeof(t_pdp_dilate), 0, A_NULL); + + class_addmethod(pdp_dilate_class, (t_method)pdp_dilate_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_dilate_class, (t_method)pdp_dilate_nbpasses, gensym("nbpasses"), A_FLOAT, A_NULL); + class_addmethod(pdp_dilate_class, (t_method)pdp_dilate_kernelw, gensym("kernelw"), A_FLOAT, A_NULL); + class_addmethod(pdp_dilate_class, (t_method)pdp_dilate_kernelh, gensym("kernelh"), A_FLOAT, A_NULL); + class_sethelpsymbol( pdp_dilate_class, gensym("pdp_dilate.pd") ); +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/pdp_disintegration.c b/modules/pdp_disintegration.c new file mode 100644 index 0000000..93eeec7 --- /dev/null +++ b/modules/pdp_disintegration.c @@ -0,0 +1,280 @@ +/* + * PiDiP module + * Copyright (c) by Yves Degoyon ( ydegoyon@free.fr ) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* This object is a piksels sum-up operator + */ + +#include "pdp.h" +#include "yuv.h" +#include <math.h> +#include <stdio.h> + +static char *pdp_disintegration_version = "pdp_disintegration: piksels sum-up version 0.1 written by Yves Degoyon (ydegoyon@free.fr)"; + +typedef struct pdp_disintegration_struct +{ + t_object x_obj; + + t_int x_packet0; + t_int x_packet1; + t_int x_queue_id; + t_int x_dropped; + + t_int x_vwidth; + t_int x_vheight; + t_int x_vsize; + t_int x_nbpasses; // number of passes + t_int x_reductor; // fraction reductor + short int *x_frame; // keep a copy of current frame for transformations + + t_outlet *x_pdp_output; // output packets + +} t_pdp_disintegration; + +static void pdp_disintegration_nbpasses(t_pdp_disintegration *x, t_floatarg fpasses ) +{ + if ( fpasses>=1.) + { + x->x_nbpasses = (t_int)fpasses; + } +} + +static void pdp_disintegration_reductor(t_pdp_disintegration *x, t_floatarg freductor ) +{ + if ( freductor>=1.) + { + x->x_reductor = (t_int)freductor; + } +} + +static void pdp_disintegration_allocate(t_pdp_disintegration *x) +{ + x->x_frame = (short int *) getbytes ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 ); + + if ( !x->x_frame ) + { + post( "pdp_disintegration : severe error : cannot allocate buffer !!! "); + return; + } +} + +static void pdp_disintegration_free_ressources(t_pdp_disintegration *x) +{ + if ( x->x_frame ) freebytes ( x->x_frame, ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 ); +} + +static void pdp_disintegration_process_yv12(t_pdp_disintegration *x) +{ + t_pdp *header = pdp_packet_header(x->x_packet0); + short int *data = (short int *)pdp_packet_data(x->x_packet0); + t_pdp *newheader = pdp_packet_header(x->x_packet1); + short int *newdata = (short int *)pdp_packet_data(x->x_packet1); + t_int i; + t_int px=0, py=0; + short int *pfY, *pfU, *pfV; + t_int ppx, ppy, ix, iy, pn; + t_int nvalue; + + // allocate all ressources + if ( ( (int)header->info.image.width != x->x_vwidth ) || + ( (int)header->info.image.height != x->x_vheight ) ) + { + pdp_disintegration_free_ressources( x ); + x->x_vwidth = header->info.image.width; + x->x_vheight = header->info.image.height; + x->x_vsize = x->x_vwidth*x->x_vheight; + pdp_disintegration_allocate( x ); + post( "pdp_disintegration : reallocated buffers" ); + } + + // post( "pdp_disintegration : newheader:%x", newheader ); + + newheader->info.image.encoding = header->info.image.encoding; + newheader->info.image.width = x->x_vwidth; + newheader->info.image.height = x->x_vheight; + + memcpy( newdata, data, x->x_vsize+(x->x_vsize>>1)<<1 ); + memcpy( x->x_frame, data, x->x_vsize+(x->x_vsize>>1)<<1 ); + + pfY = x->x_frame; + pfV = x->x_frame+x->x_vsize; + pfU = x->x_frame+x->x_vsize+(x->x_vsize>>2); + + // foreground piksels are now 1 + for ( py=0; py<x->x_vheight; py++ ) + { + for ( px=0; px<x->x_vwidth; px++ ) + { + if ( *(pfY+py*x->x_vwidth+px) == ((255)<<7) ) + { + *(pfY+py*x->x_vwidth+px) = ((1)<<7); + } + } + } + + for ( pn=0; pn<x->x_nbpasses; pn++ ) + { + memcpy( x->x_frame, newdata, x->x_vsize+(x->x_vsize>>1)<<1 ); + for ( py=0; py<x->x_vheight; py++ ) + { + for ( px=0; px<x->x_vwidth; px++ ) + { + nvalue = 0; + for (ix=-1; ix<=1; ix++) + { + ppx=px+ix; + if ( (ppx>=0) && (ppx<x->x_vwidth) ) + { + for (iy=-1; iy<=1; iy++) + { + ppy=py+iy; + if ( (ppy>=0) && (ppy<x->x_vheight) ) + { + nvalue += *(pfY+ppy*x->x_vwidth+ppx); + } + } + } + } + if ( nvalue > ((255)<<7)*9 ) + { + *(newdata+py*x->x_vwidth+px) = ((255)<<7); + } + else + { + *(newdata+py*x->x_vwidth+px) = nvalue/x->x_reductor; + } + } + } + } + + return; +} + +static void pdp_disintegration_sendpacket(t_pdp_disintegration *x) +{ + /* release the packet */ + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = -1; + + /* unregister and propagate if valid dest packet */ + pdp_packet_pass_if_valid(x->x_pdp_output, &x->x_packet1); +} + +static void pdp_disintegration_process(t_pdp_disintegration *x) +{ + int encoding; + t_pdp *header = 0; + + /* check if image data packets are compatible */ + if ( (header = pdp_packet_header(x->x_packet0)) + && (PDP_IMAGE == header->type)){ + + /* pdp_disintegration_process inputs and write into active inlet */ + switch(pdp_packet_header(x->x_packet0)->info.image.encoding) + { + + case PDP_IMAGE_YV12: + x->x_packet1 = pdp_packet_clone_rw(x->x_packet0); + pdp_queue_add(x, pdp_disintegration_process_yv12, pdp_disintegration_sendpacket, &x->x_queue_id); + break; + + case PDP_IMAGE_GREY: + // should write something to handle these one day + // but i don't use this mode + break; + + default: + /* don't know the type, so dont pdp_disintegration_process */ + break; + + } + } + +} + +static void pdp_disintegration_input_0(t_pdp_disintegration *x, t_symbol *s, t_floatarg f) +{ + /* if this is a register_ro message or register_rw message, register with packet factory */ + + if (s== gensym("register_rw")) + { + x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("image/YCrCb/*") ); + } + + if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)) + { + pdp_disintegration_process(x); + } +} + +static void pdp_disintegration_free(t_pdp_disintegration *x) +{ + int i; + + pdp_packet_mark_unused(x->x_packet0); + pdp_disintegration_free_ressources( x ); +} + +t_class *pdp_disintegration_class; + +void *pdp_disintegration_new(void) +{ + int i; + + t_pdp_disintegration *x = (t_pdp_disintegration *)pd_new(pdp_disintegration_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("nbpasses")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("reductor")); + + x->x_pdp_output = outlet_new(&x->x_obj, &s_anything); + + x->x_packet0 = -1; + x->x_packet1 = -1; + x->x_vwidth = -1; + x->x_vheight = -1; + x->x_vsize = -1; + x->x_frame = NULL; + x->x_nbpasses = 3; + x->x_reductor = 5; + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_disintegration_setup(void) +{ + // post( pdp_disintegration_version ); + pdp_disintegration_class = class_new(gensym("pdp_disintegration"), (t_newmethod)pdp_disintegration_new, + (t_method)pdp_disintegration_free, sizeof(t_pdp_disintegration), 0, A_NULL); + + class_addmethod(pdp_disintegration_class, (t_method)pdp_disintegration_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_disintegration_class, (t_method)pdp_disintegration_nbpasses, gensym("nbpasses"), A_FLOAT, A_NULL); + class_addmethod(pdp_disintegration_class, (t_method)pdp_disintegration_reductor, gensym("reductor"), A_FLOAT, A_NULL); + class_sethelpsymbol( pdp_disintegration_class, gensym("pdp_disintegration.pd") ); +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/pdp_distance.c b/modules/pdp_distance.c new file mode 100644 index 0000000..34b3ddf --- /dev/null +++ b/modules/pdp_distance.c @@ -0,0 +1,337 @@ +/* + * PiDiP module + * Copyright (c) by Yves Degoyon ( ydegoyon@free.fr ) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* This object is a salience distance operator + * ( inspired by Paul Rosin, 91, http://www.cs.cf.ac.uk/User/Paul.Rosin/resources/sdt/ ) + */ + +#include "pdp.h" +#include "yuv.h" +#include <math.h> +#include <stdio.h> + +static char *pdp_distance_version = "pdp_distance: morphology : distance operator version 0.1 written by Yves Degoyon (ydegoyon@free.fr)"; + +typedef struct pdp_distance_struct +{ + t_object x_obj; + + t_int x_packet0; + t_int x_packet1; + t_int x_queue_id; + t_int x_dropped; + + t_int x_vwidth; + t_int x_vheight; + t_int x_vsize; + short int *x_frame; // keep a copy of current frame for transformations + + t_int x_coeff1; + t_int x_coeff2; + t_int x_coeff3; + t_int x_coeff4; + + t_outlet *x_pdp_output; // output packets + +} t_pdp_distance; + +static void pdp_distance_allocate(t_pdp_distance *x) +{ + x->x_frame = (short int *) getbytes ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 ); + + if ( !x->x_frame ) + { + post( "pdp_distance : severe error : cannot allocate buffer !!! "); + return; + } +} + +static void pdp_distance_coeff1(t_pdp_distance *x, t_floatarg fcoeff1 ) +{ + x->x_coeff1 = (int) fcoeff1; +} + +static void pdp_distance_coeff2(t_pdp_distance *x, t_floatarg fcoeff2 ) +{ + x->x_coeff2 = (int) fcoeff2; +} + +static void pdp_distance_coeff3(t_pdp_distance *x, t_floatarg fcoeff3 ) +{ + x->x_coeff3 = (int) fcoeff3; +} + +static void pdp_distance_coeff4(t_pdp_distance *x, t_floatarg fcoeff4 ) +{ + x->x_coeff4 = (int) fcoeff4; +} + +static void pdp_distance_free_ressources(t_pdp_distance *x) +{ + if ( x->x_frame ) freebytes ( x->x_frame, ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 ); +} + +static void pdp_distance_process_yv12(t_pdp_distance *x) +{ + t_pdp *header = pdp_packet_header(x->x_packet0); + short int *data = (short int *)pdp_packet_data(x->x_packet0); + t_pdp *newheader = pdp_packet_header(x->x_packet1); + short int *newdata = (short int *)pdp_packet_data(x->x_packet1); + t_int i; + t_int px=0, py=0; + short int *pfY, *pfU, *pfV; + t_int nvalues, values[5], ival, mval; + + // allocate all ressources + if ( ( (int)header->info.image.width != x->x_vwidth ) || + ( (int)header->info.image.height != x->x_vheight ) ) + { + pdp_distance_free_ressources( x ); + x->x_vwidth = header->info.image.width; + x->x_vheight = header->info.image.height; + x->x_vsize = x->x_vwidth*x->x_vheight; + pdp_distance_allocate( x ); + post( "pdp_distance : reallocated buffers" ); + } + + // post( "pdp_distance : newheader:%x", newheader ); + + newheader->info.image.encoding = header->info.image.encoding; + newheader->info.image.width = x->x_vwidth; + newheader->info.image.height = x->x_vheight; + + memcpy( newdata, data, x->x_vsize+(x->x_vsize>>1)<<1 ); + memcpy( x->x_frame, data, x->x_vsize+(x->x_vsize>>1)<<1 ); + + pfY = x->x_frame; + pfV = x->x_frame+x->x_vsize; + pfU = x->x_frame+x->x_vsize+(x->x_vsize>>2); + + // thresholding + for ( py=0; py<x->x_vheight; py++ ) + { + for ( px=0; px<x->x_vwidth; px++ ) + { + if ( *(pfY+py*x->x_vwidth+px) > ((128)<<7) ) + { + *(pfY+py*x->x_vwidth+px) = ((128)<<7); + } + } + } + + // forward pass + for ( py=0; py<x->x_vheight; py++ ) + { + for ( px=0; px<x->x_vwidth; px++ ) + { + nvalues = 0; + if ( ((px-1)>=0) && ((py-1)>=0) ) + { + values[nvalues] = *(pfY+(py-1)*x->x_vwidth+(px-1)) + (x->x_coeff1<<7); + nvalues++; + } + if ( (py-1)>=0 ) + { + values[nvalues] = *(pfY+(py-1)*x->x_vwidth+px) + (x->x_coeff2<<7); + nvalues++; + } + if ( ((px+1)<x->x_vwidth) && ((py-1)>=0) ) + { + values[nvalues] = *(pfY+(py-1)*x->x_vwidth+(px+1)) + (x->x_coeff3<<7); + nvalues++; + } + if ( (px-1)>=0 ) + { + values[nvalues] = *(pfY+py*x->x_vwidth+(px-1)) + (x->x_coeff4<<7); + nvalues++; + } + values[nvalues] = *(pfY+py*x->x_vwidth+px); + nvalues++; + + mval = values[0]; + for (ival=0; ival<nvalues; ival++) + { + if (values[ival]<mval) mval=values[ival]; + } + *(x->x_frame+py*x->x_vwidth+px)=mval; + } + } + + // backward pass + for ( py=x->x_vheight-1; py>=0; py-- ) + { + for ( px=x->x_vwidth-1; px>=0; px-- ) + { + nvalues = 0; + if ( ((px-1)>=0) && ((py+1)<x->x_vheight) ) + { + values[nvalues] = *(pfY+(py+1)*x->x_vwidth+(px-1)) + (x->x_coeff1<<7); + nvalues++; + } + if ( (py+1)<x->x_vheight ) + { + values[nvalues] = *(pfY+(py+1)*x->x_vwidth+px) + (x->x_coeff2<<7); + nvalues++; + } + if ( ((px+1)<x->x_vwidth) && ((py+1)<x->x_vheight) ) + { + values[nvalues] = *(pfY+(py+1)*x->x_vwidth+(px+1)) + (x->x_coeff3<<7); + nvalues++; + } + if ( (px+1)<x->x_vwidth ) + { + values[nvalues] = *(pfY+py*x->x_vwidth+(px+1)) + (x->x_coeff4<<7); + nvalues++; + } + values[nvalues] = *(pfY+py*x->x_vwidth+px); + nvalues++; + + mval = values[0]; + for (ival=0; ival<nvalues; ival++) + { + if (values[ival]<mval) mval=values[ival]; + } + *(x->x_frame+py*x->x_vwidth+px)=mval; + } + } + + memcpy( newdata, x->x_frame, x->x_vsize+(x->x_vsize>>1)<<1 ); + + return; +} + +static void pdp_distance_sendpacket(t_pdp_distance *x) +{ + /* release the packet */ + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = -1; + + /* unregister and propagate if valid dest packet */ + pdp_packet_pass_if_valid(x->x_pdp_output, &x->x_packet1); +} + +static void pdp_distance_process(t_pdp_distance *x) +{ + int encoding; + t_pdp *header = 0; + + /* check if image data packets are compatible */ + if ( (header = pdp_packet_header(x->x_packet0)) + && (PDP_IMAGE == header->type)){ + + /* pdp_distance_process inputs and write into active inlet */ + switch(pdp_packet_header(x->x_packet0)->info.image.encoding) + { + + case PDP_IMAGE_YV12: + x->x_packet1 = pdp_packet_clone_rw(x->x_packet0); + pdp_queue_add(x, pdp_distance_process_yv12, pdp_distance_sendpacket, &x->x_queue_id); + break; + + case PDP_IMAGE_GREY: + // should write something to handle these one day + // but i don't use this mode + break; + + default: + /* don't know the type, so dont pdp_distance_process */ + break; + + } + } + +} + +static void pdp_distance_input_0(t_pdp_distance *x, t_symbol *s, t_floatarg f) +{ + /* if this is a register_ro message or register_rw message, register with packet factory */ + + if (s== gensym("register_rw")) + { + x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("image/YCrCb/*") ); + } + + if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)) + { + pdp_distance_process(x); + } +} + +static void pdp_distance_free(t_pdp_distance *x) +{ + int i; + + pdp_packet_mark_unused(x->x_packet0); + pdp_distance_free_ressources( x ); +} + +t_class *pdp_distance_class; + +void *pdp_distance_new(void) +{ + int i; + + t_pdp_distance *x = (t_pdp_distance *)pd_new(pdp_distance_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("coeff1")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("coeff2")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("coeff3")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("coeff4")); + + x->x_pdp_output = outlet_new(&x->x_obj, &s_anything); + + x->x_packet0 = -1; + x->x_packet1 = -1; + x->x_vwidth = -1; + x->x_vheight = -1; + x->x_vsize = -1; + x->x_frame = NULL; + + x->x_coeff1 = 4; + x->x_coeff2 = 3; + x->x_coeff3 = 4; + x->x_coeff4 = 3; + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_distance_setup(void) +{ + // post( pdp_distance_version ); + pdp_distance_class = class_new(gensym("pdp_distance"), (t_newmethod)pdp_distance_new, + (t_method)pdp_distance_free, sizeof(t_pdp_distance), 0, A_NULL); + + class_addmethod(pdp_distance_class, (t_method)pdp_distance_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_distance_class, (t_method)pdp_distance_coeff1, gensym("coeff1"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_distance_class, (t_method)pdp_distance_coeff2, gensym("coeff2"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_distance_class, (t_method)pdp_distance_coeff3, gensym("coeff3"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_distance_class, (t_method)pdp_distance_coeff4, gensym("coeff4"), A_DEFFLOAT, A_NULL); + class_sethelpsymbol( pdp_distance_class, gensym("pdp_distance.pd") ); +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/pdp_erode.c b/modules/pdp_erode.c new file mode 100644 index 0000000..a843308 --- /dev/null +++ b/modules/pdp_erode.c @@ -0,0 +1,281 @@ +/* + * PiDiP module + * Copyright (c) by Yves Degoyon ( ydegoyon@free.fr ) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* This object is a morphological operator for erosion using as a structuring element a WxH square + */ + +#include "pdp.h" +#include "yuv.h" +#include <math.h> +#include <stdio.h> + +static char *pdp_erode_version = "pdp_erode: morphology : erosion version 0.1 written by Yves Degoyon (ydegoyon@free.fr)"; + +typedef struct pdp_erode_struct +{ + t_object x_obj; + + t_int x_packet0; + t_int x_packet1; + t_int x_queue_id; + t_int x_dropped; + + t_int x_vwidth; + t_int x_vheight; + t_int x_vsize; + t_int x_kernelw; // width of the (square) kernel + t_int x_kernelh; // height of the square kernel + t_int x_nbpasses; // number of passes + short int *x_frame; // keep a copy of current frame for transformations + + t_outlet *x_pdp_output; // output packets + +} t_pdp_erode; + +static void pdp_erode_nbpasses(t_pdp_erode *x, t_floatarg fpasses ) +{ + if ( fpasses>=1.) + { + x->x_nbpasses = (t_int)fpasses; + } +} + +static void pdp_erode_kernelw(t_pdp_erode *x, t_floatarg fkernelw ) +{ + if ( fkernelw>=0.) + { + x->x_kernelw = (t_int)fkernelw; + } +} + +static void pdp_erode_kernelh(t_pdp_erode *x, t_floatarg fkernelh ) +{ + if ( fkernelh>=0.) + { + x->x_kernelh = (t_int)fkernelh; + } +} + +static void pdp_erode_allocate(t_pdp_erode *x) +{ + x->x_frame = (short int *) getbytes ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 ); + + if ( !x->x_frame ) + { + post( "pdp_erode : severe error : cannot allocate buffer !!! "); + return; + } +} + +static void pdp_erode_free_ressources(t_pdp_erode *x) +{ + if ( x->x_frame ) freebytes ( x->x_frame, ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 ); +} + +static void pdp_erode_process_yv12(t_pdp_erode *x) +{ + t_pdp *header = pdp_packet_header(x->x_packet0); + short int *data = (short int *)pdp_packet_data(x->x_packet0); + t_pdp *newheader = pdp_packet_header(x->x_packet1); + short int *newdata = (short int *)pdp_packet_data(x->x_packet1); + t_int i; + t_int px=0, py=0; + short int *pfY, *pfU, *pfV; + t_int ppx, ppy, ix, iy, pn, kx, ky; + + // allocate all ressources + if ( ( (int)header->info.image.width != x->x_vwidth ) || + ( (int)header->info.image.height != x->x_vheight ) ) + { + pdp_erode_free_ressources( x ); + x->x_vwidth = header->info.image.width; + x->x_vheight = header->info.image.height; + x->x_vsize = x->x_vwidth*x->x_vheight; + pdp_erode_allocate( x ); + post( "pdp_erode : reallocated buffers" ); + } + + // post( "pdp_erode : newheader:%x", newheader ); + + newheader->info.image.encoding = header->info.image.encoding; + newheader->info.image.width = x->x_vwidth; + newheader->info.image.height = x->x_vheight; + + memcpy( newdata, data, x->x_vsize+(x->x_vsize>>1)<<1 ); + memcpy( x->x_frame, data, x->x_vsize+(x->x_vsize>>1)<<1 ); + + // erode (supposedly) binary image by using a 3x3 square as a structuring element + pfY = x->x_frame; + pfV = x->x_frame+x->x_vsize; + pfU = x->x_frame+x->x_vsize+(x->x_vsize>>2); + kx = (x->x_kernelw/2); + ky = (x->x_kernelh/2); + for ( pn=0; pn<x->x_nbpasses; pn++ ) + { + memcpy( x->x_frame, newdata, x->x_vsize+(x->x_vsize>>1)<<1 ); + for ( py=0; py<x->x_vheight; py++ ) + { + for ( px=0; px<x->x_vwidth; px++ ) + { + if ( *(pfY+py*x->x_vwidth+px) != 0 ) + { + for (ix=-kx; ix<=kx; ix++) + { + ppx=px+ix; + if ( (ppx>=0) && (ppx<x->x_vwidth) ) + { + for (iy=-ky; iy<=ky; iy++) + { + ppy=py+iy; + if ( (ppy>=0) && (ppy<x->x_vheight) ) + { + if( *(pfY+ppy*x->x_vwidth+ppx) != ((255)<<7) ) + { + *(newdata+py*x->x_vwidth+px) = 0; + break; + } + } + } + if ( *(newdata+py*x->x_vwidth+px) == 0 ) break; + } + } + } + } + } + } + + return; +} + +static void pdp_erode_sendpacket(t_pdp_erode *x) +{ + /* release the packet */ + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = -1; + + /* unregister and propagate if valid dest packet */ + pdp_packet_pass_if_valid(x->x_pdp_output, &x->x_packet1); +} + +static void pdp_erode_process(t_pdp_erode *x) +{ + int encoding; + t_pdp *header = 0; + + /* check if image data packets are compatible */ + if ( (header = pdp_packet_header(x->x_packet0)) + && (PDP_IMAGE == header->type)){ + + /* pdp_erode_process inputs and write into active inlet */ + switch(pdp_packet_header(x->x_packet0)->info.image.encoding) + { + + case PDP_IMAGE_YV12: + x->x_packet1 = pdp_packet_clone_rw(x->x_packet0); + pdp_queue_add(x, pdp_erode_process_yv12, pdp_erode_sendpacket, &x->x_queue_id); + break; + + case PDP_IMAGE_GREY: + // should write something to handle these one day + // but i don't use this mode + break; + + default: + /* don't know the type, so dont pdp_erode_process */ + break; + + } + } + +} + +static void pdp_erode_input_0(t_pdp_erode *x, t_symbol *s, t_floatarg f) +{ + /* if this is a register_ro message or register_rw message, register with packet factory */ + + if (s== gensym("register_rw")) + { + x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("image/YCrCb/*") ); + } + + if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)) + { + pdp_erode_process(x); + } +} + +static void pdp_erode_free(t_pdp_erode *x) +{ + int i; + + pdp_packet_mark_unused(x->x_packet0); + pdp_erode_free_ressources( x ); +} + +t_class *pdp_erode_class; + +void *pdp_erode_new(void) +{ + int i; + + t_pdp_erode *x = (t_pdp_erode *)pd_new(pdp_erode_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("nbpasses")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("kernelw")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("kernelh")); + + x->x_pdp_output = outlet_new(&x->x_obj, &s_anything); + + x->x_packet0 = -1; + x->x_packet1 = -1; + x->x_vwidth = -1; + x->x_vheight = -1; + x->x_vsize = -1; + x->x_frame = NULL; + x->x_kernelw = 3; + x->x_kernelh = 3; + + x->x_nbpasses = 1; + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_erode_setup(void) +{ + // post( pdp_erode_version ); + pdp_erode_class = class_new(gensym("pdp_erode"), (t_newmethod)pdp_erode_new, + (t_method)pdp_erode_free, sizeof(t_pdp_erode), 0, A_NULL); + + class_addmethod(pdp_erode_class, (t_method)pdp_erode_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_erode_class, (t_method)pdp_erode_nbpasses, gensym("nbpasses"), A_FLOAT, A_NULL); + class_addmethod(pdp_erode_class, (t_method)pdp_erode_kernelw, gensym("kernelw"), A_FLOAT, A_NULL); + class_addmethod(pdp_erode_class, (t_method)pdp_erode_kernelh, gensym("kernelh"), A_FLOAT, A_NULL); + class_sethelpsymbol( pdp_erode_class, gensym("pdp_erode.pd") ); +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/pdp_hitandmiss.c b/modules/pdp_hitandmiss.c new file mode 100644 index 0000000..0664605 --- /dev/null +++ b/modules/pdp_hitandmiss.c @@ -0,0 +1,386 @@ +/* + * PiDiP module + * Copyright (c) by Yves Degoyon ( ydegoyon@free.fr ) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* This object is a morphological operator for hit and miss agorithm + * using as a structuring element a WxH square + */ + +#include "pdp.h" +#include "yuv.h" +#include <math.h> +#include <stdio.h> + +static char *pdp_hitandmiss_version = "pdp_hitandmiss: morphology : hit&miss version 0.1 written by Yves Degoyon (ydegoyon@free.fr)"; + +typedef struct pdp_hitandmiss_struct +{ + t_object x_obj; + + t_int x_packet0; + t_int x_packet1; + t_int x_queue_id; + t_int x_dropped; + + t_int x_vwidth; + t_int x_vheight; + t_int x_vsize; + t_int x_kernelw; // width of the (square) kernel + t_int x_kernelh; // height of the square kernel + char *x_kdata; // kernel data + t_int x_nbpasses; // number of passes + short int *x_frame; // keep a copy of current frame for transformations + + t_outlet *x_pdp_output; // output packets + +} t_pdp_hitandmiss; + +static void pdp_hitandmiss_nbpasses(t_pdp_hitandmiss *x, t_floatarg fpasses ) +{ + if ( fpasses>=1.) + { + x->x_nbpasses = (t_int)fpasses; + } +} + +static void pdp_hitandmiss_kernelw(t_pdp_hitandmiss *x, t_floatarg fkernelw ) +{ + t_int oldw, minw; + char *nkdata; + + if ( fkernelw>=0.) + { + oldw = x->x_kernelw; + x->x_kernelw = (t_int)fkernelw; + + nkdata= (char*) malloc( x->x_kernelw*x->x_kernelh ); + + minw = (x->x_kernelw>oldw?oldw:x->x_kernelw ); + memcpy( nkdata, x->x_kdata, minw*x->x_kernelh ); + + if ( x->x_kdata ) + { + free( x->x_kdata ); + } + x->x_kdata = nkdata; + } + +} + +static void pdp_hitandmiss_kernelh(t_pdp_hitandmiss *x, t_floatarg fkernelh ) +{ + t_int oldh, minh; + char *nkdata; + + if ( fkernelh>=0.) + { + oldh = x->x_kernelh; + x->x_kernelh = (t_int)fkernelh; + + nkdata= (char*) malloc( x->x_kernelw*x->x_kernelh ); + + minh = (x->x_kernelh>oldh?oldh:x->x_kernelh ); + memcpy( nkdata, x->x_kdata, x->x_kernelw*minh ); + + if ( x->x_kdata ) + { + free( x->x_kdata ); + } + x->x_kdata = nkdata; + } +} + +static void pdp_hitandmiss_kdata(t_pdp_hitandmiss *x, t_symbol *s, int argc, t_atom *argv) +{ + t_int nbvalues, ivalue, iv; + + if ( argc > x->x_kernelw*x->x_kernelh ) + { + nbvalues = x->x_kernelh*x->x_kernelw; + post( "pdp_hitandmiss : too many data for the kernel, it should be %dx%d", x->x_kernelw, x->x_kernelh ); + post( "pdp_hitandmiss : truncated to %d", nbvalues ); + } + else if ( argc < x->x_kernelw*x->x_kernelh ) + { + nbvalues = argc; + post( "pdp_hitandmiss : too few data for the kernel, it should be %dx%d", x->x_kernelw, x->x_kernelh ); + post( "pdp_hitandmiss : padding with -1 (as if not used)" ); + for ( iv=argc; iv<x->x_kernelw*x->x_kernelh; iv++ ) + { + x->x_kdata[iv] = -1; + } + } + else + { + nbvalues = argc; + } + + for ( iv=0; iv<nbvalues; iv++ ) + { + if ( argv[iv].a_type != A_FLOAT ) + { + post( "pdp_hitandmiss : wrong data (%d), unchanged", iv ); + } + else + { + ivalue = (t_int) argv[iv].a_w.w_float; + if ( ( ivalue != 0 ) && ( ivalue != 1 ) && ( ivalue != -1 ) ) + { + post( "pdp_hitandmiss : wrong data (%d), unchanged", iv ); + } + else + { + x->x_kdata[iv] = ivalue; + } + } + } +} + +static void pdp_hitandmiss_allocate(t_pdp_hitandmiss *x) +{ + x->x_frame = (short int *) getbytes ( ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 ); + + if ( !x->x_frame ) + { + post( "pdp_hitandmiss : severe error : cannot allocate buffer !!! "); + return; + } +} + +static void pdp_hitandmiss_free_ressources(t_pdp_hitandmiss *x) +{ + if ( x->x_frame ) freebytes ( x->x_frame, ( x->x_vsize + ( x->x_vsize>>1 ) ) << 1 ); +} + +static void pdp_hitandmiss_process_yv12(t_pdp_hitandmiss *x) +{ + t_pdp *header = pdp_packet_header(x->x_packet0); + short int *data = (short int *)pdp_packet_data(x->x_packet0); + t_pdp *newheader = pdp_packet_header(x->x_packet1); + short int *newdata = (short int *)pdp_packet_data(x->x_packet1); + t_int i; + t_int px=0, py=0; + short int *pfY, *pfU, *pfV; + t_int ppx, ppy, ix, iy, pn, kx, ky; + short int pvalue; + + // allocate all ressources + if ( ( (int)header->info.image.width != x->x_vwidth ) || + ( (int)header->info.image.height != x->x_vheight ) ) + { + pdp_hitandmiss_free_ressources( x ); + x->x_vwidth = header->info.image.width; + x->x_vheight = header->info.image.height; + x->x_vsize = x->x_vwidth*x->x_vheight; + pdp_hitandmiss_allocate( x ); + post( "pdp_hitandmiss : reallocated buffers" ); + } + + // post( "pdp_hitandmiss : newheader:%x", newheader ); + + newheader->info.image.encoding = header->info.image.encoding; + newheader->info.image.width = x->x_vwidth; + newheader->info.image.height = x->x_vheight; + + memcpy( newdata, data, x->x_vsize+(x->x_vsize>>1)<<1 ); + memcpy( x->x_frame, data, x->x_vsize+(x->x_vsize>>1)<<1 ); + + // hit and miss (supposedly) binary image by using a 3x3 square as a structuring element + pfY = x->x_frame; + pfV = x->x_frame+x->x_vsize; + pfU = x->x_frame+x->x_vsize+(x->x_vsize>>2); + kx = (x->x_kernelw/2); + ky = (x->x_kernelh/2); + for ( pn=0; pn<x->x_nbpasses; pn++ ) + { + memcpy( x->x_frame, newdata, x->x_vsize+(x->x_vsize>>1)<<1 ); + for ( py=0; py<x->x_vheight; py++ ) + { + for ( px=0; px<x->x_vwidth; px++ ) + { + *(newdata+py*x->x_vwidth+px) = ((255)<<7); + for (ix=-kx; ix<=kx; ix++) + { + ppx=px+ix; + if ( (ppx>=0) && (ppx<x->x_vwidth) ) + { + for (iy=-ky; iy<=ky; iy++) + { + ppy=py+iy; + if ( (ppy>=0) && (ppy<x->x_vheight) ) + { + if ( x->x_kdata[(ky+iy)*x->x_kernelw+(kx+ix)] == 1 ) + { + pvalue = ((255)<<7); + } + else if ( x->x_kdata[(ky+iy)*x->x_kernelw+(kx+ix)] == 0 ) + { + pvalue = 0; + } + else // unused bit in the kernel, usually -1 + { + continue; + } + if( *(pfY+ppy*x->x_vwidth+ppx) != pvalue ) + { + *(newdata+py*x->x_vwidth+px) = 0; + break; + } + } + } + if ( *(newdata+py*x->x_vwidth+px) == 0 ) break; + } + } + } + } + } + + return; +} + +static void pdp_hitandmiss_sendpacket(t_pdp_hitandmiss *x) +{ + /* release the packet */ + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = -1; + + /* unregister and propagate if valid dest packet */ + pdp_packet_pass_if_valid(x->x_pdp_output, &x->x_packet1); +} + +static void pdp_hitandmiss_process(t_pdp_hitandmiss *x) +{ + int encoding; + t_pdp *header = 0; + + /* check if image data packets are compatible */ + if ( (header = pdp_packet_header(x->x_packet0)) + && (PDP_IMAGE == header->type)){ + + /* pdp_hitandmiss_process inputs and write into active inlet */ + switch(pdp_packet_header(x->x_packet0)->info.image.encoding) + { + + case PDP_IMAGE_YV12: + x->x_packet1 = pdp_packet_clone_rw(x->x_packet0); + pdp_queue_add(x, pdp_hitandmiss_process_yv12, pdp_hitandmiss_sendpacket, &x->x_queue_id); + break; + + case PDP_IMAGE_GREY: + // should write something to handle these one day + // but i don't use this mode + break; + + default: + /* don't know the type, so dont pdp_hitandmiss_process */ + break; + + } + } + +} + +static void pdp_hitandmiss_input_0(t_pdp_hitandmiss *x, t_symbol *s, t_floatarg f) +{ + /* if this is a register_ro message or register_rw message, register with packet factory */ + + if (s== gensym("register_rw")) + { + x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("image/YCrCb/*") ); + } + + if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)) + { + pdp_hitandmiss_process(x); + } +} + +static void pdp_hitandmiss_free(t_pdp_hitandmiss *x) +{ + int i; + + pdp_packet_mark_unused(x->x_packet0); + pdp_hitandmiss_free_ressources( x ); +} + +t_class *pdp_hitandmiss_class; + +void *pdp_hitandmiss_new(void) +{ + int i; + + t_pdp_hitandmiss *x = (t_pdp_hitandmiss *)pd_new(pdp_hitandmiss_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("nbpasses")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("kernelw")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("kernelh")); + + x->x_pdp_output = outlet_new(&x->x_obj, &s_anything); + + x->x_packet0 = -1; + x->x_packet1 = -1; + x->x_vwidth = -1; + x->x_vheight = -1; + x->x_vsize = -1; + x->x_frame = NULL; + x->x_kernelw = 3; + x->x_kernelh = 3; + x->x_kdata = (char *)malloc( x->x_kernelw*x->x_kernelh ); + x->x_kdata[0] = -1; + x->x_kdata[1] = 1; + x->x_kdata[2] = -1; + x->x_kdata[3] = 0; + x->x_kdata[4] = 1; + x->x_kdata[5] = 1; + x->x_kdata[6] = 0; + x->x_kdata[7] = 0; + x->x_kdata[8] = -1; + // that is : + // | -1 1 -1 | + // | 0 1 1 | + // | 0 0 -1 | + + x->x_nbpasses = 1; + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_hitandmiss_setup(void) +{ + // post( pdp_hitandmiss_version ); + pdp_hitandmiss_class = class_new(gensym("pdp_hitandmiss"), (t_newmethod)pdp_hitandmiss_new, + (t_method)pdp_hitandmiss_free, sizeof(t_pdp_hitandmiss), 0, A_NULL); + + class_addmethod(pdp_hitandmiss_class, (t_method)pdp_hitandmiss_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_hitandmiss_class, (t_method)pdp_hitandmiss_nbpasses, gensym("nbpasses"), A_FLOAT, A_NULL); + class_addmethod(pdp_hitandmiss_class, (t_method)pdp_hitandmiss_kernelw, gensym("kernelw"), A_FLOAT, A_NULL); + class_addmethod(pdp_hitandmiss_class, (t_method)pdp_hitandmiss_kernelh, gensym("kernelh"), A_FLOAT, A_NULL); + class_addmethod(pdp_hitandmiss_class, (t_method)pdp_hitandmiss_kdata, gensym("kernel"), A_GIMME, A_NULL); + class_sethelpsymbol( pdp_hitandmiss_class, gensym("pdp_hitandmiss.pd") ); +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/pdp_theorin~.c b/modules/pdp_theorin~.c new file mode 100644 index 0000000..2a7c72b --- /dev/null +++ b/modules/pdp_theorin~.c @@ -0,0 +1,970 @@ +/* + * PiDiP module. + * Copyright (c) by Yves Degoyon (ydegoyon@free.fr) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* This object is a theora file decoder object + * It uses libtheora and some of it code samples ( copyright xiph.org ) + * Copyleft by Yves Degoyon ( ydegoyon@free.fr ) + */ + + +#include "pdp.h" +#include "yuv.h" +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> +#include <math.h> +#include <time.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <signal.h> + +#include <theora/theora.h> /* theora stuff */ +#include <vorbis/codec.h> /* vorbis stuff */ + +#define VIDEO_BUFFER_SIZE (1024*1024) +#define MAX_AUDIO_PACKET_SIZE (64 * 1024) +#define MIN_AUDIO_SIZE (64*1024) + +#define DEFAULT_CHANNELS 1 +#define DEFAULT_WIDTH 320 +#define DEFAULT_HEIGHT 240 +#define DEFAULT_FRAME_RATE 25 +#define END_OF_STREAM 20 +#define MIN_PRIORITY 0 +#define DEFAULT_PRIORITY 1 +#define MAX_PRIORITY 20 + +#define THEORA_NUM_HEADER_PACKETS 3 + +static char *pdp_theorin_version = "pdp_theorin~: version 0.1, a theora file reader ( ydegoyon@free.fr)."; + +typedef struct pdp_theorin_struct +{ + t_object x_obj; + t_float x_f; + + t_int x_packet0; + t_int x_dropped; + + t_pdp *x_header; + unsigned char *x_data; + t_int x_vwidth; + t_int x_vheight; + t_int x_vsize; + + t_outlet *x_pdp_out; // output decoded pdp packets + t_outlet *x_outlet_left; // left audio output + t_outlet *x_outlet_right; // right audio output + t_outlet *x_outlet_nbframes; // number of frames emitted + t_outlet *x_outlet_framerate; // real framerate + t_outlet *x_outlet_endoffile; // for signaling the end of the file + t_outlet *x_outlet_filesize; // for informing of the file size + + pthread_t x_decodechild; // file decoding thread + t_int x_usethread; // flag to activate decoding in a thread + t_int x_autoplay; // flag to autoplay the file ( default = true ) + t_int x_nextimage; // flag to play next image in manual mode + t_int x_priority; // priority of decoding thread + + char *x_filename; + FILE *x_infile; // file descriptor + t_int x_decoding; // decoding flag + t_int x_theorainit; // flag for indicating that theora is initialized + t_int x_videoready; // video ready flag + t_int x_newpicture; // new picture flag + t_int x_newpictureready;// new picture ready flag + t_int x_loop; // looping flag ( default = on ) + t_int x_notpackets; // number of theora packets decoded + t_int x_novpackets; // number of vorbis packets decoded + t_int x_endoffile; // end of the file reached + t_int x_nbframes; // number of frames emitted + t_int x_framerate; // framerate + t_int x_samplerate; // audio sample rate + t_int x_audiochannels; // audio channels + t_int x_blocksize; // audio block size + t_int x_audioon; // audio buffer filling flag + t_int x_reading; // file reading flag + t_int x_cursec; // current second + t_int x_secondcount; // number of frames received in the current second + struct timeval x_starttime; // reading starting time + + /* vorbis/theora structures */ + ogg_sync_state x_sync_state; // ogg sync state + ogg_page x_ogg_page; // ogg page + ogg_packet x_ogg_packet; // ogg packet + ogg_stream_state x_statev; // vorbis stream state + ogg_stream_state x_statet; // theora stream state + theora_info x_theora_info; // theora info + theora_comment x_theora_comment; // theora comment + theora_state x_theora_state; // theora state + vorbis_info x_vorbis_info; // vorbis info + vorbis_dsp_state x_dsp_state; // vorbis dsp state + vorbis_block x_vorbis_block; // vorbis block + vorbis_comment x_vorbis_comment; // vorbis comment + yuv_buffer x_yuvbuffer; // yuv buffer + + /* audio structures */ + t_int x_audio; // flag to activate the decoding of audio + t_float x_audio_inl[4*MAX_AUDIO_PACKET_SIZE]; /* buffer for float audio decoded from ogg */ + t_float x_audio_inr[4*MAX_AUDIO_PACKET_SIZE]; /* buffer for float audio decoded from ogg */ + t_int x_audioin_position; // writing position for incoming audio + +} t_pdp_theorin; + +static void pdp_theorin_priority(t_pdp_theorin *x, t_floatarg fpriority ) +{ + if ( ( x->x_priority >= MIN_PRIORITY ) && ( x->x_priority <= MAX_PRIORITY ) ) + { + x->x_priority = (int)fpriority; + } +} + +static void pdp_theorin_threadify(t_pdp_theorin *x, t_floatarg fusethread ) +{ + if ( ( fusethread == 0 ) || ( fusethread == 1 ) ) + { + x->x_usethread = (int)fusethread; + } +} + +static void pdp_theorin_audio(t_pdp_theorin *x, t_floatarg faudio ) +{ + if ( ( faudio == 0. ) || ( faudio == 1. ) ) + { + x->x_audio = (int)faudio; + } +} + +static void pdp_theorin_autoplay(t_pdp_theorin *x, t_floatarg fautoplay ) +{ + if ( ( fautoplay == 0. ) || ( fautoplay == 1. ) ) + { + x->x_autoplay = (int)fautoplay; + } +} + +static void pdp_theorin_loop(t_pdp_theorin *x, t_floatarg floop ) +{ + if ( ( floop == 0. ) || ( floop == 1. ) ) + { + x->x_loop = (int)floop; + } +} + +static void pdp_theorin_bang(t_pdp_theorin *x) +{ + if ( x->x_nextimage == 1 ) + { + // post( "pdp_theorin~ : banging too fast, previous image is not decoded yet... ignored" ); + return; + } + x->x_nextimage = 1; +} + +static t_int pdp_theorin_get_buffer_from_file(FILE *in, ogg_sync_state *oy) +{ + char *buffer; + t_int bytes; + + buffer=ogg_sync_buffer(oy,4096); + bytes=fread(buffer,1,4096,in); + ogg_sync_wrote(oy,bytes); + return(bytes); +} + +static t_int pdp_theorin_queue_page(t_pdp_theorin *x) +{ + if(x->x_notpackets) ogg_stream_pagein(&x->x_statet, &x->x_ogg_page); + if(x->x_novpackets) ogg_stream_pagein(&x->x_statev, &x->x_ogg_page); + return 0; +} + +static t_int pdp_theorin_decode_packet(t_pdp_theorin *x) +{ + int ret, count, maxsamples, samples, si=0, sj=0; + float **pcm; + struct timespec mwait; + struct timeval ctime; + long long tplaying; + long long ttheoretical; + unsigned char *pY, *pU, *pV; + unsigned char *psY, *psU, *psV; + t_int px, py; + + // post( "pdp_theorin~ : decode packet" ); + + if ( !x->x_reading ) return -1; + + while ( x->x_novpackets && !x->x_audioon ) + { + /* if there's pending, decoded audio, grab it */ + if((ret=vorbis_synthesis_pcmout(&x->x_dsp_state, &pcm))>0) + { + if (x->x_audio) + { + maxsamples=(3*MAX_AUDIO_PACKET_SIZE-x->x_audioin_position); + samples=(ret<maxsamples)?ret:maxsamples; + + if ( x->x_audioin_position + samples*x->x_audiochannels < 3*MAX_AUDIO_PACKET_SIZE ) + { + memcpy( (void*)&x->x_audio_inl[x->x_audioin_position], pcm[0], samples*sizeof(t_float) ); + memcpy( (void*)&x->x_audio_inr[x->x_audioin_position], pcm[1], samples*sizeof(t_float) ); + x->x_audioin_position = ( x->x_audioin_position + samples ) % (4*MAX_AUDIO_PACKET_SIZE); + } + else + { + post( "pdp_theorin~ : audio overflow : packet ignored..."); + x->x_audioin_position = 0; + } + if ( ( x->x_audioin_position > MIN_AUDIO_SIZE ) && (!x->x_audioon) ) + { + x->x_audioon = 1; + // post( "pdp_theorin~ : audio on (audioin=%d)", x->x_audioin_position ); + } + // tell vorbis how many samples were read + // post( "pdp_theorin~ : got %d audio samples (audioin=%d)", samples, x->x_audioin_position ); + vorbis_synthesis_read(&x->x_dsp_state, samples); + } + else + { + break; + } + } + else + { + // no pending audio: is there a pending packet to decode? + if( ogg_stream_packetout(&x->x_statev, &x->x_ogg_packet)>0 ) + { + if(vorbis_synthesis(&x->x_vorbis_block, &x->x_ogg_packet)==0) + { + vorbis_synthesis_blockin(&x->x_dsp_state, &x->x_vorbis_block); + } + } + else /* we need more data; suck in another page */ + { + break; + } + } + } + + if ( !x->x_newpictureready && !x->x_newpicture ) + { + while(x->x_notpackets && !x->x_videoready) + { + // theora is one in, one out... + if(ogg_stream_packetout(&x->x_statet, &x->x_ogg_packet)>0) + { + theora_decode_packetin(&x->x_theora_state, &x->x_ogg_packet); + // post( "pdp_theorin~ : got one video frame" ); + x->x_videoready=1; + } + else + { + // post( "pdp_theorin~ : no more video frame (frames=%d)", x->x_nbframes ); + if ( x->x_nbframes > 0 ) + { + if ( !x->x_loop ) + { + x->x_endoffile = 1; + } + else + { + // restart a new loop + if ( gettimeofday(&x->x_starttime, NULL) == -1) + { + post("pdp_theorin~ : could not set start time" ); + } + } + x->x_nbframes = 0; + x->x_audioin_position = 0; // reset audio + x->x_audioon = 0; + } + break; + } + } + + if ( x->x_videoready ) + { + theora_decode_YUVout(&x->x_theora_state, &x->x_yuvbuffer); + + // create a new pdp packet from PIX_FMT_YUV420P image format + x->x_vwidth = x->x_yuvbuffer.y_width; + x->x_vheight = x->x_yuvbuffer.y_height; + x->x_vsize = x->x_vwidth*x->x_vheight; + x->x_packet0 = pdp_packet_new_bitmap_yv12( x->x_vwidth, x->x_vheight ); + // post( "pdp_theorin~ : allocated packet %d", x->x_packet0 ); + x->x_header = pdp_packet_header(x->x_packet0); + x->x_data = (unsigned char*) pdp_packet_data(x->x_packet0); + + x->x_header->info.image.encoding = PDP_BITMAP_YV12; + x->x_header->info.image.width = x->x_vwidth; + x->x_header->info.image.height = x->x_vheight; + + pY = x->x_data; + pV = x->x_data+x->x_vsize; + pU = x->x_data+x->x_vsize+(x->x_vsize>>2); + + psY = x->x_yuvbuffer.y; + psU = x->x_yuvbuffer.u; + psV = x->x_yuvbuffer.v; + + for ( py=0; py<x->x_vheight; py++) + { + memcpy( (void*)pY, (void*)psY, x->x_vwidth ); + pY += x->x_vwidth; + psY += x->x_yuvbuffer.y_stride; + if ( py%2==0 ) + { + memcpy( (void*)pU, (void*)psU, (x->x_vwidth>>1) ); + memcpy( (void*)pV, (void*)psV, (x->x_vwidth>>1) ); + pU += (x->x_vwidth>>1); + pV += (x->x_vwidth>>1); + psU += x->x_yuvbuffer.uv_stride; + psV += x->x_yuvbuffer.uv_stride; + } + } + if ( !x->x_autoplay ) + { + x->x_newpicture = 1; + } + else + { + x->x_newpictureready = 1; + } + } + } + + if ( x->x_newpictureready ) + { + if ( gettimeofday(&ctime, NULL) == -1) + { + post("pdp_theorin~ : could not read time" ); + } + + tplaying = ( ctime.tv_sec-x->x_starttime.tv_sec )*1000 + + ( ctime.tv_usec-x->x_starttime.tv_usec )/1000; + ttheoretical = ((x->x_nbframes)*1000 )/x->x_framerate; + // post( "pdp-theorin~ : %d playing since : %lldms ( theory : %lldms )", + // x->x_nbframes, tplaying, ttheoretical ); + + if ( ttheoretical <= tplaying ) + { + x->x_newpicture = 1; + x->x_newpictureready = 0; + } + + } + + // check end of file + if(!x->x_videoready && feof(x->x_infile)) + { + if ( x->x_loop ) + { + if ( fseek( x->x_infile, 0x0, SEEK_SET ) < 0 ) + { + post( "pdp_theorin~ : could not reset file." ); + perror( "fseek" ); + } + } + } + + // read more data in + if( ( x->x_audioin_position < MIN_AUDIO_SIZE ) || ( !x->x_newpicture && !x->x_newpictureready ) ) + { + ret=pdp_theorin_get_buffer_from_file(x->x_infile, &x->x_sync_state); + // post( "pdp_theorin~ : read %d bytes from file", ret ); + while( ogg_sync_pageout(&x->x_sync_state, &x->x_ogg_page)>0 ) + { + pdp_theorin_queue_page(x); + } + } + + x->x_videoready = 0; + + return 0; + +} + +static void *pdp_decode_file(void *tdata) +{ + t_pdp_theorin *x = (t_pdp_theorin*)tdata; + struct sched_param schedprio; + t_int pmin, pmax, p1; + struct timespec twait; + + twait.tv_sec = 0; + twait.tv_nsec = 5000000; // 5 ms + + schedprio.sched_priority = sched_get_priority_min(SCHED_FIFO) + x->x_priority; + if ( sched_setscheduler(0, SCHED_FIFO, &schedprio) == -1) + { + post("pdp_theorin~ : couldn't set priority for decoding thread."); + } + + while ( x->x_decodechild ) + { + if ( ( x->x_reading ) && ( ( x->x_autoplay ) || ( x->x_nextimage == 1 ) ) ) + { + x->x_decoding = 1; + + // decode incoming packets + if ( x->x_reading ) pdp_theorin_decode_packet( x ); + nanosleep( &twait, NULL ); + x->x_nextimage = -1; + } + else + { + x->x_decoding = 0; + nanosleep( &twait, NULL ); // nothing to do, just wait + } + } + + x->x_decoding = 0; + post("pdp_theorin~ : decoding child exiting." ); + return NULL; +} + +static void pdp_theorin_close(t_pdp_theorin *x) +{ + t_int ret, i, count=0; + struct timespec twait; + + twait.tv_sec = 0; + twait.tv_nsec = 10000000; // 10 ms + + if ( x->x_infile == NULL ) + { + post("pdp_theorin~ : close request but no file is played ... ignored" ); + return; + } + + if ( x->x_reading ) + { + x->x_newpicture = 0; + x->x_reading = 0; + post("pdp_theorin~ : waiting end of decoding..." ); + while ( x->x_decoding ) nanosleep( &twait, NULL ); + + if ( fclose( x->x_infile ) < 0 ) + { + post( "pdp_theorin~ : could not close input file" ); + perror( "fclose" ); + } + x->x_infile = NULL; + + if ( x->x_notpackets > 0 ) + { + ogg_stream_clear(&x->x_statet); + theora_clear(&x->x_theora_state); + theora_comment_clear(&x->x_theora_comment); + theora_info_clear(&x->x_theora_info); + } + + if ( x->x_novpackets > 0 ) + { + ogg_stream_clear(&x->x_statev); + vorbis_block_clear(&x->x_vorbis_block); + vorbis_dsp_clear(&x->x_dsp_state); + vorbis_comment_clear(&x->x_vorbis_comment); + vorbis_info_clear(&x->x_vorbis_info); + } + + } + + x->x_notpackets = 0; + x->x_novpackets = 0; + x->x_endoffile = 0; + x->x_nbframes = 0; + x->x_decoding = 0; + x->x_theorainit = 0; + + x->x_videoready = 0; + x->x_newpicture = 0; + + x->x_nbframes = 0; + outlet_float( x->x_outlet_nbframes, x->x_nbframes ); + x->x_framerate = 0; + outlet_float( x->x_outlet_framerate, x->x_framerate ); +} + +static void pdp_theorin_open(t_pdp_theorin *x, t_symbol *s) +{ + t_int ret, i; + pthread_attr_t decode_child_attr; + ogg_stream_state o_tempstate; + struct stat fileinfos; + + if ( x->x_infile != NULL ) + { + post("pdp_theorin~ : open request but a file is open ... closing" ); + pdp_theorin_close(x); + } + + if ( x->x_filename ) free( x->x_filename ); + x->x_filename = (char*) malloc( strlen( s->s_name ) + 1 ); + strcpy( x->x_filename, s->s_name ); + post( "pdp_theorin~ : opening file : %s", x->x_filename ); + + if ( ( x->x_infile = fopen(x->x_filename,"r") ) == NULL ) + { + post( "pdp_theorin~ : unable to open file >%s<", x->x_filename ); + return; + } + + ogg_sync_init(&x->x_sync_state); + + // init supporting Vorbis structures needed in header parsing + vorbis_info_init(&x->x_vorbis_info); + vorbis_comment_init(&x->x_vorbis_comment); + + // init supporting Theora structures needed in header parsing + theora_comment_init(&x->x_theora_comment); + theora_info_init(&x->x_theora_info); + + // parse headers + while( !x->x_theorainit ) + { + if ( ( ret = pdp_theorin_get_buffer_from_file(x->x_infile, &x->x_sync_state) )==0) break; + + while( ogg_sync_pageout(&x->x_sync_state, &x->x_ogg_page) > 0 ) + { + /* is this a mandated initial header? If not, stop parsing */ + if(!ogg_page_bos(&x->x_ogg_page)) + { + pdp_theorin_queue_page(x); + x->x_theorainit = 1; + break; + } + + ogg_stream_init(&o_tempstate, ogg_page_serialno(&x->x_ogg_page)); + ogg_stream_pagein(&o_tempstate, &x->x_ogg_page); + ogg_stream_packetout(&o_tempstate, &x->x_ogg_packet); + + /* identify the codec: try theora */ + if(!x->x_notpackets && + theora_decode_header(&x->x_theora_info, &x->x_theora_comment, &x->x_ogg_packet)>=0) + { + /* it is theora */ + memcpy(&x->x_statet, &o_tempstate, sizeof(o_tempstate)); + x->x_notpackets=1; + }else + if(!x->x_novpackets && + vorbis_synthesis_headerin(&x->x_vorbis_info, &x->x_vorbis_comment, &x->x_ogg_packet)>=0){ + memcpy(&x->x_statev, &o_tempstate, sizeof(o_tempstate)); + x->x_novpackets=1; + }else{ + /* whatever it is, we don't care about it */ + ogg_stream_clear(&o_tempstate); + } + } + } + + // we're expecting more header packets. + while( (x->x_notpackets && x->x_notpackets<3) || (x->x_novpackets && x->x_novpackets<3) ) + { + // look for further theora headers + while(x->x_notpackets && (x->x_notpackets<3) && + (ret=ogg_stream_packetout(&x->x_statet, &x->x_ogg_packet))) + { + if( ret<0 ) + { + post("pdp_theorin~ : error parsing theora stream headers\n"); + x->x_theorainit = 0; + return; + } + if( theora_decode_header(&x->x_theora_info, &x->x_theora_comment, &x->x_ogg_packet) ) + { + post("pdp_theorin~ : error parsing theora stream headers\n"); + x->x_theorainit = 0; + return; + } + x->x_notpackets++; + if(x->x_notpackets==3) break; + } + + /* look for more vorbis header packets */ + while(x->x_novpackets && (x->x_novpackets<3) && + (ret=ogg_stream_packetout(&x->x_statev, &x->x_ogg_packet))) + { + if(ret<0) + { + post("pdp_theorin~ : error parsing theora stream headers\n"); + x->x_theorainit = 0; + return; + } + if( vorbis_synthesis_headerin(&x->x_vorbis_info, &x->x_vorbis_comment, &x->x_ogg_packet) ) + { + post("pdp_theorin~ : error parsing theora stream headers\n"); + x->x_theorainit = 0; + return; + } + x->x_novpackets++; + if(x->x_novpackets==3) break; + } + + if(ogg_sync_pageout(&x->x_sync_state, &x->x_ogg_page)>0) + { + pdp_theorin_queue_page(x); + } + else + { + if( (ret=pdp_theorin_get_buffer_from_file(x->x_infile, &x->x_sync_state))==0 ) + { + post("pdp_theorin~ : end of file while parsing headers\n"); + x->x_theorainit = 0; + return; + } + } + } + post( "pdp_theorin~ : parsed headers ok." ); + + // initialize decoders + if( x->x_notpackets ) + { + theora_decode_init(&x->x_theora_state, &x->x_theora_info); + x->x_framerate = (t_int)x->x_theora_info.fps_numerator/x->x_theora_info.fps_denominator; + post("pdp_theorin~ : stream %x is theora %dx%d %d fps video.", + x->x_statet.serialno, + x->x_theora_info.width,x->x_theora_info.height, + x->x_framerate); + if(x->x_theora_info.width!=x->x_theora_info.frame_width || + x->x_theora_info.height!=x->x_theora_info.frame_height) + { + post("pdp_theorin~ : frame content is %dx%d with offset (%d,%d).", + x->x_theora_info.frame_width, x->x_theora_info.frame_height, + x->x_theora_info.offset_x, x->x_theora_info.offset_y); + } + x->x_vwidth = x->x_theora_info.width; + x->x_vheight = x->x_theora_info.height; + x->x_vsize = x->x_vwidth*x->x_vheight; + + switch(x->x_theora_info.colorspace) + { + case OC_CS_UNSPECIFIED: + /* nothing to report */ + break;; + case OC_CS_ITU_REC_470M: + post("pdp_theorin~ : encoder specified ITU Rec 470M (NTSC) color."); + break;; + case OC_CS_ITU_REC_470BG: + post("pdp_theorin~ : encoder specified ITU Rec 470BG (PAL) color."); + break;; + default: + post("pdp_theorin~ : warning: encoder specified unknown colorspace (%d).", + x->x_theora_info.colorspace); + break;; + } + } + else + { + // tear down the partial theora setup + theora_info_clear(&x->x_theora_info); + theora_comment_clear(&x->x_theora_comment); + post("pdp_theorin~ : could not initialize theora decoder."); + x->x_theorainit = 0; + return; + } + + if( x->x_novpackets ) + { + vorbis_synthesis_init(&x->x_dsp_state, &x->x_vorbis_info); + vorbis_block_init(&x->x_dsp_state, &x->x_vorbis_block); + x->x_audiochannels = x->x_vorbis_info.channels; + x->x_samplerate = x->x_vorbis_info.rate; + post("pdp_theorin~ : ogg logical stream %x is vorbis %d channel %d Hz audio.", + x->x_statev.serialno, + x->x_audiochannels, x->x_samplerate); + } + else + { + /* tear down the partial vorbis setup */ + vorbis_info_clear(&x->x_vorbis_info); + vorbis_comment_clear(&x->x_vorbis_comment); + post("pdp_theorin~ : could not initialize vorbis decoder."); + // x->x_theorainit = 0; + // return; + x->x_audio = 0; + } + // everything seems to be ready + x->x_reading = 1; + + if ( x->x_usethread && ( x->x_decodechild == 0 ) ) + { + x->x_decodechild = 1; // trick & treets + // launch decoding thread + if ( pthread_attr_init( &decode_child_attr ) < 0 ) + { + post( "pdp_theorin~ : could not launch decoding thread" ); + perror( "pthread_attr_init" ); + pthread_exit(NULL); + } + if ( pthread_create( &x->x_decodechild, &decode_child_attr, pdp_decode_file, x ) < 0 ) + { + post( "pdp_theorin~ : could not launch decoding thread" ); + perror( "pthread_create" ); + pthread_exit(NULL); + } + else + { + // post( "pdp_theorin~ : decoding thread %d launched", (int)x->x_decodechild ); + } + } + + if ( stat( x->x_filename, &fileinfos ) < 0 ) + { + post("pdp_theorin~ : couldn't get file informations" ); + perror( "stat" ); + } + else + { + outlet_float( x->x_outlet_filesize, (fileinfos.st_size)/1024 ); + } + + if ( gettimeofday(&x->x_starttime, NULL) == -1) + { + post("pdp_theorin~ : could not set start time" ); + } + + x->x_nbframes = 0; + x->x_endoffile = -1; + + return; +} + +static void pdp_theorin_frame_cold(t_pdp_theorin *x, t_floatarg kbytes) +{ + int pos = (int)kbytes; + int ret; + + if (x->x_infile==NULL) return; + + pdp_theorin_open(x, gensym(x->x_filename)); + + // it's very approximative, we're are positioning the file on the number of requested kilobytes + if ( fseek( x->x_infile, pos*1024, SEEK_SET ) < 0 ) + { + post( "pdp_theorin~ : could not set file at that position (%d kilobytes)", pos ); + perror( "fseek" ); + return; + } + // post( "pdp_theorin~ : file seeked at %d kilobytes", pos ); +} + + /* decode the audio buffer */ +static t_int *pdp_theorin_perform(t_int *w) +{ + t_float *out1 = (t_float *)(w[1]); // left audio inlet + t_float *out2 = (t_float *)(w[2]); // right audio inlet + t_pdp_theorin *x = (t_pdp_theorin *)(w[3]); + int n = (int)(w[4]); // number of samples + struct timeval etime; + t_int sn; + + // decode a packet if not in thread mode + if ( !x->x_usethread && x->x_reading ) + { + pdp_theorin_decode_packet( x ); + } + + x->x_blocksize = n; + + // just read the buffer + if ( x->x_audioon ) + { + sn=0; + while (n--) + { + *(out1)=x->x_audio_inl[ sn ]; + if ( x->x_audiochannels == 1 ) + { + *(out2) = *(out1); + sn++; + } + if ( x->x_audiochannels == 2 ) + { + *(out2)=x->x_audio_inr[ sn++ ]; + } + out1++; + out2++; + } + memcpy( &x->x_audio_inl[0], &x->x_audio_inl[sn], (x->x_audioin_position-sn)*sizeof(t_float) ); + memcpy( &x->x_audio_inr[0], &x->x_audio_inr[sn], (x->x_audioin_position-sn)*sizeof(t_float) ); + x->x_audioin_position-=sn; + // post( "pdp_theorin~ : audio in position : %d", x->x_audioin_position ); + if ( x->x_audioin_position <= sn ) + { + x->x_audioon = 0; + // post( "pdp_theorin~ : audio off ( audioin : %d, channels=%d )", + // x->x_audioin_position, x->x_audiochannels ); + } + } + else + { + // post("pdp_theorin~ : no available audio" ); + while (n--) + { + *(out1++) = 0.0; + *(out2++) = 0.0; + } + } + + // check if the framerate has been exceeded + if ( gettimeofday(&etime, NULL) == -1) + { + post("pdp_theorin~ : could not read time" ); + } + if ( etime.tv_sec != x->x_cursec ) + { + x->x_cursec = etime.tv_sec; + if (x->x_reading) outlet_float( x->x_outlet_framerate, x->x_secondcount ); + x->x_secondcount = 0; + } + + // output image if there's a new one decoded + if ( x->x_newpicture ) + { + pdp_packet_pass_if_valid(x->x_pdp_out, &x->x_packet0); + x->x_newpicture = 0; + + // update streaming status + x->x_nbframes++; + x->x_secondcount++; + outlet_float( x->x_outlet_nbframes, x->x_nbframes ); + + } + if ( x->x_endoffile == 1 ) // only once + { + outlet_float( x->x_outlet_endoffile, x->x_endoffile ); + x->x_endoffile = 0; + } + if ( x->x_endoffile == -1 ) // reset + { + x->x_endoffile = 0; + outlet_float( x->x_outlet_endoffile, x->x_endoffile ); + } + + return (w+5); +} + +static void pdp_theorin_dsp(t_pdp_theorin *x, t_signal **sp) +{ + dsp_add(pdp_theorin_perform, 4, sp[0]->s_vec, sp[1]->s_vec, x, sp[0]->s_n); +} + +static void pdp_theorin_free(t_pdp_theorin *x) +{ + int i; + + if ( x->x_decodechild ) + { + x->x_decodechild = 0; + } + + if ( x->x_reading ) + { + pdp_theorin_close(x); + } + + post( "pdp_theorin~ : freeing object" ); +} + +t_class *pdp_theorin_class; + +void *pdp_theorin_new(void) +{ + int i; + + t_pdp_theorin *x = (t_pdp_theorin *)pd_new(pdp_theorin_class); + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("frame_cold")); + + x->x_pdp_out = outlet_new(&x->x_obj, &s_anything); + + x->x_outlet_left = outlet_new(&x->x_obj, &s_signal); + x->x_outlet_right = outlet_new(&x->x_obj, &s_signal); + + x->x_outlet_nbframes = outlet_new(&x->x_obj, &s_float); + x->x_outlet_framerate = outlet_new(&x->x_obj, &s_float); + x->x_outlet_endoffile = outlet_new(&x->x_obj, &s_float); + x->x_outlet_filesize = outlet_new(&x->x_obj, &s_float); + + x->x_packet0 = -1; + x->x_decodechild = 0; + x->x_decoding = 0; + x->x_theorainit = 0; + x->x_usethread = 1; + x->x_priority = DEFAULT_PRIORITY; + x->x_framerate = DEFAULT_FRAME_RATE; + x->x_nbframes = 0; + x->x_samplerate = 0; + x->x_audio = 1; + x->x_audiochannels = 0; + x->x_audioin_position = 0; + x->x_videoready = 0; + x->x_newpicture = 0; + x->x_newpictureready = 0; + x->x_endoffile = 0; + x->x_notpackets = 0; + x->x_novpackets = 0; + x->x_blocksize = MIN_AUDIO_SIZE; + x->x_autoplay = 1; + x->x_loop = 1; + x->x_nextimage = 0; + x->x_infile = NULL; + x->x_reading = 0; + + memset( &x->x_audio_inl[0], 0x0, 4*MAX_AUDIO_PACKET_SIZE*sizeof(t_float) ); + memset( &x->x_audio_inr[0], 0x0, 4*MAX_AUDIO_PACKET_SIZE*sizeof(t_float) ); + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_theorin_tilde_setup(void) +{ + // post( pdp_theorin_version ); + pdp_theorin_class = class_new(gensym("pdp_theorin~"), (t_newmethod)pdp_theorin_new, + (t_method)pdp_theorin_free, sizeof(t_pdp_theorin), 0, A_NULL); + + class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_dsp, gensym("dsp"), A_NULL); + class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_open, gensym("open"), A_SYMBOL, A_NULL); + class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_close, gensym("close"), A_NULL); + class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_priority, gensym("priority"), A_FLOAT, A_NULL); + class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_audio, gensym("audio"), A_FLOAT, A_NULL); + class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_autoplay, gensym("autoplay"), A_FLOAT, A_NULL); + class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_loop, gensym("loop"), A_FLOAT, A_NULL); + class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_threadify, gensym("thread"), A_FLOAT, A_NULL); + class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_bang, gensym("bang"), A_NULL); + class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_frame_cold, gensym("frame_cold"), A_FLOAT, A_NULL); + class_sethelpsymbol( pdp_theorin_class, gensym("pdp_theorin~.pd") ); + +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/pdp_theorout~.c b/modules/pdp_theorout~.c new file mode 100644 index 0000000..96d610a --- /dev/null +++ b/modules/pdp_theorout~.c @@ -0,0 +1,884 @@ +/* + * PiDiP module. + * Copyright (c) by Yves Degoyon <ydegoyon@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* This object is a theora file encoder object + * It uses libtheora and some of it code samples ( copyright xiph.org ) + * Copyleft by Yves Degoyon ( ydegoyon@free.fr ) + * + */ + + +#include "pdp.h" +#include <math.h> +#include <time.h> +#include <sys/time.h> +#include <theora/theora.h> +#include <vorbis/codec.h> +#include <vorbis/vorbisenc.h> + +#define DEFAULT_FRAME_RATE 25 +#define MIN_VIDEO_QUALITY 0 +#define MAX_VIDEO_QUALITY 63 +#define DEFAULT_VIDEO_QUALITY 16 +#define MIN_VIDEO_BITRATE 45 +#define MAX_VIDEO_BITRATE 2000 +#define DEFAULT_VIDEO_BITRATE 96 +#define MIN_AUDIO_QUALITY -0.1 +#define MAX_AUDIO_QUALITY 1.0 +#define DEFAULT_AUDIO_QUALITY 0.5 +#define MIN_AUDIO_BITRATE 8 +#define MAX_AUDIO_BITRATE 2000 +#define DEFAULT_AUDIO_BITRATE 32 + +#define DEFAULT_CHANNELS 2 +#define DEFAULT_BITS 8 +#define MAX_AUDIO_PACKET_SIZE (128 * 1024) +// streams hard-coded serial numbers +#define STREAMV_SNO 0x987654 +#define STREAMA_SNO 0x456789 + +#ifndef _REENTRANT +# define _REENTRANT +#endif + +static char *pdp_theorout_version = "pdp_theorout~: version 0.1, a theora video/audio recording object, written by ydegoyon@free.fr"; + +typedef struct pdp_theorout_struct +{ + t_object x_obj; + t_float x_f; + + t_outlet *x_outlet0; + t_int x_packet0; + t_int x_packet1; + t_int x_dropped; + t_int x_queue_id; + + t_int x_vwidth; + t_int x_tvwidth; /* theora 16 pixels aligned width value */ + t_int x_vheight; + t_int x_tvheight; /* theora 16 pixels aligned height value */ + t_int x_vsize; + + FILE *x_tfile; + t_int x_framerate; + t_int x_newfile; + t_int x_einit; + t_int x_recflag; + t_int x_enduprec;; + t_int x_frameswritten; + t_int x_frames; + struct timeval x_tstart; + struct timeval x_tzero; + struct timeval x_tcurrent; + struct timeval x_tlastrec; + + /* vorbis/theora structures */ + ogg_page x_ogg_page; // ogg page + ogg_packet x_ogg_packet; // ogg packet + ogg_stream_state x_statev; // vorbis stream state + ogg_stream_state x_statet; // theora stream state + theora_info x_theora_info; // theora info + theora_comment x_theora_comment; // theora comment + theora_state x_theora_state; // theora state + vorbis_info x_vorbis_info; // vorbis info + vorbis_dsp_state x_dsp_state; // vorbis dsp state + vorbis_block x_vorbis_block; // vorbis block + vorbis_comment x_vorbis_comment; // vorbis comment + yuv_buffer x_yuvbuffer; // yuv buffer + + t_int x_akbps; // audio bit rate + t_int x_vkbps; // video bit rate + t_float x_aquality; // audio quality + t_int x_vquality; // video quality + t_int x_abytesout; // audio bytes written + t_int x_vbytesout; // video bytes written + + /* audio structures */ + t_float **x_audio_buf; /* buffer for incoming audio */ + t_int x_audioin_position; // writing position for incoming audio + t_int x_channels; // audio channels + t_int x_samplerate; // audio sample rate + t_int x_bits; // audio bits + +} t_pdp_theorout; + + /* allocate internal ressources */ +static void pdp_theorout_allocate(t_pdp_theorout *x) +{ + int ret; + + x->x_yuvbuffer.y_width=x->x_vwidth; + x->x_yuvbuffer.y_height=x->x_vheight; + x->x_yuvbuffer.y_stride=x->x_vwidth; + + x->x_yuvbuffer.uv_width=x->x_vwidth>>1; + x->x_yuvbuffer.uv_height=x->x_vheight>>1; + x->x_yuvbuffer.uv_stride=x->x_vwidth>>1; + + x->x_yuvbuffer.y = (char *)malloc( x->x_yuvbuffer.y_width * x->x_yuvbuffer.y_height ); + x->x_yuvbuffer.u = (char *)malloc( x->x_yuvbuffer.uv_width * x->x_yuvbuffer.uv_height ); + x->x_yuvbuffer.v = (char *)malloc( x->x_yuvbuffer.uv_width * x->x_yuvbuffer.uv_height ); +} + + /* free internal ressources */ +static void pdp_theorout_free_ressources(t_pdp_theorout *x) +{ + if ( x->x_yuvbuffer.y ) free( x->x_yuvbuffer.y ); + if ( x->x_yuvbuffer.u ) free( x->x_yuvbuffer.u ); + if ( x->x_yuvbuffer.v ) free( x->x_yuvbuffer.v ); +} + + /* initialize the encoder */ +static void pdp_theorout_init_encoder(t_pdp_theorout *x) +{ + t_int ret; + + x->x_einit=0; + + // init streams + ogg_stream_init(&x->x_statet, STREAMA_SNO); + ogg_stream_init(&x->x_statev, STREAMV_SNO); + + theora_info_init(&x->x_theora_info); + x->x_theora_info.width=x->x_tvwidth; + x->x_theora_info.height=x->x_tvheight; + x->x_theora_info.frame_width=x->x_vwidth; + x->x_theora_info.frame_height=x->x_vheight; + x->x_theora_info.offset_x=(x->x_tvwidth-x->x_vwidth)>>1; + x->x_theora_info.offset_y=(x->x_tvheight-x->x_vheight)>>1; + x->x_theora_info.fps_numerator=x->x_framerate; + x->x_theora_info.fps_denominator=1; + x->x_theora_info.aspect_numerator=x->x_vwidth; + x->x_theora_info.aspect_denominator=x->x_vheight; + x->x_theora_info.colorspace=OC_CS_UNSPECIFIED; + x->x_theora_info.target_bitrate=x->x_vkbps; + x->x_theora_info.quality=x->x_vquality; + + x->x_theora_info.dropframes_p=0; + x->x_theora_info.quick_p=1; + x->x_theora_info.keyframe_auto_p=1; + x->x_theora_info.keyframe_frequency=64; + x->x_theora_info.keyframe_frequency_force=64; + x->x_theora_info.keyframe_data_target_bitrate=x->x_vkbps*1.5; + x->x_theora_info.keyframe_auto_threshold=80; + x->x_theora_info.keyframe_mindistance=8; + x->x_theora_info.noise_sensitivity=1; + + theora_encode_init(&x->x_theora_state,&x->x_theora_info); + + vorbis_info_init(&x->x_vorbis_info); + + if(x->x_aquality > -0.1) + { + ret = vorbis_encode_init_vbr(&x->x_vorbis_info, x->x_channels, x->x_samplerate, x->x_aquality); + } + else + { + ret = vorbis_encode_init(&x->x_vorbis_info, x->x_channels, x->x_samplerate, -1, x->x_akbps, -1); + } + + if (ret) + { + post( "pdp_theorout~ : could not initialize vorbis encoder" ); + x->x_einit=0; + return; + } + + vorbis_comment_init(&x->x_vorbis_comment); + vorbis_analysis_init(&x->x_dsp_state,&x->x_vorbis_info); + vorbis_block_init(&x->x_dsp_state,&x->x_vorbis_block); + + post( "pdp_theorout~ : encoder initialized." ); + x->x_einit=1; + +} + +static void pdp_theorout_write_headers(t_pdp_theorout *x) +{ + t_int ret; + ogg_packet aheader, aheadercomm, aheadercode; + + if ( !x->x_einit ) + { + post( "pdp_theorout~ : trying to write headers but encoder is not initialized." ); + return; + } + + if ( x->x_tfile == NULL ) + { + post( "pdp_theorout~ : trying to write headers but no file is opened." ); + return; + } + + theora_encode_header(&x->x_theora_state, &x->x_ogg_packet); + ogg_stream_packetin(&x->x_statet, &x->x_ogg_packet); + if(ogg_stream_pageout(&x->x_statet, &x->x_ogg_page)!=1) + { + post( "pdp_theorout~ : ogg encoding error." ); + return; + } + if ( ( ret = fwrite(x->x_ogg_page.header, 1, x->x_ogg_page.header_len, x->x_tfile) ) <= 0 ) + { + post( "pdp_theorout~ : could not write headers (ret=%d).", ret ); + perror( "fwrite" ); + return; + } + if ( ( ret = fwrite(x->x_ogg_page.body, 1, x->x_ogg_page.body_len, x->x_tfile) ) <= 0 ) + { + post( "pdp_theorout~ : could not write headers (ret=%d).", ret ); + perror( "fwrite" ); + return; + } + + theora_comment_init(&x->x_theora_comment); + theora_encode_comment(&x->x_theora_comment, &x->x_ogg_packet); + ogg_stream_packetin(&x->x_statet, &x->x_ogg_packet); + theora_encode_tables(&x->x_theora_state, &x->x_ogg_packet); + ogg_stream_packetin(&x->x_statet, &x->x_ogg_packet); + + vorbis_analysis_headerout(&x->x_dsp_state, &x->x_vorbis_comment, + &aheader,&aheadercomm,&aheadercode); + ogg_stream_packetin(&x->x_statev,&aheader); + + if(ogg_stream_pageout(&x->x_statev, &x->x_ogg_page)!=1) + { + post( "pdp_theorout~ : ogg encoding error." ); + return; + } + if ( ( ret = fwrite(x->x_ogg_page.header, 1, x->x_ogg_page.header_len, x->x_tfile) ) <= 0 ) + { + post( "pdp_theorout~ : could not write headers (ret=%d).", ret ); + perror( "fwrite" ); + return; + } + if ( ( ret = fwrite(x->x_ogg_page.body, 1, x->x_ogg_page.body_len, x->x_tfile) ) <= 0 ) + { + post( "pdp_theorout~ : could not write headers (ret=%d).", ret ); + perror( "fwrite" ); + return; + } + + // remaining vorbis header packets + ogg_stream_packetin(&x->x_statev, &aheadercomm); + ogg_stream_packetin(&x->x_statev, &aheadercode); + + // flush all the headers + while(1) + { + ret = ogg_stream_flush(&x->x_statet, &x->x_ogg_page); + if(ret<0){ + post( "pdp_theorout~ : ogg encoding error." ); + return; + } + if(ret==0)break; + if ( ( ret = fwrite(x->x_ogg_page.header, 1, x->x_ogg_page.header_len, x->x_tfile) ) <= 0 ) + { + post( "pdp_theorout~ : could not write headers (ret=%d).", ret ); + perror( "fwrite" ); + return; + } + if ( ( ret = fwrite(x->x_ogg_page.body, 1, x->x_ogg_page.body_len, x->x_tfile) ) <= 0 ) + { + post( "pdp_theorout~ : could not write headers (ret=%d).", ret ); + perror( "fwrite" ); + return; + } + } + + while(1) + { + ret = ogg_stream_flush(&x->x_statev, &x->x_ogg_page); + if(ret<0){ + post( "pdp_theorout~ : ogg encoding error." ); + return; + } + if(ret==0)break; + if ( ( ret = fwrite(x->x_ogg_page.header, 1, x->x_ogg_page.header_len, x->x_tfile) ) <= 0 ) + { + post( "pdp_theorout~ : could not write headers (ret=%d).", ret ); + perror( "fwrite" ); + return; + } + if ( ( ret = fwrite(x->x_ogg_page.body, 1, x->x_ogg_page.body_len, x->x_tfile) ) <= 0 ) + { + post( "pdp_theorout~ : could not write headers (ret=%d).", ret ); + perror( "fwrite" ); + return; + } + } +} + + /* terminate the encoding process */ +static void pdp_theorout_shutdown_encoder(t_pdp_theorout *x) +{ + ogg_stream_clear(&x->x_statev); + vorbis_block_clear(&x->x_vorbis_block); + vorbis_dsp_clear(&x->x_dsp_state); + vorbis_comment_clear(&x->x_vorbis_comment); + vorbis_info_clear(&x->x_vorbis_info); + ogg_stream_clear(&x->x_statet); + theora_clear(&x->x_theora_state); +} + + + /* close a video file */ +static void pdp_theorout_close(t_pdp_theorout *x) +{ + int ret; + + if ( x->x_tfile ) + { + if ( fclose( x->x_tfile ) < 0 ) + { + post( "pdp_theorout~ : could not close output file" ); + perror( "fclose" ); + } + x->x_tfile = NULL; + } +} + + /* open a new video file */ +static void pdp_theorout_open(t_pdp_theorout *x, t_symbol *sfile) +{ + t_int ret=0; + + // close previous video file if existing + pdp_theorout_close(x); + + if ( x->x_recflag ) { + x->x_recflag = 0; + } + x->x_frameswritten = 0; + + if ( ( x->x_tfile = fopen( sfile->s_name, "w+" ) ) == NULL ) + { + post( "pdp_theorout~ : could not open output file" ); + perror( "fopen" ); + return; + } + else + { + post( "pdp_theorout~ : opened >%s<", sfile->s_name); + } + x->x_newfile = 1; + +} + + /* start recording */ +static void pdp_theorout_start(t_pdp_theorout *x) +{ + if ( !x->x_tfile ) + { + post("pdp_theorout~ : start received but no file has been opened ... ignored."); + return; + } + + if ( x->x_recflag == 1 ) + { + post("pdp_theorout~ : start received but recording is started ... ignored."); + return; + } + + if ( gettimeofday(&x->x_tstart, NULL) == -1) + { + post("pdp_theorout~ : could not set start time" ); + } + + x->x_recflag = 1; + pdp_theorout_init_encoder( x ); + pdp_theorout_write_headers( x ); + post("pdp_theorout~ : start recording at %d frames/second", x->x_framerate); +} + + /* stop recording */ +static void pdp_theorout_stop(t_pdp_theorout *x) +{ + if ( !x->x_tfile ) + { + post("pdp_theorout~ : stop received but no file has been opened ... ignored."); + return; + } + + if ( x->x_recflag == 0 ) + { + post("pdp_theorout~ : stop received but recording is stopped ... ignored."); + return; + } + + x->x_recflag = 0; + + // record last packet + x->x_enduprec = 1; + +} + + /* set video bitrate */ +static void pdp_theorout_vbitrate(t_pdp_theorout *x, t_floatarg vbitrate ) +{ + if ( ( (t_int) vbitrate < MIN_VIDEO_BITRATE ) || ( (t_int) vbitrate > MAX_VIDEO_BITRATE ) ) + { + post( "pdp_theorout~ : wrong video bitrate %d : should be in [%d,%d] kbps", + (t_int) vbitrate, MIN_VIDEO_BITRATE, MAX_VIDEO_BITRATE ); + return; + } + x->x_vkbps = (t_int) vbitrate; +} + + /* set audio bitrate */ +static void pdp_theorout_abitrate(t_pdp_theorout *x, t_floatarg abitrate ) +{ + if ( ( (t_int) abitrate < MIN_AUDIO_BITRATE ) || ( (t_int) abitrate > MAX_AUDIO_BITRATE ) ) + { + post( "pdp_theorout~ : wrong audio bitrate %d : should be in [%d,%d] kbps", + (t_int) abitrate, MIN_AUDIO_BITRATE, MAX_AUDIO_BITRATE ); + return; + } + x->x_akbps = (t_int) abitrate; +} + + /* set video quality */ +static void pdp_theorout_vquality(t_pdp_theorout *x, t_floatarg vquality ) +{ + if ( ( (t_int) vquality < MIN_VIDEO_QUALITY ) || ( (t_int) vquality > MAX_VIDEO_QUALITY ) ) + { + post( "pdp_theorout~ : wrong video quality %d : should be in [%d,%d]", + (t_int) vquality, MIN_VIDEO_QUALITY, MAX_VIDEO_QUALITY ); + return; + } + x->x_vquality = (t_int) vquality; +} + + /* set audio quality */ +static void pdp_theorout_aquality(t_pdp_theorout *x, t_floatarg aquality ) +{ + if ( ( (t_int) aquality < MIN_AUDIO_QUALITY ) || ( (t_int) aquality > MAX_AUDIO_QUALITY ) ) + { + post( "pdp_theorout~ : wrong audio quality %d : should be in [%d,%d]", + (t_int) aquality, MIN_AUDIO_QUALITY, MAX_AUDIO_QUALITY ); + return; + } + x->x_aquality = (t_int) aquality; +} + + /* store audio data in PCM format in a buffer for now */ +static t_int *pdp_theorout_perform(t_int *w) +{ + t_float *in1 = (t_float *)(w[1]); // left audio inlet + t_float *in2 = (t_float *)(w[2]); // right audio inlet + t_pdp_theorout *x = (t_pdp_theorout *)(w[3]); + int n = (int)(w[4]); // number of samples + t_float fsample; + t_int isample, i; + + if ( x->x_recflag ) + { + // just fills the buffer + while (n--) + { + fsample=*(in1++); + if (fsample > 1.0) { fsample = 1.0; } + if (fsample < -1.0) { fsample = -1.0; } + x->x_audio_buf[0][x->x_audioin_position]=fsample; + fsample=*(in2++); + if (fsample > 1.0) { fsample = 1.0; } + if (fsample < -1.0) { fsample = -1.0; } + x->x_audio_buf[1][x->x_audioin_position]=fsample; + x->x_audioin_position=(x->x_audioin_position+1)%(MAX_AUDIO_PACKET_SIZE); + if ( x->x_audioin_position == MAX_AUDIO_PACKET_SIZE-1 ) + { + post( "pdp_theorout~ : reaching end of audio buffer" ); + } + } + } + + return (w+5); +} + +static void pdp_theorout_dsp(t_pdp_theorout *x, t_signal **sp) +{ + dsp_add(pdp_theorout_perform, 4, sp[0]->s_vec, sp[1]->s_vec, x, sp[0]->s_n); +} + +static void pdp_theorout_process_yv12(t_pdp_theorout *x) +{ + t_pdp *header = pdp_packet_header(x->x_packet0); + unsigned char *data = (unsigned char *)pdp_packet_data(x->x_packet0); + t_int i, ret; + t_int px, py; + char *pY, *pU, *pV; + struct timeval trec; + t_int nbaudiosamples, nbusecs, nbrecorded; + t_float fframerate=0.0; + t_int precflag; + ogg_page apage; + ogg_page vpage; + t_float **vbuffer; + double videotime, audiotime; + + if ( ( (int)(header->info.image.width) != x->x_vwidth ) || + ( (int)(header->info.image.height) != x->x_vheight ) || + ( x->x_newfile ) ) + { + precflag = x->x_recflag; + x->x_recflag = 0; + pdp_theorout_free_ressources( x ); + pdp_theorout_shutdown_encoder( x ); + x->x_vwidth = header->info.image.width; + x->x_vheight = header->info.image.height; + x->x_vsize = x->x_vwidth*x->x_vheight; + x->x_tvwidth=((x->x_vwidth + 15) >>4)<<4; + x->x_tvheight=((x->x_vheight + 15) >>4)<<4; + pdp_theorout_allocate( x ); + if ( x->x_tzero.tv_sec != 0 ) + { + pdp_theorout_init_encoder( x ); + pdp_theorout_write_headers( x ); + } + x->x_recflag = precflag; + x->x_newfile = 0; + } + + if ( x->x_tzero.tv_sec == 0 ) + { + if ( gettimeofday(&x->x_tzero, NULL) == -1) + { + post("pdp_theorout~ : could get initial time" ); + } + } + + x->x_frames++; + + // calculate current framerate + if ( gettimeofday(&x->x_tcurrent, NULL) == -1) + { + post("pdp_theorout~ : could get current time" ); + } + + // calculate frame rate if it hasn't been set + if ( ( x->x_tcurrent.tv_sec - x->x_tzero.tv_sec ) > 0 ) + { + x->x_framerate = x->x_frames / ( x->x_tcurrent.tv_sec - x->x_tzero.tv_sec ); + } + else + { + x->x_framerate = DEFAULT_FRAME_RATE; + } + + if ( x->x_frameswritten == 0 ) + { + if ( gettimeofday(&x->x_tlastrec, NULL) == -1) + { + post("pdp_theorout~ : could set start time" ); + } + } + + pY = x->x_yuvbuffer.y; + memcpy( (void*)pY, (void*)&data[0], x->x_vsize ); + pV = x->x_yuvbuffer.v; + memcpy( (void*)pV, (void*)&data[x->x_vsize], (x->x_vsize>>2) ); + pU = x->x_yuvbuffer.u; + memcpy( (void*)pU, (void*)&data[x->x_vsize+(x->x_vsize>>2)], (x->x_vsize>>2) ); + + if ( x->x_tfile && x->x_recflag && !x->x_enduprec) + { + + if ( ( ret = theora_encode_YUVin( &x->x_theora_state, &x->x_yuvbuffer ) ) != 0 ) + { + post( "pdp_theorout~ : could not encode yuv image (ret=%d).", ret ); + } + else + { + // stream one packet + theora_encode_packetout(&x->x_theora_state, 0, &x->x_ogg_packet); + ogg_stream_packetin(&x->x_statet, &x->x_ogg_packet); + // post( "pdp_theorout~ : new (theora) ogg packet : bytes:%ld, bos:%ld, eos:%ld, no:%lld", + // x->x_ogg_packet.bytes, x->x_ogg_packet.b_o_s, + // x->x_ogg_packet.e_o_s, x->x_ogg_packet.packetno ); + + while( ( ret = ogg_stream_pageout(&x->x_statet, &vpage) ) >0 ) + { + videotime = theora_granule_time(&x->x_theora_state, ogg_page_granulepos(&vpage)); + x->x_vbytesout+=fwrite(vpage.header, 1, vpage.header_len, x->x_tfile ); + x->x_vbytesout+=fwrite(vpage.body, 1, vpage.body_len, x->x_tfile ); + } + } + + // calculate the number of audio samples to output + if ( gettimeofday(&trec, NULL) == -1) + { + post("pdp_theorout~ : could set stop time" ); + } + // calculate time diff in micro seconds + nbusecs = ( trec.tv_usec - x->x_tlastrec.tv_usec ) + + ( trec.tv_sec - x->x_tlastrec.tv_sec )*1000000; + nbaudiosamples = (sys_getsr()*1000000)/nbusecs; + memcpy( &x->x_tlastrec, &trec, sizeof( struct timeval) ); + + if ( x->x_audioin_position > nbaudiosamples ) + { + nbrecorded = nbaudiosamples; + } + else + { + nbrecorded = x->x_audioin_position; + } + + vbuffer=vorbis_analysis_buffer( &x->x_dsp_state, nbrecorded ); + memcpy( (void*)&vbuffer[0][0], (void*)&x->x_audio_buf[0][0], nbrecorded*sizeof( t_float ) ); + memcpy( (void*)&vbuffer[1][0], (void*)&x->x_audio_buf[1][0], nbrecorded*sizeof( t_float ) ); + + vorbis_analysis_wrote( &x->x_dsp_state, nbrecorded); + + while(vorbis_analysis_blockout( &x->x_dsp_state, &x->x_vorbis_block)==1) + { + + // analysis, assume we want to use bitrate management + vorbis_analysis( &x->x_vorbis_block, NULL); + vorbis_bitrate_addblock( &x->x_vorbis_block ); + + // weld packets into the bitstream + while(vorbis_bitrate_flushpacket( &x->x_dsp_state, &x->x_ogg_packet)) + { + ogg_stream_packetin( &x->x_statev, &x->x_ogg_packet); + } + + } + + while( ogg_stream_pageout( &x->x_statev, &apage) >0 ) + { + audiotime = vorbis_granule_time(&x->x_dsp_state, ogg_page_granulepos(&apage)); + x->x_abytesout+=fwrite(apage.header, 1, apage.header_len, x->x_tfile ); + x->x_abytesout+=fwrite(apage.body, 1, apage.body_len, x->x_tfile ); + } + + memcpy( &x->x_audio_buf[0][0], &x->x_audio_buf[0][nbrecorded], + ( x->x_audioin_position-nbrecorded ) * sizeof( t_float ) ); + memcpy( &x->x_audio_buf[1][0], &x->x_audio_buf[1][nbrecorded], + ( x->x_audioin_position-nbrecorded ) * sizeof( t_float ) ); + x->x_audioin_position -= nbrecorded; + // post ( "pdp_theorout~ : recorded %d samples.", nbrecorded ); + + x->x_frameswritten++; + + } + + if ( x->x_tfile && x->x_enduprec ) + { + x->x_enduprec = 0; + post( "pdp_theorout~ : ending up recording." ); + x->x_frameswritten++; + + if ( ( ret = theora_encode_YUVin( &x->x_theora_state, &x->x_yuvbuffer ) ) != 0 ) + { + post( "pdp_theorout~ : could not encode yuv image (ret=%d).", ret ); + } + else + { + // stream one packet + theora_encode_packetout(&x->x_theora_state, 1, &x->x_ogg_packet); + ogg_stream_packetin( &x->x_statet, &x->x_ogg_packet); + + while( ( ret = ogg_stream_pageout( &x->x_statet, &vpage) ) > 0 ) + { + videotime = theora_granule_time(&x->x_theora_state, ogg_page_granulepos(&vpage)); + x->x_vbytesout+=fwrite(vpage.header, 1, vpage.header_len, x->x_tfile ); + x->x_vbytesout+=fwrite(vpage.body, 1, vpage.body_len, x->x_tfile ); + } + } + + // end up audio stream + vorbis_analysis_wrote( &x->x_dsp_state, 0); + + while(vorbis_analysis_blockout( &x->x_dsp_state, &x->x_vorbis_block)==1) + { + // analysis, assume we want to use bitrate management + vorbis_analysis( &x->x_vorbis_block, NULL); + vorbis_bitrate_addblock( &x->x_vorbis_block); + + // weld packets into the bitstream + while(vorbis_bitrate_flushpacket( &x->x_dsp_state, &x->x_ogg_packet)) + { + ogg_stream_packetin( &x->x_statev, &x->x_ogg_packet); + } + } + + while( ogg_stream_pageout( &x->x_statev, &apage) >0 ) + { + audiotime = vorbis_granule_time(&x->x_dsp_state, ogg_page_granulepos(&apage)); + x->x_abytesout+=fwrite(apage.header, 1, apage.header_len, x->x_tfile ); + x->x_abytesout+=fwrite(apage.body, 1, apage.body_len, x->x_tfile ); + } + + post("pdp_theorout~ : stop recording"); + + pdp_theorout_shutdown_encoder( x ); + pdp_theorout_close(x); + } + + return; +} + +static void pdp_theorout_killpacket(t_pdp_theorout *x) +{ + /* release the packet */ + pdp_packet_mark_unused(x->x_packet0); + x->x_packet0 = -1; +} + +static void pdp_theorout_process(t_pdp_theorout *x) +{ + int encoding; + t_pdp *header = 0; + + /* check if image data packets are compatible */ + if ( (header = pdp_packet_header(x->x_packet0)) + && (PDP_BITMAP == header->type)){ + + /* pdp_theorout_process inputs and write into active inlet */ + switch(pdp_packet_header(x->x_packet0)->info.image.encoding) + { + + case PDP_BITMAP_YV12: + if ( x->x_tfile && x->x_recflag ) + { + outlet_float( x->x_obj.ob_outlet, x->x_frameswritten ); + } + pdp_queue_add(x, pdp_theorout_process_yv12, pdp_theorout_killpacket, &x->x_queue_id); + break; + + default: + /* don't know the type, so dont pdp_theorout_process */ + break; + + } + } + +} + +static void pdp_theorout_input_0(t_pdp_theorout *x, t_symbol *s, t_floatarg f) +{ + /* if this is a register_ro message or register_rw message, register with packet factory */ + + if (s== gensym("register_rw")) + { + x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("bitmap/yv12/*") ); + } + + if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)) + { + /* add the process method and callback to the process queue */ + pdp_theorout_process(x); + } + +} + +static void pdp_theorout_free(t_pdp_theorout *x) +{ + int i; + + pdp_queue_finish(x->x_queue_id); + pdp_packet_mark_unused(x->x_packet0); + // close video file if existing + pdp_theorout_close(x); + for ( i=0; i<x->x_channels; i++) + { + if ( x->x_audio_buf[i] ) freebytes( x->x_audio_buf[i], MAX_AUDIO_PACKET_SIZE*sizeof(t_float) ); + } + if ( x->x_audio_buf ) freebytes( x->x_audio_buf, x->x_channels*sizeof(t_float*) ); + +} + +t_class *pdp_theorout_class; + +void *pdp_theorout_new(void) +{ + t_int i; + + t_pdp_theorout *x = (t_pdp_theorout *)pd_new(pdp_theorout_class); + inlet_new (&x->x_obj, &x->x_obj.ob_pd, gensym ("signal"), gensym ("signal")); + outlet_new (&x->x_obj, &s_float); + + x->x_packet0 = -1; + x->x_packet1 = -1; + x->x_queue_id = -1; + + x->x_tfile = NULL; + x->x_yuvbuffer.y = NULL; + x->x_yuvbuffer.u = NULL; + x->x_yuvbuffer.v = NULL; + + /* audio defaults */ + x->x_samplerate = sys_getsr(); + x->x_channels = DEFAULT_CHANNELS; + x->x_bits = DEFAULT_BITS; + + x->x_framerate = DEFAULT_FRAME_RATE; + x->x_vkbps = DEFAULT_VIDEO_BITRATE; + x->x_vquality = DEFAULT_VIDEO_QUALITY; + x->x_akbps = DEFAULT_AUDIO_BITRATE; + x->x_aquality = DEFAULT_AUDIO_QUALITY; + + x->x_audio_buf = (t_float**) getbytes( x->x_channels*sizeof(t_float*) ); + for ( i=0; i<x->x_channels; i++) + { + x->x_audio_buf[i] = (t_float*) getbytes( MAX_AUDIO_PACKET_SIZE*sizeof(t_float) ); + } + + x->x_newfile = 0; + x->x_frames = 0; + x->x_frameswritten = 0; + + x->x_tzero.tv_sec = 0; + + return (void *)x; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void pdp_theorout_tilde_setup(void) +{ + // post( pdp_theorout_version ); + pdp_theorout_class = class_new(gensym("pdp_theorout~"), (t_newmethod)pdp_theorout_new, + (t_method)pdp_theorout_free, sizeof(t_pdp_theorout), 0, A_NULL); + + CLASS_MAINSIGNALIN(pdp_theorout_class, t_pdp_theorout, x_f ); + class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_dsp, gensym("dsp"), 0); + class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_open, gensym("open"), A_SYMBOL, A_NULL); + class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_close, gensym("close"), A_NULL); + class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_start, gensym("start"), A_NULL); + class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_stop, gensym("stop"), A_NULL); + class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_abitrate, gensym("audiobitrate"), A_FLOAT, A_NULL); + class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_vbitrate, gensym("videobitrate"), A_FLOAT, A_NULL); + class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_aquality, gensym("audioquality"), A_FLOAT, A_NULL); + class_addmethod(pdp_theorout_class, (t_method)pdp_theorout_vquality, gensym("videoquality"), A_FLOAT, A_NULL); + class_sethelpsymbol( pdp_theorout_class, gensym("pdp_theorout~.pd") ); + +} + +#ifdef __cplusplus +} +#endif diff --git a/patches/cutandpaste.pd b/patches/cutandpaste.pd new file mode 100644 index 0000000..bbb0283 --- /dev/null +++ b/patches/cutandpaste.pd @@ -0,0 +1,114 @@ +#N canvas 237 21 712 664 10; +#X obj 164 55 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 71 103 loop \$1; +#X obj 71 81 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 1 +; +#X msg 55 55 open \$1; +#X obj 55 31 openpanel; +#X obj 55 9 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 -1 +; +#X floatatom 216 56 5 0 0 0 - - -; +#X msg 125 53 stop; +#X obj 157 92 metro 70; +#X obj 152 124 pdp_yqt; +#X obj 263 113 pdp_v4l; +#X obj 263 87 metro 70; +#X obj 303 56 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 264 55 stop; +#X msg 326 87 open /dev/video; +#X obj 582 496 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 582 548 pdp_control; +#X msg 582 521 thread \$1; +#X floatatom 582 609 5 0 0 0 - - -; +#X obj 582 580 route pdp_drop; +#X obj 176 274 pdp_cropper; +#X floatatom 336 230 5 0 0 0 - - -; +#X floatatom 381 229 5 0 0 0 - - -; +#X floatatom 295 251 5 0 0 0 - - -; +#X floatatom 294 272 5 0 0 0 - - -; +#X obj 257 501 pack f f; +#X floatatom 258 462 5 0 0 0 - - -; +#X floatatom 308 462 5 0 0 0 - - -; +#X obj 298 481 t b f; +#X msg 257 525 offset 2 \$1 \$2; +#X msg 308 439 100; +#X obj 152 169 pdp_scale 320 240; +#X msg 338 249 20; +#X msg 381 208 180; +#X obj 41 605 pdp_xv; +#X msg 492 213 bang; +#X text 532 213 Crop!; +#X msg 258 440 34; +#X msg 336 209 100; +#X msg 337 271 100; +#X obj 353 448 loadbang; +#X obj 176 360 pdp_canvas 320 240 2; +#X obj 371 323 pdp_background; +#X msg 489 322 0; +#X obj 525 322 loadbang; +#X obj 176 395 pdp_rotate; +#X floatatom 257 384 5 0 0 0 - - -; +#X obj 41 545 pdp_ocanvas 320 240 2; +#X msg 258 548 alpha 1 0.3; +#X msg 258 569 alpha 2 0.7; +#X connect 0 0 8 0; +#X connect 1 0 9 0; +#X connect 2 0 1 0; +#X connect 3 0 9 0; +#X connect 4 0 3 0; +#X connect 5 0 4 0; +#X connect 6 0 8 1; +#X connect 7 0 8 0; +#X connect 8 0 9 0; +#X connect 8 0 42 0; +#X connect 9 0 31 0; +#X connect 10 0 31 0; +#X connect 11 0 10 0; +#X connect 12 0 11 0; +#X connect 13 0 11 0; +#X connect 14 0 10 0; +#X connect 15 0 17 0; +#X connect 16 0 19 0; +#X connect 17 0 16 0; +#X connect 19 0 18 0; +#X connect 20 0 41 2; +#X connect 21 0 20 1; +#X connect 22 0 20 2; +#X connect 23 0 20 3; +#X connect 24 0 20 4; +#X connect 25 0 29 0; +#X connect 26 0 25 0; +#X connect 27 0 28 0; +#X connect 28 0 25 0; +#X connect 28 1 25 1; +#X connect 29 0 41 0; +#X connect 30 0 27 0; +#X connect 31 0 20 0; +#X connect 31 0 47 1; +#X connect 32 0 23 0; +#X connect 33 0 22 0; +#X connect 35 0 33 0; +#X connect 35 0 38 0; +#X connect 35 0 32 0; +#X connect 35 0 39 0; +#X connect 37 0 26 0; +#X connect 38 0 21 0; +#X connect 39 0 24 0; +#X connect 40 0 37 0; +#X connect 40 0 30 0; +#X connect 40 0 48 0; +#X connect 40 0 49 0; +#X connect 41 0 45 0; +#X connect 42 0 41 1; +#X connect 43 0 42 3; +#X connect 43 0 42 2; +#X connect 43 0 42 1; +#X connect 44 0 43 0; +#X connect 45 0 47 2; +#X connect 46 0 45 1; +#X connect 47 0 34 0; +#X connect 48 0 47 0; +#X connect 49 0 47 0; diff --git a/patches/morphology/help-closing.pd b/patches/morphology/help-closing.pd new file mode 100644 index 0000000..de4f8a8 --- /dev/null +++ b/patches/morphology/help-closing.pd @@ -0,0 +1,98 @@ +#N canvas 381 0 781 666 10; +#X obj 341 20 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 196 92 loop \$1; +#X obj 197 70 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 1 +; +#X msg 453 93 open \$1; +#X obj 452 69 openpanel; +#X obj 437 52 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X floatatom 389 55 5 0 0 0 - - -; +#X msg 298 21 stop; +#X obj 396 24 hsl 300 15 0 1000 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 6900 1; +#X obj 330 91 metro 70; +#X obj 325 123 pdp_yqt; +#X obj 25 193 pdp_v4l; +#X obj 34 162 metro 70; +#X obj 79 128 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 36 129 stop; +#X msg 121 160 open /dev/video; +#X text 301 612 written by Yves Degoyon ( ydegoyon@free.fr ); +#X msg 31 236 pick; +#X floatatom 248 262 5 0 0 0 - - -; +#X obj 594 197 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 594 249 pdp_control; +#X msg 594 222 thread \$1; +#X floatatom 594 310 5 0 0 0 - - -; +#X obj 594 281 route pdp_drop; +#X msg 72 237 setcur \$1 \$2; +#X floatatom 174 328 5 0 0 0 - - -; +#X floatatom 224 329 5 0 0 0 - - -; +#X floatatom 271 328 5 0 0 0 - - -; +#X text 294 261 Tolerance ( default = 55 ); +#X obj 138 289 pdp_binary ----; +#X obj 41 369 route press drag release; +#X msg 42 311 cursor 1; +#X floatatom 250 370 5 0 0 0 - - -; +#X text 296 369 Number of passes ( default = 1 ); +#X obj 41 342 pdp_glx; +#X floatatom 271 396 5 0 0 0 - - -; +#X floatatom 292 420 5 0 0 0 - - -; +#X text 317 395 Kernel width ( default = 3 ); +#X text 337 417 Kernel height ( default = 3 ); +#X floatatom 265 450 5 0 0 0 - - -; +#X text 311 449 Number of passes ( default = 1 ); +#X text 302 594 morphology : opening; +#X obj 148 550 pdp_glx; +#X obj 61 508 pdp_xor; +#X obj 61 547 pdp_glx; +#X obj 148 437 pdp_dilate ----; +#X obj 148 509 pdp_erode ----; +#X connect 0 0 9 0; +#X connect 1 0 10 0; +#X connect 2 0 1 0; +#X connect 3 0 10 0; +#X connect 4 0 3 0; +#X connect 5 0 4 0; +#X connect 6 0 9 1; +#X connect 7 0 9 0; +#X connect 8 0 6 0; +#X connect 9 0 10 0; +#X connect 10 0 29 0; +#X connect 11 0 29 0; +#X connect 12 0 11 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 11 0; +#X connect 17 0 29 0; +#X connect 18 0 29 6; +#X connect 19 0 21 0; +#X connect 20 0 23 0; +#X connect 21 0 20 0; +#X connect 23 0 22 0; +#X connect 24 0 17 0; +#X connect 24 0 29 0; +#X connect 29 0 34 0; +#X connect 29 0 31 0; +#X connect 29 0 43 0; +#X connect 29 0 45 0; +#X connect 29 1 25 0; +#X connect 29 2 26 0; +#X connect 29 3 27 0; +#X connect 30 0 24 0; +#X connect 31 0 34 0; +#X connect 32 0 45 1; +#X connect 34 0 30 0; +#X connect 35 0 45 2; +#X connect 35 0 46 2; +#X connect 36 0 45 3; +#X connect 36 0 46 3; +#X connect 39 0 46 1; +#X connect 43 0 44 0; +#X connect 45 0 46 0; +#X connect 46 0 42 0; +#X connect 46 0 43 1; diff --git a/patches/morphology/help-opening.pd b/patches/morphology/help-opening.pd new file mode 100644 index 0000000..660a59e --- /dev/null +++ b/patches/morphology/help-opening.pd @@ -0,0 +1,98 @@ +#N canvas 381 0 781 666 10; +#X obj 341 20 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 196 92 loop \$1; +#X obj 197 70 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 1 +; +#X msg 453 93 open \$1; +#X obj 452 69 openpanel; +#X obj 437 52 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X floatatom 389 55 5 0 0 0 - - -; +#X msg 298 21 stop; +#X obj 396 24 hsl 300 15 0 1000 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X obj 330 91 metro 70; +#X obj 325 123 pdp_yqt; +#X obj 25 193 pdp_v4l; +#X obj 34 162 metro 70; +#X obj 79 128 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 36 129 stop; +#X msg 121 160 open /dev/video; +#X text 301 612 written by Yves Degoyon ( ydegoyon@free.fr ); +#X msg 31 236 pick; +#X floatatom 248 262 5 0 0 0 - - -; +#X obj 594 197 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 594 249 pdp_control; +#X msg 594 222 thread \$1; +#X floatatom 594 310 5 0 0 0 - - -; +#X obj 594 281 route pdp_drop; +#X msg 72 237 setcur \$1 \$2; +#X floatatom 174 328 5 0 0 0 - - -; +#X floatatom 224 329 5 0 0 0 - - -; +#X floatatom 271 328 5 0 0 0 - - -; +#X text 294 261 Tolerance ( default = 55 ); +#X obj 138 289 pdp_binary ----; +#X obj 41 369 route press drag release; +#X msg 42 311 cursor 1; +#X floatatom 250 370 5 0 0 0 - - -; +#X text 296 369 Number of passes ( default = 1 ); +#X obj 41 342 pdp_glx; +#X floatatom 271 396 5 0 0 0 - - -; +#X floatatom 292 420 5 0 0 0 - - -; +#X text 317 395 Kernel width ( default = 3 ); +#X text 337 417 Kernel height ( default = 3 ); +#X obj 148 437 pdp_erode ----; +#X floatatom 265 450 5 0 0 0 - - -; +#X text 311 449 Number of passes ( default = 1 ); +#X text 302 594 morphology : opening; +#X obj 148 509 pdp_dilate ----; +#X obj 148 550 pdp_glx; +#X obj 61 508 pdp_xor; +#X obj 61 547 pdp_glx; +#X connect 0 0 9 0; +#X connect 1 0 10 0; +#X connect 2 0 1 0; +#X connect 3 0 10 0; +#X connect 4 0 3 0; +#X connect 5 0 4 0; +#X connect 6 0 9 1; +#X connect 7 0 9 0; +#X connect 8 0 6 0; +#X connect 9 0 10 0; +#X connect 10 0 29 0; +#X connect 11 0 29 0; +#X connect 12 0 11 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 11 0; +#X connect 17 0 29 0; +#X connect 18 0 29 6; +#X connect 19 0 21 0; +#X connect 20 0 23 0; +#X connect 21 0 20 0; +#X connect 23 0 22 0; +#X connect 24 0 17 0; +#X connect 24 0 29 0; +#X connect 29 0 34 0; +#X connect 29 0 31 0; +#X connect 29 0 39 0; +#X connect 29 0 45 0; +#X connect 29 1 25 0; +#X connect 29 2 26 0; +#X connect 29 3 27 0; +#X connect 30 0 24 0; +#X connect 31 0 34 0; +#X connect 32 0 39 1; +#X connect 34 0 30 0; +#X connect 35 0 39 2; +#X connect 35 0 43 2; +#X connect 36 0 39 3; +#X connect 36 0 43 3; +#X connect 39 0 43 0; +#X connect 40 0 43 1; +#X connect 43 0 44 0; +#X connect 43 0 45 1; +#X connect 45 0 46 0; diff --git a/patches/morphology/help-skeletization.pd b/patches/morphology/help-skeletization.pd new file mode 100644 index 0000000..342f6cb --- /dev/null +++ b/patches/morphology/help-skeletization.pd @@ -0,0 +1,113 @@ +#N canvas 368 0 781 666 10; +#X obj 341 20 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 196 92 loop \$1; +#X obj 197 70 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 1 +; +#X msg 453 93 open \$1; +#X obj 452 69 openpanel; +#X obj 437 52 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X floatatom 389 55 5 0 0 0 - - -; +#X msg 298 21 stop; +#X obj 396 24 hsl 300 15 0 1000 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X obj 330 91 metro 70; +#X obj 325 123 pdp_yqt; +#X obj 25 193 pdp_v4l; +#X obj 34 162 metro 70; +#X obj 79 128 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 36 129 stop; +#X msg 121 160 open /dev/video; +#X obj 594 197 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 594 249 pdp_control; +#X msg 594 222 thread \$1; +#X floatatom 594 310 5 0 0 0 - - -; +#X obj 594 281 route pdp_drop; +#X obj 114 339 pdp_distance ----; +#X obj 287 289 pdp_glx; +#X text 297 552 morphology : skeletization; +#X text 297 570 written by Yves Degoyon ( ydegoyon@free.fr ); +#X floatatom 270 471 5 0 0 0 - - -; +#X floatatom 150 510 5 0 0 0 - - -; +#X floatatom 200 511 5 0 0 0 - - -; +#X floatatom 247 510 5 0 0 0 - - -; +#X text 270 443 Tolerance ( default = 55 ); +#X obj 114 471 pdp_binary ----; +#X floatatom 110 445 5 0 0 0 - - -; +#X text 157 443 Luma component; +#X obj 138 413 pdp_glx; +#X obj 347 470 loadbang; +#X obj 114 289 pdp_binary ----; +#X floatatom 228 257 5 0 0 0 - - -; +#X text 275 256 Tolerance ( default = 55 ); +#X obj 114 543 pdp_glx; +#X obj 114 384 pdp_gain; +#X floatatom 176 363 5 0 0 0 - - -; +#X msg 229 362 2; +#X obj 264 362 loadbang; +#X obj 11 445 loadbang; +#X msg 76 444 200; +#X msg 313 471 55; +#X msg 116 240 pick; +#X msg 115 262 setcur \$1 \$2; +#X floatatom 148 317 5 0 0 0 - - -; +#X floatatom 189 317 5 0 0 0 - - -; +#X floatatom 236 317 5 0 0 0 - - -; +#X obj 287 315 route press drag release; +#X msg 227 232 cursor 1; +#X obj 344 161 pdp_glx; +#X connect 0 0 9 0; +#X connect 1 0 10 0; +#X connect 2 0 1 0; +#X connect 3 0 10 0; +#X connect 4 0 3 0; +#X connect 5 0 4 0; +#X connect 6 0 9 1; +#X connect 7 0 9 0; +#X connect 8 0 6 0; +#X connect 9 0 10 0; +#X connect 10 0 35 0; +#X connect 10 0 52 0; +#X connect 10 0 53 0; +#X connect 11 0 35 0; +#X connect 12 0 11 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 11 0; +#X connect 16 0 18 0; +#X connect 17 0 20 0; +#X connect 18 0 17 0; +#X connect 20 0 19 0; +#X connect 21 0 39 0; +#X connect 22 0 51 0; +#X connect 25 0 30 6; +#X connect 30 0 38 0; +#X connect 30 1 26 0; +#X connect 30 2 27 0; +#X connect 30 3 28 0; +#X connect 31 0 30 1; +#X connect 34 0 45 0; +#X connect 35 0 22 0; +#X connect 35 0 21 0; +#X connect 35 1 48 0; +#X connect 35 2 49 0; +#X connect 35 3 50 0; +#X connect 36 0 35 6; +#X connect 39 0 33 0; +#X connect 39 0 30 0; +#X connect 40 0 39 1; +#X connect 41 0 40 0; +#X connect 42 0 41 0; +#X connect 43 0 44 0; +#X connect 44 0 31 0; +#X connect 45 0 25 0; +#X connect 46 0 35 0; +#X connect 47 0 46 0; +#X connect 47 0 35 0; +#X connect 51 0 47 0; +#X connect 52 0 22 0; +#X connect 52 0 53 0; +#X connect 53 0 51 0; diff --git a/patches/morphology/help-thickening.pd b/patches/morphology/help-thickening.pd new file mode 100644 index 0000000..4bb41ca --- /dev/null +++ b/patches/morphology/help-thickening.pd @@ -0,0 +1,100 @@ +#N canvas 381 0 781 666 10; +#X obj 341 20 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 196 92 loop \$1; +#X obj 197 70 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 1 +; +#X msg 453 93 open \$1; +#X obj 452 69 openpanel; +#X obj 437 52 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X floatatom 389 55 5 0 0 0 - - -; +#X msg 298 21 stop; +#X obj 396 24 hsl 300 15 0 1000 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X obj 330 91 metro 70; +#X obj 325 123 pdp_yqt; +#X obj 25 193 pdp_v4l; +#X obj 34 162 metro 70; +#X obj 79 128 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 36 129 stop; +#X msg 121 160 open /dev/video; +#X text 306 611 written by Yves Degoyon ( ydegoyon@free.fr ); +#X msg 31 236 pick; +#X floatatom 248 262 5 0 0 0 - - -; +#X obj 594 197 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 594 249 pdp_control; +#X msg 594 222 thread \$1; +#X floatatom 594 310 5 0 0 0 - - -; +#X obj 594 281 route pdp_drop; +#X msg 72 237 setcur \$1 \$2; +#X floatatom 174 328 5 0 0 0 - - -; +#X floatatom 224 329 5 0 0 0 - - -; +#X floatatom 271 328 5 0 0 0 - - -; +#X text 294 261 Tolerance ( default = 55 ); +#X obj 41 369 route press drag release; +#X msg 42 311 cursor 1; +#X text 296 369 Number of passes ( default = 1 ); +#X floatatom 271 396 5 0 0 0 - - -; +#X floatatom 292 420 5 0 0 0 - - -; +#X text 317 395 Kernel width ( default = 3 ); +#X text 338 418 Kernel height ( default = 3 ); +#X obj 143 501 pdp_hitandmiss ----; +#X obj 41 342 pdp_glx; +#X obj 63 576 pdp_glx; +#X obj 138 289 pdp_binary ----; +#X text 307 594 morphology : thinning; +#X floatatom 247 368 5 0 0 0 - - -; +#X msg 329 494 kernel -1 1 -1 0 1 1 0 0 -1; +#X msg 327 471 kernel 1 1 -1 1 0 -1 1 -1 0; +#X obj 327 444 loadbang; +#X obj 64 550 pdp_or; +#X obj 152 560 pdp_xor; +#X obj 152 589 pdp_glx; +#X connect 0 0 9 0; +#X connect 1 0 10 0; +#X connect 2 0 1 0; +#X connect 3 0 10 0; +#X connect 4 0 3 0; +#X connect 5 0 4 0; +#X connect 6 0 9 1; +#X connect 7 0 9 0; +#X connect 8 0 6 0; +#X connect 9 0 10 0; +#X connect 10 0 39 0; +#X connect 11 0 39 0; +#X connect 12 0 11 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 11 0; +#X connect 17 0 39 0; +#X connect 18 0 39 6; +#X connect 19 0 21 0; +#X connect 20 0 23 0; +#X connect 21 0 20 0; +#X connect 23 0 22 0; +#X connect 24 0 17 0; +#X connect 24 0 39 0; +#X connect 29 0 24 0; +#X connect 30 0 37 0; +#X connect 32 0 36 2; +#X connect 33 0 36 3; +#X connect 36 0 45 1; +#X connect 37 0 29 0; +#X connect 39 0 30 0; +#X connect 39 0 36 0; +#X connect 39 0 37 0; +#X connect 39 0 45 0; +#X connect 39 0 46 1; +#X connect 39 1 25 0; +#X connect 39 2 26 0; +#X connect 39 3 27 0; +#X connect 41 0 36 1; +#X connect 42 0 36 0; +#X connect 43 0 36 0; +#X connect 44 0 43 0; +#X connect 45 0 38 0; +#X connect 45 0 46 0; +#X connect 46 0 47 0; diff --git a/patches/morphology/help-thinning.pd b/patches/morphology/help-thinning.pd new file mode 100644 index 0000000..5b49da0 --- /dev/null +++ b/patches/morphology/help-thinning.pd @@ -0,0 +1,95 @@ +#N canvas 381 0 781 666 10; +#X obj 341 20 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 196 92 loop \$1; +#X obj 197 70 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 1 +; +#X msg 453 93 open \$1; +#X obj 452 69 openpanel; +#X obj 437 52 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X floatatom 389 55 5 0 0 0 - - -; +#X msg 298 21 stop; +#X obj 396 24 hsl 300 15 0 1000 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X obj 330 91 metro 70; +#X obj 325 123 pdp_yqt; +#X obj 25 193 pdp_v4l; +#X obj 34 162 metro 70; +#X obj 79 128 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X msg 36 129 stop; +#X msg 121 160 open /dev/video; +#X text 306 611 written by Yves Degoyon ( ydegoyon@free.fr ); +#X msg 31 236 pick; +#X floatatom 248 262 5 0 0 0 - - -; +#X obj 594 197 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 594 249 pdp_control; +#X msg 594 222 thread \$1; +#X floatatom 594 310 5 0 0 0 - - -; +#X obj 594 281 route pdp_drop; +#X msg 72 237 setcur \$1 \$2; +#X floatatom 174 328 5 0 0 0 - - -; +#X floatatom 224 329 5 0 0 0 - - -; +#X floatatom 271 328 5 0 0 0 - - -; +#X text 294 261 Tolerance ( default = 55 ); +#X obj 41 369 route press drag release; +#X msg 42 311 cursor 1; +#X text 296 369 Number of passes ( default = 1 ); +#X floatatom 271 396 5 0 0 0 - - -; +#X floatatom 292 420 5 0 0 0 - - -; +#X text 317 395 Kernel width ( default = 3 ); +#X text 338 418 Kernel height ( default = 3 ); +#X obj 143 501 pdp_hitandmiss ----; +#X obj 41 342 pdp_glx; +#X obj 63 576 pdp_glx; +#X obj 138 289 pdp_binary ----; +#X text 307 594 morphology : thinning; +#X floatatom 247 368 5 0 0 0 - - -; +#X msg 329 494 kernel -1 1 -1 0 1 1 0 0 -1; +#X obj 64 551 pdp_xor; +#X msg 327 471 kernel -1 -1 -1 -1 1 -1 1 1 1; +#X obj 326 444 loadbang; +#X connect 0 0 9 0; +#X connect 1 0 10 0; +#X connect 2 0 1 0; +#X connect 3 0 10 0; +#X connect 4 0 3 0; +#X connect 5 0 4 0; +#X connect 6 0 9 1; +#X connect 7 0 9 0; +#X connect 8 0 6 0; +#X connect 9 0 10 0; +#X connect 10 0 39 0; +#X connect 11 0 39 0; +#X connect 12 0 11 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 11 0; +#X connect 17 0 39 0; +#X connect 18 0 39 6; +#X connect 19 0 21 0; +#X connect 20 0 23 0; +#X connect 21 0 20 0; +#X connect 23 0 22 0; +#X connect 24 0 17 0; +#X connect 24 0 39 0; +#X connect 29 0 24 0; +#X connect 30 0 37 0; +#X connect 32 0 36 2; +#X connect 33 0 36 3; +#X connect 36 0 43 1; +#X connect 37 0 29 0; +#X connect 39 0 30 0; +#X connect 39 0 36 0; +#X connect 39 0 37 0; +#X connect 39 0 43 0; +#X connect 39 1 25 0; +#X connect 39 2 26 0; +#X connect 39 3 27 0; +#X connect 41 0 36 1; +#X connect 42 0 36 0; +#X connect 43 0 38 0; +#X connect 44 0 36 0; +#X connect 45 0 44 0; |