aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.LOG54
-rw-r--r--COPYING340
-rw-r--r--Makefile49
-rw-r--r--Makefile.config45
-rw-r--r--Makefile.linux4
-rw-r--r--Makefile.linux_mmx4
-rw-r--r--README185
-rw-r--r--TODO33
-rw-r--r--abstractions/pdp_blur.pd27
-rw-r--r--abstractions/pdp_blur_hor.pd27
-rw-r--r--abstractions/pdp_blur_ver.pd27
-rw-r--r--abstractions/pdp_conv_alledge.pd28
-rw-r--r--abstractions/pdp_conv_emboss.pd34
-rw-r--r--abstractions/pdp_conv_smooth.pd14
-rw-r--r--abstractions/pdp_conv_sobel_edge.pd19
-rw-r--r--abstractions/pdp_conv_sobel_hor.pd15
-rw-r--r--abstractions/pdp_conv_sobel_ver.pd16
-rw-r--r--abstractions/pdp_motion_blur.pd14
-rw-r--r--abstractions/pdp_motion_phase.pd14
-rw-r--r--abstractions/pdp_phase.pd70
-rw-r--r--abstractions/pdp_phase_hor.pd41
-rw-r--r--abstractions/pdp_phase_ver.pd41
-rw-r--r--abstractions/pdp_pps.pd18
-rw-r--r--abstractions/pdp_saturation.pd13
-rw-r--r--debug/gdb_pdp_load25
-rw-r--r--debug/gdb_pdp_load_rt10
-rw-r--r--doc/control.pd17
-rw-r--r--doc/examples/example01.pd45
-rw-r--r--doc/examples/example02.pd44
-rw-r--r--doc/examples/example03.pd78
-rw-r--r--doc/input_output.pd53
-rw-r--r--doc/quicktime.pd101
-rw-r--r--doc/reference.txt64
-rw-r--r--doc/traffic.pd101
-rw-r--r--include/Makefile6
-rw-r--r--include/pdp.h223
-rw-r--r--include/pdp_imageproc.h150
-rw-r--r--include/pdp_internals.h50
-rw-r--r--include/pdp_llconv.h78
-rw-r--r--include/pdp_mmx.h158
-rw-r--r--include/pdp_resample.h42
-rw-r--r--include/pdp_types.h36
-rw-r--r--include/pwc-ioctl.h123
-rw-r--r--modules/Makefile16
-rw-r--r--modules/README33
-rw-r--r--modules/pdp_add.c205
-rw-r--r--modules/pdp_affine.c223
-rw-r--r--modules/pdp_bq.c698
-rw-r--r--modules/pdp_chrot.c201
-rw-r--r--modules/pdp_conv.c325
-rw-r--r--modules/pdp_del.c196
-rw-r--r--modules/pdp_gain.c227
-rw-r--r--modules/pdp_gradient.c331
-rw-r--r--modules/pdp_grey.c168
-rw-r--r--modules/pdp_mix.c279
-rw-r--r--modules/pdp_mul.c205
-rw-r--r--modules/pdp_noise.c230
-rw-r--r--modules/pdp_qt.c941
-rw-r--r--modules/pdp_randmix.c228
-rw-r--r--modules/pdp_reg.c132
-rw-r--r--modules/pdp_route.c129
-rw-r--r--modules/pdp_scale.c267
-rw-r--r--modules/pdp_scope.c312
-rw-r--r--modules/pdp_snap.c146
-rw-r--r--modules/pdp_trigger.c105
-rw-r--r--modules/pdp_v4l.c734
-rw-r--r--modules/pdp_xv.c534
-rw-r--r--modules/pdp_zoom.c264
-rw-r--r--scaf/COPYING340
-rw-r--r--scaf/Makefile22
-rw-r--r--scaf/Makefile.config34
-rw-r--r--scaf/README88
-rw-r--r--scaf/README.scaf98
-rw-r--r--scaf/include/Makefile6
-rw-r--r--scaf/include/pdp_ca.h71
-rw-r--r--scaf/modules/Makefile21
-rw-r--r--scaf/modules/carules.scaf117
-rw-r--r--scaf/pdp/Makefile13
-rw-r--r--scaf/pdp/pdp_ca.c725
-rw-r--r--scaf/pdp/pdp_ca_system.c228
-rw-r--r--scaf/system/Makefile21
-rw-r--r--scaf/system/kernel.scaf130
-rw-r--r--scaf/system/optim.rules74
-rw-r--r--scaf/system/scaf_feeder.s49
-rw-r--r--scaf/system/scaf_feeder_test.c30
-rwxr-xr-xscaf/system/scafc.pl269
-rw-r--r--scaf/system/scafmacro.s487
-rw-r--r--scaf/test/test_pdp_ca.pd132
-rw-r--r--scaf/test/test_pdp_ca2.pd154
-rw-r--r--system/Makefile20
-rw-r--r--system/Makefile.linux2
-rw-r--r--system/Makefile.linux_mmx4
-rw-r--r--system/mmx/Makefile29
-rw-r--r--system/mmx/pdp_mmx_test.c62
-rw-r--r--system/mmx/pixel_add_s16.s55
-rw-r--r--system/mmx/pixel_affine_s16.s59
-rw-r--r--system/mmx/pixel_biquad_dirI_s16.s361
-rw-r--r--system/mmx/pixel_biquad_s16.s451
-rw-r--r--system/mmx/pixel_ca_s1.s189
-rw-r--r--system/mmx/pixel_cascade_s16.s330
-rw-r--r--system/mmx/pixel_conv_hor_s16.s134
-rw-r--r--system/mmx/pixel_conv_ver_s16.s128
-rw-r--r--system/mmx/pixel_crot_s16.s153
-rw-r--r--system/mmx/pixel_gain.s83
-rw-r--r--system/mmx/pixel_gain_s16.s71
-rw-r--r--system/mmx/pixel_mix_s16.s68
-rw-r--r--system/mmx/pixel_mul_s16.s56
-rw-r--r--system/mmx/pixel_pack_s16u8.s126
-rw-r--r--system/mmx/pixel_rand_s16.s76
-rw-r--r--system/mmx/pixel_randmix_s16.s91
-rw-r--r--system/mmx/pixel_s1.s201
-rw-r--r--system/mmx/pixel_unpack_u8s16.s113
-rw-r--r--system/pdp.c115
-rw-r--r--system/pdp_comm.c119
-rw-r--r--system/pdp_control.c162
-rw-r--r--system/pdp_imageproc_mmx.c319
-rw-r--r--system/pdp_imageproc_portable.c492
-rw-r--r--system/pdp_llconv.c293
-rw-r--r--system/pdp_llconv_mmx.c55
-rw-r--r--system/pdp_llconv_portable.c81
-rw-r--r--system/pdp_packet.c239
-rw-r--r--system/pdp_queue.c337
-rw-r--r--system/pdp_resample.c135
-rw-r--r--system/pdp_type.c143
-rw-r--r--system/pdp_ut.c195
-rw-r--r--test/pdp_abstractions.pd22
-rw-r--r--test/test_oscil.pd69
-rw-r--r--test/test_pdp_add.pd96
-rw-r--r--test/test_pdp_affine.pd80
-rw-r--r--test/test_pdp_bq.pd136
-rw-r--r--test/test_pdp_bq2.pd146
-rw-r--r--test/test_pdp_bqt.pd91
-rw-r--r--test/test_pdp_chrot.pd32
-rw-r--r--test/test_pdp_conv.pd115
-rw-r--r--test/test_pdp_debug.pd18
-rw-r--r--test/test_pdp_del.pd41
-rw-r--r--test/test_pdp_gain.pd46
-rw-r--r--test/test_pdp_gradient.pd52
-rw-r--r--test/test_pdp_mix.pd114
-rw-r--r--test/test_pdp_mul.pd44
-rw-r--r--test/test_pdp_noise.pd40
-rw-r--r--test/test_pdp_pctv.pd47
-rw-r--r--test/test_pdp_portable.pd41
-rw-r--r--test/test_pdp_qt_read.pd164
-rw-r--r--test/test_pdp_qt_read2.pd45
-rw-r--r--test/test_pdp_randmix.pd31
-rw-r--r--test/test_pdp_reg.pd21
-rw-r--r--test/test_pdp_scale.pd38
-rw-r--r--test/test_pdp_scope.pd21
-rw-r--r--test/test_pdp_snap.pd16
-rw-r--r--test/test_pdp_thread.pd33
-rw-r--r--test/test_pdp_trigger.pd13
-rw-r--r--test/test_pdp_v4l.pd91
-rw-r--r--test/test_pdp_v4l_2.pd26
-rw-r--r--test/test_pdp_xv.pd44
-rw-r--r--test/test_pdp_zoom.pd73
-rw-r--r--test/test_warpfeedback.pd49
157 files changed, 20216 insertions, 0 deletions
diff --git a/CHANGES.LOG b/CHANGES.LOG
new file mode 100644
index 0000000..1c16d49
--- /dev/null
+++ b/CHANGES.LOG
@@ -0,0 +1,54 @@
+last modified: 2003/01/12
+
+
+ChangeLog:
+
+v0.1: 2002/11/23
+ initial release
+
+v0.2: 2002/11/27
+ added support for BC_YUV422 video and audio playback in pdp_qt /
+ pdp_qt~ (thanks to Yves Degoyon for contrib)
+ some makefile cleanups
+
+v0.3: 2002/11/28
+ pdp_qt / pdp_qt~: fixed some bugs in audio playback and added
+ suport for BC_RGB888 colormodel (loads as greyscale until there
+ is internal support for a rgb image packet)
+
+v0.4: 2002/12/03
+ code style changes
+ added scaf / cellular automata support.
+ added some basic filter abstractions. (blur, phase)
+
+v0.5: 2002/12/13
+ first attempt at a documentation (see doc/)
+ added support for processing in separate lower priority thread
+ with a packet dropping mechanism to avoid audio dropouts.
+ added pdp_control object for controlling pdp's scheduling and
+ detecting packet drops
+ pdp api cleanup (name changes)
+ added some more filter abstractions
+ (motion blur/phase, emboss, sobel, edge)
+ added pdp_route
+
+v0.6: 2003/01/03
+ added pdp_gain, finished pdp_gradient
+ added channel method to pdp_v4l, display method to pdp_xv
+ added some examples in doc/examples
+ fixed gcc3 compilation probs
+ fixed some pdp_qt bugs (shouldn't crash any more)
+
+v0.7: 2003/01/12
+ moved image format conversion routines to pdp_llconv.c
+ added support for rgb->PDP_IMAGE_YV12 in pdp_v4l, pdp_qt
+ added pdp_grey, pdp_chrot, pdp_scope~
+ moved mmx wrappers to pdp_imageproc_mmx.c
+ added portable c code in pdp_imageproc_portable.c
+ added mmx code for pdp_gain
+ fixed bug in pdp_mix/pdp_mix2
+ fixed bug in pdp_bq (removed state reset)
+ move CA stuff to separate lib (see scaf/)
+ (0.7.1) fixed rgb colour conversion bug
+
+v0.8: added pdp_scale, pdp_zoom
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..7f87ef8
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR PDP.LICENSE, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..14ae460
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,49 @@
+include Makefile.config
+
+PDP_DISTRO = $(PDP_DIR)/../pdp-$(PDP_VERSION)
+PDP_TARBALL = $(PDP_DISTRO).tar.gz
+PDP_WWWDIR = /net/zwizwa/www/zwizwa.fartit.com/pd/pdp
+PDP_WWWTESTDIR = /net/zwizwa/www/zwizwa.fartit.com/pd/pdp/test
+
+all: pdp.pd_linux
+
+include Makefile.$(PDP_TARGET)
+
+pdp_all:
+ make -C system
+ make -C modules
+
+buildclean:
+ make -C include clean
+ make -C system clean
+ make -C modules clean
+
+clean: buildclean
+ rm -f pdp.pd_linux
+ rm -f *~
+
+tags:
+ etags --language=auto include/*.h system/mmx/*.s system/*.c modules/*.c
+
+tagsclean:
+ rm -f TAGS
+
+distro: clean
+ rm -rf $(PDP_DISTRO)
+ mkdir $(PDP_DISTRO)
+ cp -av $(PDP_DIR)/* $(PDP_DISTRO)
+ #strip --strip-unneeded $(PDP_DISTRO)/pdp.pd_linux
+ rm -rf $(PDP_DISTRO)/CVS
+ rm -rf $(PDP_DISTRO)/*/CVS
+ rm -rf $(PDP_DISTRO)/*/*/CVS
+ rm -rf $(PDP_DISTRO)/*/*.o
+ rm -rf $(PDP_DISTRO)/*/TAGS
+ cd $(PDP_DISTRO)/.. && tar vczf pdp-$(PDP_VERSION).tar.gz pdp-$(PDP_VERSION)
+ rm -rf $(PDP_DISTRO)
+
+www: $(PDP_TARBALL)
+ cp -av $(PDP_TARBALL) $(PDP_WWWDIR)
+ cp -av $(PDP_DIR)/README $(PDP_WWWDIR)/README.txt
+
+www-test:$(PDP_TARBALL)
+ cp -av $(PDP_TARBALL) $(PDP_WWWTESTDIR)
diff --git a/Makefile.config b/Makefile.config
new file mode 100644
index 0000000..ab45cdc
--- /dev/null
+++ b/Makefile.config
@@ -0,0 +1,45 @@
+# pd's directory
+PD_DIR = /home/tom/pd/distro/pd
+PDP_DIR = /home/tom/pd/packet
+
+#PD_DIR = /usr/local/pd
+#PDP_DIR = /usr/local/pdp
+
+# uncomment for philips webcam support
+# PDP_PWC = -DHAVE_V4LPWC
+
+# specify target
+#PDP_TARGET = linux
+PDP_TARGET = linux_mmx
+
+
+#################################################
+
+
+PDP_VERSION = 0.8-test-2
+PDP_DEFINES = $(PDP_PWC)
+
+# build flags
+
+PDP_INCLUDE = -I$(PD_DIR)/src -I. -I/usr/X11R6/include -I../include
+PDP_LIBS = -L/usr/X11R6/lib -lX11 -lXv -lXext -lm -lquicktime -ldl
+PDP_AFLAGS =
+#--gstabs
+PDP_CFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer -ffast-math \
+ -Wall -W -Wstrict-prototypes -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch $(PDP_DEFINES)\
+ -DPDP_VERSION=\"$(PDP_VERSION)\" \
+ -g
+# -Wshadow
+
+# compiler and assembler
+#CC = gcc-3.2
+CC = gcc
+AS = as
+
+# build rules
+
+.c.o:
+ $(CC) $(PDP_CFLAGS) $(PDP_INCLUDE) -o $*.o -c $*.c
+.s.o:
+ $(AS) -o $*.o $*.s $(PDP_AFLAGS)
diff --git a/Makefile.linux b/Makefile.linux
new file mode 100644
index 0000000..156a5e6
--- /dev/null
+++ b/Makefile.linux
@@ -0,0 +1,4 @@
+pdp.pd_linux: pdp_all
+ rm -f pdp.pd_linux
+ gcc -export_dynamic -shared -o pdp.pd_linux modules/*.o system/*.o $(PDP_LIBS)
+ #strip --strip-unneeded pdp.pd_linux
diff --git a/Makefile.linux_mmx b/Makefile.linux_mmx
new file mode 100644
index 0000000..2d988ec
--- /dev/null
+++ b/Makefile.linux_mmx
@@ -0,0 +1,4 @@
+pdp.pd_linux: pdp_all
+ rm -f pdp.pd_linux
+ gcc -export_dynamic -shared -o pdp.pd_linux modules/*.o system/*.o system/mmx/*.o $(PDP_LIBS)
+ #strip --strip-unneeded pdp.pd_linux
diff --git a/README b/README
new file mode 100644
index 0000000..eb53d0c
--- /dev/null
+++ b/README
@@ -0,0 +1,185 @@
+PDP - Pure Data Packet v0.7
+a packet processing library for pure data
+
+Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+The GNU Public Licence can be found in the file COPYING
+
+
+------------------------------------------------------------------
+
+This external pd library is a framework for image/video processing (and
+other raw data packets) that is fast, simple and flexible and as much
+as possible compatible with the pd messaging system.
+
+Unfortunately, since the main idea is to "have something for myself to
+play with", i haven't payed much attention to portability or even
+compilablility yet. So if some of the requirements are missing on your
+system, you'll have to tinker a bit to get it working until i move to
+automatic configuration and building...
+
+The goal (for now) is not to write a general purpose video processing
+tool for pd, the goal is to experiment with cache optimization, mmx
+integer processing, time and space feedback in video, nonlinear
+difference equations, cellular automata, computer vision, and other
+buzzwords...
+
+
+Features:
+
+* packet formats: greyscale and YV12 encoded images,
+ binary cellular automata (CA)
+* sources: noise, video4linux and quicktime (with audio), CA
+* sink: xvideo display
+* filters: convolution, biquad time, biquad space, CA
+* transforms: colour translation/scaling, grey->palette
+* add, mul, mix, random pixel mix
+* utility objs: packet register, snapshot, trigger
+* packet delay line
+* minimal forth system for defining CA rules (only for mmx)
+
+
+Implementation:
+
+* mmx/c 16bit internal integer processing
+* sort of cache optimized (locality + minimal memory usage)
+
+
+Requirements:
+
+* pd
+* linux
+* a video4linux device for video input. special support for
+philips webcam included.
+* libquicktime (not quicktime4linux!) for quicktime playback.
+* an X display with XVideo extension for video display
+
+
+Documentation:
+
+Have a look in doc/ for documentation. It is not finished yet. More info
+in modules/README, scaf/README, the files in abstractions/ and test/ and
+the code. If you wan't to make your own pdp modules, you can take the
+simplest one (modules/pdp_add.c) as an example.
+The file doc/reference.txt contains a list of all objects.
+
+
+Building:
+
+Edit Makefile.config to reflect your system settings. For now this
+should be the pd dir, the pdp dir, a toggle for philips web cam
+support and the compilation target (linux / linux_mmx).
+type "make" in the top directory. Remember to type
+"make clean all" after editing Makefile.config
+
+
+Using:
+
+launch pd with the options -lib $PDP_DIR/pdp -path $PDP_DIR/abstractions
+
+
+Bugs:
+
+see the TODO file
+
+
+Additional Remarks:
+
+* If some of the modules don't compile due to some missing libraries,
+you can try to comment out the offending code in modules/Makefile and
+system/pdp.c If compilation or linking fails due to other reasons,
+please let me know. if you have both libquicktime and quicktime4linux
+installed. make sure pdp.pd_linux loads the right library.
+
+* The reason i use YV12 and not RGB is simple: it's faster, and for
+linear operations it doesn't make much difference. Most camera's and
+codecs use a luma/chroma system, and most video cards support hardware
+accellerated display. Note that in YUV, the u (Cb) and v (Cr) components
+can be negative, so saturation after multiplication with a positive
+(or negative) value produces not only black and white, but also red,
+green, blue and their complements. In short, in YUV, nonlinear operations
+have a different effect than in RGB. Another thing: all the spatial
+operations are not implemented "correctly" because of the subsampling
+involved.
+
+* The image packets are 16bit/component planar. This is to simplify
+the mmx code and to have a little more headroom and precision for
+processing.
+
+* Packets can be processed in a low priority thread with a dropping
+mechanism to prevent overload or audio drops, or they can be processed
+in the main pd thread. This can be set/unset by sending a "thread x"
+message to pdp_control. Processing in thread is on by default. If you
+don't need audio, (i.e. if you are using 2 pd's, one for audio and one
+for video) having threads disabled can have advantages, since no pdp
+frames are dropped and no extra delays are introduced. Even when you use
+audio and pdp in the same pd session, it is possible to run with threads
+disabled and without audio dropouts by tuning pd's fragsize and keeping
+the frame rate low.
+
+* There have been some requests for an osx port, but i wil probably not
+do this myself (at least not right now). However, i've ported all
+the mmx code to c, so it should work on other architectures as well.
+This should ease porting a bit for anyone who wants to give it a try.
+Also i've moved all the image conversion routines to pdp_llconv.c
+This means porting is reduced to writing new objects for the os specific
+stuff like video/movie input/output.
+
+* Have a look at Yves Degoyon's PiDiP library. It contains some extra
+effects (from EffecTV and FreeJ), a quicktime recording object, some
+streaming modules, ... (the list is growing rapidly ;) see
+http://ydegoyon.free.fr/
+
+* Some quicktime remarks: pdp_qt~ is still a bit experimental, you might
+try pdp_yqt in yves' lib to see if it works better for you. Also, it
+seems that libquicktime does not work with compressed headers. The
+suggested codec is jpeg (photo) and uncompressed audio with the same
+samplerate as the one pd is using. (hint: compile libquicktime with
+mmx jpeg support)
+
+* The cellular automata object (pdp_ca) is now moved to a separate lib.
+It requires mmx to be compiled. see the scaf/ dir.
+
+* New versions of this package can be found at
+http://zwizwa.fartit.com/pd/pdp
+Experimental relases are in the subdirectory test/
+
+
+Directory structure:
+
+abstractions/ some abstractions that use the pdp objects
+doc/ start of a decent set of document patches
+debug/ debug scripts
+include/ header files
+modules/ pdp module code
+scaf/ CA extension lib (needs to be compiled separately)
+system/ core pdp system
+system/mmx/ mmx assembler files
+test/ some test patches (pretty complete doc but cryptic)
+
+
+
+Please let me know if you discover a bug or think something doesn't work
+right. Code, documentation or example patches are more than welcome of
+course.
+
+Have Fun,
+
+Tom
+
+
+last modified: 2003/01/19
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..62929c4
--- /dev/null
+++ b/TODO
@@ -0,0 +1,33 @@
+
+bugs:
+
+* some image dimensions cause crashes: solution: add checks in sources (pdp_v4l / pdp_qt / pdp_ca)
+(workaround: use a multiple of 8x8 to prevent this. ca dims should be a multiple of 64x2)
+* pdp_xv: catch sigpipe when window is closed (workaround: don't close the video windows manually ;)
+
+todo 0.8:
+* rotate
+* crop, shift (pad+scroll)
+* efficient rescalers: pdp_double pdp_halve
+* move float color conversion and float<->fixed point conv code to system
+* thresholding / color "waveshaping"
+* documentation (+cleanup)
+
+todo:
+
+* add audio resampling in pdp_qt~
+* clean up and add some ca rules
+* add some more abstractions to have faster acces to different modes of all the modules
+* fix dimension problems on input (for now, make sure images have correct dim, else generate error)
+* use pd_error instead of post for errors
+* finish documentation
+* add developer documentation
+* move to autoconf/automake/libtool
+* interface with gem
+* think about the memory allocation strategy (there is no garbage collection right now)
+* add general x window display code (hmm, this is more hassle than i thought..)
+
+wish list:
+* colour keying
+* camera controller (motion tracking ?)
+
diff --git a/abstractions/pdp_blur.pd b/abstractions/pdp_blur.pd
new file mode 100644
index 0000000..46425dd
--- /dev/null
+++ b/abstractions/pdp_blur.pd
@@ -0,0 +1,27 @@
+#N canvas 344 526 521 227 10;
+#X obj 26 33 inlet;
+#X obj 26 174 outlet;
+#X obj 26 134 pdp_bq;
+#X obj 70 66 pdp_ut_addscaleclip -1 -0.5 0.05 0.48;
+#X obj 70 33 inlet;
+#X msg 181 34 2;
+#X msg 70 98 lpf \$1 0.25;
+#X msg 136 34 0;
+#X obj 136 10 loadbang;
+#X msg 163 98 hor 1;
+#X msg 209 98 ver 1;
+#X text 100 138 this uses pdp_bq as a 2 pass lowpass filter to produce
+a blur effect in all directions;
+#X connect 0 0 2 0;
+#X connect 2 0 1 0;
+#X connect 3 0 6 0;
+#X connect 4 0 3 0;
+#X connect 5 0 2 1;
+#X connect 6 0 2 0;
+#X connect 7 0 3 0;
+#X connect 8 0 7 0;
+#X connect 8 0 5 0;
+#X connect 8 0 9 0;
+#X connect 8 0 10 0;
+#X connect 9 0 2 0;
+#X connect 10 0 2 0;
diff --git a/abstractions/pdp_blur_hor.pd b/abstractions/pdp_blur_hor.pd
new file mode 100644
index 0000000..00c4f89
--- /dev/null
+++ b/abstractions/pdp_blur_hor.pd
@@ -0,0 +1,27 @@
+#N canvas 344 526 521 227 10;
+#X obj 26 33 inlet;
+#X obj 26 174 outlet;
+#X obj 26 134 pdp_bq;
+#X obj 70 66 pdp_ut_addscaleclip -1 -0.5 0.05 0.48;
+#X obj 70 33 inlet;
+#X msg 181 34 2;
+#X msg 70 98 lpf \$1 0.25;
+#X msg 136 34 0;
+#X obj 136 10 loadbang;
+#X msg 163 98 hor 1;
+#X msg 209 98 ver 0;
+#X text 100 138 this uses pdp_bq as a 2 pass lowpass filter to produce
+a horzontal blur effect;
+#X connect 0 0 2 0;
+#X connect 2 0 1 0;
+#X connect 3 0 6 0;
+#X connect 4 0 3 0;
+#X connect 5 0 2 1;
+#X connect 6 0 2 0;
+#X connect 7 0 3 0;
+#X connect 8 0 7 0;
+#X connect 8 0 5 0;
+#X connect 8 0 9 0;
+#X connect 8 0 10 0;
+#X connect 9 0 2 0;
+#X connect 10 0 2 0;
diff --git a/abstractions/pdp_blur_ver.pd b/abstractions/pdp_blur_ver.pd
new file mode 100644
index 0000000..915931f
--- /dev/null
+++ b/abstractions/pdp_blur_ver.pd
@@ -0,0 +1,27 @@
+#N canvas 368 520 521 227 10;
+#X obj 26 33 inlet;
+#X obj 26 174 outlet;
+#X obj 26 134 pdp_bq;
+#X obj 70 66 pdp_ut_addscaleclip -1 -0.5 0.05 0.48;
+#X obj 70 33 inlet;
+#X msg 181 34 2;
+#X msg 70 98 lpf \$1 0.25;
+#X msg 136 34 0;
+#X obj 136 10 loadbang;
+#X text 100 138 this uses pdp_bq as a 2 pass lowpass filter to produce
+a vertical blur effect;
+#X msg 209 98 ver 1;
+#X msg 163 98 hor 0;
+#X connect 0 0 2 0;
+#X connect 2 0 1 0;
+#X connect 3 0 6 0;
+#X connect 4 0 3 0;
+#X connect 5 0 2 1;
+#X connect 6 0 2 0;
+#X connect 7 0 3 0;
+#X connect 8 0 7 0;
+#X connect 8 0 5 0;
+#X connect 8 0 11 0;
+#X connect 8 0 10 0;
+#X connect 10 0 2 0;
+#X connect 11 0 2 0;
diff --git a/abstractions/pdp_conv_alledge.pd b/abstractions/pdp_conv_alledge.pd
new file mode 100644
index 0000000..0433c16
--- /dev/null
+++ b/abstractions/pdp_conv_alledge.pd
@@ -0,0 +1,28 @@
+#N canvas 245 202 522 199 10;
+#X obj 29 17 inlet;
+#X obj 29 156 outlet;
+#X obj 29 97 pdp_conv;
+#X msg 95 36 hmask 0.33 0.33 0.33;
+#X msg 95 59 vmask -0.33 -0.33 -0.33;
+#X obj 29 126 pdp_add;
+#X obj 95 13 loadbang;
+#X obj 292 34 int;
+#X obj 292 56 * 2;
+#X obj 292 79 - 1;
+#X obj 292 12 inlet;
+#X text 101 115 pdp_alledge is an all edge sensitive convolution filter
+using pdp_add and pdp_conv to compose a non separable edge detection
+convolution mask (pdp_conv can only compute separable convolution masks).
+the right inlet sets number of times the filter is run (2n-1);
+#X connect 0 0 2 0;
+#X connect 0 0 5 1;
+#X connect 2 0 5 0;
+#X connect 3 0 2 0;
+#X connect 3 0 4 0;
+#X connect 4 0 2 0;
+#X connect 5 0 1 0;
+#X connect 6 0 3 0;
+#X connect 7 0 8 0;
+#X connect 8 0 9 0;
+#X connect 9 0 2 1;
+#X connect 10 0 7 0;
diff --git a/abstractions/pdp_conv_emboss.pd b/abstractions/pdp_conv_emboss.pd
new file mode 100644
index 0000000..427ee45
--- /dev/null
+++ b/abstractions/pdp_conv_emboss.pd
@@ -0,0 +1,34 @@
+#N canvas 222 642 591 233 10;
+#X obj 30 55 inlet;
+#X obj 29 206 outlet;
+#X obj 29 93 pdp_conv;
+#X obj 29 126 pdp_add;
+#X obj 108 9 loadbang;
+#X obj 218 86 pdp_conv;
+#X obj 29 176 pdp_affine 1;
+#X msg 108 151 0.5;
+#X msg 108 37 hmask 1 0 0;
+#X msg 218 35 hmask 0 0 1;
+#X obj 145 151 inlet;
+#X text 142 178 this uses pdp_conv \, pdp_add and pdp_affine to produce
+an emboss effect using the convolution mask (-1 0 0 \; 0 0 0 \; 0 0
+1) the right inlet sets the chroma offset.;
+#X msg 218 60 vmask 0 0 1;
+#X msg 108 60 vmask -1 0 0;
+#X connect 0 0 2 0;
+#X connect 0 0 5 0;
+#X connect 2 0 3 0;
+#X connect 3 0 6 0;
+#X connect 4 0 8 0;
+#X connect 4 0 9 0;
+#X connect 5 0 3 1;
+#X connect 6 0 1 0;
+#X connect 7 0 6 2;
+#X connect 8 0 2 0;
+#X connect 8 0 13 0;
+#X connect 9 0 5 0;
+#X connect 9 0 12 0;
+#X connect 10 0 6 2;
+#X connect 12 0 5 0;
+#X connect 13 0 2 0;
+#X connect 13 0 7 0;
diff --git a/abstractions/pdp_conv_smooth.pd b/abstractions/pdp_conv_smooth.pd
new file mode 100644
index 0000000..e37320e
--- /dev/null
+++ b/abstractions/pdp_conv_smooth.pd
@@ -0,0 +1,14 @@
+#N canvas 490 446 522 199 10;
+#X obj 29 17 inlet;
+#X obj 29 156 outlet;
+#X obj 29 97 pdp_conv;
+#X obj 95 13 loadbang;
+#X obj 292 12 inlet;
+#X msg 95 36 mask 0.33 0.33 0.33;
+#X text 107 108 pdp_conv_smooth is an averaging convolution filter.
+second inlet sets number of passes.;
+#X connect 0 0 2 0;
+#X connect 2 0 1 0;
+#X connect 3 0 5 0;
+#X connect 4 0 2 1;
+#X connect 5 0 2 0;
diff --git a/abstractions/pdp_conv_sobel_edge.pd b/abstractions/pdp_conv_sobel_edge.pd
new file mode 100644
index 0000000..ccf0c38
--- /dev/null
+++ b/abstractions/pdp_conv_sobel_edge.pd
@@ -0,0 +1,19 @@
+#N canvas 222 642 607 202 10;
+#X obj 15 35 pdp_conv_sobel_hor;
+#X obj 149 34 pdp_conv_sobel_ver;
+#X obj 15 114 pdp_add;
+#X obj 15 74 pdp_mul;
+#X obj 149 71 pdp_mul;
+#X text 123 105 this uses the horizontal and vertical sobel directional
+masks squared as an edge detector.;
+#X obj 15 9 inlet;
+#X obj 15 151 outlet;
+#X connect 0 0 3 0;
+#X connect 0 0 3 1;
+#X connect 1 0 4 0;
+#X connect 1 0 4 1;
+#X connect 2 0 7 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 1;
+#X connect 6 0 0 0;
+#X connect 6 0 1 0;
diff --git a/abstractions/pdp_conv_sobel_hor.pd b/abstractions/pdp_conv_sobel_hor.pd
new file mode 100644
index 0000000..599034e
--- /dev/null
+++ b/abstractions/pdp_conv_sobel_hor.pd
@@ -0,0 +1,15 @@
+#N canvas 222 642 591 202 10;
+#X obj 29 55 inlet;
+#X obj 29 132 outlet;
+#X obj 29 93 pdp_conv;
+#X obj 108 9 loadbang;
+#X msg 108 37 vmask 0.5 1 0.5;
+#X msg 108 60 hmask -1 0 1;
+#X text 108 101 this uses pdp_conv to produce the vertical sobel edge
+detector with convolution mask (-.5 0 0.5 \; -1 0 1 \; -0.5 0 .5);
+#X connect 0 0 2 0;
+#X connect 2 0 1 0;
+#X connect 3 0 4 0;
+#X connect 4 0 2 0;
+#X connect 4 0 5 0;
+#X connect 5 0 2 0;
diff --git a/abstractions/pdp_conv_sobel_ver.pd b/abstractions/pdp_conv_sobel_ver.pd
new file mode 100644
index 0000000..5ff2edd
--- /dev/null
+++ b/abstractions/pdp_conv_sobel_ver.pd
@@ -0,0 +1,16 @@
+#N canvas 222 642 591 202 10;
+#X obj 29 55 inlet;
+#X obj 29 131 outlet;
+#X obj 29 93 pdp_conv;
+#X obj 108 9 loadbang;
+#X msg 108 37 hmask 0.5 1 0.5;
+#X msg 108 60 vmask 1 0 -1;
+#X text 108 101 this uses pdp_conv to produce the horizontal sobel
+edge detector with convolution mask (-.5 -1 -0.5 \; 0 0 0 \; 0.5 1
+.5);
+#X connect 0 0 2 0;
+#X connect 2 0 1 0;
+#X connect 3 0 4 0;
+#X connect 4 0 2 0;
+#X connect 4 0 5 0;
+#X connect 5 0 2 0;
diff --git a/abstractions/pdp_motion_blur.pd b/abstractions/pdp_motion_blur.pd
new file mode 100644
index 0000000..cc3b8c9
--- /dev/null
+++ b/abstractions/pdp_motion_blur.pd
@@ -0,0 +1,14 @@
+#N canvas 119 483 508 168 10;
+#X obj 29 17 inlet;
+#X obj 29 124 outlet;
+#X obj 29 99 pdp_bqt;
+#X obj 87 18 inlet;
+#X obj 87 42 pdp_ut_logmap_comp 0.005 0.4;
+#X msg 87 68 lpf \$1 0.25;
+#X text 97 108 pdp_motion_blur uses pdp_bqt (time biquad filter) configured
+as a lowpass filter to produce a motion blur effect.;
+#X connect 0 0 2 0;
+#X connect 2 0 1 0;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 5 0 2 0;
diff --git a/abstractions/pdp_motion_phase.pd b/abstractions/pdp_motion_phase.pd
new file mode 100644
index 0000000..2bded3d
--- /dev/null
+++ b/abstractions/pdp_motion_phase.pd
@@ -0,0 +1,14 @@
+#N canvas 58 0 508 168 10;
+#X obj 29 17 inlet;
+#X obj 29 124 outlet;
+#X obj 29 99 pdp_bqt;
+#X obj 87 18 inlet;
+#X text 94 102 pdp_motion_blur uses pdp_bqt (time biquad filter) configured
+as an allpass filter to produce a motion phase shift effect.;
+#X obj 87 42 pdp_ut_logmap_comp 0.01 0.4;
+#X msg 87 68 apf \$1 0.25;
+#X connect 0 0 2 0;
+#X connect 2 0 1 0;
+#X connect 3 0 5 0;
+#X connect 5 0 6 0;
+#X connect 6 0 2 0;
diff --git a/abstractions/pdp_phase.pd b/abstractions/pdp_phase.pd
new file mode 100644
index 0000000..2927fd9
--- /dev/null
+++ b/abstractions/pdp_phase.pd
@@ -0,0 +1,70 @@
+#N canvas 304 524 746 291 10;
+#X obj 25 21 inlet;
+#X obj 25 249 outlet;
+#X obj 25 209 pdp_bq;
+#X obj 42 144 pdp_ut_addscaleclip -1 -0.5 0.05 0.48;
+#X obj 42 44 inlet;
+#X msg 118 109 0;
+#X obj 178 22 loadbang;
+#X msg 304 191 lr 1;
+#X msg 344 191 rl 0;
+#X msg 42 176 apf \$1 0.15;
+#X obj 287 22 inlet;
+#X msg 384 191 lr 0;
+#X msg 422 191 rl 1;
+#X msg 539 191 bt 1;
+#X msg 579 191 tb 0;
+#X msg 619 191 bt 0;
+#X msg 672 191 tb 1;
+#X obj 287 86 select 0;
+#X msg 227 191 lr 0;
+#X msg 265 191 rl 0;
+#X obj 522 19 inlet;
+#X obj 522 84 select 0;
+#X obj 338 114 moses 0;
+#X obj 573 114 moses 0;
+#X msg 241 53 1;
+#X msg 463 191 tb 0;
+#X msg 501 191 bt 0;
+#X text 99 235 this uses pdp_bq as an allpass filter to produce a phase
+shift effect. 2nd inlet sets amount. 3rd and 4t inlets set directions.
+;
+#X connect 0 0 2 0;
+#X connect 2 0 1 0;
+#X connect 3 0 9 0;
+#X connect 4 0 3 0;
+#X connect 5 0 3 0;
+#X connect 6 0 5 0;
+#X connect 6 0 7 0;
+#X connect 6 0 8 0;
+#X connect 6 0 24 0;
+#X connect 7 0 2 0;
+#X connect 8 0 2 0;
+#X connect 9 0 2 0;
+#X connect 10 0 17 0;
+#X connect 11 0 2 0;
+#X connect 12 0 2 0;
+#X connect 13 0 2 0;
+#X connect 14 0 2 0;
+#X connect 16 0 2 0;
+#X connect 17 0 18 0;
+#X connect 17 0 19 0;
+#X connect 17 1 22 0;
+#X connect 18 0 2 0;
+#X connect 19 0 2 0;
+#X connect 20 0 21 0;
+#X connect 21 0 25 0;
+#X connect 21 0 26 0;
+#X connect 21 1 23 0;
+#X connect 22 0 8 0;
+#X connect 22 0 7 0;
+#X connect 22 1 12 0;
+#X connect 22 1 11 0;
+#X connect 23 0 14 0;
+#X connect 23 0 13 0;
+#X connect 23 1 16 0;
+#X connect 23 1 15 0;
+#X connect 24 0 17 0;
+#X connect 24 0 21 0;
+#X connect 25 0 2 0;
+#X connect 26 0 2 0;
diff --git a/abstractions/pdp_phase_hor.pd b/abstractions/pdp_phase_hor.pd
new file mode 100644
index 0000000..8dcac9d
--- /dev/null
+++ b/abstractions/pdp_phase_hor.pd
@@ -0,0 +1,41 @@
+#N canvas 304 524 534 291 10;
+#X obj 25 21 inlet;
+#X obj 25 249 outlet;
+#X obj 25 209 pdp_bq;
+#X obj 42 144 pdp_ut_addscaleclip -1 -0.5 0.05 0.48;
+#X obj 42 44 inlet;
+#X msg 89 44 0;
+#X obj 89 18 loadbang;
+#X msg 42 176 apf \$1 0.15;
+#X obj 338 114 moses 0;
+#X text 99 235 this uses pdp_bq as an allpass filter to produce a phase
+shift effect in the horizontal direction. 2nd inlet sets direction
+and amount. range is from -1 to 1;
+#X obj 42 93 abs;
+#X msg 304 191 lr 0;
+#X msg 344 191 rl 1;
+#X msg 384 191 lr 1;
+#X msg 422 191 rl 0;
+#X msg 89 93 ver 0;
+#X connect 0 0 2 0;
+#X connect 2 0 1 0;
+#X connect 3 0 7 0;
+#X connect 4 0 10 0;
+#X connect 4 0 8 0;
+#X connect 5 0 10 0;
+#X connect 5 0 8 0;
+#X connect 5 0 15 0;
+#X connect 6 0 5 0;
+#X connect 6 0 11 0;
+#X connect 6 0 12 0;
+#X connect 7 0 2 0;
+#X connect 8 0 12 0;
+#X connect 8 0 11 0;
+#X connect 8 1 14 0;
+#X connect 8 1 13 0;
+#X connect 10 0 3 0;
+#X connect 11 0 2 0;
+#X connect 12 0 2 0;
+#X connect 13 0 2 0;
+#X connect 14 0 2 0;
+#X connect 15 0 2 0;
diff --git a/abstractions/pdp_phase_ver.pd b/abstractions/pdp_phase_ver.pd
new file mode 100644
index 0000000..7af57df
--- /dev/null
+++ b/abstractions/pdp_phase_ver.pd
@@ -0,0 +1,41 @@
+#N canvas 304 524 518 291 10;
+#X obj 25 21 inlet;
+#X obj 25 249 outlet;
+#X obj 25 209 pdp_bq;
+#X obj 42 144 pdp_ut_addscaleclip -1 -0.5 0.05 0.48;
+#X obj 42 44 inlet;
+#X msg 89 44 0;
+#X obj 89 18 loadbang;
+#X obj 338 114 moses 0;
+#X obj 42 93 abs;
+#X msg 42 176 apf \$1 0.15;
+#X msg 89 93 hor 0;
+#X msg 304 191 tb 1;
+#X msg 344 191 bt 0;
+#X msg 384 191 tb 0;
+#X msg 422 191 bt 1;
+#X text 99 235 this uses pdp_bq as an allpass filter to produce a phase
+shift effect in the vertical direction. 2nd inlet sets direction and
+amount. range is from -1 to 1;
+#X connect 0 0 2 0;
+#X connect 2 0 1 0;
+#X connect 3 0 9 0;
+#X connect 4 0 8 0;
+#X connect 4 0 7 0;
+#X connect 5 0 8 0;
+#X connect 5 0 7 0;
+#X connect 5 0 10 0;
+#X connect 6 0 5 0;
+#X connect 6 0 11 0;
+#X connect 6 0 12 0;
+#X connect 7 0 12 0;
+#X connect 7 0 11 0;
+#X connect 7 1 14 0;
+#X connect 7 1 13 0;
+#X connect 8 0 3 0;
+#X connect 9 0 2 0;
+#X connect 10 0 2 0;
+#X connect 11 0 2 0;
+#X connect 12 0 2 0;
+#X connect 13 0 2 0;
+#X connect 14 0 2 0;
diff --git a/abstractions/pdp_pps.pd b/abstractions/pdp_pps.pd
new file mode 100644
index 0000000..8abb1dc
--- /dev/null
+++ b/abstractions/pdp_pps.pd
@@ -0,0 +1,18 @@
+#N canvas 115 450 614 279 10;
+#X obj 41 53 pdp_trigger;
+#X obj 113 90 timer;
+#X obj 113 187 /;
+#X obj 113 125 t b f;
+#X msg 113 155 1000;
+#X obj 41 21 inlet;
+#X obj 113 219 outlet;
+#X text 151 36 pdp_pps uses pdp_trigger to measure the number of packets
+per second. you can use this as a performance monitor.;
+#X connect 0 1 1 1;
+#X connect 0 1 1 0;
+#X connect 1 0 3 0;
+#X connect 2 0 6 0;
+#X connect 3 0 4 0;
+#X connect 3 1 2 1;
+#X connect 4 0 2 0;
+#X connect 5 0 0 0;
diff --git a/abstractions/pdp_saturation.pd b/abstractions/pdp_saturation.pd
new file mode 100644
index 0000000..f96f79d
--- /dev/null
+++ b/abstractions/pdp_saturation.pd
@@ -0,0 +1,13 @@
+#N canvas 247 212 237 275 10;
+#X obj 44 52 inlet;
+#X obj 139 53 inlet;
+#X obj 44 202 outlet;
+#X obj 44 139 pdp_gain;
+#X msg 101 103 u \$1;
+#X msg 139 103 v \$1;
+#X connect 0 0 3 0;
+#X connect 1 0 4 0;
+#X connect 1 0 5 0;
+#X connect 3 0 2 0;
+#X connect 4 0 3 0;
+#X connect 5 0 3 0;
diff --git a/debug/gdb_pdp_load b/debug/gdb_pdp_load
new file mode 100644
index 0000000..552372b
--- /dev/null
+++ b/debug/gdb_pdp_load
@@ -0,0 +1,25 @@
+cd ~/pd/packet
+file ~/pd/distro/pd/bin/pd.debug
+# file ~/pd/distro/pd/bin/pd
+set args -r 44100 -alsa -frags 64 -lib pdp -nodac -noadc -path abstractions test/test_pdp_scale.pd
+# set args -lib pdp -nodac -noadc -path abstractions test/test_pdp_thread.pd
+# set args -lib pdp -nodac -noadc test/test_pdp_ca.pd
+# set args -r 44100 -alsa -frags 64 -lib pdp -nodac -noadc test/test_pdp_qt_read.pd
+# dir ~/pd/distro/pd/src
+dir modules
+dir system
+dir mmx
+dir scaf
+dir scaf/modules
+dir scaf/system
+
+# until i figure out how to stop pd without hanging it
+# or set a breakpoint before a library is loaded
+# i'll use the bng_new routine (alt-b) to stop
+
+break bng_new
+
+# uncomment this to break in the library loader
+# break sys_load_lib
+
+
diff --git a/debug/gdb_pdp_load_rt b/debug/gdb_pdp_load_rt
new file mode 100644
index 0000000..7ab3681
--- /dev/null
+++ b/debug/gdb_pdp_load_rt
@@ -0,0 +1,10 @@
+cd /home/tom/pd/packet
+file /home/tom/pd/distro/pd/bin/pd.debug
+# file ~/pd/distro/pd/bin/pd
+set args -rt -r 44100 -alsa -frags 64 -lib pdp -nodac -noadc -nogui test/test_pdp_qt_read.pd
+dir modules
+dir system
+dir mmx
+dir scaf
+dir scaf/modules
+dir scaf/system
diff --git a/doc/control.pd b/doc/control.pd
new file mode 100644
index 0000000..3898e1e
--- /dev/null
+++ b/doc/control.pd
@@ -0,0 +1,17 @@
+#N canvas 372 355 668 154 10;
+#X obj 33 107 pdp_xv;
+#X obj 33 57 pdp_v4l;
+#X msg 33 12 bang;
+#X obj 33 81 pdp_trigger;
+#X obj 33 35 metro 1000;
+#X obj 105 108 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 140 20 pdp_trigger sends out a bang message on the right outlet
+before it passes the incoming pdp message on the left outlet.;
+#X msg 73 12 stop;
+#X connect 1 0 3 0;
+#X connect 2 0 4 0;
+#X connect 3 0 0 0;
+#X connect 3 1 5 0;
+#X connect 4 0 1 0;
+#X connect 7 0 4 0;
diff --git a/doc/examples/example01.pd b/doc/examples/example01.pd
new file mode 100644
index 0000000..d4afc19
--- /dev/null
+++ b/doc/examples/example01.pd
@@ -0,0 +1,45 @@
+#N canvas 142 294 518 446 10;
+#X obj 133 414 pdp_xv;
+#X obj 177 76 pdp_v4l;
+#X obj 177 33 metro 40;
+#X obj 176 8 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 35 149 pdp_conv;
+#X obj 35 173 pdp_conv_sobel_edge;
+#X obj 412 60 pdp_control;
+#X msg 412 32 thread \$1;
+#X obj 412 8 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 133 352 pdp_gradient;
+#X obj 133 288 pdp_motion_phase;
+#X msg 254 30 type grey;
+#X obj 35 125 pdp_del 8;
+#X obj 35 198 pdp_gain 6;
+#X msg 240 252 0.45;
+#X text 223 125 8 frames delay;
+#X text 223 149 smooth;
+#X text 223 174 edge detect;
+#X text 222 200 amplify;
+#X text 232 6 process in greyscale;
+#X obj 133 252 pdp_add;
+#X text 322 287 motion phase shifter;
+#X text 320 354 grey -> colour palette;
+#X msg 36 323 rgb 1 0.5 0;
+#X floatatom 170 386 5 0 0;
+#X connect 1 0 12 0;
+#X connect 1 0 20 1;
+#X connect 2 0 1 0;
+#X connect 3 0 2 0;
+#X connect 4 0 5 0;
+#X connect 5 0 13 0;
+#X connect 7 0 6 0;
+#X connect 8 0 7 0;
+#X connect 9 0 0 0;
+#X connect 10 0 9 0;
+#X connect 11 0 1 0;
+#X connect 12 0 4 0;
+#X connect 13 0 20 0;
+#X connect 14 0 10 1;
+#X connect 20 0 10 0;
+#X connect 23 0 9 0;
+#X connect 24 0 0 1;
diff --git a/doc/examples/example02.pd b/doc/examples/example02.pd
new file mode 100644
index 0000000..0a46e04
--- /dev/null
+++ b/doc/examples/example02.pd
@@ -0,0 +1,44 @@
+#N canvas 85 437 473 316 10;
+#X obj 91 268 pdp_xv;
+#X obj 91 73 pdp_v4l;
+#X obj 91 30 metro 40;
+#X obj 90 5 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 -1
+;
+#X obj 326 57 pdp_control;
+#X msg 326 29 thread \$1;
+#X obj 326 5 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X text 146 3 process in greyscale;
+#X obj 135 195 pdp_gain;
+#X obj 135 222 pdp_gain;
+#X msg 168 27 type yv12;
+#X obj 91 129 pdp_mix;
+#X msg 169 51 type grey;
+#X obj 216 194 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10
+-262144 -1 -1 0.62 256;
+#X obj 139 103 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10
+-262144 -1 -1 0.82 256;
+#X obj 215 133 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10
+-262144 -1 -1 8 256;
+#X obj 135 162 pdp_del 25;
+#X obj 216 173 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -6 0 10
+-262144 -1 -1 1.5 256;
+#X text 289 177 gains clip at -1 \, 1;
+#X msg 159 129 reset;
+#X connect 1 0 11 0;
+#X connect 2 0 1 0;
+#X connect 3 0 2 0;
+#X connect 5 0 4 0;
+#X connect 6 0 5 0;
+#X connect 8 0 9 0;
+#X connect 9 0 11 1;
+#X connect 10 0 1 0;
+#X connect 11 0 0 0;
+#X connect 11 0 16 0;
+#X connect 12 0 1 0;
+#X connect 13 0 9 1;
+#X connect 14 0 11 2;
+#X connect 15 0 16 1;
+#X connect 16 0 8 0;
+#X connect 17 0 8 1;
+#X connect 19 0 16 0;
diff --git a/doc/examples/example03.pd b/doc/examples/example03.pd
new file mode 100644
index 0000000..85f1c01
--- /dev/null
+++ b/doc/examples/example03.pd
@@ -0,0 +1,78 @@
+#N canvas 326 208 841 704 10;
+#X obj 68 318 pdp_noise;
+#X obj 68 85 metro 40;
+#X obj 68 58 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 68 484 pdp_del 50;
+#X obj 112 424 pdp_gain;
+#X floatatom 240 518 5 0 0;
+#X obj 68 514 pdp_blur;
+#X obj 243 499 hsl 128 15 0 1 0 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 2400 1;
+#X floatatom 240 367 5 0 0;
+#X obj 243 342 hsl 128 15 0 5 0 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 4400 1;
+#X floatatom 240 587 5 0 0;
+#X obj 243 567 hsl 128 15 0 1 0 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 5400 1;
+#X floatatom 239 428 5 0 0;
+#X obj 242 409 hsl 128 15 -5 5 0 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 4200 1;
+#X msg 15 460 reset;
+#X obj 68 459 pdp_add;
+#X obj 68 357 pdp_gain;
+#X text 203 7 this example shows how to use a delay line with a loop
+gain > 1 and some processing inside the loop to produce a plasma like
+effect. (WARNING: this can produce a very intense strobe effect \,
+so if you're sensitive to flashing lights please be careful...);
+#X text 391 407 a |gain| > 1 ensures regeneration;
+#X floatatom 119 56 5 0 0;
+#X obj 68 582 pdp_motion_phase;
+#X floatatom 133 459 5 0 0;
+#X text 392 495 blur ensures spatial coupling (determines the speed
+at which "blobs" move around the screen);
+#X text 392 565 a motion phase effect to spice it up (this causes local
+negative feedback around suddon changes);
+#X msg 109 13 40;
+#X msg 144 13 1000;
+#X msg 109 250 type grey;
+#X msg 109 135 type yv12;
+#X obj 68 619 pdp_xv;
+#X text 201 247 it also works for black and white \, but all negative
+colours will be clipped to 0 (black) on output.;
+#X text 393 340 mix in some noise to get it going (set blur to minimal
+when starting so the added noise won't be blurred to black);
+#X text 202 96 it illustrates one of the advantages of working in an
+additive/subtractive colour space. (here yuv or YCrCb). since legal
+colours can be both positive and negative \, the analogy with audio
+signals is easily drawn. this network can be seen as a nonlinear feedback
+delay network. (nonlinear because of the saturating gain). the image
+delay line can be seen as a parallel delay line \, one for each pixel.
+coupling between the delays is done using a spatial blur effect. the
+additional temporal filtering in't necessary \, but it produces a nice
+additional effect.;
+#X connect 0 0 16 0;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X connect 3 0 6 0;
+#X connect 4 0 15 1;
+#X connect 6 0 20 0;
+#X connect 7 0 5 0;
+#X connect 7 0 6 1;
+#X connect 9 0 8 0;
+#X connect 9 0 16 1;
+#X connect 11 0 10 0;
+#X connect 11 0 20 1;
+#X connect 13 0 12 0;
+#X connect 13 0 4 1;
+#X connect 14 0 3 0;
+#X connect 15 0 3 0;
+#X connect 16 0 15 0;
+#X connect 19 0 1 1;
+#X connect 20 0 4 0;
+#X connect 20 0 28 0;
+#X connect 21 0 3 1;
+#X connect 24 0 19 0;
+#X connect 25 0 19 0;
+#X connect 26 0 0 0;
+#X connect 27 0 0 0;
diff --git a/doc/input_output.pd b/doc/input_output.pd
new file mode 100644
index 0000000..fe6ccc1
--- /dev/null
+++ b/doc/input_output.pd
@@ -0,0 +1,53 @@
+#N canvas 182 220 831 596 10;
+#X obj 107 307 pdp_v4l;
+#X obj 107 53 metro 40;
+#X msg 159 14 stop;
+#X msg 107 14 bang;
+#X msg 51 14 bang;
+#X obj 107 538 pdp_xv;
+#X msg 209 93 open /dev/video0;
+#X msg 209 117 open /dev/video1;
+#X text 347 95 you can choose the input device using the 'open' message.
+the default is /dev/video0;
+#X msg 209 142 close;
+#X text 348 143 closes the video port;
+#X msg 209 168 type yv12;
+#X msg 209 192 type grey;
+#X text 348 171 type sets the ouput image package type. currently only
+yv12 (luma/chroma color) and greyscale are supported.;
+#X msg 210 221 dim 320 240;
+#X msg 210 244 dim 640 480;
+#X text 348 215 dim sets the dimensions of the captured frame. please
+note that in all objects dimensions and packet type (color/greyscale)
+have to be the same to be combined (i.e. mixed);
+#X msg 210 433 dim 320 240;
+#X msg 210 456 dim 640 480;
+#X text 349 436 dim sets the window dimensions;
+#X msg 210 387 create;
+#X msg 210 408 destroy;
+#X text 208 324 pdp_xv ouputs video in a window using the xVideo extension.
+if your graphics card/driver supports it you can have multiple output
+windows. if a pdp message is received and a window is not open \, one
+is created automaticly.;
+#X text 349 390 use these messages to explicitly create/destroy the
+window;
+#X text 207 18 pdp_v4l grabs video from the video4linux device. it
+grabs a frame whenever a bang message is received. the output rate
+is limited by the maximum framerate of the video device. if there is
+no device opened \, it will attempt to open /dev/video0;
+#X connect 0 0 5 0;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 0;
+#X connect 4 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
+#X connect 9 0 0 0;
+#X connect 11 0 0 0;
+#X connect 12 0 0 0;
+#X connect 14 0 0 0;
+#X connect 15 0 0 0;
+#X connect 17 0 5 0;
+#X connect 18 0 5 0;
+#X connect 20 0 5 0;
+#X connect 21 0 5 0;
diff --git a/doc/quicktime.pd b/doc/quicktime.pd
new file mode 100644
index 0000000..2f32cfd
--- /dev/null
+++ b/doc/quicktime.pd
@@ -0,0 +1,101 @@
+#N canvas 400 126 715 814 10;
+#X obj 59 391 pdp_qt;
+#X obj 59 462 pdp_xv;
+#X floatatom 77 429 5 0 0;
+#X floatatom 127 430 5 0 0;
+#X obj 56 41 metro 40;
+#X msg 56 13 bang;
+#X msg 97 13 stop;
+#X msg 15 13 bang;
+#X obj 140 41 openpanel;
+#X msg 140 66 open \$1;
+#X msg 140 13 bang;
+#X msg 140 92 close;
+#X text 249 66 open/close for file access;
+#X floatatom 140 120 5 0 0;
+#X floatatom 140 146 5 0 0;
+#X text 248 117 float on left inlet selects a frame for output;
+#X msg 140 197 loop \$1;
+#X obj 203 182 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X text 250 198 automatic looping can be enabled/disabled;
+#X text 251 9 pdp_qt plays a quicktime movie.;
+#X text 250 221 this enables automatic playback at the frame rate specified
+in the movie file. in pdp_qt~ playback is synchronized to the audio
+stream.;
+#X obj 335 535 table array;
+#X msg 142 341 dump array 0;
+#X text 252 330 if the movie contains audio \, this command dumps the
+audio data into an array specified by the first argument. the second
+argument is the audio channel (default = 0 = left);
+#X msg 142 291 stop;
+#X text 251 289 stops automatic playback (same as autoplay 0);
+#X msg 141 222 autoplay 1;
+#X msg 142 267 play;
+#X text 252 432 the second outlet outputs the current frame number.
+the third outlet outputs the total number of frames in a movie when
+it is opened.;
+#X obj 56 786 pdp_xv;
+#X obj 56 715 pdp_qt~;
+#X obj 84 757 dac~;
+#X msg 33 644 play;
+#X obj 127 635 openpanel;
+#X msg 127 660 open \$1;
+#X msg 127 607 bang;
+#X msg 9 760 close;
+#X text 251 660 pdp_qt~ is the same as pdp_qt exept that it also outputs
+the audio data corresponding to the current frame on its 2 rightmost
+outlets. if there is a lag between audio and video a pdp_del object
+can be inserted to delay the image. note that in order to get acceptable
+audio quality with relatively few dropouts you might need to increase
+the pd audio latency.;
+#X msg 7 429 close;
+#X msg 142 315 cont;
+#X text 251 269 starts automatic playback (same as 0 \, autplay 1 \,
+bang);
+#X text 251 310 resumes automatic playback (same as autplay 1 \, bang)
+;
+#X msg 9 617 loop 1;
+#X floatatom 78 645 5 0 0;
+#X obj 448 535 tabplay~ array;
+#X obj 448 576 dac~;
+#X obj 448 506 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 126 685 dump array 0;
+#X text 249 137 float on right inlet selects the frame to be read on
+the next sync event (bang message / internal sync).;
+#X connect 0 0 1 0;
+#X connect 0 1 2 0;
+#X connect 0 2 3 0;
+#X connect 4 0 0 0;
+#X connect 5 0 4 0;
+#X connect 6 0 4 0;
+#X connect 7 0 0 0;
+#X connect 8 0 9 0;
+#X connect 9 0 0 0;
+#X connect 10 0 8 0;
+#X connect 11 0 0 0;
+#X connect 13 0 0 0;
+#X connect 14 0 0 1;
+#X connect 16 0 0 0;
+#X connect 17 0 16 0;
+#X connect 22 0 0 0;
+#X connect 24 0 0 0;
+#X connect 26 0 0 0;
+#X connect 27 0 0 0;
+#X connect 30 0 29 0;
+#X connect 30 3 31 0;
+#X connect 30 4 31 1;
+#X connect 32 0 30 0;
+#X connect 33 0 34 0;
+#X connect 34 0 30 0;
+#X connect 35 0 33 0;
+#X connect 36 0 29 0;
+#X connect 38 0 1 0;
+#X connect 39 0 0 0;
+#X connect 42 0 30 0;
+#X connect 43 0 30 1;
+#X connect 44 0 45 0;
+#X connect 44 0 45 1;
+#X connect 46 0 44 0;
+#X connect 47 0 30 0;
diff --git a/doc/reference.txt b/doc/reference.txt
new file mode 100644
index 0000000..1def808
--- /dev/null
+++ b/doc/reference.txt
@@ -0,0 +1,64 @@
+This is a list of all pdp objects and abstractions with a minimal description.
+Take a look at the patches in the doc/ directory for more info.
+(Messy doc/test patches can be found in the test/ directory.)
+
+general purpose pdp modules:
+
+pdp_del a packet delay line
+pdp_reg a packet register
+pdp_snap takes a snapshot of a packet stream
+pdp_trigger sends out a bang message when a packet is recieved
+pdp_route routes a packet to a specific outlet
+
+image inputs/outputs:
+
+pdp_xv displays images using the xvideo extension
+pdp_v4l reads images from a video4linux device
+pdp_qt reads quicktime movies
+
+image processors:
+
+pdp_add adds two images
+pdp_bq spatial biquad filter
+pdp_bqt temporal biquad filter
+pdp_conv horizontal/vertical seperable convolution filter
+pdp_gradient converts a greyscale image using a colour palette
+pdp_grey converts an image to greyscale
+pdp_mul multiplies two images
+pdp_affine shifts and scales a colour plane
+pdp_mix crossfade between 2 images
+pdp_mix2 mixes 2 images after applying a gain to each of them
+pdp_randmix crossfades 2 images by taking random pixels
+pdp_noise a noise generator
+pdp_scope~ a very simple oscilloscope
+pdp_chrot rotates the chroma components
+pdp_scale rescale an image
+pdp_zoom tiled zoom
+
+utility abstractions
+
+pdp_pps computes the packet rate in packets/sec
+
+image abstractions:
+
+pdp_blur blurs an image
+pdp_blur_hor horizontal blur
+pdp_blur_ver vertical blur
+pdp_phase applies an allpass filter to an image
+pdp_phase_hor horizontal allpass
+pdp_phase_ver vertical allpass
+pdp_motion_blur blurs motion
+pdp_motion_phase phase shifts motion
+pdp_alledge an all edge detector
+pdp_conv_emboss emboss
+pdp_conv_sobel_hor horizontal sobel edge detector
+pdp_conv_sobel_ver vertical sobel edge detector
+pdp_conv_sobel_edge sum of squares of hor and ver
+pdp_saturation change colour saturation
+
+cellular automata:
+
+pdp_ca computes a cellular automaton (as a generator or a filter)
+pdp_ca2image converts a CA packet to a greyscale image
+pdp_image2ca converts an image to a CA packet (black and white)
+
diff --git a/doc/traffic.pd b/doc/traffic.pd
new file mode 100644
index 0000000..40f102d
--- /dev/null
+++ b/doc/traffic.pd
@@ -0,0 +1,101 @@
+#N canvas 155 92 978 574 10;
+#X msg 362 2 stop;
+#X obj 362 27 metro 40;
+#X obj 362 53 pdp_v4l;
+#X obj 32 524 pdp_xv;
+#X obj 847 336 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 847 388 pdp_control;
+#X msg 847 361 thread \$1;
+#X obj 434 56 hdl 15 1 1 4 empty empty empty 0 -6 0 8 -262144 -1 -1
+2;
+#X obj 432 278 pdp_del 25;
+#X obj 410 332 pdp_mix;
+#X obj 457 305 hsl 128 15 0 1 0 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 6500 1;
+#X floatatom 497 249 5 0 0;
+#X text 457 83 packet router. second inlet sets destination outlet.
+creation argument sets number of outlets.;
+#X obj 240 333 pdp_snap;
+#X obj 240 302 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 249 357 packet snapshot;
+#X msg 262 301 snap;
+#X obj 410 456 pdp_trigger;
+#X text 508 463 before it passes the packet;
+#X text 507 450 trigger sends a bang on right outlet;
+#X obj 482 487 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 248 389 bang sends out packet;
+#X obj 434 146 send packet;
+#X text 524 138 pdp packets can be sent over send/receive pairs;
+#X text 523 152 (not over netsend/netreceive pairs!);
+#X obj 451 382 pdp_pps;
+#X floatatom 451 412 5 0 0;
+#X text 513 381 packet rate calculator;
+#X obj 32 21 receive packet;
+#X obj 203 254 pdp_reg;
+#X text 68 222 a packet register;
+#X text 58 235 (like int and float);
+#X obj 32 81 pdp_mix;
+#X obj 79 51 hsl 128 15 0 1 0 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 10500 1;
+#X obj 32 136 pdp_conv;
+#X obj 203 227 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 115 70 feedback;
+#X obj 362 87 pdp_route 4;
+#X text 107 82 is allowed;
+#X obj 335 3 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 754 292 enable or disable processing;
+#X text 754 307 in separate thread;
+#X text 471 342 second inlet 0->1;
+#X text 472 328 mix (crossfade) 2 packets.;
+#X floatatom 83 111 5 0 0;
+#X text 58 253 left: hot packet;
+#X text 58 267 right: cold packet;
+#X floatatom 847 449 5 0 0;
+#X obj 847 420 route pdp_drop;
+#X text 801 473 dropped packet counter;
+#X text 43 159 convolution: default is blur;
+#X text 135 110 number of passes;
+#X text 248 373 snap takes snapshot;
+#X text 134 118 comment;
+#X text 431 185 packet delay line. second inlet sets delay. creation
+argument sets total delay line length. WARNING: this uses a lot of
+memory. keep the size small to prevent the system to start swapping
+to disk.;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 37 0;
+#X connect 4 0 6 0;
+#X connect 5 0 48 0;
+#X connect 6 0 5 0;
+#X connect 7 0 37 1;
+#X connect 8 0 9 1;
+#X connect 9 0 17 0;
+#X connect 9 0 25 0;
+#X connect 10 0 9 2;
+#X connect 11 0 8 1;
+#X connect 13 0 3 0;
+#X connect 14 0 13 0;
+#X connect 16 0 13 0;
+#X connect 17 0 3 0;
+#X connect 17 1 20 0;
+#X connect 25 0 26 0;
+#X connect 28 0 32 0;
+#X connect 29 0 3 0;
+#X connect 32 0 34 0;
+#X connect 33 0 32 2;
+#X connect 34 0 32 1;
+#X connect 34 0 3 0;
+#X connect 35 0 29 0;
+#X connect 37 0 29 1;
+#X connect 37 1 13 1;
+#X connect 37 2 8 0;
+#X connect 37 2 9 0;
+#X connect 37 3 22 0;
+#X connect 39 0 1 0;
+#X connect 44 0 34 1;
+#X connect 48 0 47 0;
diff --git a/include/Makefile b/include/Makefile
new file mode 100644
index 0000000..1aba02c
--- /dev/null
+++ b/include/Makefile
@@ -0,0 +1,6 @@
+current:
+
+
+clean:
+ rm -f *~
+
diff --git a/include/pdp.h b/include/pdp.h
new file mode 100644
index 0000000..4cfd789
--- /dev/null
+++ b/include/pdp.h
@@ -0,0 +1,223 @@
+/*
+ * Pure Data Packet header file.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#ifndef PDP_H
+#define PDP_H
+
+
+/* header size in bytes */
+#define PDP_HEADER_SIZE 64
+
+/* subheader size in bytes */
+#define PDP_SUBHEADER_SIZE 48
+
+#include <string.h>
+#include <stdlib.h>
+#include "m_pd.h"
+
+#include "pdp_mmx.h"
+#include "pdp_imageproc.h"
+#include "pdp_types.h"
+
+/* hope this won't conflict with other types */
+#ifndef __cplusplus
+typedef int bool;
+#define true 1;
+#define false 0;
+#endif
+
+/* remark: planar processing ensures (vector assembler) code reusability
+ for grayscale / rgb(a) / yuv processing. so it's best
+ to keep away from interleaved formats: deinterleaving
+ and interleaving can be done in the source/sink modules
+ (it will probably be very hard to eliminate extra copying
+ anyway, and this enables the possibility to ensure alignment
+ and correct (i.e. multiple of 8 or 16) image dimensions)
+
+ all image data is short int (16 bit)
+
+*/
+
+
+
+
+/* image data packet */
+typedef struct
+{
+ unsigned int encoding; /* image encoding (data format ) */
+ unsigned int width; /* image width in pixels */
+ unsigned int height; /* image height in pixels */
+ unsigned int channels; /* number of colour planes if PDP_IMAGE_MCHP */
+} t_image;
+
+
+/* image encodings */
+#define PDP_IMAGE_YV12 1 /* 24bbp: 16 bit Y plane followed by 16 bit 2x2 subsampled V and U planes.*/
+#define PDP_IMAGE_GREY 2 /* 16bbp: 16 bit Y plane */
+#define PDP_IMAGE_RGBP 3 /* 48bpp: 16 bit planar RGB */
+#define PDP_IMAGE_MCHP 4 /* generic 16bit multi channel planar */
+
+/*
+PDP_IMAGE_GREY = PDP_IMAGE_MCHP, channels = 1
+PDP_IMAGE_RGBP = PDP_IMAGE_MCHP, channels = 3
+
+remark: only 1 and 2 are implemented at this moment
+
+*/
+
+
+/* generic packet subheader */
+//typedef unsigned char t_raw[PDP_SUBHEADER_SIZE];
+typedef unsigned int t_raw;
+
+/* general pdp header struct */
+typedef struct
+{
+ unsigned int type; /* datatype of this object */
+ unsigned int size; /* datasize including header */
+ unsigned int users; /* nb users of this object, readonly if > 1 */
+ unsigned int __pad__;
+ union
+ {
+ t_raw raw; /* raw subheader (for extensions unkown to pdp core system) */
+ t_image image; /* bitmap image */
+ //t_ca ca; /* cellular automaton state data */
+ } info;
+
+} t_pdp;
+
+/* pdp data packet types */
+#define PDP_IMAGE 1 /* 16bit signed planar scanline encoded image packet */
+//RESERVED: #define PDP_CA 2 /* 1bit toroidial shifted scanline encoded cellular automaton */
+
+
+
+
+/* pdp specific constants */
+#define PDP_ALIGN 8
+
+
+/* this needs to be able to grow dynamically, think about it later */
+#define PDP_OBJECT_ARRAY_SIZE 1024
+
+
+/* all symbols are C-style */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ //extern t_pdp* pdp_stack[];
+ //extern t_symbol* pdp_sym_register_rw;
+ //extern t_symbol* pdp_sym_register_ro;
+ //extern t_symbol* pdp_sym_process;
+
+/* setup methods */
+
+void pdp_init(void);
+void pdp_destroy(void);
+
+
+/* object manips */
+
+extern int pdp_packet_new(unsigned int datatype, unsigned int datasize); /* create a new packet */
+extern t_pdp* pdp_packet_header(int handle); /* get packet header */
+extern void* pdp_packet_data(int handle); /* get packet raw data */
+extern int pdp_packet_copy_ro(int handle); /* get a read only copy */
+extern int pdp_packet_copy_rw(int handle); /* get a read/write copy */
+extern int pdp_packet_clone_rw(int handle); /* get an empty read/write packet of the same type (only copy header) */
+extern void pdp_packet_mark_unused(int handle); /* indicate that you're done with the packet */
+
+/*
+
+If an owner unregisters a packet, he can still pass it along to clients. More
+specificly this is the desired behaviour. It is a simple way to have in place
+data processing (if there is only one client) and garbage collection. The first
+register call revives the object.
+
+WARNING: it is an error to call pdp_packet_new inside a pdp packet handler BEFORE
+a packet is registered.
+
+packet id -1 is the id of an invalid packet. it is not an error to unregister it.
+packet id -2 can be used as a bogus id. it is an error to unregister it though.
+
+*/
+
+
+/* processor queue methods, callable from main pd thread */
+/* warning: only pdp_packet_header and pdp_packet_data are legal inside process routine!! */
+
+/* add a method to the processing queue */
+void pdp_queue_add(void *owner, void *process, void *callback, int *queue_id);
+
+/* halt main tread until processing is done */
+void pdp_queue_wait(void);
+
+/* halt main tread until processing is done and remove
+ callback from queue(for destructors) */
+void pdp_queue_finish(int queue_id);
+
+
+/* misc signals to pdp */
+void pdp_control_notify_drop(int packet);
+
+
+/* helper methods */
+
+/* send a packet to an outlet */
+void outlet_pdp(t_outlet *out, int packetid);
+
+
+/* if packet is valid, mark it unused and send it to an outlet */
+void pdp_pass_if_valid(t_outlet *outlet, int *packet);
+
+/* if source packet is valid, release dest packet and move src->dest */
+void pdp_replace_if_valid(int *dpacket, int *spacket);
+
+/* copy_ro if dest packet if invalid, else drop source
+ (don't copy) + send drop notif to pdp system
+ returns 1 if dropped, 0 if copied */
+int pdp_packet_copy_ro_or_drop(int *dpacket, int spacket);
+
+/* copy_rw if dest packit is invalid, else drop source
+ (don't copy) + send drop notif to pdp system
+ returns 1 if dropped, zero if copied */
+int pdp_packet_copy_rw_or_drop(int *dpacket, int spacket);
+
+
+/* check if packets are compatible */
+int pdp_type_compat(int packet0, int packet1);
+int pdp_type_compat_image(int packet0, int packet1);
+
+int pdp_type_isvalid_image(int packet);
+
+
+/* short cuts to create specific packets */
+int pdp_packet_new_image_yv12(u32 width, u32 height);
+int pdp_packet_new_image_grey(u32 width, u32 height);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/pdp_imageproc.h b/include/pdp_imageproc.h
new file mode 100644
index 0000000..4921612
--- /dev/null
+++ b/include/pdp_imageproc.h
@@ -0,0 +1,150 @@
+
+/*
+ * Pure Data Packet. Header file for image processing routines (used in modules).
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* this is a c wrapper around platform specific (mmx) code */
+
+
+#ifndef PDP_IMAGEPROC_H
+#define PDP_IMAGEPROC_H
+
+/*
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+*/
+
+/****************************** 16 bit signed (pixel) routines ***************************************/
+
+#include "pdp_types.h"
+//typedef unsigned long u32;
+//typedef unsigned long long u64;
+//typedef short s16;
+//typedef long s32;
+
+// mix 2 images
+void *pdp_imageproc_mix_new(void);
+void pdp_imageproc_mix_delete(void *x);
+void pdp_imageproc_mix_setleftgain(void *x, float gain);
+void pdp_imageproc_mix_setrightgain(void *x, float gain);
+void pdp_imageproc_mix_process(void *x, s16 *image, s16 *image2, u32 width, u32 height);
+
+// random mix 2 images
+// note: random number generator can be platform specific
+// however, it should be seeded. (same seed produces the same result)
+// threshold = 0 -> left image
+// threshold = 1 -> right image
+
+void *pdp_imageproc_randmix_new(void);
+void pdp_imageproc_randmix_delete(void *x);
+void pdp_imageproc_randmix_setthreshold(void *x, float threshold);
+void pdp_imageproc_randmix_setseed(void *x, float seed);
+void pdp_imageproc_randmix_process(void *x, s16 *image, s16 *image2, u32 width, u32 height);
+
+
+// produce a random image
+// note: random number generator can be platform specific
+// however, it should be seeded. (same seed produces the same result)
+void *pdp_imageproc_random_new(void);
+void pdp_imageproc_random_delete(void *x);
+void pdp_imageproc_random_setseed(void *x, float seed);
+void pdp_imageproc_random_process(void *x, s16 *image, u32 width, u32 height);
+
+
+// apply a gain to an image
+void *pdp_imageproc_gain_new(void);
+void pdp_imageproc_gain_delete(void *x);
+void pdp_imageproc_gain_setgain(void *x, float gain);
+void pdp_imageproc_gain_process(void *x, s16 *image, u32 width, u32 height);
+
+
+
+// add two images
+void pdp_imageproc_add_process(s16 *image, s16 *image2, u32 width, u32 height);
+
+// mul two images
+void pdp_imageproc_mul_process(s16 *image, s16 *image2, u32 width, u32 height);
+
+
+// affine transformation (applies gain + adds offset)
+void *pdp_imageproc_affine_new(void);
+void pdp_imageproc_affine_delete(void *x);
+void pdp_imageproc_affine_setgain(void *x, float gain);
+void pdp_imageproc_affine_setoffset(void *x, float offset);
+void pdp_imageproc_affine_process(void *x, s16 *image, u32 width, u32 height);
+
+// 3x1 or 1x3 in place convolution
+// orientation
+#define PDP_IMAGEPROC_CONV_HORIZONTAL 0
+#define PDP_IMAGEPROC_CONV_VERTICAL 1
+void *pdp_imageproc_conv_new(void);
+void pdp_imageproc_conv_delete(void *x);
+void pdp_imageproc_conv_setmin1(void *x, float val);
+void pdp_imageproc_conv_setzero(void *x, float val);
+void pdp_imageproc_conv_setplus1(void *x, float val);
+void pdp_imageproc_conv_setbordercolor(void *x, float intensity);
+void pdp_imageproc_conv_process(void *x, s16 *image, u32 width, u32 height, u32 orientation, u32 nbpasses);
+
+
+// colour rotation for 2 colour planes
+// matrix is column encoded
+void *pdp_imageproc_crot2d_new(void);
+void pdp_imageproc_crot2d_delete(void *x);
+void pdp_imageproc_crot2d_setmatrix(void *x, float *matrix);
+void pdp_imageproc_crot2d_process(void *x, s16 *image, u32 width, u32 height);
+
+// colour rotation for 3 colour planes
+void *pdp_imageproc_crot3d_new(void);
+void pdp_imageproc_crot3d_delete(void *x);
+void pdp_imageproc_crot3d_setmatrix(void *x, float *matrix);
+void pdp_imageproc_crot3d_process(void *x, s16 *image, u32 width, u32 height);
+
+
+
+
+// biquad space
+
+// directions
+#define PDP_IMAGEPROC_BIQUAD_TOP2BOTTOM (1<<0)
+#define PDP_IMAGEPROC_BIQUAD_BOTTOM2TOP (1<<1)
+#define PDP_IMAGEPROC_BIQUAD_LEFT2RIGHT (1<<2)
+#define PDP_IMAGEPROC_BIQUAD_RIGHT2LEFT (1<<3)
+void *pdp_imageproc_bq_new(void);
+void pdp_imageproc_bq_delete(void *x);
+void pdp_imageproc_bq_setcoef(void *x, float *coef); // a0,a1,a2,b0,b1,b2
+void pdp_imageproc_bq_process(void *x, s16 *image, u32 width, u32 height, u32 direction, u32 nbpasses);
+
+
+// biquad time
+void *pdp_imageproc_bqt_new(void);
+void pdp_imageproc_bqt_delete(void *x);
+void pdp_imageproc_bqt_setcoef(void *x, float *coef); // a0,a1,a2,b0,b1,b2
+void pdp_imageproc_bqt_process(void *x, s16 *image, s16 *state0, s16 *state1, u32 width, u32 height);
+
+
+
+/*
+#ifdef __cplusplus
+}
+#endif
+*/
+
+#endif //PDP_IMAGEPROC_H
diff --git a/include/pdp_internals.h b/include/pdp_internals.h
new file mode 100644
index 0000000..0c580fb
--- /dev/null
+++ b/include/pdp_internals.h
@@ -0,0 +1,50 @@
+
+/*
+ * Pure Data Packet internal header file.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/* this file contains prototypes for "private" pdp methods */
+
+
+/* pdp system code is not very well organized, this is an
+ attempt to do better. */
+
+
+#ifndef PDP_INTERNALS_H
+#define PDP_INTERNALS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//#include "pdp.h"
+//#include <pthread.h>
+//#include <unistd.h>
+//#include <stdio.h>
+
+void pdp_queue_use_thread(int t);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/include/pdp_llconv.h b/include/pdp_llconv.h
new file mode 100644
index 0000000..7b31882
--- /dev/null
+++ b/include/pdp_llconv.h
@@ -0,0 +1,78 @@
+/*
+ * Pure Data Packet system implementation. : low level format conversion code
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* this file contains low level conversion code
+ it is a wrapper around some machine code routines padded
+ with some extra c code */
+
+/* don't rely too much on the calling conventions here
+ this is mainly to tuck away "ugly" parts of the code
+ that come up in several places */
+
+
+
+#include "pdp.h"
+
+/* all symbols are C style */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+/* raw image formats (RIF) descriptions used for low level conversion routines
+ format: RIF_[component names and order]_[data arganization]_[data type]
+
+ component names: R(red), G(green), B(blue), Y(chroma), V(chroma red), U(chroma blue)
+ component type: [S/U][nb bits] ex: S16, U8
+ data organization: [P/P[samplefrequency]] ex: P(packed) P411(planar, 2nd and 3rd 2x2 subsampled)
+
+
+*/
+
+enum RIF {
+ RIF_YVU__P411_U8,
+ RIF_YUV__P411_U8,
+ RIF_YVU__P411_S16,
+ RIF_YVU__P444_S16,
+ RIF_YUYV_P____U8,
+ RIF_RGB__P____U8,
+ RIF_RGBA_P____U8,
+ RIF_RGB__P444_S16,
+ RIF_GREY______S16,
+ RIF_GREY______U8
+
+};
+
+/* pdp_llconv is NOT thread safe !*/
+/* gain = 1.0 means maximal */
+/* low level convert 2 images */
+void pdp_llconv(void *src, int stype, void *dest, int dtype, int w, int h);
+
+
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/include/pdp_mmx.h b/include/pdp_mmx.h
new file mode 100644
index 0000000..8e70779
--- /dev/null
+++ b/include/pdp_mmx.h
@@ -0,0 +1,158 @@
+
+/*
+ * Pure Data Packet. Header file for mmx routines.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#ifndef PDP_MMX_H
+#define PDP_MMX_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************** 16 bit signed (pixel) routines ***************************************/
+
+/* pack: gain is 8.8 fixed point */
+void pixel_pack_s16u8_y(short int *input_pixels,
+ unsigned char *output_pixels,
+ int nb_pixels_div_8);
+
+void pixel_pack_s16u8_uv(short int *input_pixels,
+ unsigned char *output_pixels,
+ int nb_pixels_div_8);
+
+
+/* unpack: gain is not used -> full scale unpack */
+void pixel_unpack_u8s16_y(unsigned char *input_pixels,
+ short int *output_pixels,
+ int nb_pixels_div_8);
+
+void pixel_unpack_u8s16_uv(unsigned char *input_pixels,
+ short int *output_pixels,
+ int nb_pixels_div_8);
+
+
+/* gain */
+/* gain = integer */
+/* shift is down shift count */
+void pixel_gain_s16(short int *image,
+ int nb_4pixel_vectors,
+ short int gain[4],
+ unsigned long long *shift);
+
+
+/* mix: left = gain_left * left + gain_right * right / gains are s.15 fixed point */
+void pixel_mix_s16(short int *left,
+ short int *right,
+ int nb_4pixel_vectors,
+ short int gain_left[4],
+ short int gain_right[4]);
+
+void pixel_randmix_s16(short int *left,
+ short int *right,
+ int nb_4pixel_vectors,
+ short int random_seed[4],
+ short int threshold[4]);
+
+void pixel_rand_s16(short int *image,
+ int nb_4pixel_vectors,
+ short int random_seed[4]);
+
+void pixel_add_s16(short int *left,
+ short int *right,
+ int nb_4pixel_vectors);
+
+void pixel_mul_s16(short int *left,
+ short int *right,
+ int nb_4pixel_vectors);
+
+
+/* affine transfo */
+void pixel_affine_s16(short int *buf,
+ int nb_4pixel_vectors,
+ short int gain[4],
+ short int offset[4]);
+
+/* conv */
+void pixel_conv_hor_s16(short int *pixel_array,
+ int nb_4_pixel_vectors,
+ short int border[4],
+ short int mask[12]);
+
+void pixel_conv_ver_s16(short int *pixel_array,
+ int nb_4_pixel_vectors,
+ int row_byte_size,
+ short int border[4],
+ short int mask[12]);
+
+/* biquad */
+
+void pixel_biquad_vertb_s16(short int *pixel_array,
+ int nb_4x4_pixblocks,
+ int linewidth,
+ short int coef[20],
+ short int state[8]);
+
+void pixel_biquad_verbt_s16(short int *pixel_array,
+ int nb_4x4_pixblocks,
+ int linewidth,
+ short int coef[20],
+ short int state[8]);
+
+
+void pixel_biquad_horlr_s16(short int *pixel_array,
+ int nb_4x4_pixblocks,
+ int linewidth,
+ short int coef[20],
+ short int state[8]);
+
+void pixel_biquad_horrl_s16(short int *pixel_array,
+ int nb_4x4_pixblocks,
+ int linewidth,
+ short int coef[20],
+ short int state[8]);
+
+void pixel_biquad_time_s16(short int *pixel_array,
+ short int *state_array1,
+ short int *state_array2,
+ short int *coefs,
+ int nb_4_pix_vectors);
+
+/********************************** PLANAR COLOUR OPERATIONS ***************************************/
+
+/* color rotation for 3 colour planes */
+void pixel_crot3d_s16(short int *pixel_array,
+ int nb_4pixel_vectors_per_plane,
+ short int *row_encoded_vector_matrix);
+
+
+/* color rotation for 2 colour planes */
+void pixel_crot2d_s16(short int *pixel_array,
+ int nb_4pixel_vectors_per_plane,
+ short int *row_encoded_vector_matrix);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif //PDP_MMX_H
diff --git a/include/pdp_resample.h b/include/pdp_resample.h
new file mode 100644
index 0000000..773c12c
--- /dev/null
+++ b/include/pdp_resample.h
@@ -0,0 +1,42 @@
+/*
+ * Pure Data Packet header file. - image resampling prototypes
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef PDP_RESAMPLE_H
+#define PDP_RESAMPLE_H
+
+#include "pdp_types.h"
+
+
+/* image resampling methods */
+void pdp_resample_scale_bilin(s16 *src_image, s16 *dst_image, s32 src_w, s32 src_h, s32 dst_w, s32 dst_h);
+void pdp_resample_scale_nn(s16 *src_image, s16 *dst_image, s32 src_w, s32 src_h, s32 dst_w, s32 dst_h);
+
+void pdp_resample_zoom_tiled_bilin(s16 *src_image, s16 *dst_image, s32 w, s32 h,
+ float zoom_x, float zoom_y, float center_x_relative, float center_y_relative);
+
+//void pdp_resample_zoom_tiled_nn(s16 *src_image, s16 *dst_image, s32 w, s32 h, float zoom_x, float zoom_y);
+
+
+
+/* core routines */
+s32 pdp_resample_bilin(s16 *image, s32 width, s32 height, s32 virt_x, s32 virt_y);
+
+
+#endif
diff --git a/include/pdp_types.h b/include/pdp_types.h
new file mode 100644
index 0000000..32ab03f
--- /dev/null
+++ b/include/pdp_types.h
@@ -0,0 +1,36 @@
+
+/*
+ * Pure Data Packet header file. Scalar type definitions.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#ifndef PDP_TYPES_H
+#define PDP_TYPES_H
+
+typedef signed char s8;
+typedef signed short s16;
+typedef signed long s32;
+typedef signed long long s64;
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+typedef unsigned long long u64;
+
+#endif
diff --git a/include/pwc-ioctl.h b/include/pwc-ioctl.h
new file mode 100644
index 0000000..19b267a
--- /dev/null
+++ b/include/pwc-ioctl.h
@@ -0,0 +1,123 @@
+#ifndef PWC_IOCTL_H
+#define PWC_IOCTL_H
+
+/* (C) 2001 Nemosoft Unv. webcam@smcc.demon.nl
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ Changes
+ 2001/08/03 Alvarado Added ioctl constants to access methods for
+ changing white balance and red/blue gains
+ */
+
+/* These are private ioctl() commands, specific for the Philips webcams.
+ They contain functions not found in other webcams, and settings not
+ specified in the Video4Linux API.
+
+ The #define names are built up like follows:
+ VIDIOC VIDeo IOCtl prefix
+ PWC Philps WebCam
+ G optional: Get
+ S optional: Set
+ ... the function
+ */
+
+
+
+
+/* The frame rate is encoded in the video_window.flags parameter using
+ the upper 16 bits, since some flags are defined nowadays. The following
+ defines provide a mask and shift to filter out this value.
+
+ In 'Snapshot' mode the camera freezes its automatic exposure and colour
+ balance controls.
+ */
+#define PWC_FPS_SHIFT 16
+#define PWC_FPS_MASK 0x00FF0000
+#define PWC_FPS_FRMASK 0x003F0000
+#define PWC_FPS_SNAPSHOT 0x00400000
+
+
+/* pwc_whitebalance.mode values */
+#define PWC_WB_INDOOR 0
+#define PWC_WB_OUTDOOR 1
+#define PWC_WB_FL 2
+#define PWC_WB_MANUAL 3
+#define PWC_WB_AUTO 4
+
+/* Used with VIDIOCPWC[SG]AWB (Auto White Balance).
+ Set mode to one of the PWC_WB_* values above.
+ *red and *blue are the respective gains of these colour components inside
+ the camera; range 0..65535
+ When mode == PWC_WB_MANUAL, manual_red and manual_blue are set or read;
+ otherwise undefined.
+ read_red and read_blue are read-only.
+*/
+
+struct pwc_whitebalance
+{
+ int mode;
+ int manual_red, manual_blue; /* R/W */
+ int read_red, read_blue; /* R/O */
+};
+
+
+/* Used with VIDIOCPWC[SG]LED */
+struct pwc_leds
+{
+ int led_on; /* Led on-time; range = 0..255 */
+ int led_off; /* */
+};
+
+
+
+ /* Restore user settings */
+#define VIDIOCPWCRUSER _IO('v', 192)
+ /* Save user settings */
+#define VIDIOCPWCSUSER _IO('v', 193)
+ /* Restore factory settings */
+#define VIDIOCPWCFACTORY _IO('v', 194)
+
+ /* You can manipulate the compression factor. A compression preference of 0
+ means use uncompressed modes when available; 1 is low compression, 2 is
+ medium and 3 is high compression preferred. Of course, the higher the
+ compression, the lower the bandwidth used but more chance of artefacts
+ in the image. The driver automatically chooses a higher compression when
+ the preferred mode is not available.
+ */
+ /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */
+#define VIDIOCPWCSCQUAL _IOW('v', 195, int)
+ /* Get preferred compression quality */
+#define VIDIOCPWCGCQUAL _IOR('v', 195, int)
+
+ /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */
+#define VIDIOCPWCSAGC _IOW('v', 200, int)
+ /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCGAGC _IOR('v', 200, int)
+ /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCSSHUTTER _IOW('v', 201, int)
+
+ /* Color compensation (Auto White Balance) */
+#define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance)
+#define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance)
+
+ /* Turn LED on/off ; int range 0..65535 */
+#define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds)
+ /* Get state of LED; int range 0..65535 */
+#define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds)
+
+#endif
diff --git a/modules/Makefile b/modules/Makefile
new file mode 100644
index 0000000..3b5d402
--- /dev/null
+++ b/modules/Makefile
@@ -0,0 +1,16 @@
+current: all_modules
+
+include ../Makefile.config
+
+OBJECTS = pdp_xv.o pdp_qt.o pdp_add.o pdp_reg.o pdp_conv.o \
+ pdp_mix.o pdp_v4l.o pdp_affine.o pdp_del.o pdp_mul.o pdp_randmix.o \
+ pdp_snap.o pdp_trigger.o pdp_bq.o pdp_noise.o pdp_gradient.o \
+ pdp_route.o pdp_gain.o pdp_grey.o pdp_chrot.o pdp_scope.o \
+ pdp_scale.o pdp_zoom.o
+
+all_modules: $(OBJECTS)
+
+clean:
+ rm -f *~
+ rm -f *.o
+
diff --git a/modules/README b/modules/README
new file mode 100644
index 0000000..537ff2d
--- /dev/null
+++ b/modules/README
@@ -0,0 +1,33 @@
+This file describes the protocol used for communicating packets.
+See include/pdp.h and the sources in this directory for more info.
+
+There are 3 kinds of pdp messages:
+
+[pdp register_ro <packet_id>]
+[pdp register_rw <packet_id>]
+[pdp process]
+
+An object can receive a packet by catching the 3 kinds of messages:
+
+When a register_ro message is received, the object can call
+pdp_packet_copy_ro(packet) to reseve a read only copy for itself.
+The only operations on the packet at that time are read only
+operations.
+
+The same goes for handling the register_rw message. You can
+reserve a read/write copy by using pdp_packet_copy_rw(packet)
+
+When a process message is received, the object is allowed to start
+processing the data.
+
+In the register_ro or register_rw phases, the object can inspect
+the packet to see if it wants to register it (using pdp_packet_header
+and pdp_packet_data operations) but it is not allowed to allocate other objects
+in that phase. This is only allowed in the process phase. (or after
+the receiving packet is registerd.)
+
+An object can send out a pdp message using the outlet_pdp(outlet, packet)
+function. This sends out these 3 messages in sequence. It is best to
+unregister a packet using pdp_packet_mark_unused(packet) before sending it out,
+if it is no longer used by the sending object. This eliminates one extra
+copy operation on the data.
diff --git a/modules/pdp_add.c b/modules/pdp_add.c
new file mode 100644
index 0000000..9bf8c13
--- /dev/null
+++ b/modules/pdp_add.c
@@ -0,0 +1,205 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+
+typedef struct pdp_add_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0; // packet outlet
+
+ int x_packet0; // current hot packet (left inlet)
+ int x_packet1; // current cold packet (right inlet)
+ int x_packet1next; // next cold packet (right inlet)
+ int x_queue_id; // task id in process queue (for callback cancelling)
+ int x_dropped; // indicate if a packet was dropped during register_rw cycle
+
+} t_pdp_add;
+
+
+
+static void pdp_add_process_yv12(t_pdp_add *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+
+ // set hight so it includes the chroma frames
+ h = h + (h>>1);
+
+ pdp_imageproc_add_process((short int*)data0, (short int*)data1, w, h);
+
+
+ return;
+}
+
+static void pdp_add_process_grey(t_pdp_add *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ pdp_imageproc_add_process((short int*)data0, (short int*)data1, w, h);
+
+
+ return;
+}
+
+static void pdp_add_process(t_pdp_add *x)
+{
+ int encoding;
+
+ /* check if image data packets are compatible */
+ if (pdp_type_compat_image(x->x_packet0, x->x_packet1)){
+
+ /* dispatch to process thread */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_add_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_add_process_grey(x);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont process */
+
+ }
+ }
+}
+
+/* this method is called after the thread has finished processing */
+static void pdp_add_sendpacket(t_pdp_add *x)
+{
+
+ /* unregister (mark unused) packet and propagate if packet is valid */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+
+}
+
+static void pdp_add_input_0(t_pdp_add *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* if a cold packet was received in the meantime
+ swap it in, else keep the old one */
+
+ pdp_replace_if_valid(&x->x_packet1, &x->x_packet1next);
+
+
+ /* add the process method and callback to the process queue */
+
+ pdp_queue_add(x, pdp_add_process, pdp_add_sendpacket, &x->x_queue_id);
+ }
+}
+
+static void pdp_add_input_1(t_pdp_add *x, t_symbol *s, t_floatarg f)
+{
+ /* store the packet and trow away
+ the old one, if there is any */
+
+ int p = (int)f;
+
+ if(s == gensym("register_ro")) pdp_packet_copy_ro_or_drop(&x->x_packet1next, p);
+
+}
+
+
+
+
+
+static void pdp_add_free(t_pdp_add *x)
+{
+ /* remove process method from queue before deleting data */
+ pdp_queue_finish(x->x_queue_id);
+
+ /* delete stuff */
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+ pdp_packet_mark_unused(x->x_packet1next);
+
+}
+
+t_class *pdp_add_class;
+
+
+
+void *pdp_add_new(void)
+{
+ t_pdp_add *x = (t_pdp_add *)pd_new(pdp_add_class);
+
+ /* init in/out */
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ /* init pdp vars */
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_packet1next = -1;
+ x->x_queue_id = -1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_add_setup(void)
+{
+
+
+ pdp_add_class = class_new(gensym("pdp_add"), (t_newmethod)pdp_add_new,
+ (t_method)pdp_add_free, sizeof(t_pdp_add), 0, A_NULL);
+
+
+ class_addmethod(pdp_add_class, (t_method)pdp_add_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_add_class, (t_method)pdp_add_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_affine.c b/modules/pdp_affine.c
new file mode 100644
index 0000000..06d41ac
--- /dev/null
+++ b/modules/pdp_affine.c
@@ -0,0 +1,223 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+#include "pdp_mmx.h"
+
+
+typedef struct pdp_affine_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ int x_packet0;
+ int x_queue_id;
+ int x_dropped; // indicate if a packet was dropped during register_rw cycle
+
+ int x_channel;
+
+ void *x_affine;
+
+} t_pdp_affine;
+
+
+
+static void pdp_affine_process_yv12(t_pdp_affine *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data (x->x_packet0);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ unsigned int size = w*h;
+ unsigned int v_offset = size;
+ unsigned int u_offset = size + (size >> 2) ;
+ unsigned int i,j;
+
+ short int * idata = (short int *)data0;
+ int ch = x->x_channel;
+
+ if((ch == 0) || (ch==1)) pdp_imageproc_affine_process(x->x_affine, &idata[0], w, h);
+ if((ch == 0) || (ch==2)) pdp_imageproc_affine_process(x->x_affine, &idata[v_offset], w>>1, h>>1);
+ if((ch == 0) || (ch==3)) pdp_imageproc_affine_process(x->x_affine, &idata[u_offset], w>>1, h>>1);
+
+ return;
+
+
+}
+
+static void pdp_affine_process_grey(t_pdp_affine *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data (x->x_packet0);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ short int * idata = (short int *)data0;
+ int ch = x->x_channel;
+
+ if((ch == 0) || (ch==1)) pdp_imageproc_affine_process(x->x_affine, &idata[0], w, h);
+
+ return;
+
+
+}
+
+static void pdp_affine_process(t_pdp_affine *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+
+ /* check data packets */
+
+ if ((header0) && (PDP_IMAGE == header0->type)){
+
+ /* pdp_affine_process inputs and write into active inlet */
+ switch(header0->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_affine_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_affine_process_grey(x);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont pdp_affine_process */
+
+ }
+ }
+
+}
+
+static void pdp_affine_sendpacket(t_pdp_affine *x)
+{
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_affine_input_0(t_pdp_affine *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+
+ /* add the process method and callback to the process queue */
+
+ pdp_queue_add(x, pdp_affine_process, pdp_affine_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+
+
+static void pdp_affine_gain(t_pdp_affine *x, t_floatarg f)
+{
+ pdp_imageproc_affine_setgain(x->x_affine, f);
+
+}
+
+static void pdp_affine_offset(t_pdp_affine *x, t_floatarg f)
+{
+ pdp_imageproc_affine_setoffset(x->x_affine, f);
+}
+
+static void pdp_affine_channel(t_pdp_affine *x, t_floatarg f)
+{
+ int ch = (int)f;
+
+
+ if ((ch < 1) || (ch > 3)) ch = 0;
+
+ x->x_channel = ch;
+
+
+}
+static void pdp_affine_free(t_pdp_affine *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_imageproc_affine_delete(x->x_affine);
+ pdp_packet_mark_unused(x->x_packet0);
+
+}
+
+t_class *pdp_affine_class;
+
+
+
+void *pdp_affine_new(t_floatarg f)
+{
+ t_pdp_affine *x = (t_pdp_affine *)pd_new(pdp_affine_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("gain"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("offset"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+
+ x->x_affine = pdp_imageproc_affine_new();
+
+ pdp_affine_gain(x, 1.0f);
+ pdp_affine_offset(x, 0.0f);
+ pdp_affine_channel(x, f);
+
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_affine_setup(void)
+{
+
+
+ pdp_affine_class = class_new(gensym("pdp_affine"), (t_newmethod)pdp_affine_new,
+ (t_method)pdp_affine_free, sizeof(t_pdp_affine), 0, A_DEFFLOAT, A_NULL);
+
+
+ class_addmethod(pdp_affine_class, (t_method)pdp_affine_gain, gensym("gain"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_affine_class, (t_method)pdp_affine_offset, gensym("offset"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_affine_class, (t_method)pdp_affine_channel, gensym("chan"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_affine_class, (t_method)pdp_affine_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_bq.c b/modules/pdp_bq.c
new file mode 100644
index 0000000..b7c33c2
--- /dev/null
+++ b/modules/pdp_bq.c
@@ -0,0 +1,698 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+#include "pdp_mmx.h"
+#include <math.h>
+
+/* computes a transfer function:
+ *
+ * b0 + b1 z^(-1) + b2 z^(-2)
+ * T(z) = --------------------------
+ * 1 + a1 z^(-1) + a2 z^(-2)
+ *
+ * TODO: think about scaling.
+ */
+
+
+/*
+ * TODO:
+ * add another time processing class
+ * add methods for separate horizontal/vertical filters
+ */
+
+
+typedef struct pdp_bq_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+ //_outlet *x_outlet1;
+ //t_outlet *x_outlet2;
+
+ /* pass through packet */
+ int x_packet0;
+
+ /* state packets for bqt */
+ int x_packet1;
+ int x_packet2;
+
+ int x_dropped;
+ int x_queue_id;
+
+ unsigned int x_nbpasses;
+
+ /* single direction */
+ unsigned int x_direction;
+
+ bool x_reset_on_formatchange;
+
+
+ void *x_biquad;
+
+ float x_coefs_a[3]; // a0, -a1, -a2
+ float x_coefs_b[3]; // b0, b1, b2
+ float x_state_u[2]; // u0, u1
+ float x_state_u_save[2]; // u0, u1 (for reset)
+
+} t_pdp_bq;
+
+
+/************************* COEFFICIENT METHODS ****************************/
+
+static void pdp_bq_a0(t_pdp_bq *x, t_floatarg f){x->x_coefs_a[0] = f;}
+static void pdp_bq_a1(t_pdp_bq *x, t_floatarg f){x->x_coefs_a[1] = -f;}
+static void pdp_bq_a2(t_pdp_bq *x, t_floatarg f){x->x_coefs_a[2] = -f;}
+
+static void pdp_bq_b0(t_pdp_bq *x, t_floatarg f){x->x_coefs_b[0] = f;}
+static void pdp_bq_b1(t_pdp_bq *x, t_floatarg f){x->x_coefs_b[1] = f;}
+static void pdp_bq_b2(t_pdp_bq *x, t_floatarg f){x->x_coefs_b[2] = f;}
+
+static void pdp_bq_u0(t_pdp_bq *x, t_floatarg f){x->x_state_u_save[0] = f;}
+static void pdp_bq_u1(t_pdp_bq *x, t_floatarg f){x->x_state_u_save[1] = f;}
+
+
+static void pdp_bq_setcoefs(t_pdp_bq *x,
+ float a0, float a1, float a2,
+ float b0, float b1, float b2)
+{
+ pdp_bq_a0(x,a0);
+ pdp_bq_a1(x,a1);
+ pdp_bq_a2(x,a2);
+ pdp_bq_b0(x,b0);
+ pdp_bq_b1(x,b1);
+ pdp_bq_b2(x,b2);
+ pdp_imageproc_bq_setcoef(x->x_biquad, x->x_coefs_a);
+}
+
+static void pdp_bq_setstate(t_pdp_bq *x, float u0, float u1)
+{
+ pdp_bq_u0(x,u0);
+ pdp_bq_u1(x,u1);
+ pdp_imageproc_bq_setcoef(x->x_biquad, x->x_coefs_a);
+}
+
+
+
+/* reso lowpass */
+static void pdp_bq_lpf(t_pdp_bq *x, t_floatarg f, t_floatarg Q)
+{
+ float a0, a1, a2, b0, b1, b2, cs, sn, w, alpha;
+ w = 2.0 * M_PI * f;
+ cs = cos(w);
+ sn = sin(w);
+
+ alpha = sn*sinh(1.0f/(2.0f*Q));
+ b0 = (1.0 - cs)/2.0;
+ b1 = 1.0 - cs;
+ b2 = (1.0 - cs)/2.0;
+ a0 = (1.0 + alpha);
+ a1 = -2.0*cs;
+ a2 = 1.0 - alpha;
+
+ pdp_bq_setcoefs(x, a0, a1, a2, b0, b1, b2);
+
+}
+
+/* reso highpass */
+static void pdp_bq_hpf(t_pdp_bq *x, t_floatarg f, t_floatarg Q)
+{
+ float a0, a1, a2, b0, b1, b2, cs, sn, w, alpha;
+ w = 2.0 * M_PI * f;
+ cs = cos(w);
+ sn = sin(w);
+
+ alpha = sn*sinh(1.0f/(2.0f*Q));
+
+ b0 = (1.0 + cs)/2.0;
+ b1 = -1.0 - cs;
+ b2 = (1.0 + cs)/2.0;
+ a0 = (1.0 + alpha);
+ a1 = -2.0*cs;
+ a2 = 1.0 - alpha;
+
+ pdp_bq_setcoefs(x, a0, a1, a2, b0, b1, b2);
+
+}
+
+
+/* reso allpass */
+static void pdp_bq_apf(t_pdp_bq *x, t_floatarg f, t_floatarg Q)
+{
+ float a0, a1, a2, b0, b1, b2, cs, sn, w, alpha;
+ w = 2.0 * M_PI * f;
+ cs = cos(w);
+ sn = sin(w);
+
+ alpha = sn*sinh(1.0f/(2.0f*Q));
+
+ b0 = (1.0 - alpha);
+ b1 = -2.0 * cs;
+ b2 = (1.0 + alpha);
+ a0 = (1.0 + alpha);
+ a1 = -2.0*cs;
+ a2 = 1.0 - alpha;
+
+ pdp_bq_setcoefs(x, a0, a1, a2, b0, b1, b2);
+}
+
+/* reso band stop (notch) */
+static void pdp_bq_bsf(t_pdp_bq *x, t_floatarg f, t_floatarg Q)
+{
+ float a0, a1, a2, b0, b1, b2, cs, sn, w, alpha;
+ w = 2.0 * M_PI * f;
+ cs = cos(w);
+ sn = sin(w);
+
+ alpha = sn*sinh(1.0f/(2.0f*Q));
+
+ b0 = 1.0;
+ b1 = -2.0 * cs;
+ b2 = 1.0;
+ a0 = (1.0 + alpha);
+ a1 = -2.0*cs;
+ a2 = 1.0 - alpha;
+
+ pdp_bq_setcoefs(x, a0, a1, a2, b0, b1, b2);
+
+}
+
+static void pdp_bq_onep(t_pdp_bq *x, t_floatarg f)
+{
+ float a0,a1,a2,b0,b1,b2;
+
+ if (f>1.0f) f = 1.0f;
+ if (f<0.0f) f = 0.0f;
+
+ a0 = 1.0f;
+ a1 = -(1.0f - f);
+ a2 = 0.0f;
+ b0 = f;
+ b1 = 0.0f;
+ b2 = 0.0f;
+ pdp_bq_setcoefs(x, a0, a1, a2, b0, b1, b2);
+}
+
+static void pdp_bq_twop(t_pdp_bq *x, t_floatarg f)
+{
+ float f1;
+ float a0,a1,a2,b0,b1,b2;
+
+ if (f>1.0) f = 1.0;
+ if (f<0.0) f = 0.0;
+
+ f1 = 1.0 - f;
+
+ a0 = 1.0f;
+ a1 = -2.0f*f1;
+ a2 = f1*f1;
+ b0 = f*f;
+ b1 = 0.0f;
+ b2 = 0.0f;
+
+ pdp_bq_setcoefs(x, a0, a1, a2, b0, b1, b2);
+}
+
+
+
+
+
+/************************* PROCESS METHODS ****************************/
+
+
+static void pdp_bqt_process_yv12(t_pdp_bq *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ t_pdp *header2 = pdp_packet_header(x->x_packet2);
+
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+ void *data2 = pdp_packet_data (x->x_packet2);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ h = h + (h>>1);
+
+ pdp_imageproc_bqt_process(x->x_biquad, (short int*)data0, (short int*)data1, (short int *)data2, w, h);
+
+ return;
+}
+
+
+
+static void pdp_bqt_process_grey(t_pdp_bq *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ t_pdp *header2 = pdp_packet_header(x->x_packet2);
+
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+ void *data2 = pdp_packet_data (x->x_packet2);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ pdp_imageproc_bqt_process(x->x_biquad, (short int*)data0, (short int*)data1, (short int *)data2, w, h);
+
+ return;
+}
+
+
+
+
+static void pdp_bq_process_yv12(t_pdp_bq *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data (x->x_packet0);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ unsigned int size = w*h;
+ unsigned int v_offset = size;
+ unsigned int u_offset = size + (size >> 2);
+
+ unsigned int nbp = x->x_nbpasses;
+
+ short int * idata = (short int *)data0;
+
+ pdp_imageproc_bq_process(x->x_biquad, idata, w, h, x->x_direction, nbp);
+ pdp_imageproc_bq_process(x->x_biquad, idata + v_offset, w>>1, h>>1, x->x_direction, nbp);
+ pdp_imageproc_bq_process(x->x_biquad, idata + u_offset, w>>1, h>>1, x->x_direction, nbp);
+
+ return;
+}
+
+
+static void pdp_bq_process_grey(t_pdp_bq *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data (x->x_packet0);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ unsigned int nbp = x->x_nbpasses;
+
+ short int * idata = (short int *)data0;
+ pdp_imageproc_bq_process(x->x_biquad, idata, w, h, x->x_direction, nbp);
+
+ return;
+
+}
+
+
+static void pdp_bqt_process(t_pdp_bq *x)
+{
+ int encoding;
+
+ /* image data packets are compatible, this is ensured in the pdp method */
+ /* when the hot packet is received */
+
+ /* process inputs and write into active inlet */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_bqt_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_bqt_process_grey(x);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont process */
+
+ }
+
+}
+
+
+static void pdp_bq_process(t_pdp_bq *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+
+ /* check data packets */
+
+ if ((header0) && (PDP_IMAGE == header0->type)){
+
+ /* process inputs and write into active inlet */
+ switch(header0->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_bq_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_bq_process_grey(x);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont process */
+
+ }
+ }
+
+}
+
+
+static void pdp_bqt_reset(t_pdp_bq *x)
+{
+ t_pdp* header1 = pdp_packet_header(x->x_packet1);
+ t_pdp* header2 = pdp_packet_header(x->x_packet2);
+ void *data1 = pdp_packet_data(x->x_packet1);
+ void *data2 = pdp_packet_data(x->x_packet1);
+ unsigned int w,h,nbpixels,count;
+
+ if (!(header1 && header2)) return;
+ if (header1->type != PDP_IMAGE) return;
+
+ w = header1->info.image.width;
+ h = header1->info.image.height;
+ nbpixels = w*h;
+
+ post("pdp_bqt: resetting state");
+ switch (header1->info.image.encoding){
+ case PDP_IMAGE_YV12:
+ count = (nbpixels + nbpixels >> 1) << 1;
+ bzero(data1, count);
+ bzero(data2, count);
+ break;
+ case PDP_IMAGE_GREY:
+ count = (nbpixels) << 1;
+ bzero(data1, count);
+ bzero(data2, count);
+ break;
+ default:
+ break;
+ }
+
+}
+
+
+
+/************************* INPUT HANDLERS ****************************/
+
+static void pdp_bq_sendpacket(t_pdp_bq *x)
+{
+
+ /* output state packets for those that are interested */
+ //if(x->x_packet2 != -1) outlet_pdp(x->x_outlet2, x->x_packet2);
+ //if(x->x_packet1 != -1) outlet_pdp(x->x_outlet1, x->x_packet1);
+
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_bq_input_0(t_pdp_bq *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+ int passes, i;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* add the process method and callback to the process queue */
+ pdp_queue_add(x, pdp_bq_process, pdp_bq_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+
+
+static void pdp_bqt_input_0(t_pdp_bq *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+ int passes, i;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* check if state packets are compatible */
+ if (!( (pdp_type_compat_image(x->x_packet0, x->x_packet1))
+ && (pdp_packet_header(x->x_packet0)->info.image.encoding
+ == pdp_packet_header(x->x_packet1)->info.image.encoding))){
+
+
+ /* if not, create new state packets by copying the input packets */
+ post("pdp_bqt: created new state packets");
+ pdp_packet_mark_unused(x->x_packet1);
+ pdp_packet_mark_unused(x->x_packet2);
+ x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
+ x->x_packet2 = pdp_packet_clone_rw(x->x_packet0);
+
+ /* reset */
+ if (x->x_reset_on_formatchange) pdp_bqt_reset(x);
+ }
+
+ /* add the process method and callback to the process queue */
+ pdp_queue_add(x, pdp_bqt_process, pdp_bq_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+
+
+/************************* CONFIG METHODS ****************************/
+
+
+static void pdp_bq_passes(t_pdp_bq *x, t_floatarg f)
+{
+ int passes = (int)f;
+ passes = passes < 0 ? 0 : passes;
+ x->x_nbpasses = passes;
+
+}
+
+static void pdp_bq_lr(t_pdp_bq *x, t_floatarg f)
+{
+ if (f == 1.0f) x->x_direction |= PDP_IMAGEPROC_BIQUAD_LEFT2RIGHT;
+ if (f == 0.0f) x->x_direction &= ~PDP_IMAGEPROC_BIQUAD_LEFT2RIGHT;
+}
+
+static void pdp_bq_rl(t_pdp_bq *x, t_floatarg f)
+{
+ if (f == 1.0f) x->x_direction |= PDP_IMAGEPROC_BIQUAD_RIGHT2LEFT;
+ if (f == 0.0f) x->x_direction &= ~PDP_IMAGEPROC_BIQUAD_RIGHT2LEFT;
+}
+static void pdp_bq_tb(t_pdp_bq *x, t_floatarg f)
+{
+ if (f == 1.0f) x->x_direction |= PDP_IMAGEPROC_BIQUAD_TOP2BOTTOM;
+ if (f == 0.0f) x->x_direction &= ~PDP_IMAGEPROC_BIQUAD_TOP2BOTTOM;
+}
+
+static void pdp_bq_bt(t_pdp_bq *x, t_floatarg f)
+{
+ if (f == 1.0f) x->x_direction |= PDP_IMAGEPROC_BIQUAD_BOTTOM2TOP;
+ if (f == 0.0f) x->x_direction &= ~PDP_IMAGEPROC_BIQUAD_BOTTOM2TOP;
+}
+
+
+static void pdp_bq_hor(t_pdp_bq *x, t_floatarg f)
+{
+ pdp_bq_lr(x, f);
+ pdp_bq_rl(x, f);
+}
+static void pdp_bq_ver(t_pdp_bq *x, t_floatarg f)
+{
+ pdp_bq_tb(x, f);
+ pdp_bq_bt(x, f);
+}
+
+
+
+/************************* DES/CONSTRUCTORS ****************************/
+
+static void pdp_bq_free(t_pdp_bq *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_imageproc_bq_delete(x->x_biquad);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+ pdp_packet_mark_unused(x->x_packet2);
+
+}
+
+
+void pdp_bq_init(t_pdp_bq *x)
+{
+
+
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_packet2 = -1;
+
+ x->x_queue_id = -1;
+
+ x->x_nbpasses = 1;
+ x->x_reset_on_formatchange = true;
+
+ x->x_biquad = pdp_imageproc_bq_new();
+
+
+ pdp_bq_setstate(x, 0.0f, 0.0f);
+ pdp_bq_onep(x, 0.1f);
+
+}
+
+
+
+/* class pointers */
+
+t_class *pdp_bq_class; /* biquad spacial processing */
+t_class *pdp_bqt_class; /* biquad time processing */
+
+void *pdp_bq_new(void)
+{
+ t_pdp_bq *x = (t_pdp_bq *)pd_new(pdp_bq_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("passes"));
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ pdp_bq_init(x);
+ return (void *)x;
+}
+
+void *pdp_bqt_new(void)
+{
+ t_pdp_bq *x = (t_pdp_bq *)pd_new(pdp_bqt_class);
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ //x->x_outlet1 = outlet_new(&x->x_obj, &s_anything);
+ //x->x_outlet2 = outlet_new(&x->x_obj, &s_anything);
+ pdp_bq_init(x);
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+
+
+
+/************************* CLASS CONSTRUCTORS ****************************/
+
+
+void pdp_bq_setup(void)
+{
+
+ /* setup spatial processing class */
+
+ pdp_bq_class = class_new(gensym("pdp_bq"), (t_newmethod)pdp_bq_new,
+ (t_method)pdp_bq_free, sizeof(t_pdp_bq), 0, A_NULL);
+
+
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_passes, gensym("passes"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_hor, gensym("hor"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_ver, gensym("ver"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_tb, gensym("tb"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_bt, gensym("bt"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_lr, gensym("lr"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_rl, gensym("rl"), A_FLOAT, A_NULL);
+
+
+
+ /* raw coefficient methods */
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_a1, gensym("a1"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_a2, gensym("a2"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_b0, gensym("b0"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_b1, gensym("b1"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_b2, gensym("b2"), A_FLOAT, A_NULL);
+ //class_addmethod(pdp_bq_class, (t_method)pdp_bq_u1, gensym("u1"), A_FLOAT, A_NULL);
+ //class_addmethod(pdp_bq_class, (t_method)pdp_bq_u2, gensym("u2"), A_FLOAT, A_NULL);
+
+ /* real pole filters */
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_onep, gensym("onep"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_twop, gensym("twop"), A_FLOAT, A_NULL);
+
+ /* resonnant pole filters */
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_lpf, gensym("lpf"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_hpf, gensym("hpf"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_apf, gensym("apf"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_bsf, gensym("bsf"), A_FLOAT, A_FLOAT, A_NULL);
+
+
+ class_addmethod(pdp_bq_class, (t_method)pdp_bq_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+
+
+
+
+
+
+ /* setup time processing class */
+ pdp_bqt_class = class_new(gensym("pdp_bqt"), (t_newmethod)pdp_bqt_new,
+ (t_method)pdp_bq_free, sizeof(t_pdp_bq), 0, A_NULL);
+
+
+ /* raw coefficient methods */
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_a1, gensym("a1"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_a2, gensym("a2"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_b0, gensym("b0"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_b1, gensym("b1"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_b2, gensym("b2"), A_FLOAT, A_NULL);
+ //class_addmethod(pdp_bqt_class, (t_method)pdp_bq_u1, gensym("u1"), A_FLOAT, A_NULL);
+ //class_addmethod(pdp_bqt_class, (t_method)pdp_bq_u2, gensym("u2"), A_FLOAT, A_NULL);
+
+ /* real pole filters */
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_onep, gensym("onep"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_twop, gensym("twop"), A_FLOAT, A_NULL);
+
+ /* resonnant pole filters */
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_lpf, gensym("lpf"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_hpf, gensym("hpf"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_apf, gensym("apf"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bq_bsf, gensym("bsf"), A_FLOAT, A_FLOAT, A_NULL);
+
+ /* control */
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bqt_reset, gensym("reset"), A_NULL);
+
+
+
+ /* pdp */
+ class_addmethod(pdp_bqt_class, (t_method)pdp_bqt_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+
+
+
+
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_chrot.c b/modules/pdp_chrot.c
new file mode 100644
index 0000000..5181195
--- /dev/null
+++ b/modules/pdp_chrot.c
@@ -0,0 +1,201 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+#include "pdp_mmx.h"
+#include <math.h>
+
+
+typedef struct pdp_chrot_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ int x_packet0;
+ int x_queue_id;
+ int x_dropped; // indicate if a packet was dropped during register_rw cycle
+
+ int x_channel;
+
+ float x_matrix[4];
+
+ void *x_crot2d;
+
+} t_pdp_chrot;
+
+
+
+static void pdp_chrot_process_yv12(t_pdp_chrot *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data (x->x_packet0);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ unsigned int size = w*h;
+ unsigned int v_offset = size;
+
+ short int * idata = (short int *)data0;
+
+
+ /* color rotation for 2 colour planes */
+ pdp_imageproc_crot2d_process(x->x_crot2d, idata + v_offset, w>>1, h>>1);
+
+
+ return;
+
+
+}
+
+static void pdp_chrot_process(t_pdp_chrot *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+
+ /* check data packets */
+
+ if ((header0) && (PDP_IMAGE == header0->type)){
+
+ /* pdp_chrot_process inputs and write into active inlet */
+ switch(header0->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_chrot_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont pdp_chrot_process */
+
+ }
+ }
+
+}
+
+static void pdp_chrot_sendpacket(t_pdp_chrot *x)
+{
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_chrot_input_0(t_pdp_chrot *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+
+ /* add the process method and callback to the process queue */
+
+ pdp_queue_add(x, pdp_chrot_process, pdp_chrot_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+
+static void pdp_chrot_setelement(t_pdp_chrot *x, int element, float f)
+{
+ x->x_matrix[element] = f;
+
+}
+
+static void pdp_chrot_angle_radians(t_pdp_chrot *x, t_floatarg angle)
+{
+ float c = cos(angle);
+ float s = sin(angle);
+
+ pdp_chrot_setelement(x, 0, c);
+ pdp_chrot_setelement(x, 1, s);
+ pdp_chrot_setelement(x, 2, -s);
+ pdp_chrot_setelement(x, 3, c);
+
+ pdp_imageproc_crot2d_setmatrix(x->x_crot2d, x->x_matrix);
+}
+
+static void pdp_chrot_angle_degrees(t_pdp_chrot *x, t_floatarg angle)
+{
+ pdp_chrot_angle_radians(x, (angle * (M_PI / 180.f)));
+
+}
+
+static void pdp_chrot_free(t_pdp_chrot *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_imageproc_crot2d_delete(x->x_crot2d);
+ pdp_packet_mark_unused(x->x_packet0);
+
+}
+
+t_class *pdp_chrot_class;
+
+
+
+void *pdp_chrot_new(t_floatarg f)
+{
+ t_pdp_chrot *x = (t_pdp_chrot *)pd_new(pdp_chrot_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("angle"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+
+ x->x_crot2d = pdp_imageproc_crot2d_new();
+ pdp_chrot_angle_radians(x, 0.0f);
+
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_chrot_setup(void)
+{
+
+
+ pdp_chrot_class = class_new(gensym("pdp_chrot"), (t_newmethod)pdp_chrot_new,
+ (t_method)pdp_chrot_free, sizeof(t_pdp_chrot), 0, A_DEFFLOAT, A_NULL);
+
+
+ class_addmethod(pdp_chrot_class, (t_method)pdp_chrot_angle_degrees, gensym("angle"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_chrot_class, (t_method)pdp_chrot_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_conv.c b/modules/pdp_conv.c
new file mode 100644
index 0000000..885b86b
--- /dev/null
+++ b/modules/pdp_conv.c
@@ -0,0 +1,325 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+#include "pdp_mmx.h"
+
+
+typedef struct pdp_conv_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+
+ int x_packet0;
+ int x_dropped;
+ int x_queue_id;
+
+ unsigned int x_nbpasses;
+ bool x_horizontal;
+ bool x_vertical;
+
+ void *x_convolver_hor;
+ void *x_convolver_ver;
+
+} t_pdp_conv;
+
+
+
+static void pdp_conv_process_yv12(t_pdp_conv *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data (x->x_packet0);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ unsigned int size = w*h;
+ unsigned int v_offset = size;
+ unsigned int u_offset = size + (size >> 2) ;
+
+
+ unsigned int i,j;
+ unsigned int nbpasses = x->x_nbpasses;
+
+ short int * idata = (short int *)data0;
+
+ int orient;
+
+
+
+
+ orient = PDP_IMAGEPROC_CONV_VERTICAL;
+ if (x->x_vertical){
+ pdp_imageproc_conv_process(x->x_convolver_ver, idata, w, h, orient, nbpasses);
+ pdp_imageproc_conv_process(x->x_convolver_ver, idata+v_offset, w>>1, h>>1, orient, nbpasses);
+ pdp_imageproc_conv_process(x->x_convolver_ver, idata+u_offset, w>>1, h>>1, orient, nbpasses);
+ }
+
+
+
+ orient = PDP_IMAGEPROC_CONV_HORIZONTAL;
+ if (x->x_horizontal){
+ pdp_imageproc_conv_process(x->x_convolver_hor, idata, w, h, orient, nbpasses);
+ pdp_imageproc_conv_process(x->x_convolver_hor, idata+v_offset, w>>1, h>>1, orient, nbpasses);
+ pdp_imageproc_conv_process(x->x_convolver_hor, idata+u_offset, w>>1, h>>1, orient, nbpasses);
+ }
+
+
+ return;
+
+
+}
+static void pdp_conv_process_grey(t_pdp_conv *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data (x->x_packet0);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ unsigned int size = w*h;
+
+
+ unsigned int i,j;
+ unsigned int nbpasses = x->x_nbpasses;
+
+ short int * idata = (short int *)data0;
+
+ int orient;
+
+ if (x->x_vertical){
+ orient = PDP_IMAGEPROC_CONV_VERTICAL;
+ pdp_imageproc_conv_process(x->x_convolver_ver, idata, w, h, orient, nbpasses);
+ }
+
+ if (x->x_horizontal){
+ orient = PDP_IMAGEPROC_CONV_HORIZONTAL;
+ pdp_imageproc_conv_process(x->x_convolver_hor, idata, w, h, orient, nbpasses);
+ }
+
+
+}
+
+static void pdp_conv_process(t_pdp_conv *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+
+ /* check data packets */
+
+ if ((header0) && (PDP_IMAGE == header0->type)){
+
+ /* pdp_conv_process inputs and write into active inlet */
+ switch(header0->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_conv_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_conv_process_grey(x);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont process */
+
+ }
+ }
+
+}
+
+
+static void pdp_conv_sendpacket(t_pdp_conv *x)
+{
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_conv_input_0(t_pdp_conv *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+ int passes, i;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* add the process method and callback to the process queue */
+
+ pdp_queue_add(x, pdp_conv_process, pdp_conv_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+
+
+
+static void pdp_conv_passes(t_pdp_conv *x, t_floatarg f)
+{
+ int passes = (int)f;
+ passes = passes < 0 ? 0 : passes;
+ x->x_nbpasses = passes;
+
+}
+static void pdp_conv_hor(t_pdp_conv *x, t_floatarg f)
+{
+ int hor = (int)f;
+ x->x_horizontal = (hor != 0);
+
+}
+static void pdp_conv_ver(t_pdp_conv *x, t_floatarg f)
+{
+ int ver = (int)f;
+ x->x_vertical = (ver != 0);
+}
+static void pdp_conv_free(t_pdp_conv *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_imageproc_conv_delete(x->x_convolver_hor);
+ pdp_imageproc_conv_delete(x->x_convolver_ver);
+ pdp_packet_mark_unused(x->x_packet0);
+
+}
+
+/* setup hmask */
+
+static void pdp_conv_hleft(t_pdp_conv *x, t_floatarg f)
+{
+ pdp_imageproc_conv_setmin1(x->x_convolver_hor, f);
+
+}
+static void pdp_conv_hmiddle(t_pdp_conv *x, t_floatarg f)
+{
+ pdp_imageproc_conv_setzero(x->x_convolver_hor, f);
+}
+static void pdp_conv_hright(t_pdp_conv *x, t_floatarg f)
+{
+ pdp_imageproc_conv_setplus1(x->x_convolver_hor, f);
+}
+
+static void pdp_conv_hmask(t_pdp_conv *x, t_floatarg l, t_floatarg m, t_floatarg r)
+{
+ pdp_conv_hleft(x, l);
+ pdp_conv_hmiddle(x, m);
+ pdp_conv_hright(x, r);
+}
+
+static void pdp_conv_vtop(t_pdp_conv *x, t_floatarg f)
+{
+ pdp_imageproc_conv_setmin1(x->x_convolver_ver, f);
+}
+static void pdp_conv_vmiddle(t_pdp_conv *x, t_floatarg f)
+{
+ pdp_imageproc_conv_setzero(x->x_convolver_ver, f);
+
+}
+static void pdp_conv_vbottom(t_pdp_conv *x, t_floatarg f)
+{
+ pdp_imageproc_conv_setplus1(x->x_convolver_ver, f);
+}
+
+static void pdp_conv_vmask(t_pdp_conv *x, t_floatarg l, t_floatarg m, t_floatarg r)
+{
+ pdp_conv_vtop(x, l);
+ pdp_conv_vmiddle(x, m);
+ pdp_conv_vbottom(x, r);
+}
+
+
+static void pdp_conv_mask(t_pdp_conv *x, t_floatarg l, t_floatarg m, t_floatarg r)
+{
+ pdp_conv_hmask(x, l, m, r);
+ pdp_conv_vmask(x, l, m, r);
+}
+
+t_class *pdp_conv_class;
+
+
+
+void *pdp_conv_new(void)
+{
+ t_pdp_conv *x = (t_pdp_conv *)pd_new(pdp_conv_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("passes"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+ x->x_nbpasses = 1;
+ x->x_horizontal = true;
+ x->x_vertical = true;
+
+ x->x_convolver_hor = pdp_imageproc_conv_new();
+ x->x_convolver_ver = pdp_imageproc_conv_new();
+
+ pdp_imageproc_conv_setbordercolor(x->x_convolver_hor, 0);
+ pdp_imageproc_conv_setbordercolor(x->x_convolver_ver, 0);
+
+ pdp_conv_mask(x, .25,.5,.25);
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_conv_setup(void)
+{
+
+
+ pdp_conv_class = class_new(gensym("pdp_conv"), (t_newmethod)pdp_conv_new,
+ (t_method)pdp_conv_free, sizeof(t_pdp_conv), 0, A_NULL);
+
+
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_passes, gensym("passes"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_hor, gensym("hor"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_ver, gensym("ver"), A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_hleft, gensym("hleft"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_hmiddle, gensym("hmiddle"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_hright, gensym("hright"), A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_vtop, gensym("vtop"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_vmiddle, gensym("vmiddle"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_vbottom, gensym("vbottom"), A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_vmask, gensym("vmask"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_hmask, gensym("hmask"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_mask, gensym("mask"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+
+ class_addmethod(pdp_conv_class, (t_method)pdp_conv_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_del.c b/modules/pdp_del.c
new file mode 100644
index 0000000..97e47fd
--- /dev/null
+++ b/modules/pdp_del.c
@@ -0,0 +1,196 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef struct pdp_del_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ int *x_packet;
+ int x_order;
+ int x_head;
+ int x_delay;
+} t_pdp_del;
+
+
+
+
+
+static void pdp_del_input_0(t_pdp_del *x, t_symbol *s, t_floatarg f)
+{
+ int in;
+ int out;
+ int packet;
+
+
+ /* if this is a register_ro message or register_rw message, register with packet factory */
+ /* if this is a process message, start the processing + propagate stuff to outputs */
+
+ if (s == gensym("register_ro")){
+ in = (x->x_head & (x->x_order-1));
+ //post("pdp_del: marking unused packed id=%d on loc %d", x->x_packet[0], in);
+ pdp_packet_mark_unused(x->x_packet[in]);
+ packet = pdp_packet_copy_ro((int)f);
+ x->x_packet[in] = packet;
+ //post("pdp_del: writing packed id=%d on loc %d", packet, in);
+ }
+ else if (s == gensym("process")){
+ out = ((x->x_head + x->x_delay) & (x->x_order-1));
+ packet = x->x_packet[out];
+
+ if (-1 != packet){
+ //post("pdp_del: packet %d has id %d", out, packet);
+ pdp_packet_mark_unused(packet);
+ outlet_pdp(x->x_outlet0, packet);
+ x->x_packet[out] = -1;
+ }
+ else {
+ //post("pdp_del: packet %d is empty", out);
+ }
+ x->x_head--;
+ }
+
+
+}
+
+
+
+
+
+static void pdp_del_delay(t_pdp_del *x, t_floatarg fdel)
+{
+ int del = (int)fdel;
+ if (del < 0) del = 0;
+ if (del >= x->x_order) del = x->x_order - 1;
+
+ x->x_delay = del;
+
+}
+
+static void pdp_del_reset(t_pdp_del *x)
+{
+ int i;
+ for (i=0; i<x->x_order; i++) {
+ pdp_packet_mark_unused(x->x_packet[i]);
+ x->x_packet[i] = -1;
+ }
+ x->x_head = 0;
+
+}
+
+static void pdp_del_free(t_pdp_del *x)
+{
+ pdp_del_reset(x);
+ free (x->x_packet);
+}
+
+t_class *pdp_del_class;
+
+
+
+void *pdp_del_new(t_floatarg forder, t_floatarg fdel)
+{
+ int order = (int)forder;
+ int del;
+ int logorder;
+ int i;
+ t_pdp_del *x = (t_pdp_del *)pd_new(pdp_del_class);
+
+
+ del = order;
+ order++;
+
+ if (del < 0) del = 0;
+
+
+ if (order <= 2) order = 2;
+ else {
+
+ order--;
+ logorder = 1;
+
+
+ while ((order | 1) != 1) {
+ order >>= 1;
+ logorder++;
+ }
+
+ order = 1 << logorder;
+ }
+
+ post("pdp_del: order = %d", order);
+
+ x->x_order = order;
+ x->x_packet = (int *)malloc(sizeof(int)*order);
+ for(i=0; i<order; i++) x->x_packet[i] = -1;
+
+ x->x_delay = del;
+
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("delay"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_del_setup(void)
+{
+
+
+ pdp_del_class = class_new(gensym("pdp_del"), (t_newmethod)pdp_del_new,
+ (t_method)pdp_del_free, sizeof(t_pdp_del), 0, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_del_class, (t_method)pdp_del_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_del_class, (t_method)pdp_del_delay, gensym("delay"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_del_class, (t_method)pdp_del_reset, gensym("reset"), A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_gain.c b/modules/pdp_gain.c
new file mode 100644
index 0000000..a334656
--- /dev/null
+++ b/modules/pdp_gain.c
@@ -0,0 +1,227 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+
+
+
+typedef struct pdp_gain_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+
+ int x_packet0;
+ int x_dropped;
+ int x_queue_id;
+
+ void *x_gain_y;
+ void *x_gain_v;
+ void *x_gain_u;
+
+} t_pdp_gain;
+
+
+
+static void pdp_gain_process_yv12(t_pdp_gain *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data (x->x_packet0);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ short int * idata = (short int *)data0;
+ unsigned int size = w*h;
+
+ pdp_imageproc_gain_process(x->x_gain_y, idata, w, h);
+ pdp_imageproc_gain_process(x->x_gain_u, idata + size, w>>1, h>>1);
+ pdp_imageproc_gain_process(x->x_gain_v, idata + size + (size>>2) , w>>1, h>>1);
+
+
+ return;
+
+
+}
+static void pdp_gain_process_grey(t_pdp_gain *x)
+{
+
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ void *data0 = pdp_packet_data (x->x_packet0);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ unsigned int size = w*h;
+ short int * idata = (short int *)data0;
+
+ pdp_imageproc_gain_process(x->x_gain_y, idata, w, h);
+
+ return;
+
+
+}
+
+static void pdp_gain_process(t_pdp_gain *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+
+ /* check data packets */
+
+ if ((header0) && (PDP_IMAGE == header0->type)){
+
+ /* pdp_gain_process inputs and write into active inlet */
+ switch(header0->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_gain_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_gain_process_grey(x);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont process */
+
+ }
+ }
+
+}
+
+
+static void pdp_gain_sendpacket(t_pdp_gain *x)
+{
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_gain_input_0(t_pdp_gain *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+ int passes, i;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* add the process method and callback to the process queue */
+
+ pdp_queue_add(x, pdp_gain_process, pdp_gain_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+
+
+
+static void pdp_gain_gainy(t_pdp_gain *x, t_floatarg f)
+{
+ pdp_imageproc_gain_setgain(x->x_gain_y, f);
+}
+
+static void pdp_gain_gainv(t_pdp_gain *x, t_floatarg f)
+{
+ pdp_imageproc_gain_setgain(x->x_gain_v, f);
+}
+
+static void pdp_gain_gainu(t_pdp_gain *x, t_floatarg f)
+{
+ pdp_imageproc_gain_setgain(x->x_gain_u, f);
+}
+
+static void pdp_gain_gain(t_pdp_gain *x, t_floatarg f)
+{
+ pdp_gain_gainy(x, f);
+ pdp_gain_gainv(x, f);
+ pdp_gain_gainu(x, f);
+
+}
+
+
+
+t_class *pdp_gain_class;
+
+
+
+void pdp_gain_free(t_pdp_gain *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_imageproc_gain_delete(x->x_gain_y);
+ pdp_imageproc_gain_delete(x->x_gain_u);
+ pdp_imageproc_gain_delete(x->x_gain_v);
+}
+
+void *pdp_gain_new(t_floatarg f)
+{
+ t_pdp_gain *x = (t_pdp_gain *)pd_new(pdp_gain_class);
+
+
+ /* no arg, or zero -> gain = 1 */
+ if (f==0.0f) f = 1.0f;
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("gain"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+
+ x->x_gain_y = pdp_imageproc_gain_new();
+ x->x_gain_u = pdp_imageproc_gain_new();
+ x->x_gain_v = pdp_imageproc_gain_new();
+ pdp_gain_gain(x, f);
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_gain_setup(void)
+{
+
+
+ pdp_gain_class = class_new(gensym("pdp_gain"), (t_newmethod)pdp_gain_new,
+ (t_method)pdp_gain_free, sizeof(t_pdp_gain), 0, A_DEFFLOAT, A_NULL);
+
+
+ class_addmethod(pdp_gain_class, (t_method)pdp_gain_gain, gensym("gain"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_gain_class, (t_method)pdp_gain_gainy, gensym("y"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_gain_class, (t_method)pdp_gain_gainu, gensym("v"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_gain_class, (t_method)pdp_gain_gainv, gensym("u"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_gain_class, (t_method)pdp_gain_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_gradient.c b/modules/pdp_gradient.c
new file mode 100644
index 0000000..5c92e12
--- /dev/null
+++ b/modules/pdp_gradient.c
@@ -0,0 +1,331 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+
+
+typedef struct yv12_palette_struct
+{
+ short int y;
+ short int u;
+ short int v;
+} t_yv12_palette;
+
+typedef struct pdp_gradient_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ int x_packet0;
+ int x_dropped;
+ int x_queue_id;
+
+ t_yv12_palette x_palette[512];
+
+} t_pdp_gradient;
+
+
+unsigned int float2fixed(float f)
+{
+ f *= 0x8000;
+ if(f>0x7fff) f = 0x7fff;
+ if(f<-0x7fff) f = -0x7fff;
+ return (short int)f;
+}
+
+static void pdp_gradient_yuv_index(t_pdp_gradient *x,
+ t_floatarg index,
+ t_floatarg y,
+ t_floatarg u,
+ t_floatarg v)
+{
+ int i = ((int)index) & 511;
+ x->x_palette[i].y = float2fixed(y);
+ x->x_palette[i].u = float2fixed(u);
+ x->x_palette[i].v = float2fixed(v);
+}
+
+static void pdp_gradient_yuv(t_pdp_gradient *x,
+ t_floatarg y,
+ t_floatarg u,
+ t_floatarg v)
+{
+ int i;
+ float inc = 1.0f / 256.0f;
+ float frac = -1.0f;
+ for(i=-256; i<256; i++) {
+ pdp_gradient_yuv_index(x, i, frac*y, frac*u, frac*v);
+ frac += inc;
+ }
+}
+
+static void pdp_gradient_rgb_index(t_pdp_gradient *x,
+ t_floatarg index,
+ t_floatarg r,
+ t_floatarg g,
+ t_floatarg b)
+{
+ float y,u,v;
+
+
+ y = 0.299f * r + 0.587f * g + 0.114f * b;
+ u = (r-y) * 0.713f;
+ v = (b-y) * 0.565f;
+
+ pdp_gradient_yuv_index(x, index, y,u,v);
+}
+
+static void pdp_gradient_rgb(t_pdp_gradient *x,
+ t_floatarg r,
+ t_floatarg g,
+ t_floatarg b)
+{
+ int i;
+ float inc = 1.0f / 256.0f;
+ float frac = -1.0f;
+ for(i=-256; i<256; i++) {
+ pdp_gradient_rgb_index(x, i, frac*r, frac*g, frac*b);
+ frac += inc;
+ }
+}
+
+/*
+static void pdp_gradient_hsv_index(t_pdp_gradient *x,
+ t_floatarg index,
+ t_floatarg h,
+ t_floatarg s,
+ t_floatarg v)
+{
+ float r,g,b;
+
+ r = h;
+ g = s;
+ b = v;
+
+ pdp_gradient_rgb_index(x, index, r,g,b);
+}
+
+static void pdp_gradient_hsv(t_pdp_gradient *x,
+ t_floatarg h,
+ t_floatarg s,
+ t_floatarg v)
+{
+ int i;
+ float inc = 1.0f / 256.0f;
+ float frac = -1.0f;
+ for(i=-256; i<256; i++) {
+ pdp_gradient_hsv_index(x, i, h, s, frac*v);
+ frac += inc;
+ }
+}
+*/
+
+static void pdp_gradient_process_grey(t_pdp_gradient *x)
+{
+ t_pdp *header = pdp_packet_header(x->x_packet0);
+ short int *data = (short int *)pdp_packet_data (x->x_packet0);
+ t_pdp *newheader = 0;
+ short int *newdata = 0;
+ int newpacket = -1;
+
+ unsigned int w = header->info.image.width;
+ unsigned int h = header->info.image.height;
+
+ unsigned int size = w*h;
+ unsigned int totalnbpixels = size;
+ unsigned int u_offset = size;
+ unsigned int v_offset = size + (size>>2);
+
+ unsigned int row, col;
+
+ newpacket = pdp_packet_new(PDP_IMAGE, (size + (size>>1))<<1);
+ newheader = pdp_packet_header(newpacket);
+ newdata = (short int *)pdp_packet_data(newpacket);
+
+ newheader->info.image.encoding = PDP_IMAGE_YV12;
+ newheader->info.image.width = w;
+ newheader->info.image.height = h;
+
+ /* convert every pixel according to palette */
+ for(row=0; row < size; row += (w<<1)){
+ for(col=0; col < w; col += 2){
+ short int u_acc, v_acc;
+ short int grey;
+
+ /* top left pixel */
+ grey = ((data[row+col])>>7) & 511;
+ newdata[row+col] = x->x_palette[grey].y;
+ u_acc = (x->x_palette[grey].u)>>2;
+ v_acc = (x->x_palette[grey].v)>>2;
+
+ /* top right pixel */
+ grey = ((data[row+col+1])>>7) & 511;
+ newdata[row+col+1] = x->x_palette[grey].y;
+ u_acc += (x->x_palette[grey].u)>>2;
+ v_acc += (x->x_palette[grey].v)>>2;
+
+ /* bottom left pixel */
+ grey = ((data[row+col+w])>>7) & 511;
+ newdata[row+col+w] = x->x_palette[grey].y;
+ u_acc += (x->x_palette[grey].u)>>2;
+ v_acc += (x->x_palette[grey].v)>>2;
+
+ /* bottom right pixel */
+ grey = ((data[row+col+w+1])>>7) & 511;
+ newdata[row+col+w+1] = x->x_palette[grey].y;
+ u_acc += (x->x_palette[grey].u)>>2;
+ v_acc += (x->x_palette[grey].v)>>2;
+
+ /* store uv comp */
+ newdata[u_offset + (row>>2) + (col>>1)] = u_acc;
+ newdata[v_offset + (row>>2) + (col>>1)] = v_acc;
+ }
+ }
+
+
+
+ /* delete source packet and replace with new packet */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = newpacket;
+ return;
+}
+
+static void pdp_gradient_process_yv12(t_pdp_gradient *x)
+{
+ /* pdp_gradient_process only the luminance channel */
+ pdp_gradient_process_grey(x);
+}
+
+
+
+static void pdp_gradient_process(t_pdp_gradient *x)
+{
+ int encoding;
+ t_pdp *header = 0;
+
+ /* check if image data packets are compatible */
+ if ( (header = pdp_packet_header(x->x_packet0))
+ && (PDP_IMAGE == header->type)){
+
+ /* pdp_gradient_process inputs and write into active inlet */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_gradient_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_gradient_process_grey(x);
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_gradient_process */
+
+ break;
+ }
+ }
+}
+
+static void pdp_gradient_sendpacket(t_pdp_gradient *x)
+{
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_gradient_input_0(t_pdp_gradient *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+
+ /* add the process method and callback to the process queue */
+
+ pdp_queue_add(x, pdp_gradient_process, pdp_gradient_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+
+
+static void pdp_gradient_free(t_pdp_gradient *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+
+}
+
+t_class *pdp_gradient_class;
+
+
+
+void *pdp_gradient_new(void)
+{
+ int i;
+
+ t_pdp_gradient *x = (t_pdp_gradient *)pd_new(pdp_gradient_class);
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+
+ for (i=-256; i<256; i++){
+ x->x_palette[i&511].y = i << 7;
+ x->x_palette[i&511].u = (-i) << 6;
+ x->x_palette[i&511].v = (i) << 5;
+ }
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_gradient_setup(void)
+{
+
+
+ pdp_gradient_class = class_new(gensym("pdp_gradient"), (t_newmethod)pdp_gradient_new,
+ (t_method)pdp_gradient_free, sizeof(t_pdp_gradient), 0, A_NULL);
+
+
+ class_addmethod(pdp_gradient_class, (t_method)pdp_gradient_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_gradient_class, (t_method)pdp_gradient_yuv, gensym("yuv"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_gradient_class, (t_method)pdp_gradient_rgb, gensym("rgb"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ // class_addmethod(pdp_gradient_class, (t_method)pdp_gradient_hsv, gensym("hsv"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_grey.c b/modules/pdp_grey.c
new file mode 100644
index 0000000..0626ea9
--- /dev/null
+++ b/modules/pdp_grey.c
@@ -0,0 +1,168 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+
+
+typedef struct pdp_grey_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+
+ int x_packet0;
+
+} t_pdp_grey;
+
+
+
+static void pdp_grey_process(t_pdp_grey *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *headernew;
+ int newpacket;
+ int w;
+ int h;
+
+ /* check data packets */
+
+ if ((header0) && (PDP_IMAGE == header0->type)){
+
+ /* pdp_grey_process inputs and write into active inlet */
+ switch(header0->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ w = header0->info.image.width;
+ h = header0->info.image.height;
+ newpacket = pdp_packet_new(PDP_IMAGE, w*h*2);
+ headernew = pdp_packet_header(newpacket);
+ headernew->info.image.encoding = PDP_IMAGE_GREY;
+ headernew->info.image.width = w;
+ headernew->info.image.height = h;
+ memcpy(pdp_packet_data(newpacket), pdp_packet_data(x->x_packet0), 2*w*h);
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = newpacket;
+ break;
+
+ case PDP_IMAGE_GREY:
+ /* just pass along */
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont process */
+
+ }
+ }
+
+}
+
+
+static void pdp_grey_sendpacket(t_pdp_grey *x)
+{
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_grey_input_0(t_pdp_grey *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+ int passes, i;
+
+ if (s== gensym("register_rw")) pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0)){
+
+ pdp_grey_process(x);
+ pdp_grey_sendpacket(x);
+ }
+
+}
+
+
+
+
+short int pdp_grey_fixedpoint(float f)
+{
+
+ float min = (float)-0x7fff;
+ float max = (float)0x7fff;
+ f *= (float)0x100;
+ if (f>max) f = max;
+ if (f<min) f = min;
+
+ return (short int)f;
+
+}
+
+
+t_class *pdp_grey_class;
+
+
+
+void pdp_grey_free(t_pdp_grey *x)
+{
+}
+
+void *pdp_grey_new(t_floatarg f)
+{
+ t_pdp_grey *x = (t_pdp_grey *)pd_new(pdp_grey_class);
+
+
+ /* no arg, or zero -> gain = 1 */
+ if (f==0.0f) f = 1.0f;
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("gain"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_grey_setup(void)
+{
+
+
+ pdp_grey_class = class_new(gensym("pdp_grey"), (t_newmethod)pdp_grey_new,
+ (t_method)pdp_grey_free, sizeof(t_pdp_grey), 0, A_DEFFLOAT, A_NULL);
+
+
+ class_addmethod(pdp_grey_class, (t_method)pdp_grey_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_mix.c b/modules/pdp_mix.c
new file mode 100644
index 0000000..9602c4b
--- /dev/null
+++ b/modules/pdp_mix.c
@@ -0,0 +1,279 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+
+
+typedef struct pdp_mix_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+ t_outlet *x_outlet1;
+
+ int x_packet0; // hot packet
+ int x_packet1; // cold packet
+ int x_packet1next; // next cold packet
+ int x_dropped;
+
+ int x_queue_id; // identifier of method in the processing queue
+
+ void *x_mixer;
+
+ int x_extrapolate;
+
+} t_pdp_mix;
+
+
+
+static void pdp_mix_process_yv12(t_pdp_mix *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+
+ h = h + (h>>1);
+ pdp_imageproc_mix_process(x->x_mixer,(short int*)data0, (short int*)data1, w, h);
+
+ return;
+
+
+
+}
+
+static void pdp_mix_process_grey(t_pdp_mix *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ pdp_imageproc_mix_process(x->x_mixer,(short int*)data0, (short int*)data1, w, h);
+
+ return;
+
+
+
+}
+
+static void pdp_mix_process(t_pdp_mix *x)
+{
+ int encoding;
+
+ /* check if image data packets are compatible */
+ if (pdp_type_compat_image(x->x_packet0, x->x_packet1)){
+
+ /* dispatch to process thread */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_mix_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_mix_process_grey(x);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont pdp_mix_process */
+
+ }
+ }
+
+}
+
+static void pdp_mix_sendpacket(t_pdp_mix *x)
+{
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_mix_input_0(t_pdp_mix *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* if a cold packet was received in the meantime
+ swap it in, else keep the old one */
+
+ pdp_replace_if_valid(&x->x_packet1, &x->x_packet1next);
+
+
+ /* add the process method and callback to the process queue */
+
+ pdp_queue_add(x, pdp_mix_process, pdp_mix_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+static void pdp_mix_input_1(t_pdp_mix *x, t_symbol *s, t_floatarg f)
+{
+ /* store the packet and drop
+ the old one, if there is any */
+
+ if(s == gensym("register_ro")) pdp_packet_copy_ro_or_drop(&x->x_packet1next, (int)f);
+
+}
+
+
+
+static void pdp_mix_mix(t_pdp_mix *x, t_floatarg f)
+{
+ float f2;
+ if (!x->x_extrapolate){
+ if (f < 0.0f) f = 0.0f;
+ if (f > 1.0f) f = 1.0f;
+ }
+
+ f2 = (1.0f - f);
+ pdp_imageproc_mix_setleftgain(x->x_mixer, f2);
+ pdp_imageproc_mix_setrightgain(x->x_mixer, f);
+
+}
+
+static void pdp_mix_mix1(t_pdp_mix *x, t_floatarg f)
+{
+ pdp_imageproc_mix_setleftgain(x->x_mixer, f);
+
+}
+static void pdp_mix_mix2(t_pdp_mix *x, t_floatarg f2)
+{
+ pdp_imageproc_mix_setrightgain(x->x_mixer, f2);
+}
+
+static void pdp_mix_extrapolate(t_pdp_mix *x, t_floatarg f)
+{
+ if (f == 0.0f) x->x_extrapolate = 0;
+ if (f == 1.0f) x->x_extrapolate = 1;
+}
+
+
+static void pdp_mix_free(t_pdp_mix *x)
+{
+ /* remove the method from the queue before deleting stuff */
+ pdp_queue_finish(x->x_queue_id);
+
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+ pdp_packet_mark_unused(x->x_packet1next);
+
+ pdp_imageproc_mix_delete(x->x_mixer);
+}
+
+t_class *pdp_mix_class;
+t_class *pdp_mix2_class;
+
+
+void *pdp_mix_common_init(t_pdp_mix *x)
+{
+ int i;
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_packet1next = -1;
+ x->x_queue_id = -1;
+ x->x_extrapolate = 0;
+
+
+ x->x_mixer = pdp_imageproc_mix_new();
+ pdp_mix_mix(x, 0.0f);
+
+
+ return (void *)x;
+}
+
+
+void *pdp_mix_new(t_floatarg mix)
+{
+ t_pdp_mix *x = (t_pdp_mix *)pd_new(pdp_mix_class);
+ pdp_mix_common_init(x);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("mix"));
+ if (mix == 0.0f) mix = 0.5f;
+ pdp_mix_mix(x, mix);
+ return (void *)x;
+}
+
+void *pdp_mix2_new(t_floatarg mix1, t_floatarg mix2)
+{
+ t_pdp_mix *x = (t_pdp_mix *)pd_new(pdp_mix2_class);
+ pdp_mix_common_init(x);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("mix1"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("mix2"));
+ if ((mix1 == 0.0f) && (mix2 == 0.0f)) mix1 = mix2 = 0.5f;
+ pdp_mix_mix1(x, mix1);
+ pdp_mix_mix2(x, mix2);
+ return (void *)x;
+}
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+void pdp_mix_setup(void)
+{
+
+
+ pdp_mix_class = class_new(gensym("pdp_mix"), (t_newmethod)pdp_mix_new,
+ (t_method)pdp_mix_free, sizeof(t_pdp_mix), 0, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_mix_class, (t_method)pdp_mix_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mix_class, (t_method)pdp_mix_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mix_class, (t_method)pdp_mix_mix, gensym("mix"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mix_class, (t_method)pdp_mix_extrapolate, gensym("extrapolate"), A_DEFFLOAT, A_NULL);
+
+ pdp_mix2_class = class_new(gensym("pdp_mix2"), (t_newmethod)pdp_mix2_new,
+ (t_method)pdp_mix_free, sizeof(t_pdp_mix), 0, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_mix2_class, (t_method)pdp_mix_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mix2_class, (t_method)pdp_mix_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mix2_class, (t_method)pdp_mix_mix1, gensym("mix1"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mix2_class, (t_method)pdp_mix_mix2, gensym("mix2"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mix2_class, (t_method)pdp_mix_extrapolate, gensym("extrapolate"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_mul.c b/modules/pdp_mul.c
new file mode 100644
index 0000000..8c06087
--- /dev/null
+++ b/modules/pdp_mul.c
@@ -0,0 +1,205 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+
+
+typedef struct pdp_mul_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+ t_outlet *x_outlet1;
+
+ int x_packet0;
+ int x_packet1;
+ int x_packet1next;
+ int x_queue_id;
+ int x_dropped;
+
+} t_pdp_mul;
+
+
+static void pdp_mul_process_yv12(t_pdp_mul *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ // set hight so it includes the chroma frames
+ h = h + (h>>1);
+
+ pdp_imageproc_mul_process((short int*)data0, (short int*)data1, w, h);
+
+ return;
+
+
+
+}
+static void pdp_mul_process_grey(t_pdp_mul *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ // set hight so it includes the chroma frames
+ h = h + (h>>1);
+
+ pdp_imageproc_mul_process((short int*)data0, (short int*)data1, w, h);
+
+ return;
+
+
+
+}
+
+static void pdp_mul_process(t_pdp_mul *x)
+{
+ int encoding;
+
+ /* check if image data packets are compatible */
+ if (pdp_type_compat_image(x->x_packet0, x->x_packet1)){
+
+ /* pdp_mul_process inputs and write into active inlet */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_mul_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_mul_process_grey(x);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont pdp_mul_process */
+
+ }
+ }
+}
+
+static void pdp_mul_sendpacket(t_pdp_mul *x)
+{
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_mul_input_0(t_pdp_mul *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* if a cold packet was received in the meantime
+ swap it in, else keep the old one */
+
+ pdp_replace_if_valid(&x->x_packet1, &x->x_packet1next);
+
+
+ /* add the process method and callback to the process queue */
+
+ pdp_queue_add(x, pdp_mul_process, pdp_mul_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+static void pdp_mul_input_1(t_pdp_mul *x, t_symbol *s, t_floatarg f)
+{
+ /* store the packet and drop
+ the old one, if there is any */
+
+ if(s == gensym("register_ro")) pdp_packet_copy_ro_or_drop(&x->x_packet1next, (int)f);
+
+}
+
+
+
+
+
+
+
+static void pdp_mul_free(t_pdp_mul *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+
+}
+
+t_class *pdp_mul_class;
+
+
+
+void *pdp_mul_new(void)
+{
+ t_pdp_mul *x = (t_pdp_mul *)pd_new(pdp_mul_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_packet1next = -1;
+ x->x_queue_id = -1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_mul_setup(void)
+{
+
+
+ pdp_mul_class = class_new(gensym("pdp_mul"), (t_newmethod)pdp_mul_new,
+ (t_method)pdp_mul_free, sizeof(t_pdp_mul), 0, A_NULL);
+
+
+
+ class_addmethod(pdp_mul_class, (t_method)pdp_mul_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mul_class, (t_method)pdp_mul_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_noise.c b/modules/pdp_noise.c
new file mode 100644
index 0000000..f1a4661
--- /dev/null
+++ b/modules/pdp_noise.c
@@ -0,0 +1,230 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+
+
+
+typedef struct pdp_noise_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ void *x_noisegen;
+
+ int x_packet0;
+ int x_queue_id;
+
+ int x_pdp_image_type;
+
+ unsigned int x_width;
+ unsigned int x_height;
+
+} t_pdp_noise;
+
+
+
+void pdp_noise_type(t_pdp_noise *x, t_symbol *s)
+{
+ if (gensym("yv12") == s) {x->x_pdp_image_type = PDP_IMAGE_YV12; return;}
+ if (gensym("grey") == s) {x->x_pdp_image_type = PDP_IMAGE_GREY; return;}
+
+ x->x_pdp_image_type = -1;
+
+}
+
+
+void pdp_noise_random(t_pdp_noise *x, t_floatarg seed)
+{
+ if (seed == 0.0f) seed = (float)random();
+ pdp_imageproc_random_setseed(x->x_noisegen, seed);
+
+}
+
+
+
+static void pdp_noise_createpacket_yv12(t_pdp_noise *x)
+{
+ /* create new packet */
+ x->x_packet0 = pdp_packet_new_image_yv12(x->x_width, x->x_height);
+
+ /* seed the 16 bit rng with a new random number from the clib */
+ pdp_noise_random(x, 0.0f);
+}
+
+static void pdp_noise_generate_yv12(t_pdp_noise *x)
+{
+ short int *data;
+ unsigned int w = x->x_width;
+ unsigned int h = x->x_height;
+
+ h = h + (h>>1);
+
+ data = (short int *) pdp_packet_data(x->x_packet0);
+
+ pdp_noise_random(x, 0.0f);
+ pdp_imageproc_random_process(x->x_noisegen, data, w, h);
+
+ return;
+
+}
+
+static void pdp_noise_createpacket_grey(t_pdp_noise *x)
+{
+ /* create new packet */
+ x->x_packet0 = pdp_packet_new_image_grey(x->x_width, x->x_height);
+
+ /* seed the 16 bit rng with a new random number from the clib */
+ pdp_noise_random(x, 0.0f);
+}
+
+static void pdp_noise_generate_grey(t_pdp_noise *x)
+{
+ unsigned int w = x->x_width;
+ unsigned int h = x->x_height;
+ short int *data = (short int *) pdp_packet_data(x->x_packet0);
+
+ data = (short int *) pdp_packet_data(x->x_packet0);
+
+ pdp_noise_random(x, 0.0f);
+ pdp_imageproc_random_process(x->x_noisegen, data, w, h);
+
+
+ return;
+}
+
+static void pdp_noise_sendpacket(t_pdp_noise *x, t_floatarg w, t_floatarg h)
+{
+ /* propagate if valid */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+
+static void pdp_noise_bang(t_pdp_noise *x)
+{
+
+ int encoding;
+
+ /* if we have an active packet, don't do anything */
+ if (-1 != x->x_packet0) return;
+
+ switch(x->x_pdp_image_type){
+
+ case PDP_IMAGE_YV12:
+ pdp_noise_createpacket_yv12(x); // don't create inside thread!!!
+ pdp_queue_add(x, pdp_noise_generate_yv12, pdp_noise_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_noise_createpacket_grey(x); // don't create inside thread!!!
+ pdp_queue_add(x, pdp_noise_generate_grey, pdp_noise_sendpacket, &x->x_queue_id);
+ break;
+
+ default:
+ break;
+
+ }
+
+
+ /* release the packet */
+
+}
+
+
+static void pdp_noise_dim(t_pdp_noise *x, t_floatarg w, t_floatarg h)
+{
+ if (w<32.0f) w = 32.0f;
+ if (h<32.0f) h = 32.0f;
+
+ x->x_width = (unsigned int)w;
+ x->x_height = (unsigned int)h;
+}
+
+
+static void pdp_noise_free(t_pdp_noise *x)
+{
+
+ /* remove callback from process queue */
+ pdp_queue_finish(x->x_queue_id);
+
+
+ /* tidy up */
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_imageproc_random_delete(x->x_noisegen);
+
+}
+
+t_class *pdp_noise_class;
+
+
+
+
+void *pdp_noise_new(void)
+{
+ int i;
+
+ t_pdp_noise *x = (t_pdp_noise *)pd_new(pdp_noise_class);
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+ x->x_width = 320;
+ x->x_height = 240;
+
+ x->x_noisegen = pdp_imageproc_random_new();
+
+ pdp_noise_random(x, 0.0f);
+
+ pdp_noise_type(x, gensym("yv12"));
+
+ return (void *)x;
+}
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+void pdp_noise_setup(void)
+{
+
+
+ pdp_noise_class = class_new(gensym("pdp_noise"), (t_newmethod)pdp_noise_new,
+ (t_method)pdp_noise_free, sizeof(t_pdp_noise), 0, A_NULL);
+
+ class_addmethod(pdp_noise_class, (t_method)pdp_noise_random, gensym("seed"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_noise_class, (t_method)pdp_noise_type, gensym("type"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_noise_class, (t_method)pdp_noise_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_noise_class, (t_method)pdp_noise_bang, gensym("bang"), A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_qt.c b/modules/pdp_qt.c
new file mode 100644
index 0000000..1c778d5
--- /dev/null
+++ b/modules/pdp_qt.c
@@ -0,0 +1,941 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+#include "pdp_llconv.h"
+#include <quicktime/lqt.h>
+#include <quicktime/colormodels.h>
+
+
+#define min(x,y) ((x<y)?(x):(y))
+
+
+
+#define FREE(x) {if (x) {free(x); x=0;} else post("free null pointer");}
+
+
+/* debug macro */
+//#define DEBUG_MSG_ENABLED
+
+#ifdef DEBUG_MSG_ENABLED
+
+#define DEBUG_MSG(EXP)\
+fprintf (stderr, "mark start: [" #EXP "], on line %d\n", __LINE__);\
+ EXP \
+fprintf (stderr, "mark end: [" #EXP "], on line %d\n", __LINE__);
+
+#else
+#define DEBUG_MSG(EXP) EXP
+#endif
+
+typedef struct pdp_qt_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ float x_gain;
+
+
+ t_symbol *x_name; // this is our name
+ int x_istilde; // 0==pdp_qt / 1==pdp_qt~
+ int x_syncaudio;
+
+
+ /* clock object */
+ t_clock *x_clock;
+ int x_counter;
+ int x_queue_id;
+
+ /* audio outlets */
+ t_outlet *x_outleft;
+ t_outlet *x_outright;
+
+ /* message outlets */
+ t_outlet *x_outlet0;
+ t_outlet *x_outlet1;
+ t_outlet *x_outlet2;
+
+ /* pdp data */
+ int x_packet0;
+
+ /* toggles */
+ int x_loop;
+ int x_autoplay;
+
+ /* qt data */
+ unsigned char ** x_qt_rows; // pointer array to rows / colour planes
+ float ** x_qt_audiochans; // pointer array to audio channel buffers
+ unsigned char * x_qt_frame;
+ quicktime_t *x_qt;
+ int x_qt_cmodel;
+
+ //t_pdp_qt_data *x_state_data;
+
+ /* audio data */
+ int x_chunk_current;
+ float *x_chunk_buf;
+ float *x_chunk[2][2];
+ int x_chunk_used[2]; // marks if chunk is used or not
+ int x_chunk_size;
+ int x_chunk_pos;
+
+ /* global state */
+ int x_initialized;
+ int x_frame;
+ int x_frame_thread;
+ int x_process_in_thread;
+
+
+ /* audio info */
+ int x_audio_tracks; // ==0 means audio not available
+ int x_audio_channels;
+ long x_audio_samplerate;
+ long x_audio_length;
+
+ /* video info */
+ int x_video_tracks; // ==0 means video not available
+ float x_video_framerate;
+ long x_video_length;
+ unsigned int x_video_width;
+ unsigned int x_video_height;
+
+
+} t_pdp_qt;
+
+
+static void pdp_qt_bang(t_pdp_qt *x);
+
+static void pdp_qt_close(t_pdp_qt *x)
+{
+ /* disable clock */
+ clock_unset(x->x_clock);
+ pdp_queue_finish(x->x_queue_id);
+
+ if (x->x_initialized){
+ /* close file */
+ quicktime_close(x->x_qt);
+ x->x_initialized = 0;
+
+
+ /* free video data */
+ if (x->x_video_tracks){
+ FREE(x->x_qt_frame);
+ FREE(x->x_qt_rows);
+ x->x_video_tracks = 0;
+ //x->x_qt_rows = 0;
+ //x->x_qt_frame = 0;
+ }
+
+ /* free audio data */
+ if (x->x_audio_tracks){
+ x->x_chunk_used[0] = 0;
+ x->x_chunk_used[1] = 0;
+ FREE(x->x_chunk_buf);
+ FREE(x->x_qt_audiochans);
+ x->x_audio_tracks = 0;
+ //x->x_qt_audiochans = 0;
+ //x->x_chunk_buf = 0;
+ x->x_chunk[0][0] = 0;
+ x->x_chunk[0][1] = 0;
+ x->x_chunk[1][0] = 0;
+ x->x_chunk[1][1] = 0;
+ }
+
+
+ }
+
+
+}
+
+void pdp_qt_create_pdp_packet(t_pdp_qt *x)
+{
+ t_pdp *header;
+ int nbpixels = x->x_video_width * x->x_video_height;
+ //int packet_size = (x->x_qt_cmodel == BC_RGB888) ? (nbpixels << 1) : (nbpixels + (nbpixels >> 1)) << 1;
+ int packet_size = (nbpixels + (nbpixels >> 1)) << 1;
+
+
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = pdp_packet_new(PDP_IMAGE, packet_size);
+ header = pdp_packet_header(x->x_packet0);
+
+ //header->info.image.encoding = (x->x_qt_cmodel == BC_RGB888) ? PDP_IMAGE_GREY : PDP_IMAGE_YV12;
+ header->info.image.encoding = PDP_IMAGE_YV12;
+ header->info.image.width = x->x_video_width;
+ header->info.image.height = x->x_video_height;
+}
+
+
+
+
+static void pdp_qt_open(t_pdp_qt *x, t_symbol *name)
+{
+ unsigned int size;
+ unsigned int i;
+ unsigned int chunk_bytesize;
+
+ post("%s: opening %s", x->x_name->s_name, name->s_name);
+
+
+ /* close previous one */
+ pdp_qt_close(x);
+
+
+ /* check if qt file */
+ if(0 == quicktime_check_sig(name->s_name)){
+ post("%s: ERROR: not a quicktime file", x->x_name->s_name);
+ goto exit;
+ }
+
+ /* open */
+ DEBUG_MSG(x->x_qt = quicktime_open(name->s_name, 1, 0);)
+ if (!(x->x_qt)){
+ post("%s: ERROR: can't open file", x->x_name->s_name);
+ goto exit;
+ }
+
+ /* check video */
+ x->x_video_tracks = 0;
+ if (quicktime_has_video(x->x_qt)) {
+ x->x_video_framerate = quicktime_frame_rate (x->x_qt, 0);
+ x->x_video_length = quicktime_video_length (x->x_qt, 0);
+ x->x_video_width = quicktime_video_width (x->x_qt, 0);
+ x->x_video_height = quicktime_video_height (x->x_qt, 0);
+ post("%s: video stream found (%dx%d pixels, %0.00f fps, %d frames, %s codec)",
+ x->x_name->s_name, x->x_video_width, x->x_video_height, x->x_video_framerate,
+ x->x_video_length, quicktime_video_compressor(x->x_qt, 0));
+ x->x_video_tracks = quicktime_video_tracks(x->x_qt);
+
+ }
+
+
+ /* check audior */
+ x->x_audio_tracks = 0;
+ if (quicktime_has_audio(x->x_qt)) {
+ x->x_audio_tracks = quicktime_audio_tracks (x->x_qt);
+ //x->x_audio_channels = quicktime_track_channels (x->x_qt, 0);
+ x->x_audio_channels = lqt_total_channels (x->x_qt);
+ x->x_audio_samplerate = quicktime_sample_rate (x->x_qt, 0);
+ x->x_audio_length = quicktime_audio_length (x->x_qt, 0);
+ x->x_chunk_size = (int)((float)x->x_audio_samplerate / x->x_video_framerate);
+ post("%s: audio stream found (%d channels, %d Hz, %d samples, chunksize %d)",
+ x->x_name->s_name, x->x_audio_channels, x->x_audio_samplerate, x->x_audio_length, x->x_chunk_size);
+ }
+
+ /* check if video codec is supported */
+ if (x->x_video_tracks){
+ if (!quicktime_supported_video(x->x_qt,0)) {
+ post("%s: WARNING: unsupported video codec",x->x_name->s_name);
+ x->x_video_tracks = 0;
+ }
+ }
+
+ /* check if audio codec is supported */
+ if (x->x_audio_tracks){
+ if (!quicktime_supported_audio(x->x_qt,0)) {
+ post("%s: WARNING: unsupported audio codec", x->x_name->s_name);
+ x->x_audio_tracks = 0;
+ }
+ }
+
+
+
+ /* check which colormodel to use */
+ if (x->x_video_tracks){
+
+ if (quicktime_reads_cmodel(x->x_qt,BC_YUV420P,0)){
+ post("%s: using colormodel YUV420P", x->x_name->s_name);
+ x->x_qt_cmodel = BC_YUV420P;
+ }
+ else if (quicktime_reads_cmodel(x->x_qt,BC_YUV422,0)){
+ post("%s: using colormodel YUV422", x->x_name->s_name);
+ x->x_qt_cmodel = BC_YUV422;
+ }
+ else if (quicktime_reads_cmodel(x->x_qt,BC_RGB888,0)){
+ post("%s: using colormodel RGB888", x->x_name->s_name);
+ x->x_qt_cmodel = BC_RGB888;
+ }
+ else {
+ post("%s: WARNING: can't find a usable colour model", x->x_name->s_name);
+ x->x_video_tracks = 0;
+ }
+
+ }
+
+
+
+ /* no video == errors */
+ if (!x->x_video_tracks) {
+ post("%s: ERROR: no usable video stream found.", x->x_name->s_name);
+ goto exit_close;
+ }
+
+
+ /* initialize video data structures */
+ if (x->x_video_tracks){
+
+ /* allocate enough space for all supported colormodels (24bpp)*/
+ x->x_frame = 0;
+ x->x_qt_frame = (unsigned char*)malloc(x->x_video_width * x->x_video_height * 3);
+ x->x_qt_rows = (unsigned char **)malloc(sizeof(unsigned char *) * x->x_video_height);
+ size = x->x_video_width * x->x_video_height;
+
+ switch(x->x_qt_cmodel){
+ case BC_YUV420P:
+ /* planar with u&v 2x2 subsampled */
+ x->x_qt_rows[0] = &x->x_qt_frame[0];
+ x->x_qt_rows[2] = &x->x_qt_frame[size];
+ x->x_qt_rows[1] = &x->x_qt_frame[size + (size>>2)];
+ break;
+
+ case BC_YUV422:
+ /* packed with u&v 2x subsampled (lines) */
+ /* later on we will convert this to planar */
+ for(i=0; i< x->x_video_height; i++) x->x_qt_rows[i] = &x->x_qt_frame[i * x->x_video_width * 2];
+ break;
+
+ case BC_RGB888:
+ /* packed rgb */
+ /* later on we will convert this to planar */
+ for(i=0; i< x->x_video_height; i++) x->x_qt_rows[i] = &x->x_qt_frame[i * x->x_video_width * 3];
+ break;
+
+ default:
+ post("%s: error on init: unkown colour model",x->x_name->s_name);
+ break;
+ }
+
+ DEBUG_MSG(quicktime_set_cmodel(x->x_qt, x->x_qt_cmodel);)
+ pdp_qt_create_pdp_packet(x);
+ outlet_float(x->x_outlet2, (float)quicktime_video_length(x->x_qt,0));
+
+ }
+
+ /* initialize audio data structures */
+ if (x->x_audio_tracks){
+ x->x_chunk_pos = 0;
+ x->x_chunk_current = 0;
+
+ chunk_bytesize = sizeof(float)*x->x_chunk_size;
+ x->x_chunk_buf = (float *)malloc(chunk_bytesize * 4);
+ memset(x->x_chunk_buf, 0, chunk_bytesize * 4);
+ x->x_chunk[0][0] = x->x_chunk_buf;
+ x->x_chunk[0][1] = x->x_chunk_buf + x->x_chunk_size ;
+ x->x_chunk[1][0] = x->x_chunk_buf + x->x_chunk_size * 2;
+ x->x_chunk[1][1] = x->x_chunk_buf + x->x_chunk_size * 3;
+ x->x_chunk_used[0] = 0;
+ x->x_chunk_used[1] = 0;
+ x->x_syncaudio = x->x_istilde; //sync on audio if this is a tilde object
+
+ DEBUG_MSG(if (x->x_audio_channels == 0) exit(1);)
+ x->x_qt_audiochans = (float **)malloc(x->x_audio_channels * sizeof(float **));
+ memset(x->x_qt_audiochans, 0, x->x_audio_channels * sizeof(float **));
+ }
+ else {
+ x->x_syncaudio = 0;
+ }
+
+
+ /* everything went well */
+ x->x_initialized = 1;
+
+ /* start playback if outplay is on */
+ if(x->x_autoplay) clock_delay(x->x_clock, 1000.0L / (double)x->x_video_framerate);
+
+ /* brag about success */
+ post("%s: %s opened", x->x_name->s_name, name->s_name);
+
+ return;
+
+ /* error exits */
+
+ exit_close:
+ DEBUG_MSG(quicktime_close(x->x_qt);)
+
+ exit:
+ x->x_initialized = 0;
+ x->x_audio_tracks = 0;
+ x->x_video_tracks = 0;
+ return;
+
+}
+
+
+//static void pdp_qt_setposition(t_pdp_qt *x, int pos)
+//{
+// x->x_frame = pos;
+// DEBUG_MSG(if(x->x_video_tracks) quicktime_set_video_position(x->x_qt, pos, 0);)
+// DEBUG_MSG(if(x->x_audio_tracks) quicktime_set_audio_position(x->x_qt, pos * x->x_chunk_size, 0);)
+//
+//}
+
+
+static void pdp_qt_bangaudio(t_pdp_qt *x)
+{
+ int lefterr=0;
+ int righterr=0;
+ int err=0;
+ int sample = 0;
+ int remaining = 0;
+ int readamount = 0;
+
+
+
+ if (!x->x_initialized){
+ //post("pdp_qt: no qt file opened");
+ return;
+ }
+
+
+ if (!x->x_audio_tracks){
+ //post("pdp_qt: no audio stream present");
+ return;
+ }
+
+
+
+ //DEBUG_MSG(sample = quicktime_audio_position(x->x_qt,0);)
+
+
+ // if the active chunk is unused, clear it and mark it used
+ if (!x->x_chunk_used[x->x_chunk_current]){
+ //post("%s: clearing unused active chunk",x->x_name->s_name);
+
+
+
+ //probably this is the !@#%&*(*)&!$() bug
+ //memset(x->x_chunk[0][x->x_chunk_current], 0, sizeof(float)*2*x->x_chunk_size);
+ //memset(x->x_chunk[1][x->x_chunk_current], 0, sizeof(float)*2*x->x_chunk_size);
+
+ memset(x->x_chunk[0][x->x_chunk_current], 0, sizeof(float) * x->x_chunk_size);
+ memset(x->x_chunk[1][x->x_chunk_current], 0, sizeof(float) * x->x_chunk_size);
+
+
+
+
+ x->x_chunk_used[x->x_chunk_current] = 1;
+ }
+
+ // compute the remaining time
+ DEBUG_MSG(remaining = (int ) ( quicktime_audio_length(x->x_qt, 0) - quicktime_audio_position(x->x_qt, 0) );)
+ readamount = min(remaining, x->x_chunk_size);
+ if (!readamount) return;
+
+
+ // if the inactive chunk is unused, fill it with the current frame's audio data and mark it used
+ if (!x->x_chunk_used[!x->x_chunk_current]){
+ switch(x->x_audio_channels){
+ case 1:
+ x->x_qt_audiochans[0] = x->x_chunk[0][!x->x_chunk_current];
+ x->x_qt_audiochans[1] = 0;
+ DEBUG_MSG(err = lqt_decode_audio(x->x_qt, NULL, x->x_qt_audiochans, readamount);)
+ break;
+ default:
+ x->x_qt_audiochans[0] = x->x_chunk[0][!x->x_chunk_current];
+ x->x_qt_audiochans[1] = x->x_chunk[1][!x->x_chunk_current];
+ DEBUG_MSG(err = lqt_decode_audio(x->x_qt, NULL, x->x_qt_audiochans, readamount);)
+ break;
+ }
+ x->x_chunk_used[!x->x_chunk_current] = 1;
+ }
+ // if it is used, something went wrong with sync
+ else{
+ //post("%s: dropping audio chunk %d.",x->x_name->s_name, x->x_frame_thread);
+ }
+
+
+ if (err) post("%s: error decoding audio",x->x_name->s_name, x->x_frame_thread);
+
+ // ensure audio pointer points to next frame's data
+ //DEBUG_MSG(quicktime_set_audio_position(x->x_qt, sample + readamount, 0);)
+
+}
+
+
+
+
+static void pdp_qt_bangvideo(t_pdp_qt *x)
+{
+ unsigned int w, h, nbpixels, packet_size, i,j;
+ unsigned int *source, *dest;
+ unsigned int uoffset, voffset;
+ short int* data;
+ t_pdp* header;
+
+ // check if we want greyscale output or not
+ //int grey = (x->x_qt_cmodel == BC_RGB888);
+
+ static short int gain[4] = {0x7fff, 0x7fff, 0x7fff, 0x7fff};
+
+ if ((!x->x_initialized) || (!x->x_video_tracks)){
+ //post("pdp_qt: no qt file opened");
+ return;
+ }
+
+ w = x->x_video_width;
+ h = x->x_video_height;
+ nbpixels = x->x_video_width * x->x_video_height;
+
+ header = pdp_packet_header(x->x_packet0);
+ data = (short int *) pdp_packet_data(x->x_packet0);
+
+
+ DEBUG_MSG(lqt_decode_video(x->x_qt, x->x_qt_rows, 0);)
+
+
+ switch(x->x_qt_cmodel){
+ case BC_YUV420P:
+ pdp_llconv(x->x_qt_frame, RIF_YVU__P411_U8, data, RIF_YVU__P411_S16, x->x_video_width, x->x_video_height);
+ break;
+
+ case BC_YUV422:
+ pdp_llconv(x->x_qt_frame, RIF_YUYV_P____U8, data, RIF_YVU__P411_S16, x->x_video_width, x->x_video_height);
+ break;
+
+ case BC_RGB888:
+ pdp_llconv(x->x_qt_frame, RIF_RGB__P____U8, data, RIF_YVU__P411_S16, x->x_video_width, x->x_video_height);
+ break;
+
+ default:
+ post("%s: error on decode: unkown colour model",x->x_name->s_name);
+ break;
+ }
+
+
+
+}
+
+static void pdp_qt_sendpacket(t_pdp_qt *x)
+{
+ if (x->x_packet0 != -1){
+ //pdp_packet_mark_unused(x->x_packet0);
+ outlet_pdp(x->x_outlet0, x->x_packet0);
+ //x->x_packet0 = -1;
+ }
+}
+
+
+static void pdp_qt_thread_bang(t_pdp_qt *x)
+{
+ // set audio position
+ if(x->x_video_tracks) quicktime_set_video_position(x->x_qt, x->x_frame_thread, 0);
+
+ // bang video
+ pdp_qt_bangvideo(x);
+
+ // if it's a tilde object, bang audio
+ if (x->x_istilde && x->x_audio_tracks){
+ quicktime_set_audio_position(x->x_qt, x->x_frame_thread * x->x_chunk_size, 0);
+ pdp_qt_bangaudio(x);
+ }
+
+}
+
+
+static void pdp_qt_bang(t_pdp_qt *x)
+{
+ int length, pos;
+
+ /* return if not initialized */
+ if (!x->x_initialized) return;
+
+ //length = quicktime_video_length(x->x_qt,0);
+ //pos = quicktime_video_position(x->x_qt,0);
+ length = x->x_video_length;
+ pos = x->x_frame;
+
+
+ /* check bounds */
+ if (x->x_loop){
+ pos = x->x_frame % length;
+ if (pos < 0) pos += length;
+ }
+ else{
+ if (pos < 0) pos = 0;
+ if (pos >= length) pos = length - 1;
+ }
+
+ /* store next frame for access in thread */
+ x->x_frame_thread = pos;
+
+
+ // if autoplay is on and we do not have audio synchro
+ // set clock to play next frame
+ if (x->x_autoplay && !x->x_syncaudio) clock_delay(x->x_clock, 1000.0L / (double)x->x_video_framerate);
+
+
+ // make sure prev decode is finished don't drop frames in this one
+ pdp_queue_finish(x->x_queue_id);
+ x->x_queue_id = -1;
+
+ /* only decode new stuff if previous is done */
+ if (-1 == x->x_queue_id){
+ // send the current frame number to outlet
+ outlet_float(x->x_outlet1, (float)pos);
+
+ //pdp_qt_setposition(x, pos);
+
+ // start process method
+ if (x->x_process_in_thread) pdp_queue_add(x, pdp_qt_thread_bang, pdp_qt_sendpacket, &x->x_queue_id);
+ else {
+ pdp_qt_thread_bang(x);
+ pdp_qt_sendpacket(x);
+ }
+ }
+ // advance frame
+ x->x_frame = pos + 1;
+
+
+ // send the packet
+ //pdp_qt_sendpacket(x);
+}
+
+
+
+//static void pdp_qt_getaudiochunk(t_pdp_qt *x, int channel)
+//{
+// if (!x->x_audio_tracks) return;
+// quicktime_decode_audio(x->x_qt, NULL, x->x_chunk[channel][x->x_chunk_current], x->x_chunk_size<<1, channel);
+//
+//}
+
+static void pdp_qt_loop(t_pdp_qt *x, t_floatarg loop)
+{
+ int loopi = (int)loop;
+ x->x_loop = !(loopi == 0);
+}
+
+static void pdp_qt_autoplay(t_pdp_qt *x, t_floatarg play)
+{
+ int playi = (int)play;
+ x->x_autoplay = !(playi == 0);
+
+
+ // reset clock if autoplay is off
+ if (!x->x_autoplay) clock_unset(x->x_clock);
+
+
+}
+
+
+
+static void pdp_qt_frame_cold(t_pdp_qt *x, t_floatarg frameindex)
+{
+ int frame = (int)frameindex;
+ //int length;
+
+
+ x->x_frame = frame;
+
+ //if (!(x->x_initialized)) return;
+
+ //length = quicktime_video_length(x->x_qt,0);
+
+ //frame = (frame >= length) ? length-1 : frame;
+ //frame = (frame < 0) ? 0 : frame;
+
+ //pdp_qt_setposition(x, frame);
+}
+
+static void pdp_qt_frame(t_pdp_qt *x, t_floatarg frameindex)
+{
+ pdp_qt_frame_cold(x, frameindex);
+ pdp_qt_bang(x);
+}
+
+static void pdp_qt_stop(t_pdp_qt *x)
+{
+ pdp_qt_autoplay(x, 0);
+}
+
+static void pdp_qt_continue(t_pdp_qt *x)
+{
+ pdp_qt_autoplay(x, 1);
+ pdp_qt_bang(x);
+}
+
+
+static void pdp_qt_play(t_pdp_qt *x){
+ pdp_qt_frame_cold(x, 0);
+ pdp_qt_continue(x);
+}
+
+
+
+
+static void pdp_qt_importaudio(t_pdp_qt *x, t_symbol *array, t_floatarg channel)
+{
+ int c = (int)channel;
+ t_garray *g;
+ int vecsize;
+ int sample;
+ float *f;
+ int i;
+
+ /* if there's no audio, there's nothing to export */
+ if (!x->x_audio_tracks) return;
+
+ /* check audio channel */
+ if ((c < 0) || (c >= x->x_audio_channels)) return;
+
+ /* check if array exists */
+ if (!(g = (t_garray *)pd_findbyclass(array, garray_class))){
+ pd_error(x, "%s: no such table", array->s_name);
+ return;
+ }
+
+ post("%s: importing audio channel %d into array %s", x->x_name->s_name, c, array->s_name);
+
+
+ // make sure decode is finished
+ pdp_queue_finish(x->x_queue_id);
+ x->x_queue_id = -1;
+
+
+ /* resize array */
+ garray_resize(g, x->x_audio_length);
+
+ /* for sanity's sake let's clear the save-in-patch flag here */
+ garray_setsaveit(g, 0);
+ garray_getfloatarray(g, &vecsize, &f);
+
+ /* if the resize failed, garray_resize reported the error */
+ if (vecsize != x->x_audio_length){
+ pd_error(x, "array resize failed");
+ return;
+ }
+
+ /* save pointer in file */
+ DEBUG_MSG(sample = quicktime_audio_position(x->x_qt, 0);)
+ DEBUG_MSG(quicktime_set_audio_position(x->x_qt, 0, 0);)
+
+ /* transfer the audio file to the end of the array */
+ DEBUG_MSG(quicktime_decode_audio(x->x_qt, NULL, f, vecsize, c);)
+
+ /* restore pointer in file */
+ DEBUG_MSG(quicktime_set_audio_position(x->x_qt, sample, 0);)
+
+
+}
+
+
+
+static t_int *pdp_qt_perform(t_int *w)
+{
+ t_pdp_qt *x = (t_pdp_qt *)w[1];
+ t_float *out0 = (t_float *)w[2];
+ t_float *out1 = (t_float *)w[3];
+ t_int n = (t_int)w[4];
+
+ t_int xfer_samples;
+ if (!x->x_initialized || !x->x_audio_tracks) goto zero;
+
+ while(1){
+ // check current chunk
+ if (!x->x_chunk_used[x->x_chunk_current]) goto zero;
+
+
+ // transfer from chunk to output
+ xfer_samples = min(n, x->x_chunk_size - x->x_chunk_pos);
+
+ //x->x_audio_channels = 1;
+
+ if (x->x_audio_channels == 1){
+ memcpy(out0, x->x_chunk[0][x->x_chunk_current] + x->x_chunk_pos, sizeof(float)*xfer_samples);
+ memcpy(out1, x->x_chunk[0][x->x_chunk_current] + x->x_chunk_pos, sizeof(float)*xfer_samples);
+ }
+ else {
+ memcpy(out0, x->x_chunk[0][x->x_chunk_current] + x->x_chunk_pos, sizeof(float)*xfer_samples);
+ memcpy(out1, x->x_chunk[1][x->x_chunk_current] + x->x_chunk_pos, sizeof(float)*xfer_samples);
+ }
+ out0 += xfer_samples;
+ out1 += xfer_samples;
+ n -= xfer_samples;
+ x->x_chunk_pos += xfer_samples;
+
+
+ // check if chunk is finished, if so mark unused, swap buffers and set clock
+ if (x->x_chunk_size == x->x_chunk_pos){
+ x->x_chunk_used[x->x_chunk_current] = 0;
+ x->x_chunk_pos = 0;
+ x->x_chunk_current ^= 1;
+ if (x->x_autoplay) clock_delay(x->x_clock, 0L);
+ }
+
+ // if chunk is not finished, the output buffer is full
+ else{
+ goto exit;
+ }
+
+ }
+
+
+ zero:
+ // fill the rest of the output with zeros
+ memset(out0, 0, sizeof(float)*n);
+ memset(out1, 0, sizeof(float)*n);
+
+ exit:
+ return(w+5);
+}
+
+static void pdp_qt_dsp(t_pdp_qt *x, t_signal **sp)
+{
+ dsp_add(pdp_qt_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+
+}
+
+static void pdp_qt_process_in_thread(t_pdp_qt *x, t_float f)
+{
+
+ int t = (f != 0.0f);
+
+ x->x_process_in_thread = t;
+
+ post("pdp_qt: thread processing switched %d", t ? "on" : "off");
+
+}
+
+static void pdp_qt_tick(t_pdp_qt *x)
+{
+
+ // bang audio/video
+ pdp_qt_bang(x);
+}
+
+static void pdp_qt_free(t_pdp_qt *x)
+{
+ clock_unset(x->x_clock);
+ pdp_qt_close(x);
+ clock_free(x->x_clock);
+ //free (x->x_state_data);
+
+}
+
+
+
+t_class *pdp_qt_class;
+t_class *pdp_qt_tilde_class;
+
+
+void pdp_qt_init_common(t_pdp_qt *x)
+{
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("frame_cold"));
+
+ /* add common outlets */
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
+
+ /* init */
+ x->x_gain = 1.0f;
+ x->x_process_in_thread = 0;
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+ x->x_initialized = 0;
+ x->x_audio_tracks = 0;
+ x->x_video_tracks = 0;
+ x->x_loop = 0;
+ x->x_autoplay = 0;
+ x->x_chunk[0][0] = 0;
+ x->x_chunk[0][1] = 0;
+ x->x_chunk[1][0] = 0;
+ x->x_chunk[1][1] = 0;
+
+ /* initialize clock object */
+ x->x_clock = clock_new(x, (t_method)pdp_qt_tick);
+
+
+
+
+}
+
+void *pdp_qt_new(void)
+{
+ t_pdp_qt *x = (t_pdp_qt *)pd_new(pdp_qt_class);
+ x->x_name = gensym("pdp_qt");
+ x->x_istilde = 0;
+ pdp_qt_init_common(x);
+ return (void *)x;
+}
+
+void *pdp_qt_tilde_new(void)
+{
+ t_pdp_qt *x = (t_pdp_qt *)pd_new(pdp_qt_tilde_class);
+ x->x_name = gensym("pdp_qt");
+ x->x_istilde = 1;
+
+ pdp_qt_init_common(x);
+
+ /* add outlets to the right so pdp_qt~ can replace pdp_qt without breaking a patch */
+ x->x_outleft = outlet_new(&x->x_obj, &s_signal);
+ x->x_outright = outlet_new(&x->x_obj, &s_signal);
+
+ return (void *)x;
+}
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_qt_setup_common(t_class *class)
+{
+ class_addmethod(class, (t_method)pdp_qt_bang, gensym("bang"), A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_close, gensym("close"), A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_open, gensym("open"), A_SYMBOL, A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_autoplay, gensym("autoplay"), A_DEFFLOAT, A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_stop, gensym("stop"), A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_play, gensym("play"), A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_continue, gensym("cont"), A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_loop, gensym("loop"), A_DEFFLOAT, A_NULL);
+ class_addfloat (class, (t_method)pdp_qt_frame);
+ class_addmethod(class, (t_method)pdp_qt_frame_cold, gensym("frame_cold"), A_FLOAT, A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_process_in_thread, gensym("thread"), A_FLOAT, A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_importaudio, gensym("importaudio"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(class, (t_method)pdp_qt_importaudio, gensym("dump"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+}
+
+void pdp_qt_setup(void)
+{
+
+ /* plain class */
+ pdp_qt_class = class_new(gensym("pdp_qt"), (t_newmethod)pdp_qt_new,
+ (t_method)pdp_qt_free, sizeof(t_pdp_qt), 0, A_NULL);
+ pdp_qt_setup_common(pdp_qt_class);
+
+
+ /* tilde class */
+ pdp_qt_tilde_class = class_new(gensym("pdp_qt~"), (t_newmethod)pdp_qt_tilde_new,
+ (t_method)pdp_qt_free, sizeof(t_pdp_qt), 0, A_NULL);
+ pdp_qt_setup_common(pdp_qt_tilde_class);
+
+ class_addmethod(pdp_qt_tilde_class, (t_method)pdp_qt_dsp, gensym("dsp"), 0);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_randmix.c b/modules/pdp_randmix.c
new file mode 100644
index 0000000..3ffea27
--- /dev/null
+++ b/modules/pdp_randmix.c
@@ -0,0 +1,228 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+
+
+typedef struct pdp_randmix_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ int x_packet0;
+ int x_packet1;
+ int x_packet1next;
+ int x_queue_id;
+ int x_dropped;
+
+ void *x_randmixer;
+
+} t_pdp_randmix;
+
+
+void pdp_randmix_random(t_pdp_randmix *x, t_floatarg seed)
+{
+ pdp_imageproc_randmix_setseed(x->x_randmixer, seed);
+}
+
+
+
+static void pdp_randmix_process_yv12(t_pdp_randmix *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ h = h + (h>>1);
+
+ pdp_imageproc_randmix_process(x->x_randmixer, (short int*)data0, (short int*)data1, w, h);
+
+ return;
+
+
+
+}
+
+static void pdp_randmix_process_grey(t_pdp_randmix *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ pdp_imageproc_randmix_process(x->x_randmixer, (short int*)data0, (short int*)data1, w, h);
+
+ return;
+
+}
+
+static void pdp_randmix_process(t_pdp_randmix *x)
+{
+
+ int encoding;
+
+ /* check if image data packets are compatible */
+ if (pdp_type_compat_image(x->x_packet0, x->x_packet1)){
+
+ /* pdp_randmix_process inputs and write into active inlet */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ pdp_randmix_process_yv12(x);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_randmix_process_grey(x);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont pdp_randmix_process */
+
+ }
+ }
+
+}
+
+static void pdp_randmix_sendpacket(t_pdp_randmix *x)
+{
+ /* unregister and propagate if valid packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+static void pdp_randmix_input_0(t_pdp_randmix *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_rw_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* if a cold packet was received in the meantime
+ swap it in, else keep the old one */
+
+ pdp_replace_if_valid(&x->x_packet1, &x->x_packet1next);
+
+
+ /* add the process method and callback to the process queue */
+
+ pdp_queue_add(x, pdp_randmix_process, pdp_randmix_sendpacket, &x->x_queue_id);
+ }
+
+}
+
+static void pdp_randmix_input_1(t_pdp_randmix *x, t_symbol *s, t_floatarg f)
+{
+ /* store the packet and drop
+ the old one, if there is any */
+
+ if(s == gensym("register_ro")) pdp_packet_copy_ro_or_drop(&x->x_packet1next, (int)f);
+
+}
+
+
+
+
+
+static void pdp_randmix_threshold(t_pdp_randmix *x, t_floatarg f)
+{
+ pdp_imageproc_randmix_setthreshold(x->x_randmixer, f);
+
+}
+
+
+
+static void pdp_randmix_free(t_pdp_randmix *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+
+ pdp_imageproc_randmix_delete(x->x_randmixer);
+
+}
+
+t_class *pdp_randmix_class;
+
+
+void *pdp_randmix_new(void)
+{
+ int i;
+
+ t_pdp_randmix *x = (t_pdp_randmix *)pd_new(pdp_randmix_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("threshold"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_packet1next = -1;
+ x->x_queue_id = -1;
+
+ x->x_randmixer = pdp_imageproc_randmix_new();
+
+ pdp_randmix_threshold(x, 0.5f);
+ pdp_randmix_random(x, 0.0f);
+
+ return (void *)x;
+}
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+void pdp_randmix_setup(void)
+{
+
+
+ pdp_randmix_class = class_new(gensym("pdp_randmix"), (t_newmethod)pdp_randmix_new,
+ (t_method)pdp_randmix_free, sizeof(t_pdp_randmix), 0, A_NULL);
+
+ class_addmethod(pdp_randmix_class, (t_method)pdp_randmix_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_randmix_class, (t_method)pdp_randmix_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_randmix_class, (t_method)pdp_randmix_threshold, gensym("threshold"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_randmix_class, (t_method)pdp_randmix_random, gensym("seed"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_reg.c b/modules/pdp_reg.c
new file mode 100644
index 0000000..e3aa721
--- /dev/null
+++ b/modules/pdp_reg.c
@@ -0,0 +1,132 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+
+
+typedef struct pdp_reg_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ int x_packet0;
+
+} t_pdp_reg;
+
+
+static void pdp_reg_bang(t_pdp_reg *x)
+{
+
+ if (-1 != x->x_packet0) outlet_pdp(x->x_outlet0, x->x_packet0);
+
+}
+
+
+
+static void pdp_reg_input_0(t_pdp_reg *x, t_symbol *s, t_floatarg f)
+{
+
+ /* if this is a register_ro message or register_rw message, register with packet factory */
+
+ /* if this is a process message, start the processing + propagate stuff to outputs */
+
+ if (s == gensym("register_ro")){
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = pdp_packet_copy_ro((int)f);
+ //post("in0ro: requested %d, got %d", (int)f, x->x_packet0);
+ }
+ else if (s == gensym("process")){
+ pdp_reg_bang(x);
+
+ }
+
+
+}
+
+
+static void pdp_reg_input_1(t_pdp_reg *x, t_symbol *s, t_floatarg f)
+{
+
+ /* if this is a register_ro message or register_rw message, register with packet factory */
+
+ /* if this is a process message, start the processing + propagate stuff to outputs */
+
+ if (s == gensym("register_ro")){
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = pdp_packet_copy_ro((int)f);
+ //post("in0ro: requested %d, got %d", (int)f, x->x_packet0);
+ }
+
+}
+
+
+
+static void pdp_reg_free(t_pdp_reg *x)
+{
+ pdp_packet_mark_unused(x->x_packet0);
+
+}
+
+t_class *pdp_reg_class;
+
+
+
+void *pdp_reg_new(void)
+{
+ t_pdp_reg *x = (t_pdp_reg *)pd_new(pdp_reg_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_reg_setup(void)
+{
+
+
+ pdp_reg_class = class_new(gensym("pdp_reg"), (t_newmethod)pdp_reg_new,
+ (t_method)pdp_reg_free, sizeof(t_pdp_reg), 0, A_NULL);
+
+
+ class_addmethod(pdp_reg_class, (t_method)pdp_reg_bang, gensym("bang"), A_NULL);
+
+ class_addmethod(pdp_reg_class, (t_method)pdp_reg_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_reg_class, (t_method)pdp_reg_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_route.c b/modules/pdp_route.c
new file mode 100644
index 0000000..7b0a0a9
--- /dev/null
+++ b/modules/pdp_route.c
@@ -0,0 +1,129 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+
+// dynamic ????
+#define PDP_ROUTE_MAX_NB_OUTLETS 100
+
+typedef struct pdp_route_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet[PDP_ROUTE_MAX_NB_OUTLETS];
+
+ int x_nb_outlets;
+ int x_route;
+ int x_route_next;
+
+
+} t_pdp_route;
+
+
+static void pdp_route_input_0(t_pdp_route *x, t_symbol *s, t_floatarg f)
+{
+ t_atom atom[2];
+ t_symbol *pdp = gensym("pdp");
+
+
+ /* trigger on register_ro */
+ if (s == gensym("register_ro")){
+ x->x_route = x->x_route_next;
+ }
+
+ /* propagate the pdp message */
+ SETSYMBOL(atom+0, s);
+ SETFLOAT(atom+1, f);
+ outlet_anything(x->x_outlet[x->x_route], pdp, 2, atom);
+
+}
+
+static void pdp_route_route(t_pdp_route *x, t_floatarg f)
+{
+ int route = (int)f;
+
+ if (route < 0) route = 0;
+ if (route >= x->x_nb_outlets) route = x->x_nb_outlets - 1;
+
+ x->x_route_next = route;
+
+}
+
+
+
+static void pdp_route_free(t_pdp_route *x)
+{
+
+}
+
+t_class *pdp_route_class;
+
+
+
+void *pdp_route_new(t_floatarg f)
+{
+ int nboutlets = (int)f;
+ int i;
+
+ t_pdp_route *x = (t_pdp_route *)pd_new(pdp_route_class);
+
+
+ if (nboutlets < 2) nboutlets = 2;
+ if (nboutlets >= PDP_ROUTE_MAX_NB_OUTLETS) nboutlets = PDP_ROUTE_MAX_NB_OUTLETS - 1;
+
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("route"));
+
+ x->x_nb_outlets = nboutlets;
+ x->x_route = 0;
+ x->x_route_next = 0;
+
+ for (i=0; i<nboutlets; i++)
+ x->x_outlet[i] = outlet_new(&x->x_obj, &s_anything);
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_route_setup(void)
+{
+
+
+ pdp_route_class = class_new(gensym("pdp_route"), (t_newmethod)pdp_route_new,
+ (t_method)pdp_route_free, sizeof(t_pdp_route), 0, A_FLOAT, A_NULL);
+
+
+ class_addmethod(pdp_route_class, (t_method)pdp_route_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_route_class, (t_method)pdp_route_route, gensym("route"), A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_scale.c b/modules/pdp_scale.c
new file mode 100644
index 0000000..82c5257
--- /dev/null
+++ b/modules/pdp_scale.c
@@ -0,0 +1,267 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+#include "pdp_resample.h"
+
+
+
+typedef struct pdp_scale_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+
+ int x_packet0;
+ int x_packet1;
+ int x_dropped;
+ int x_queue_id;
+
+ unsigned int x_width;
+ unsigned int x_height;
+ int x_quality;
+
+
+} t_pdp_scale;
+
+
+static void pdp_scale_process_yv12(t_pdp_scale *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int src_w = header0->info.image.width;
+ unsigned int src_h = header0->info.image.height;
+
+ unsigned int dst_w = header1->info.image.width;
+ unsigned int dst_h = header1->info.image.height;
+
+ short int *src_image = (short int *)data0;
+ short int *dst_image = (short int *)data1;
+
+ unsigned int src_size = src_w*src_h;
+ unsigned int src_voffset = src_size;
+ unsigned int src_uoffset = src_size + (src_size>>2);
+
+ unsigned int dst_size = dst_w*dst_h;
+ unsigned int dst_voffset = dst_size;
+ unsigned int dst_uoffset = dst_size + (dst_size>>2);
+
+ if (x->x_quality){
+ pdp_resample_scale_bilin(src_image, dst_image, src_w, src_h, dst_w, dst_h);
+ pdp_resample_scale_bilin(src_image+src_voffset, dst_image+dst_voffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1);
+ pdp_resample_scale_bilin(src_image+src_uoffset, dst_image+dst_uoffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1);
+ }
+ else{
+ pdp_resample_scale_nn(src_image, dst_image, src_w, src_h, dst_w, dst_h);
+ pdp_resample_scale_nn(src_image+src_voffset, dst_image+dst_voffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1);
+ pdp_resample_scale_nn(src_image+src_uoffset, dst_image+dst_uoffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1);
+ }
+
+ return;
+}
+
+static void pdp_scale_process_grey(t_pdp_scale *x)
+{
+
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int src_w = header0->info.image.width;
+ unsigned int src_h = header0->info.image.height;
+
+ unsigned int dst_w = header1->info.image.width;
+ unsigned int dst_h = header1->info.image.height;
+
+ short int *src_image = (short int *)data0;
+ short int *dst_image = (short int *)data1;
+
+ if (x->x_quality) pdp_resample_scale_bilin(src_image, dst_image, src_w, src_h, dst_w, dst_h);
+ else pdp_resample_scale_nn(src_image, dst_image, src_w, src_h, dst_w, dst_h);
+
+ return;
+
+
+}
+
+static void pdp_scale_sendpacket(t_pdp_scale *x)
+{
+ /* delete source packet */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = -1;
+
+ /* unregister and propagate if valid dest packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet1);
+}
+
+static void pdp_scale_process(t_pdp_scale *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+
+ /* check data packets */
+
+ if ((header0) && (PDP_IMAGE == header0->type)){
+
+ /* if dims are equal, just send the packet */
+ if ((header0->info.image.width == x->x_width)
+ && (header0->info.image.height == x->x_height)){
+ x->x_packet1 = x->x_packet0;
+ x->x_packet0 = -1;
+ pdp_scale_sendpacket(x);
+ return;
+ }
+
+ /* type hub */
+ switch(header0->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ x->x_packet1 = pdp_packet_new_image_yv12(x->x_width, x->x_height);
+ pdp_queue_add(x, pdp_scale_process_yv12, pdp_scale_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ x->x_packet1 = pdp_packet_new_image_grey(x->x_width, x->x_height);
+ pdp_queue_add(x, pdp_scale_process_grey, pdp_scale_sendpacket, &x->x_queue_id);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont process */
+
+ }
+ }
+
+}
+
+
+
+
+static void pdp_scale_input_0(t_pdp_scale *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+ int passes, i;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_ro_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* add the process method and callback to the process queue */
+ pdp_scale_process(x);
+
+ }
+
+}
+
+
+
+
+static void pdp_scale_width(t_pdp_scale *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i < 32) i = 32;
+ x->x_width = i;
+}
+
+static void pdp_scale_height(t_pdp_scale *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i < 32) i = 32;
+ x->x_height = i;
+}
+
+
+static void pdp_scale_dim(t_pdp_scale *x, t_floatarg w, t_floatarg h)
+{
+ pdp_scale_width(x, w);
+ pdp_scale_height(x, h);
+}
+
+static void pdp_scale_quality(t_pdp_scale *x, t_floatarg f)
+{
+ if (f==0) x->x_quality = 0;
+ if (f==1) x->x_quality = 1;
+}
+
+
+t_class *pdp_scale_class;
+
+
+
+void pdp_scale_free(t_pdp_scale *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+}
+
+void *pdp_scale_new(t_floatarg fw, t_floatarg fh)
+{
+ t_pdp_scale *x = (t_pdp_scale *)pd_new(pdp_scale_class);
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_queue_id = -1;
+
+ if ((fw != 0.0f) && (fh != 0.0f)) pdp_scale_dim(x, fw, fh);
+ else pdp_scale_dim(x, 320, 240);
+
+ pdp_scale_quality(x, 1);
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_scale_setup(void)
+{
+
+
+ pdp_scale_class = class_new(gensym("pdp_scale"), (t_newmethod)pdp_scale_new,
+ (t_method)pdp_scale_free, sizeof(t_pdp_scale), 0, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+
+ class_addmethod(pdp_scale_class, (t_method)pdp_scale_quality, gensym("quality"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_scale_class, (t_method)pdp_scale_width, gensym("width"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_scale_class, (t_method)pdp_scale_height, gensym("height"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_scale_class, (t_method)pdp_scale_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_scale_class, (t_method)pdp_scale_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_scope.c b/modules/pdp_scope.c
new file mode 100644
index 0000000..6c0f5c0
--- /dev/null
+++ b/modules/pdp_scope.c
@@ -0,0 +1,312 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+#include <string.h>
+
+#define BUFSIZE 2048
+
+typedef struct pdp_scope_data
+{
+ short int random_seed[4];
+
+}t_pdp_scope_data;
+
+typedef struct pdp_scope_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ t_pdp_scope_data *x_data;
+ int x_packet0;
+ int x_queue_id;
+
+ int x_pdp_image_type;
+
+ unsigned int x_width;
+ unsigned int x_height;
+
+ float *x_buffer;
+ int x_needle;
+
+
+} t_pdp_scope;
+
+
+
+void pdp_scope_type(t_pdp_scope *x, t_symbol *s)
+{
+ if (gensym("yv12") == s) {x->x_pdp_image_type = PDP_IMAGE_YV12; return;}
+ if (gensym("grey") == s) {x->x_pdp_image_type = PDP_IMAGE_GREY; return;}
+
+ x->x_pdp_image_type = -1;
+
+}
+
+
+
+
+
+static void pdp_scope_createpacket_yv12(t_pdp_scope *x)
+{
+ t_pdp *header;
+
+ unsigned int w = x->x_width;
+ unsigned int h = x->x_height;
+
+ unsigned int size = w*h;
+ unsigned int totalnbpixels = size + (size >> 1);
+ unsigned int packet_size = totalnbpixels << 1;
+
+ x->x_packet0 = pdp_packet_new(PDP_IMAGE, packet_size);
+ header = pdp_packet_header(x->x_packet0);
+
+ header->info.image.encoding = PDP_IMAGE_YV12;
+ header->info.image.width = w;
+ header->info.image.height = h;
+
+ memset(pdp_packet_data(x->x_packet0), 0, packet_size);
+
+}
+
+static void pdp_scope_generate_yv12(t_pdp_scope *x)
+{
+ unsigned int w = x->x_width;
+ unsigned int h = x->x_height;
+ unsigned int size = w*h;
+ unsigned int totalnbpixels = size + (size >> 1);
+ short int *data = (short int *) pdp_packet_data(x->x_packet0);
+
+ unsigned int i;
+ int offset = x->x_needle;
+ int val;
+ unsigned int y;
+ float fh2 = (float)(h/2);
+
+ for (i=0; i<w; i++){
+ y = (h/2) + (int)(fh2 * -x->x_buffer[(offset - w + i) & (BUFSIZE - 1)]);
+ if (y>=h) y = h-1;
+
+ data[i + y*w] = 0x7fff;
+ }
+
+ return;
+
+}
+
+static void pdp_scope_createpacket_grey(t_pdp_scope *x)
+{
+ t_pdp *header;
+ short int *data;
+
+ unsigned int w = x->x_width;
+ unsigned int h = x->x_height;
+
+ unsigned int size = w*h;
+ unsigned int totalnbpixels = size;
+ unsigned int packet_size = totalnbpixels << 1;
+
+ /* create new packet */
+ x->x_packet0 = pdp_packet_new(PDP_IMAGE, packet_size);
+
+
+ header = pdp_packet_header(x->x_packet0);
+ data = (short int *) pdp_packet_data(x->x_packet0);
+
+ header->info.image.encoding = PDP_IMAGE_GREY;
+ header->info.image.width = w;
+ header->info.image.height = h;
+
+ memset(pdp_packet_data(x->x_packet0), 0, packet_size);
+
+}
+
+static void pdp_scope_generate_grey(t_pdp_scope *x)
+{
+ unsigned int w = x->x_width;
+ unsigned int h = x->x_height;
+ unsigned int totalnbpixels = x->x_width * x->x_height;
+ short int *data = (short int *) pdp_packet_data(x->x_packet0);
+
+ unsigned int i;
+ int offset = x->x_needle;
+ int val;
+ unsigned int y;
+ float fh2 = (float)(h/2);
+
+ for (i=0; i<w; i++){
+ y = (h/2) + (int)(fh2 * -x->x_buffer[(offset - w + i) & (BUFSIZE - 1)]);
+ if (y>=h) y = h-1;
+
+ data[i + y*w] = 0x7fff;
+ }
+
+ return;
+}
+
+static void pdp_scope_sendpacket(t_pdp_scope *x)
+{
+ /* propagate if valid */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet0);
+}
+
+
+static void pdp_scope_bang(t_pdp_scope *x)
+{
+
+ int encoding;
+
+ /* if we have an active packet, don't do anything */
+ if (-1 != x->x_packet0) return;
+
+ switch(x->x_pdp_image_type){
+
+ case PDP_IMAGE_YV12:
+ pdp_scope_createpacket_yv12(x); // don't create inside thread!!!
+ pdp_scope_generate_yv12(x);
+ pdp_scope_sendpacket(x);
+ //pdp_queue_add(x, pdp_scope_generate_yv12, pdp_scope_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ pdp_scope_createpacket_grey(x); // don't create inside thread!!!
+ pdp_scope_generate_grey(x);
+ pdp_scope_sendpacket(x);
+ //pdp_queue_add(x, pdp_scope_generate_grey, pdp_scope_sendpacket, &x->x_queue_id);
+ break;
+
+ default:
+ break;
+
+ }
+
+
+ /* release the packet */
+
+}
+
+
+static void pdp_scope_dim(t_pdp_scope *x, t_floatarg w, t_floatarg h)
+{
+ if (w<32.0f) w = 32.0f;
+ if (h<32.0f) h = 32.0f;
+
+ x->x_width = (unsigned int)w;
+ x->x_height = (unsigned int)h;
+}
+
+
+static void pdp_scope_free(t_pdp_scope *x)
+{
+
+ /* remove callback from process queue */
+ pdp_queue_finish(x->x_queue_id);
+
+
+ /* tidy up */
+ pdp_packet_mark_unused(x->x_packet0);
+ free(x->x_data);
+
+}
+static t_int *pdp_scope_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_pdp_scope *x = (t_pdp_scope *)(w[1]);
+ t_int n = (t_int)(w[2]);
+ t_int i;
+
+ t_int offset = x->x_needle;
+
+ for (i=0; i<n; i++)
+ x->x_buffer[(offset+i)&(BUFSIZE-1)] = in[i];
+
+ x->x_needle = (offset + n ) & (BUFSIZE - 1);
+
+ return (w+4);
+
+}
+static void pdp_scope_dsp(t_pdp_scope *x, t_signal **sp)
+{
+ dsp_add(pdp_scope_perform, 3, x, sp[0]->s_n, sp[0]->s_vec);
+
+}
+
+t_class *pdp_scope_class;
+
+
+
+
+void *pdp_scope_new(void)
+{
+ int i;
+
+ t_pdp_scope *x = (t_pdp_scope *)pd_new(pdp_scope_class);
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+ x->x_width = 320;
+ x->x_height = 240;
+ x->x_f = 0.0;
+
+ x->x_data = (t_pdp_scope_data *)malloc(sizeof(t_pdp_scope_data));
+
+ pdp_scope_type(x, gensym("yv12"));
+
+ x->x_buffer = (float *)malloc(sizeof(float) * BUFSIZE);
+ x->x_needle = 0;
+
+ return (void *)x;
+}
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+void pdp_scope_setup(void)
+{
+
+
+ pdp_scope_class = class_new(gensym("pdp_scope~"), (t_newmethod)pdp_scope_new,
+ (t_method)pdp_scope_free, sizeof(t_pdp_scope), 0, A_NULL);
+
+ CLASS_MAINSIGNALIN(pdp_scope_class, t_pdp_scope, x_f);
+
+ class_addmethod(pdp_scope_class, (t_method)pdp_scope_type, gensym("type"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_scope_class, (t_method)pdp_scope_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_scope_class, (t_method)pdp_scope_bang, gensym("bang"), A_NULL);
+ class_addmethod(pdp_scope_class, (t_method)pdp_scope_dsp, gensym("dsp"), 0);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_snap.c b/modules/pdp_snap.c
new file mode 100644
index 0000000..3ed0da2
--- /dev/null
+++ b/modules/pdp_snap.c
@@ -0,0 +1,146 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef struct pdp_snap_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ int x_packet0;
+ bool x_snapnext;
+
+} t_pdp_snap;
+
+
+static void pdp_snap_bang(t_pdp_snap *x)
+{
+
+ if (-1 != x->x_packet0)
+ outlet_pdp(x->x_outlet0, x->x_packet0);
+
+}
+
+
+
+
+static void pdp_snap_input_1(t_pdp_snap *x, t_symbol *s, t_floatarg f)
+{
+
+ /* if this is a register_ro message or register_rw message, register with packet factory */
+
+ /* if this is a process message, start the processing + propagate stuff to outputs */
+
+ if (s == gensym("register_ro")){
+ if(x->x_snapnext) {
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = pdp_packet_copy_ro((int)f);
+ x->x_snapnext = false;
+ }
+ }
+
+}
+
+static void pdp_snap_snap(t_pdp_snap *x)
+{
+ x->x_snapnext = true;
+}
+
+static void pdp_snap_free(t_pdp_snap *x)
+{
+ pdp_packet_mark_unused(x->x_packet0);
+
+}
+
+t_class *pdp_snap_class;
+
+
+
+void *pdp_snap_new(void)
+{
+ t_pdp_snap *x = (t_pdp_snap *)pd_new(pdp_snap_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_snapnext = false;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_snap_setup(void)
+{
+
+
+ pdp_snap_class = class_new(gensym("pdp_snap"), (t_newmethod)pdp_snap_new,
+ (t_method)pdp_snap_free, sizeof(t_pdp_snap), 0, A_NULL);
+
+
+ class_addmethod(pdp_snap_class, (t_method)pdp_snap_bang, gensym("bang"), A_NULL);
+ class_addmethod(pdp_snap_class, (t_method)pdp_snap_snap, gensym("snap"), A_NULL);
+
+ class_addmethod(pdp_snap_class, (t_method)pdp_snap_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_trigger.c b/modules/pdp_trigger.c
new file mode 100644
index 0000000..e131438
--- /dev/null
+++ b/modules/pdp_trigger.c
@@ -0,0 +1,105 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+
+
+
+
+
+typedef struct pdp_trigger_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+ t_outlet *x_outlet1;
+ int x_packet;
+
+
+} t_pdp_trigger;
+
+
+
+
+static void pdp_trigger_input_0(t_pdp_trigger *x, t_symbol *s, t_floatarg f)
+{
+ t_atom atom[2];
+ t_symbol *pdp = gensym("pdp");
+
+
+ /* trigger on register_ro */
+ if (s == gensym("register_ro")){
+ outlet_bang(x->x_outlet1);
+
+ }
+
+ /* propagate the pdp message */
+ SETSYMBOL(atom+0, s);
+ SETFLOAT(atom+1, f);
+ outlet_anything(x->x_outlet0, pdp, 2, atom);
+
+}
+
+
+
+static void pdp_trigger_free(t_pdp_trigger *x)
+{
+
+}
+
+t_class *pdp_trigger_class;
+
+
+
+void *pdp_trigger_new(void)
+{
+ t_pdp_trigger *x = (t_pdp_trigger *)pd_new(pdp_trigger_class);
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_bang);
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_trigger_setup(void)
+{
+
+
+ pdp_trigger_class = class_new(gensym("pdp_trigger"), (t_newmethod)pdp_trigger_new,
+ (t_method)pdp_trigger_free, sizeof(t_pdp_trigger), 0, A_NULL);
+
+ class_addmethod(pdp_trigger_class, (t_method)pdp_trigger_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_v4l.c b/modules/pdp_v4l.c
new file mode 100644
index 0000000..e4dbff9
--- /dev/null
+++ b/modules/pdp_v4l.c
@@ -0,0 +1,734 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+#include "pdp_llconv.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <linux/types.h>
+#include <linux/videodev.h>
+#include <sys/mman.h>
+#include <sched.h>
+#include <pthread.h>
+
+// dont open any more after a set number
+// of failed attempts
+// this is to prevent locks on auto-open
+// is reset when manually opened or closed
+#define PDP_XV_RETRIES 10
+
+//uncomment this for additional philips webcam control
+//#define HAVE_V4LPWC
+#ifdef HAVE_V4LPWC
+#include "pwc-ioctl.h"
+#endif
+
+
+#define DEVICENO 0
+#define NBUF 2
+#define COMPOSITEIN 1
+
+
+
+
+typedef struct pdp_v4l_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ bool x_initialized;
+ bool x_auto_open;
+
+ unsigned int x_width;
+ unsigned int x_height;
+ int x_channel;
+ unsigned int x_norm;
+ int x_freq;
+
+ unsigned int x_framerate;
+
+ struct video_tuner x_vtuner;
+ struct video_picture x_vpicture;
+ struct video_buffer x_vbuffer;
+ struct video_capability x_vcap;
+ struct video_channel x_vchannel;
+ struct video_audio x_vaudio;
+ struct video_mbuf x_vmbuf;
+ struct video_mmap x_vmmap[NBUF];
+ struct video_window x_vwin;
+ int x_tvfd;
+ int x_frame;
+ unsigned char *x_videobuf;
+ int x_skipnext;
+ int x_mytopmargin, x_mybottommargin;
+ int x_myleftmargin, x_myrightmargin;
+
+ t_symbol *x_device;
+ t_symbol *x_image_type;
+ //int x_pdp_image_type;
+ int x_v4l_palette;
+
+ pthread_t x_thread_id;
+ int x_continue_thread;
+ int x_frame_ready;
+ int x_only_new_frames;
+ int x_last_frame;
+
+
+ int x_open_retry;
+
+
+} t_pdp_v4l;
+
+
+
+
+
+static void pdp_v4l_close(t_pdp_v4l *x)
+{
+ /* close the v4l device and dealloc buffer */
+
+ void *dummy;
+
+ /* terminate thread if there is one */
+ if(x->x_continue_thread){
+ x->x_continue_thread = 0;
+ pthread_join (x->x_thread_id, &dummy);
+ }
+
+
+ if (x->x_tvfd >= 0)
+ {
+ close(x->x_tvfd);
+ x->x_tvfd = -1;
+ }
+
+ if (x->x_initialized){
+ munmap(x->x_videobuf, x->x_vmbuf.size);
+ x->x_initialized = false;
+ }
+
+}
+
+static void pdp_v4l_close_manual(t_pdp_v4l *x)
+{
+ x->x_open_retry = PDP_XV_RETRIES;
+ pdp_v4l_close(x);
+
+}
+
+static void pdp_v4l_close_error(t_pdp_v4l *x)
+{
+ pdp_v4l_close(x);
+ if(x->x_open_retry) x->x_open_retry--;
+}
+
+
+static void pdp_v4l_pwc_init(t_pdp_v4l *x)
+{
+ /* todo add detection code for pwc */
+
+#ifdef HAVE_V4LPWC
+
+ if(ioctl(x->x_tvfd, VIDIOCPWCRUSER)){
+ perror("pdp_v4l: pwc: VIDIOCPWCRUSER");
+ goto closit;
+ }
+
+ if (ioctl(x->x_tvfd, VIDIOCGWIN, &x->x_vwin)){
+ perror("pdp_v4l: pwc: VIDIOCGWIN");
+ goto closit;
+ }
+
+
+
+ if (x->x_vwin.flags & PWC_FPS_MASK){
+ post("pdp_v4l: pwc: framerate: %d", (x->x_vwin.flags & PWC_FPS_MASK) >> PWC_FPS_SHIFT);
+ post("pdp_v4l: pwc: setting framerate to %d", x->x_framerate);
+ x->x_vwin.flags &= PWC_FPS_MASK;
+ x->x_vwin.flags |= (x->x_framerate << PWC_FPS_SHIFT);
+ if (ioctl(x->x_tvfd, VIDIOCSWIN, &x->x_vwin)){
+ perror("pdp_v4l: pwc: VIDIOCSWIN");
+ goto closit;
+ }
+ if (ioctl(x->x_tvfd, VIDIOCGWIN, &x->x_vwin)){
+ perror("pdp_v4l: pwc: VIDIOCGWIN");
+ goto closit;
+ }
+ post("pdp_v4l: pwc: framerate: %d", (x->x_vwin.flags & PWC_FPS_MASK) >> PWC_FPS_SHIFT);
+
+ }
+
+
+ return;
+
+
+
+ closit:
+ pdp_v4l_close_error(x);
+ return;
+
+#else
+ post("pdp_v4l: additional pwc support disabled");
+ return;
+#endif
+}
+
+static void pdp_v4l_sync_frame(t_pdp_v4l* x){
+ /* grab frame */
+ if (ioctl(x->x_tvfd, VIDIOCSYNC, &x->x_vmmap[x->x_frame].frame) < 0){
+ perror("pdp_v4l: VIDIOCSYNC");
+ pdp_v4l_close(x);
+ return;
+ }
+}
+
+static void pdp_v4l_capture_frame(t_pdp_v4l* x){
+ if (ioctl(x->x_tvfd, VIDIOCMCAPTURE, &x->x_vmmap[x->x_frame]) < 0){
+ if (errno == EAGAIN)
+ post("pdp_v4l: can't sync (no video source?)\n");
+ else
+ perror("pdp_v4l: VIDIOCMCAPTURE");
+ if (ioctl(x->x_tvfd, VIDIOCMCAPTURE, &x->x_vmmap[x->x_frame]) < 0)
+ perror("pdp_v4l: VIDIOCMCAPTURE2");
+
+ post("pdp_v4l: frame %d %d, format %d, width %d, height %d",
+ x->x_frame, x->x_vmmap[x->x_frame].frame, x->x_vmmap[x->x_frame].format,
+ x->x_vmmap[x->x_frame].width, x->x_vmmap[x->x_frame].height);
+
+ pdp_v4l_close(x);
+ return;
+ }
+}
+
+
+static void *pdp_v4l_thread(void *voidx)
+{
+ t_pdp_v4l *x = ((t_pdp_v4l *)voidx);
+
+
+ /* flip buffers */
+ x->x_frame ^= 0x1;
+
+ /* capture with a double buffering scheme */
+ while (x->x_continue_thread){
+
+ /* schedule capture command for next frame */
+ pdp_v4l_capture_frame(x);
+
+ /* wait until previous capture is ready */
+ x->x_frame ^= 0x1;
+ pdp_v4l_sync_frame(x);
+
+ /* setup pointers for main thread */
+ x->x_frame_ready = 1;
+ x->x_last_frame = x->x_frame;
+
+ }
+
+ return 0;
+}
+
+
+static void pdp_v4l_open(t_pdp_v4l *x, t_symbol *name)
+{
+ /* open a v4l device and allocate a buffer */
+
+ unsigned int size;
+ int i;
+
+ unsigned int width, height;
+
+
+ /* if already opened -> close */
+ if (x->x_initialized) pdp_v4l_close(x);
+
+
+ /* exit if retried too much */
+ if (!x->x_open_retry){
+ post("pdp_v4l: retry count reached zero for %s", name->s_name);
+ post("pdp_v4l: try to open manually");
+ return;
+ }
+
+ post("pdp_v4l: opening %s", name->s_name);
+
+ x->x_device = name;
+
+ if ((x->x_tvfd = open(name->s_name, O_RDWR)) < 0)
+ {
+ post("pdp_v4l: error:");
+ perror(name->s_name);
+ goto closit;
+ }
+
+
+ if (ioctl(x->x_tvfd, VIDIOCGCAP, &x->x_vcap) < 0)
+ {
+ perror("get capabilities");
+ goto closit;
+ }
+
+ post("pdp_v4l: cap: name %s type %d channels %d maxw %d maxh %d minw %d minh %d",
+ x->x_vcap.name, x->x_vcap.type, x->x_vcap.channels, x->x_vcap.maxwidth, x->x_vcap.maxheight,
+ x->x_vcap.minwidth, x->x_vcap.minheight);
+
+ if (ioctl(x->x_tvfd, VIDIOCGPICT, &x->x_vpicture) < 0)
+ {
+ perror("VIDIOCGCAP");
+ goto closit;
+ }
+
+ post("pdp_v4l: picture: brightness %d depth %d palette %d",
+ x->x_vpicture.brightness, x->x_vpicture.depth, x->x_vpicture.palette);
+
+ /* get channel info */
+ for (i = 0; i < x->x_vcap.channels; i++)
+ {
+ x->x_vchannel.channel = i;
+ if (ioctl(x->x_tvfd, VIDIOCGCHAN, &x->x_vchannel) < 0)
+ {
+ perror("VDIOCGCHAN");
+ goto closit;
+ }
+ post("pdp_v4l: channel %d name %s type %d flags %d",
+ x->x_vchannel.channel, x->x_vchannel.name,
+ x->x_vchannel.type, x->x_vchannel.flags);
+ }
+
+ /* switch to the desired channel */
+ if (x->x_channel < 0) x->x_channel = 0;
+ if (x->x_channel >= x->x_vcap.channels) x->x_channel = x->x_vcap.channels - 1;
+
+ x->x_vchannel.channel = x->x_channel;
+ if (ioctl(x->x_tvfd, VIDIOCGCHAN, &x->x_vchannel) < 0)
+ {
+ perror("pdp_v4l: warning: VDIOCGCHAN");
+ post("pdp_v4l: cant change to channel %d",x->x_channel);
+
+ // ignore error
+ // goto closit;
+ }
+ else{
+ post("pdp_v4l: switched to channel %d", x->x_channel);
+ }
+
+ x->x_vchannel.norm = x->x_norm;
+ if (ioctl(x->x_tvfd, VIDIOCSCHAN, &x->x_vchannel) < 0)
+ {
+ perror("pdp_v4l: warning: VDIOCSCHAN");
+ post("pdp_v4l: cant change to norm %d",x->x_norm);
+
+ // ignore error
+ // goto closit;
+ }
+
+ if (x->x_freq > 0){
+ if (ioctl(x->x_tvfd, VIDIOCSFREQ, &x->x_freq) < 0)
+ perror ("couldn't set frequency :");
+ }
+
+
+
+
+ /* get mmap numbers */
+ if (ioctl(x->x_tvfd, VIDIOCGMBUF, &x->x_vmbuf) < 0)
+ {
+ perror("pdp_v4l: VIDIOCGMBUF");
+ goto closit;
+ }
+ post("pdp_v4l: buffer size %d, frames %d, offset %d %d", x->x_vmbuf.size,
+ x->x_vmbuf.frames, x->x_vmbuf.offsets[0], x->x_vmbuf.offsets[1]);
+ if (!(x->x_videobuf = (unsigned char *)
+ mmap(0, x->x_vmbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, x->x_tvfd, 0)))
+ {
+ perror("pdp_v4l: mmap");
+ goto closit;
+ }
+
+ width = (x->x_width > (unsigned int)x->x_vcap.minwidth) ? x->x_width : (unsigned int)x->x_vcap.minwidth;
+ width = (width > (unsigned int)x->x_vcap.maxwidth) ?(unsigned int) x->x_vcap.maxwidth : width;
+ height = (x->x_height > (unsigned int)x->x_vcap.minheight) ? x->x_height :(unsigned int) x->x_vcap.minheight;
+ height = (height > (unsigned int)x->x_vcap.maxheight) ? (unsigned int)x->x_vcap.maxheight : height;
+
+ for (i = 0; i < NBUF; i++)
+ {
+ //x->x_vmmap[i].format = VIDEO_PALETTE_YUV420P;
+ //x->x_vmmap[i].format = VIDEO_PALETTE_UYVY;
+ x->x_vmmap[i].width = width;
+ x->x_vmmap[i].height = height;
+ x->x_vmmap[i].frame = i;
+ }
+
+
+ //goto test;
+
+ //try yuv planar format
+ x->x_v4l_palette = VIDEO_PALETTE_YUV420P;
+ for (i = 0; i < NBUF; i++) x->x_vmmap[i].format = x->x_v4l_palette;
+ if (ioctl(x->x_tvfd, VIDIOCMCAPTURE, &x->x_vmmap[x->x_frame]) < 0)
+ {
+ if (errno == EAGAIN)
+ post("pdp_v4l: can't sync (no video source?)");
+ }
+ else{
+ post("pdp_v4l: using VIDEO_PALETTE_YUV420P");
+ goto capture_ok;
+ }
+
+
+ //try VIDEO_PALETTE_YUV422 format
+ x->x_v4l_palette = VIDEO_PALETTE_YUV422;
+ for (i = 0; i < NBUF; i++) x->x_vmmap[i].format = x->x_v4l_palette;
+ if (ioctl(x->x_tvfd, VIDIOCMCAPTURE, &x->x_vmmap[x->x_frame]) < 0)
+ {
+ if (errno == EAGAIN)
+ post("pdp_v4l: can't sync (no video source?)");
+ }
+ else{
+ post("pdp_v4l: using VIDEO_PALETTE_YUV422");
+ goto capture_ok;
+ }
+
+
+ test:
+
+ //try rgb packed format
+ x->x_v4l_palette = VIDEO_PALETTE_RGB24;
+ for (i = 0; i < NBUF; i++) x->x_vmmap[i].format = x->x_v4l_palette;
+ if (ioctl(x->x_tvfd, VIDIOCMCAPTURE, &x->x_vmmap[x->x_frame]) < 0)
+ {
+ if (errno == EAGAIN)
+ post("pdp_v4l: can't sync (no video source?)");
+ }
+ else{
+ post("pdp_v4l: using VIDEO_PALETTE_RGB24");
+ goto capture_ok;
+ }
+
+
+ // none of the formats are supported
+ perror("pdp_v4l: VIDIOCMCAPTURE: format not supported");
+ goto closit;
+
+
+ capture_ok:
+
+ post("pdp_v4l: frame %d %d, format %d, width %d, height %d",
+ x->x_frame, x->x_vmmap[x->x_frame].frame, x->x_vmmap[x->x_frame].format,
+ x->x_vmmap[x->x_frame].width, x->x_vmmap[x->x_frame].height);
+
+ x->x_width = width;
+ x->x_height = height;
+
+ post("pdp_v4l: Opened video connection (%dx%d)",x->x_width,x->x_height);
+
+
+ /* do some pwc specific inits */
+ pdp_v4l_pwc_init(x);
+
+
+ x->x_initialized = true;
+
+ /* create thread */
+ x->x_continue_thread = 1;
+ x->x_frame_ready = 0;
+ pthread_create(&x->x_thread_id, 0, pdp_v4l_thread, x);
+
+ return;
+ closit:
+ pdp_v4l_close_error(x);
+
+}
+
+static void pdp_v4l_open_manual(t_pdp_v4l *x, t_symbol *name)
+{
+ x->x_open_retry = PDP_XV_RETRIES;
+ pdp_v4l_open(x, name);
+}
+
+
+static void pdp_v4l_channel(t_pdp_v4l *x, t_float f)
+{
+ int channel = (float)f;
+
+ if (x->x_initialized){
+ pdp_v4l_close(x);
+ x->x_channel = channel;
+ pdp_v4l_open(x, x->x_device);
+ }
+ else
+ x->x_channel = channel;
+}
+
+
+static void pdp_v4l_freq(t_pdp_v4l *x, t_float f)
+{
+ int freq = (int)f;
+
+ x->x_freq = freq;
+ if (x->x_freq > 0){
+ if (ioctl(x->x_tvfd, VIDIOCSFREQ, &x->x_freq) < 0)
+ perror ("couldn't set frequency :");
+ else {post("pdp_v4l: tuner frequency: %f MHz", f / 16.0f);}
+ }
+
+}
+
+static void pdp_v4l_freqMHz(t_pdp_v4l *x, t_float f)
+{
+ pdp_v4l_freq(x, f*16.0f);
+}
+
+
+static void pdp_v4l_bang(t_pdp_v4l *x)
+{
+
+ /* if initialized, grab a frame and output it */
+
+ unsigned int w,h,nbpixels,packet_size,plane1,plane2;
+ unsigned char *newimage;
+ int object,length,pos,i,encoding;
+ t_pdp* header;
+ short int * data;
+
+
+ static short int gain[4] = {0x7fff, 0x7fff, 0x7fff, 0x7fff};
+
+ if (!(x->x_initialized)){
+ post("pdp_v4l: no device opened");
+
+ if (x->x_auto_open){
+ post("pdp_v4l: attempting auto open");
+ pdp_v4l_open(x, x->x_device);
+ if (!(x->x_initialized)){
+ post("pdp_v4l: auto open failed");
+ return;
+ }
+ }
+
+ else return;
+ }
+
+
+ /* do nothing if there is no frame ready */
+ if((!x->x_frame_ready) && (x->x_only_new_frames)) return;
+ x->x_frame_ready = 0;
+
+ /* get the address of the "other" frame */
+ newimage = x->x_videobuf + x->x_vmbuf.offsets[x->x_last_frame];
+
+ /* create new packet */
+ w = x->x_width;
+ h = x->x_height;
+
+ nbpixels = w * h;
+
+/*
+ switch(x->x_pdp_image_type){
+ case PDP_IMAGE_GREY:
+ packet_size = nbpixels << 1;
+ break;
+ case PDP_IMAGE_YV12:
+ packet_size = (nbpixels + (nbpixels >> 1)) << 1;
+ break;
+ default:
+ packet_size = 0;
+ post("pdp_v4l: internal error");
+ }
+*/
+
+ packet_size = (nbpixels + (nbpixels >> 1)) << 1;
+
+
+ plane1 = nbpixels;
+ plane2 = nbpixels + (nbpixels>>2);
+
+ object = pdp_packet_new(PDP_IMAGE, packet_size);
+ header = pdp_packet_header(object);
+ data = (short int *) pdp_packet_data(object);
+
+ //header->info.image.encoding = x->x_pdp_image_type;
+ header->info.image.encoding = PDP_IMAGE_YV12;
+ header->info.image.width = w;
+ header->info.image.height = h;
+
+ /* read from the "other" frame */
+ newimage = x->x_videobuf + x->x_vmbuf.offsets[x->x_frame ^ 0x1];
+
+
+ /* convert data to pdp packet */
+
+ switch(x->x_v4l_palette){
+ case VIDEO_PALETTE_YUV420P:
+ pdp_llconv(newimage, RIF_YUV__P411_U8, data, RIF_YVU__P411_S16, w, h);
+ break;
+
+ case VIDEO_PALETTE_RGB24:
+ pdp_llconv(newimage, RIF_RGB__P____U8, data, RIF_YVU__P411_S16, w, h);
+ break;
+
+ case VIDEO_PALETTE_YUV422:
+ pdp_llconv(newimage, RIF_YUYV_P____U8, data, RIF_YVU__P411_S16, w, h);
+ break;
+
+
+ default:
+ post("pdp_v4l: unsupported palette");
+ break;
+ }
+
+/*
+ if (PDP_IMAGE_YV12 == x->x_pdp_image_type){
+ pixel_unpack_u8s16_y(&newimage[0], data, nbpixels>>3, x->x_state_data->gain);
+ pixel_unpack_u8s16_uv(&newimage[plane1], &data[plane2], nbpixels>>5, x->x_state_data->gain);
+ pixel_unpack_u8s16_uv(&newimage[plane2], &data[plane1], nbpixels>>5, x->x_state_data->gain);
+ }
+*/
+ //x->x_v4l_palette = VIDEO_PALETTE_YUV420P;
+ //x->x_v4l_palette = VIDEO_PALETTE_RGB24;
+
+/*
+
+ else if(PDP_IMAGE_GREY == x->x_pdp_image_type){
+ pixel_unpack_u8s16_y(&newimage[0], data, nbpixels>>3, x->x_state_data->gain);
+ }
+*/
+ //post("pdp_v4l: mark unused %d", object);
+
+ pdp_packet_mark_unused(object);
+ outlet_pdp(x->x_outlet0, object);
+
+
+}
+
+
+static void pdp_v4l_dim(t_pdp_v4l *x, t_floatarg xx, t_floatarg yy)
+{
+ unsigned int w,h;
+
+ xx = (xx < 0.0f) ? 0.0f : xx;
+ yy = (yy < 0.0f) ? 0.0f : yy;
+
+ w = (unsigned int)xx;
+ h = (unsigned int)yy;
+
+
+ if (x->x_initialized){
+ pdp_v4l_close(x);
+ x->x_width = w;
+ x->x_height = h;
+ pdp_v4l_open(x, x->x_device);
+
+ }
+ else{
+ x->x_width = w;
+ x->x_height = h;
+ }
+}
+
+
+static void pdp_v4l_free(t_pdp_v4l *x)
+{
+ pdp_v4l_close(x);
+}
+
+t_class *pdp_v4l_class;
+
+
+
+void *pdp_v4l_new(void)
+{
+ t_pdp_v4l *x = (t_pdp_v4l *)pd_new(pdp_v4l_class);
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_initialized = false;
+
+
+ x->x_tvfd = -1;
+ x->x_frame = 0;
+ x->x_last_frame = 0;
+
+ x->x_framerate = 27;
+
+ x->x_auto_open = true;
+ x->x_device = gensym("/dev/video0");
+
+ x->x_continue_thread = 0;
+ x->x_only_new_frames = 1;
+
+ x->x_width = 320;
+ x->x_height = 240;
+
+// pdp_v4l_type(x, gensym("yv12"));
+
+
+ x->x_open_retry = PDP_XV_RETRIES;
+
+ x->x_channel = 0;
+ x->x_freq = -1; //don't set freq by default
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_v4l_setup(void)
+{
+
+
+ pdp_v4l_class = class_new(gensym("pdp_v4l"), (t_newmethod)pdp_v4l_new,
+ (t_method)pdp_v4l_free, sizeof(t_pdp_v4l), 0, A_NULL);
+
+
+ class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_bang, gensym("bang"), A_NULL);
+ class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_close_manual, gensym("close"), A_NULL);
+ class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_open_manual, gensym("open"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_channel, gensym("channel"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_freq, gensym("freq"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_freqMHz, gensym("freqMHz"), A_FLOAT, A_NULL);
+
+
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_xv.c b/modules/pdp_xv.c
new file mode 100644
index 0000000..c859a40
--- /dev/null
+++ b/modules/pdp_xv.c
@@ -0,0 +1,534 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+
+pdp xvideo output
+
+*/
+
+
+// x stuff
+#include <X11/Xlib.h>
+#include <X11/extensions/Xv.h>
+#include <X11/extensions/Xvlib.h>
+
+// image formats for communication with the X Server
+#define FOURCC_YV12 0x32315659 /* YV12 YUV420P */
+#define FOURCC_YUV2 0x32595559 /* YUV2 YUV422 */
+#define FOURCC_I420 0x30323449 /* I420 Intel Indeo 4 */
+
+// pdp stuff
+#include "pdp.h"
+#include "pdp_llconv.h"
+
+
+/* initial image dimensions */
+#define PDP_XV_W 320
+#define PDP_XV_H 240
+
+#define PDP_XV_AUTOCREATE_RETRY 10
+
+
+typedef struct pdp_xv_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ int x_packet0;
+ int x_queue_id;
+ t_symbol *x_display;
+
+ Display *x_dpy;
+ int x_screen;
+ Window x_win;
+ GC x_gc;
+
+ int x_xv_format;
+ int x_xv_port;
+
+ int x_winwidth;
+ int x_winheight;
+
+ XvImage *x_xvi;
+ unsigned char *x_data;
+ unsigned int x_width;
+ unsigned int x_height;
+ int x_last_encoding;
+
+ int x_initialized;
+ int x_autocreate;
+
+ float x_cursor;
+
+
+} t_pdp_xv;
+
+
+static int xv_init(t_pdp_xv *x)
+{
+ unsigned int ver, rel, req, ev, err, i, j;
+ unsigned int adaptors;
+ int formats;
+ XvAdaptorInfo *ai;
+
+ if (Success != XvQueryExtension(x->x_dpy,&ver,&rel,&req,&ev,&err)) return 0;
+
+ /* find + lock port */
+ if (Success != XvQueryAdaptors(x->x_dpy,DefaultRootWindow(x->x_dpy),&adaptors,&ai))
+ return 0;
+ for (i = 0; i < adaptors; i++) {
+ if ((ai[i].type & XvInputMask) && (ai[i].type & XvImageMask)) {
+ for (j=0; j < ai[i].num_ports; j++){
+ if (Success != XvGrabPort(x->x_dpy,ai[i].base_id+j,CurrentTime)) {
+ //fprintf(stderr,"INFO: Xvideo port %ld on adapter %d: is busy, skipping\n",ai[i].base_id+j, i);
+ }
+ else {
+ x->x_xv_port = ai[i].base_id + j;
+ goto breakout;
+ }
+ }
+ }
+ }
+
+
+ breakout:
+
+ XFree(ai);
+ if (0 == x->x_xv_port) return 0;
+ post("pdp_xv: grabbed port %d on adaptor %d", x->x_xv_port, i);
+ return 1;
+}
+
+
+void pdp_xv_create_xvimage(t_pdp_xv *x)
+{
+
+ long size = (x->x_width * x->x_height + (((x->x_width>>1)*(x->x_height>>1))<<1));
+ x->x_data = (unsigned char *)malloc(size);
+ x->x_xvi = XvCreateImage(x->x_dpy, x->x_xv_port, x->x_xv_format, (char *)x->x_data, x->x_width, x->x_height);
+ x->x_last_encoding = -1;
+ if (!(x->x_xvi) || (!x->x_data)) post ("ERROR CREATING XVIMAGE");
+
+}
+
+void pdp_xv_destroy_xvimage(t_pdp_xv *x)
+{
+ if(x->x_data) free(x->x_data);
+ if (x->x_xvi) XFree(x->x_xvi);
+ x->x_xvi = 0;
+ x->x_data = 0;
+}
+
+
+static void pdp_xv_cursor(t_pdp_xv *x, t_floatarg f)
+{
+ if (!x->x_initialized) return;
+
+ if (f == 0) {
+ static char data[1] = {0};
+
+ Cursor cursor;
+ Pixmap blank;
+ XColor dummy;
+
+ blank = XCreateBitmapFromData(x->x_dpy, x->x_win, data, 1, 1);
+ cursor = XCreatePixmapCursor(x->x_dpy, blank, blank, &dummy,
+ &dummy, 0, 0);
+ XFreePixmap(x->x_dpy, blank);
+ XDefineCursor(x->x_dpy, x->x_win,cursor);
+ }
+ else
+ XUndefineCursor(x->x_dpy, x->x_win);
+
+ x->x_cursor = f;
+}
+
+
+static void pdp_xv_destroy(t_pdp_xv* x)
+{
+ XEvent e;
+
+ if (x->x_initialized){
+ XFreeGC(x->x_dpy, x->x_gc);
+ XDestroyWindow(x->x_dpy, x->x_win);
+ while(XPending(x->x_dpy)) XNextEvent(x->x_dpy, &e);
+ XvUngrabPort(x->x_dpy, x->x_xv_port, CurrentTime);
+ pdp_xv_destroy_xvimage(x);
+ XCloseDisplay(x->x_dpy);
+ x->x_initialized = false;
+
+ }
+
+}
+
+static void pdp_xv_resize(t_pdp_xv* x, t_floatarg width, t_floatarg height)
+{
+ if (x->x_initialized && (width>0) && (height>0)){
+ XResizeWindow(x->x_dpy, x->x_win, (unsigned int)width, (unsigned int)height);
+ XFlush(x->x_dpy);
+ }
+}
+
+static void pdp_xv_create(t_pdp_xv* x)
+{
+ unsigned int *uintdata = (unsigned int *)(x->x_data);
+ XEvent e;
+ unsigned int i;
+
+ if( x->x_initialized ){
+ //post("pdp_xv: window already created");
+ return;
+ }
+
+ if (NULL == (x->x_dpy = XOpenDisplay(x->x_display->s_name))){
+ post("pdp_xv: cant open display %s\n",x->x_display->s_name);
+ x->x_initialized = false;
+ return;
+ }
+
+ /* init xvideo */
+ if (xv_init(x)){
+
+ pdp_xv_create_xvimage(x);
+
+ }
+
+ else {
+ /* clean up mess */
+ post("pdp_xv: ERROR: no xv port available. closing display.");
+ XCloseDisplay(x->x_dpy);
+ x->x_initialized = false;
+ return;
+ }
+
+
+ /* create a window */
+ x->x_screen = DefaultScreen(x->x_dpy);
+
+
+ x->x_win = XCreateSimpleWindow(
+ x->x_dpy,
+ RootWindow(x->x_dpy, x->x_screen), 0, 0, x->x_winwidth, x->x_winheight, 0,
+ BlackPixel(x->x_dpy, x->x_screen),
+ BlackPixel(x->x_dpy, x->x_screen));
+
+ if(!(x->x_win)){
+ /* clean up mess */
+ post("pdp_xv: could not create window\n");
+ post("pdp_xv: unlocking xv port");
+ XvUngrabPort(x->x_dpy, x->x_xv_port, CurrentTime);
+ post("pdp_xv: freeing xvimage");
+ pdp_xv_destroy_xvimage(x);
+ post("pdp_xv: closing display");
+ XCloseDisplay(x->x_dpy);
+ x->x_initialized = false;
+ return;
+ }
+
+ XSelectInput(x->x_dpy, x->x_win, StructureNotifyMask);
+
+ XMapWindow(x->x_dpy, x->x_win);
+
+ x->x_gc = XCreateGC(x->x_dpy, x->x_win, 0, 0);
+
+ for(;;){
+ XNextEvent(x->x_dpy, &e);
+ if (e.type == MapNotify) break;
+ }
+
+
+ x->x_initialized = true;
+ pdp_xv_cursor(x, x->x_cursor);
+
+}
+
+void pdp_xv_copy_xvimage(t_pdp_xv *x, t_image *image, short int* data)
+{
+ unsigned int width = image->width;
+ unsigned int height = image->height;
+ int encoding = image->encoding;
+ unsigned int* uintdata;
+ int i;
+
+
+ /* 8bit y fulscale and 8bit u,v 2x2 subsampled */
+ //static short int gain[4] = {0x0100, 0x0100, 0x0100, 0x0100};
+ long size = (width * height + (((width>>1)*(height>>1))<<1));
+ int nbpixels = width * height;
+
+ /* check if xvimage needs to be recreated */
+ if ((width != x->x_width) || (height != x->x_height)){
+ //post("pdp_xv: replace image");
+ x->x_width = width;
+ x->x_height = height;
+ pdp_xv_destroy_xvimage(x);
+ pdp_xv_create_xvimage(x);
+ }
+
+
+ /* data holds a 16bit version of a the xvimage, so it needs to be converted */
+
+
+
+ if (data) {
+ /* convert 16bit -> 8bit */
+ if(PDP_IMAGE_YV12 == encoding){
+ pdp_llconv(data,RIF_YVU__P411_S16, x->x_data, RIF_YVU__P411_U8, x->x_width, x->x_height);
+ x->x_last_encoding = PDP_IMAGE_YV12;
+ }
+ if(PDP_IMAGE_GREY == encoding){
+ pdp_llconv(data,RIF_GREY______S16, x->x_data, RIF_GREY______U8, x->x_width, x->x_height);
+ if (PDP_IMAGE_GREY != x->x_last_encoding) {
+ post("pdp_xv: switching to greyscale");
+ /* clear u&v planes if necessary */
+ uintdata = (unsigned int *)&x->x_data[nbpixels];
+ for(i=0; i < nbpixels>>3; i++) uintdata[i]=0x80808080;
+ }
+ x->x_last_encoding = PDP_IMAGE_GREY;
+
+ }
+ }
+ else bzero(x->x_data, size);
+
+
+
+}
+
+static int pdp_xv_try_autocreate(t_pdp_xv *x)
+{
+
+ if (x->x_autocreate){
+ post("pdp_xv: autocreate window");
+ pdp_xv_create(x);
+ if (!(x->x_initialized)){
+ x->x_autocreate--;
+ if (!x->x_autocreate){
+ post ("pdp_xv: autocreate failed %d times: disabled", PDP_XV_AUTOCREATE_RETRY);
+ post ("pdp_xv: send [autocreate 1] message to re-enable");
+ return 0;
+ }
+ }
+ else return 1;
+
+ }
+ return 0;
+}
+
+static void pdp_xv_bang(t_pdp_xv *x);
+
+static void pdp_xv_process(t_pdp_xv *x)
+{
+ t_pdp *header = pdp_packet_header(x->x_packet0);
+ void *data = pdp_packet_data (x->x_packet0);
+
+
+ if (-1 != x->x_queue_id) return;
+
+ /* check if window is initialized */
+ if (!(x->x_initialized)){
+ if (!pdp_xv_try_autocreate(x)) return;
+ }
+
+ /* check data packet */
+ if (!(header)) {
+ post("pdp_xv: invalid packet header");
+ return;
+ }
+ if (PDP_IMAGE != header->type) {
+ post("pdp_xv: packet is not a PDP_IMAGE");
+ return;
+ }
+ if ((PDP_IMAGE_YV12 != header->info.image.encoding)
+ && (PDP_IMAGE_GREY != header->info.image.encoding)) {
+ post("pdp_xv: packet is not a PDP_IMAGE_YV12/GREY");
+ return;
+ }
+
+ /* copy the packet to the xvimage */
+ pdp_xv_copy_xvimage(x, &header->info.image, (short int *)data);
+
+
+ /* display the new image */
+ pdp_xv_bang(x);
+
+
+}
+
+
+static void pdp_xv_random(t_pdp_xv *x)
+{
+ unsigned int i;
+ long *intdata = (long *)(x->x_data);
+ for(i=0; i<x->x_width*x->x_height/4; i++) intdata[i]=random();
+}
+
+/* redisplays image */
+static void pdp_xv_bang_thread(t_pdp_xv *x)
+{
+
+ XEvent e;
+ unsigned int i;
+
+ //while (XEventsQueued(x->x_dpy, QueuedAlready)){
+ while (XPending(x->x_dpy)){
+ //post("pdp_xv: waiting for event");
+ XNextEvent(x->x_dpy, &e);
+ //post("pdp_xv: XEvent %d", e.type);
+ if(e.type == ConfigureNotify){
+ XConfigureEvent *ce = (XConfigureEvent *)&e;
+ x->x_winwidth = ce->width;
+ x->x_winheight = ce->height;
+
+ }
+ //post("pdp_xv: received event");
+
+ }
+
+ XvPutImage(x->x_dpy,x->x_xv_port,x->x_win,x->x_gc,x->x_xvi,
+ 0,0,x->x_width,x->x_height, 0,0,x->x_winwidth,x->x_winheight);
+ XFlush(x->x_dpy);
+}
+
+static void pdp_xv_bang_callback(t_pdp_xv *x)
+{
+ /* release the packet if there is one */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = -1;}
+
+static void pdp_xv_bang(t_pdp_xv *x)
+{
+
+
+ /* if previous queued method returned
+ schedule a new one, else ignore */
+ if (-1 == x->x_queue_id) {
+ pdp_queue_add(x, pdp_xv_bang_thread, pdp_xv_bang_callback, &x->x_queue_id);
+ }
+
+}
+
+static void pdp_xv_input_0(t_pdp_xv *x, t_symbol *s, t_floatarg f)
+{
+
+ if (s == gensym("register_ro")) pdp_packet_copy_ro_or_drop(&x->x_packet0, (int)f);
+ if (s == gensym("process")) pdp_xv_process(x);
+
+}
+
+
+static void pdp_xv_autocreate(t_pdp_xv *x, t_floatarg f)
+{
+ if (f != 0.0f) x->x_autocreate = PDP_XV_AUTOCREATE_RETRY;
+ else x->x_autocreate = 0;
+}
+
+static void pdp_xv_display(t_pdp_xv *x, t_symbol *s)
+{
+ pdp_queue_finish(x->x_queue_id);
+ x->x_queue_id = -1;
+ x->x_display = s;
+ if (x->x_initialized){
+ pdp_xv_destroy(x);
+ pdp_xv_create(x);
+ }
+}
+
+
+
+static void pdp_xv_free(t_pdp_xv *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+
+ pdp_xv_destroy(x);
+ pdp_packet_mark_unused(x->x_packet0);
+}
+
+t_class *pdp_xv_class;
+
+
+
+void *pdp_xv_new(void)
+{
+ t_pdp_xv *x = (t_pdp_xv *)pd_new(pdp_xv_class);
+
+
+ x->x_packet0 = -1;
+ x->x_queue_id = -1;
+ x->x_display = gensym(":0");
+
+
+ x->x_dpy = 0;
+ x->x_screen = -1;
+
+ x->x_xv_format = FOURCC_YV12;
+ x->x_xv_port = 0;
+
+ x->x_winwidth = PDP_XV_W;
+ x->x_winheight = PDP_XV_H;
+
+ x->x_width = PDP_XV_W;
+ x->x_height = PDP_XV_H;
+
+ x->x_data = 0;
+ x->x_xvi = 0;
+
+ x->x_initialized = 0;
+ pdp_xv_autocreate(x,1);
+ x->x_last_encoding = -1;
+
+ x->x_cursor = 0;
+
+ return (void *)x;
+}
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_xv_setup(void)
+{
+
+
+ pdp_xv_class = class_new(gensym("pdp_xv"), (t_newmethod)pdp_xv_new,
+ (t_method)pdp_xv_free, sizeof(t_pdp_xv), 0, A_NULL);
+
+
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_bang, gensym("bang"), A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_random, gensym("random"), A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_create, gensym("create"), A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_autocreate, gensym("autocreate"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_destroy, gensym("destroy"), A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_destroy, gensym("close"), A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_resize, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_resize, gensym("size"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_display, gensym("display"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_xv_class, (t_method)pdp_xv_cursor, gensym("cursor"), A_FLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_zoom.c b/modules/pdp_zoom.c
new file mode 100644
index 0000000..33207ce
--- /dev/null
+++ b/modules/pdp_zoom.c
@@ -0,0 +1,264 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+#include "pdp_resample.h"
+
+
+
+typedef struct pdp_zoom_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+
+ int x_packet0;
+ int x_packet1;
+ int x_dropped;
+ int x_queue_id;
+
+ float x_zoom_x;
+ float x_zoom_y;
+
+ float x_center_x;
+ float x_center_y;
+
+ int x_quality; //not used
+
+
+} t_pdp_zoom;
+
+
+static void pdp_zoom_process_yv12(t_pdp_zoom *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ short int *src_image = (short int *)data0;
+ short int *dst_image = (short int *)data1;
+
+ unsigned int size = w * h;
+ unsigned int voffset = size;
+ unsigned int uoffset = size + (size>>2);
+
+
+ pdp_resample_zoom_tiled_bilin(src_image, dst_image, w, h, x->x_zoom_x, x->x_zoom_y, x->x_center_x, x->x_center_y);
+ pdp_resample_zoom_tiled_bilin(src_image+voffset, dst_image+voffset, w>>1, h>>1, x->x_zoom_x, x->x_zoom_y, x->x_center_x, x->x_center_y);
+ pdp_resample_zoom_tiled_bilin(src_image+uoffset, dst_image+uoffset, w>>1, h>>1, x->x_zoom_x, x->x_zoom_y, x->x_center_x, x->x_center_y);
+
+ return;
+}
+
+static void pdp_zoom_process_grey(t_pdp_zoom *x)
+{
+
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ void *data0 = pdp_packet_data (x->x_packet0);
+ void *data1 = pdp_packet_data (x->x_packet1);
+
+ unsigned int w = header0->info.image.width;
+ unsigned int h = header0->info.image.height;
+
+ short int *src_image = (short int *)data0;
+ short int *dst_image = (short int *)data1;
+
+ pdp_resample_zoom_tiled_bilin(src_image, dst_image, w, h, x->x_zoom_x, x->x_zoom_y, x->x_center_x, x->x_center_y);
+
+ return;
+
+}
+
+static void pdp_zoom_sendpacket(t_pdp_zoom *x)
+{
+ /* delete source packet */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = -1;
+
+ /* unregister and propagate if valid dest packet */
+ pdp_pass_if_valid(x->x_outlet0, &x->x_packet1);
+}
+
+static void pdp_zoom_process(t_pdp_zoom *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+
+ /* check data packets */
+
+ if ((header0) && (PDP_IMAGE == header0->type)){
+
+
+ /* type hub */
+ switch(header0->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
+ pdp_queue_add(x, pdp_zoom_process_yv12, pdp_zoom_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
+ pdp_queue_add(x, pdp_zoom_process_grey, pdp_zoom_sendpacket, &x->x_queue_id);
+ break;
+
+ default:
+ break;
+ /* don't know the type, so dont process */
+
+ }
+ }
+
+}
+
+
+
+
+static void pdp_zoom_input_0(t_pdp_zoom *x, t_symbol *s, t_floatarg f)
+{
+
+ int p = (int)f;
+ int passes, i;
+
+ if (s== gensym("register_rw")) x->x_dropped = pdp_packet_copy_ro_or_drop(&x->x_packet0, p);
+
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped)){
+
+ /* add the process method and callback to the process queue */
+ pdp_zoom_process(x);
+
+ }
+
+}
+
+
+
+
+static void pdp_zoom_x(t_pdp_zoom *x, t_floatarg f)
+{
+ x->x_zoom_x = f;
+}
+
+static void pdp_zoom_y(t_pdp_zoom *x, t_floatarg f)
+{
+ x->x_zoom_y = f;
+}
+
+static void pdp_zoom(t_pdp_zoom *x, t_floatarg f)
+{
+ pdp_zoom_x(x, f);
+ pdp_zoom_y(x, f);
+}
+
+static void pdp_zoom_center_x(t_pdp_zoom *x, t_floatarg f)
+{
+ x->x_center_x = (f + 0.5f);
+}
+
+static void pdp_zoom_center_y(t_pdp_zoom *x, t_floatarg f)
+{
+ x->x_center_y = (f + 0.5f);
+}
+static void pdp_zoom_center(t_pdp_zoom *x, t_floatarg fx, t_floatarg fy)
+{
+ pdp_zoom_center_x(x, fx);
+ pdp_zoom_center_y(x, fy);
+}
+
+static void pdp_zoom_quality(t_pdp_zoom *x, t_floatarg f)
+{
+ if (f==0) x->x_quality = 0;
+ if (f==1) x->x_quality = 1;
+}
+
+
+t_class *pdp_zoom_class;
+
+
+
+void pdp_zoom_free(t_pdp_zoom *x)
+{
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+}
+
+void *pdp_zoom_new(t_floatarg fw, t_floatarg zoom)
+{
+ t_pdp_zoom *x = (t_pdp_zoom *)pd_new(pdp_zoom_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("zoom"));
+
+
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_queue_id = -1;
+
+ pdp_zoom_quality(x, 1);
+ pdp_zoom_center_x(x, 0);
+ pdp_zoom_center_y(x, 0);
+
+ if (zoom = 0.0f) zoom = 1.0f;
+ pdp_zoom(x, zoom);
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_zoom_setup(void)
+{
+
+
+ pdp_zoom_class = class_new(gensym("pdp_zoom"), (t_newmethod)pdp_zoom_new,
+ (t_method)pdp_zoom_free, sizeof(t_pdp_zoom), 0, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+
+ class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_quality, gensym("quality"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_center_x, gensym("centerx"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_center_y, gensym("centery"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_center, gensym("center"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_x, gensym("zoomx"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_y, gensym("zoomy"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_zoom_class, (t_method)pdp_zoom, gensym("zoom"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_zoom_class, (t_method)pdp_zoom_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/scaf/COPYING b/scaf/COPYING
new file mode 100644
index 0000000..7f87ef8
--- /dev/null
+++ b/scaf/COPYING
@@ -0,0 +1,340 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR PDP.LICENSE, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/scaf/Makefile b/scaf/Makefile
new file mode 100644
index 0000000..2ac26a5
--- /dev/null
+++ b/scaf/Makefile
@@ -0,0 +1,22 @@
+include Makefile.config
+
+all: pdp_scaf.pd_linux
+
+pdp_scaf_all:
+ make -C include
+ make -C system
+ make -C modules
+ make -C pdp
+
+clean:
+ rm -f *~
+ rm -f pdp_scaf.pd_linux
+ make -C include clean
+ make -C system clean
+ make -C modules clean
+ make -C pdp clean
+
+
+pdp_scaf.pd_linux: pdp_scaf_all
+ rm -f pdp_scaf.pd_linux
+ gcc -export_dynamic -shared -o pdp_scaf.pd_linux pdp/*.o system/scaf_feeder.o $(PDP_CA_LIBS)
diff --git a/scaf/Makefile.config b/scaf/Makefile.config
new file mode 100644
index 0000000..7106a9f
--- /dev/null
+++ b/scaf/Makefile.config
@@ -0,0 +1,34 @@
+# pd's directory
+PD_DIR = /home/tom/pd/distro/pd
+PDP_DIR = /home/tom/pd/packet
+
+#PD_DIR = /usr/local/pd
+#PDP_DIR = /usr/local/pdp
+
+SCAF_DIR = $(PDP_DIR)/scaf
+
+
+
+
+# build flags
+
+PDP_CA_INCLUDE = -I$(PD_DIR)/src -I$(PDP_DIR)/include -I$(SCAF_DIR)/include
+PDP_CA_LIBS = -ldl
+PDP_CA_AFLAGS =
+#--gstabs
+PDP_CA_CFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer -ffast-math \
+ -Wall -W -Wstrict-prototypes -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch -g
+# -Wshadow
+
+# compiler and assembler
+CC = gcc-3.2
+#CC = gcc
+AS = as
+
+# build rules
+
+.c.o:
+ $(CC) $(PDP_CA_CFLAGS) $(PDP_CA_INCLUDE) -o $*.o -c $*.c
+.s.o:
+ $(AS) -o $*.o $*.s $(PDP_CA_AFLAGS)
diff --git a/scaf/README b/scaf/README
new file mode 100644
index 0000000..60ee4dd
--- /dev/null
+++ b/scaf/README
@@ -0,0 +1,88 @@
+PDP_SCAF for pdp v0.7
+Cellular Automata modules for PDP
+
+Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+The GNU Public Licence can be found in the file COPYING
+
+
+------------------------------------------------------------------
+
+This is a pdp extension lib that contains modules for cellular
+automata built on a (very) minimal forth-like virtual system
+(scaf - simple cellular automaton forth) to define update rules. a
+compiler is included to produce scafo object code that can be
+dynamically loaded into the pdp_ca module. so it is possible to
+add/change rules without restarting pd (note however you need to close
+all lib files before the dynamic loader reloads the lib). see
+scaf/README for details.
+
+
+pdp_ca2image and pdp_image2ca are included for conversion between
+CA packets and image packets. (pdp_ca2image produces greyscale
+images)
+
+Have a look at the patches in test/ for some crude docs. The file
+README.scaf contains some more info on the internals.
+
+
+Requirements:
+
+* pd
+* pdp
+* linux
+* perl for the forth compiler
+* an intel/amd processor that supports MMX
+
+
+Building:
+
+Edit Makefile.config to reflect your system settings. For now this
+should be the pd dir, the pdp dir and the pdp_scaf dir.
+
+type "make" in the top directory. Remember to type "make clean all"
+after editing Makefile.config
+
+
+Using:
+
+add "-lib <SCAF_DIR>/pdp_scaf" to the pd command line after the
+"-lib <PDP_DIR>/pdp" part.
+
+
+
+launch pd with the options -lib $PDP_DIR/pdp -path $PDP_DIR/abstractions
+
+Directory structure:
+
+include/ header files
+pdp/ pdp external code
+system/ forth system code
+test/ some test patches (cryptic doc)
+modules/ ca rule libraries
+
+
+
+Please let me know if you discover a bug or think something doesn't work
+right. Code, documentation or example patches are more than welcome of
+course.
+
+Have Fun,
+
+Tom
+
+last modified: 2003/01/12
diff --git a/scaf/README.scaf b/scaf/README.scaf
new file mode 100644
index 0000000..0035899
--- /dev/null
+++ b/scaf/README.scaf
@@ -0,0 +1,98 @@
+SCAF - simple cellular automaton forth
+
+scaf is a virtual machine / forth environment for binary arithmic
+tailored to 2D 1 cell neighbourhood cellular automata.
+
+scaf is a compiled language. programs run inside a "feeder"
+(sort of operating system if you want)
+
+the feeder is responsable for loading/storing CA cells
+from/to memory. data in memory is organized as a scanline
+encoded toroidial bitplane (lsb = left). to simplify the feeder
+and the stack machine, the top left corner of the rectangular grid
+of pixels will shift down every processing step. this enables
+to keep a cell neighbourhood in a couple of registers.
+
+the stack machine has the following architecture:
+CA stack: (%esi), TOS: %mm0 (32x2 cells. lsb = top left)
+CA horizon: (%edi) (64x4 cells. (%edi) = top row. lsb = left)
+
+scratch register: %mm1, %mm2
+bitmask register: %mm3 = 0xffffffffffffffff
+
+4 bit counter: %mm4-%mm7
+
+the stack size / organization is not known to the stack machine.
+it can be thought of as operating on a 3x3 cell neightbourhood.
+the only purpose of the forth program is to determine the CA local update rule.
+
+the machine is supposed to be very minimal. no looping control.
+no adressing modes. no conditional code. so recursion is not allowed
+(no way to stop it) there are 9 words to load the cell neigbourhood
+on the stack. the rest is just logic and stack manips.
+
+the counter can be used for counting neighbourhood cells, like in the
+game of life. the zero test and sign bit can be used for comparisons.
+there are kernel words for loading constants into the counter register,
+and for communication between stack and register.
+
+the horizon is limited to 3x3, however it can be easily extended to
+32x3. extending it further than that would require a redesign of the
+forth + feeder.
+
+
+HOW TO CREATE NEW CA RULES
+
+edit scaf/modules/carules.scaf or create your own source lib and add
+the name to the scaf/modules/Makefile. type make in scaf/modules
+to compile. if you get error messages from the assembler saying things
+like
+
+ Error: no such instruction: `xxx'
+
+ or
+ Error: invalid character '_' in mnemonic
+
+this means there are undefined words in your source file. since not
+all characters are allowed in an asm file, the offending characters are
+converted to _SOMETHINGELSE_
+
+if you are stuck somewhere, just look at the output of scaf.pl on
+your .scaf file to determine where the problem is.
+
+words that can be accessed from inside pdp_ca have to start with the
+prefix rule_ and have to leave a single item on the data stack (the return
+value) other rules can have all the stack effect you want, but for safety
+reasons they can't be accessed from within pdp_ca.
+
+
+
+FORTH SYSTEM CODE
+
+the forth system is made up of the following files:
+
+kernel.scaf: a collection of forth kernel words
+scafmacro.s: a set of asm macro definitions used in kernel.scaf
+optim.rules: some substitution rules to eliminate redundant
+ stack manipulations
+
+scaf.pl: the compiler
+
+scaf.pl is run like this:
+
+scaf.pl -Isystemdir source.scaf
+
+if the -I switch is left out, the current directory is searched
+for the system files. the compiler produces an assembler source
+that includes scafmacro.s on standard output.
+
+the code it produces is relatively fast. it only uses and/or/xor
+and shift mmx instructions. it's not optimal use of silicon but
+it's pretty fast given what's possible. the feeder routine could
+be improved though.
+
+porting to another platform would require a rewrite of scafmacro.s
+the rest can be reused. if the target machine has 64 bit registers
+(or if you can emulate this one using more registers) porting is
+relatively easy. for larger registers a small change needs to
+be made to the feeder routine in pdp_ca.c
diff --git a/scaf/include/Makefile b/scaf/include/Makefile
new file mode 100644
index 0000000..1aba02c
--- /dev/null
+++ b/scaf/include/Makefile
@@ -0,0 +1,6 @@
+current:
+
+
+clean:
+ rm -f *~
+
diff --git a/scaf/include/pdp_ca.h b/scaf/include/pdp_ca.h
new file mode 100644
index 0000000..acaeea7
--- /dev/null
+++ b/scaf/include/pdp_ca.h
@@ -0,0 +1,71 @@
+/*
+ * Cellular Automata Extension Module for pdp - Main header file
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef PDP_CA_H
+#define PDP_CA_H
+
+#include "pdp.h"
+
+
+
+/* 2D CA DATA PACKET */
+typedef struct
+{
+ unsigned int encoding; /* CA data format */
+ unsigned int width; /* CA width (in 1 bit cells) */
+ unsigned int height; /* CA height (in 1 bit cells) */
+ unsigned int offset; /* bit offset of upper left corner */
+
+} t_ca;
+
+/* CA encodings */
+#define PDP_CA_STANDARD 1 /* rectangular CA */
+
+/* pdp data packet types */
+#define PDP_CA 2 /* 1bit toroidial shifted scanline encoded cellular automaton */
+
+
+/* all symbols are C-style */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+/* some utility methods for CA */
+int pdp_type_isvalid_ca(int packet);
+int pdp_type_ca2grey(int packet);
+int pdp_type_grey2ca(int packet, short int threshold);
+
+/* returns a pointer to the ca subheader given the pdp header */
+t_ca *pdp_type_ca_info(t_pdp *x);
+
+/* mmx feeder routine */
+unsigned long long scaf_feeder(void *tos, void *reg, void (*ca_rule)(void), void *env);
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //PDP_CA_H
diff --git a/scaf/modules/Makefile b/scaf/modules/Makefile
new file mode 100644
index 0000000..7bb0dc9
--- /dev/null
+++ b/scaf/modules/Makefile
@@ -0,0 +1,21 @@
+OBJ = carules.scafo
+
+SCAFDIR = ../system
+
+.SUFFIXES: .scaf
+.SUFFIXES: .scafo
+
+.scaf.o:
+ $(SCAFDIR)/scafc.pl -I$(SCAFDIR) $*.scaf | as -o $*.o
+
+.o.scafo:
+ gcc -export_dynamic -shared -o $*.scafo $*.o
+ rm $*.o
+ strip --strip-unneeded $*.scafo
+
+all: $(OBJ)
+
+clean:
+ rm -f *.scafo
+ rm -f *~
+
diff --git a/scaf/modules/carules.scaf b/scaf/modules/carules.scaf
new file mode 100644
index 0000000..32aef4a
--- /dev/null
+++ b/scaf/modules/carules.scaf
@@ -0,0 +1,117 @@
+( Pure Data Packet - ca rules library. )
+( Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> )
+( )
+( This program is free software; you can redistribute it and/or modify )
+( it under the terms of the GNU General Public License as published by )
+( the Free Software Foundation; either version 2 of the License, or )
+( [at your option] any later version. )
+( )
+( This program is distributed in the hope that it will be useful, )
+( but WITHOUT ANY WARRANTY; without even the implied warranty of )
+( MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the )
+( GNU General Public License for more details. )
+( )
+( You should have received a copy of the GNU General Public License )
+( along with this program; if not, write to the Free Software )
+( Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. )
+
+
+
+( this is the standard ca rules library )
+( a rule that is accessible from the ouside should start with "rule_" )
+( and has to return exactly one item on the stack (this is checked in pdp_ca) )
+
+
+( a word is a sequence of non whitespace characters (\S+) )
+( words are separated by whitespace (\s+) )
+( so "word ;" is not the same as "word;" )
+
+( all words between the "(" word and the ")" word are ignored )
+
+( ":" starts a definition, the next word is the name of the new word )
+( newline ends a definition )
+
+( no more than one definition per line )
+( no more than one line per definition )
+
+( ";" returns to calling word )
+( if no ";" is encountered the next defined word is executed )
+( this is to have multiple entry points )
+( multiple exit points don't make sense since there are no conditional words )
+
+
+
+: +(4) ++++ ; ( 4 bit add TOS - carry on TOS )
+: +(3) +++ ; ( 3 bit add TOS - carry on TOS )
+: +(2) ++ ; ( 2 bit add TOS - carry on TOS )
+
+: +top @-+ +(4) drop @0+ +(4) drop @++ +(4) ; ( add top row to reg - carry on TOS )
+: +mid @-0 +(4) drop @00 +(4) drop @+0 +(4) ; ( add mid row to reg - carry on TOS )
+: +bot @-- +(4) drop @0- +(4) drop @+- +(4) ; ( add bot row to reg - carry on TOS )
+: +all +top drop +mid drop +bot ; ( add all cells to reg - carry on TOS )
+
+: +mid-1 @-0 +(4) drop @+0 +(4) ; ( add mid row except center element to reg - carry on TOS )
+: +all-1 +top drop +mid-1 drop +bot ; ( add all cells expet middle one to reg - carry on TOS )
+
+
+: countall a-0 +all drop ; ( count all cells - no stack effect )
+: countall-1 a-0 +all-1 drop ; ( count all cells except middle one - no stack effect )
+
+: +topbot @0+ +(3) drop @0- +(3) ;
+: +leftright @+0 +(3) drop @-0 +(3) ;
+: +star +topbot drop +leftright ;
+: countstar a-0 +star drop ;
+
+: =2or3? @a2 not @a1 and ; ( sum equal to 2 or 3? only checks 3 bits )
+: =3? =2or3? @a0 and ; ( sum equal to 3 ? )
+: =2? =2or3? @a0 not and ; ( sum equal to 2 ? )
+: =4? @a2 @a1 not and @a0 not and ; ( sum equal to 4 ? )
+
+
+
+( some test rules )
+
+( : rule_one 1 ; )
+( : rule_zero 0 ; )
+( : rule_id @00 ; )
+
+
+: rule_shiftleft @+0 ;
+: rule_shifttop @0- ;
+: rule_shiftbot @0+ ;
+: rule_shifttopright @-- ;
+: rule_strobe @00 not ;
+
+( game of life )
+
+: rule_gameoflife countall-1 =2? @00 and =3? or ;
+
+( wolfram's rule 110)
+
+: rule_w110 @00 @+0 and not @-0 @00 @+0 or or and ;
+
+
+( some other rules )
+
+: rule_w110mod @0+ @+0 and not @-+ @0+ @++ or or and ;
+
+: rule_w110mod2 @0+ @+0 and not @-+ @0+ @+0 or or and ;
+: rule_w110mod3 @0+ @++ and not @-+ @0+ @++ or or and @-0 @00 @+0 or or and ;
+
+: rule_golmod countall-1 =3? @00 and =2? or ;
+: rule_golmod2 countall-1 =2? @0+ and =3? or ;
+: rule_golmod3 countall-1 =2? @++ and =3? or ;
+: rule_golmod4 countall-1 =2? @++ @-- or and =3? or ;
+: rule_golmod5 countall-1 =2? @++ @-- or and =3? @+- and or ;
+: rule_golmod6 countall-1 =2? @++ @-- or and =3? @+- and or @0+ or ;
+: rule_golmod7 countall-1 =2? @++ @-- or and =3? @+- and or @0+ or @00 and ;
+
+( ca's with a short settling time )
+
+: rule_block countstar =4? not =2? and @00 or ;
+: rule_noiseedges countstar =4? =3? or not =2? and @00 or @++ xor ;
+: rule_noiseplanes countstar =4? =3? or not =2? and @00 or @++ xor @-- xor ;
+
+
+( : rule_noiseplanes countstar =4? =3? or not =2? and @00 or @++ xor @-- xor ; )
+
diff --git a/scaf/pdp/Makefile b/scaf/pdp/Makefile
new file mode 100644
index 0000000..73c8892
--- /dev/null
+++ b/scaf/pdp/Makefile
@@ -0,0 +1,13 @@
+current: all_modules
+
+include ../Makefile.config
+
+OBJECTS = pdp_ca.o pdp_ca_system.o
+
+
+all_modules: $(OBJECTS)
+
+clean:
+ rm -f *~
+ rm -f *.o
+
diff --git a/scaf/pdp/pdp_ca.c b/scaf/pdp/pdp_ca.c
new file mode 100644
index 0000000..391b235
--- /dev/null
+++ b/scaf/pdp/pdp_ca.c
@@ -0,0 +1,725 @@
+/*
+ * Pure Data Packet module for cellular automata
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp_ca.h"
+#include <dlfcn.h>
+#include <stdio.h>
+
+t_class *pdp_ca_class; // a cellular automaton processor: single input - single output
+//t_class *pdp_ca2_class; // double input - single output
+t_class *pdp_ca2image_class; // converter from ca -> grey/yv12
+t_class *pdp_image2ca_class; // converter from grey/yv12 -> ca
+
+
+// *********************** CA CLASS STUFF *********************
+
+
+
+#define PDP_CA_STACKSIZE 256
+
+typedef struct pdp_ca_data_struct
+{
+ unsigned int env[2*4];
+ unsigned int reg[2*4];
+ unsigned int stack[2*PDP_CA_STACKSIZE];
+ short int random_seed[4];
+} t_pdp_ca_data;
+
+typedef struct pdp_ca_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+ int x_queue_id;
+
+ /* double buffering data packets */
+ int x_packet0;
+ int x_packet1;
+
+ /* some data on the ca_routine */
+ void (*x_ca_routine)(void);
+ void *x_ca_libhandle;
+ char *x_ca_rulenames;
+ int x_ca_nbrules;
+ char ** x_ca_rulename;
+
+ /* nb of iterations */
+ int x_iterations;
+
+
+
+ /* aligned vector data */
+ t_pdp_ca_data *x_data;
+
+ /* output packet type */
+ t_symbol *x_packet_type;
+
+} t_pdp_ca;
+
+
+
+/* process from packet0 -> packet1 */
+static void pdp_ca_process_ca(t_pdp_ca *x)
+{
+ t_pdp *header0 = pdp_packet_header(x->x_packet0);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+ unsigned int *data0 = (unsigned int *)pdp_packet_data (x->x_packet0);
+ unsigned int *data1 = (unsigned int *)pdp_packet_data (x->x_packet1);
+
+
+ int width = pdp_type_ca_info(header0)->width;
+ int height = pdp_type_ca_info(header0)->height;
+ int i,j;
+
+ /* load TOS in middle of buffer to limit the effect of stack errors */
+ unsigned int *tos = &x->x_data->stack[2*(PDP_CA_STACKSIZE/2)];
+ unsigned int *env = &x->x_data->env[0];
+ unsigned int *reg = &x->x_data->reg[0];
+ void *ca_routine = x->x_ca_routine;
+ unsigned int rtos;
+
+ int offset = pdp_type_ca_info(header0)->offset;
+ int xoffset = offset % width;
+ int yoffset = offset / width;
+
+ /* double word width: number of unsigned ints per row */
+ int dwwidth = width >> 5;
+
+ unsigned long long result = 0;
+
+ /* exit if there isn't a valid routine */
+ if(!ca_routine) return;
+
+ //post("pdp_ca: PRE offset: %d, xoffset: %d, yoffset: %d", offset, xoffset, yoffset);
+
+ /* calculate new offset: lines shift up, rows shift left by 16 cells */
+ xoffset = (xoffset + width - 16) % width;
+ yoffset = (yoffset + height - 1) % height;
+
+ offset = yoffset * width + xoffset;
+
+ //post("pdp_ca: PST offset: %d, xoffset: %d, yoffset: %d", offset, xoffset, yoffset);
+
+
+ pdp_type_ca_info(header1)->offset = offset;
+
+
+ for(j=0; j<dwwidth*(height - 2); j+=(dwwidth<<1)){
+ for(i=0; i < (dwwidth-1) ; i+=1){
+ env[0] = data0[i + j];
+ env[1] = data0[i + j + 1];
+ env[2] = data0[i + j + dwwidth];
+ env[3] = data0[i + j + dwwidth + 1];
+ env[4] = data0[i + j + (dwwidth<<1)];
+ env[5] = data0[i + j + (dwwidth<<1) + 1];
+ env[6] = data0[i + j + (dwwidth<<1) + dwwidth];
+ env[7] = data0[i + j + (dwwidth<<1) + dwwidth + 1];
+ result = scaf_feeder(tos, reg, ca_routine, env);
+ data1[i + j] = result & 0xffffffff;
+ data1[i + j + dwwidth] = result >> 32;
+ }
+ // i == dwwidth-1
+
+ env[0] = data0[i + j];
+ env[1] = data0[j];
+ env[2] = data0[i + j + dwwidth];
+ env[3] = data0[j + dwwidth];
+ env[4] = data0[i + j + (dwwidth<<1)];
+ env[5] = data0[j + (dwwidth<<1)];
+ env[6] = data0[i + j + (dwwidth<<1) + dwwidth];
+ env[7] = data0[j + (dwwidth<<1) + dwwidth];
+ result = scaf_feeder(tos, reg, ca_routine, env);
+ data1[i + j] = result & 0xffffffff;
+ data1[i + j + dwwidth] = result >> 32;
+ }
+
+ // j == dwwidth*(height - 2)
+ for(i=0; i < (dwwidth-1) ; i+=1){
+ env[0] = data0[i + j];
+ env[1] = data0[i + j + 1];
+ env[2] = data0[i + j + dwwidth];
+ env[3] = data0[i + j + dwwidth + 1];
+ env[4] = data0[i];
+ env[5] = data0[i + 1];
+ env[6] = data0[i + dwwidth];
+ env[7] = data0[i + dwwidth + 1];
+ result = scaf_feeder(tos, reg, ca_routine, env);
+ data1[i + j] = result & 0xffffffff;
+ data1[i + j + dwwidth] = result >> 32;
+ }
+ // j == dwwidth*(height - 2)
+ // i == dwwidth-1
+ env[0] = data0[i + j];
+ env[1] = data0[j];
+ env[2] = data0[i + j + dwwidth];
+ env[3] = data0[j + dwwidth];
+ env[4] = data0[i];
+ env[5] = data0[0];
+ env[6] = data0[i + dwwidth];
+ env[7] = data0[dwwidth];
+ result = scaf_feeder(tos, reg, ca_routine, env);
+ data1[i + j] = result & 0xffffffff;
+ data1[i + j + dwwidth] = result >> 32;
+
+
+
+ /* check data stack pointer */
+ rtos = (unsigned int)tos;
+
+ if (env[0] != rtos){
+ if (env[0] > rtos) post("pdp_ca: ERROR: stack underflow detected in ca routine");
+ if (env[0] < rtos) post("pdp_ca: ERROR: ca routine returned more than one item");
+ x->x_ca_routine = 0;
+ post("pdp_ca: rule disabled");
+
+ }
+
+ return;
+}
+
+
+static void pdp_ca_swappackets(t_pdp_ca *x)
+{
+ /* swap packets */
+ int packet = x->x_packet1;
+ x->x_packet1 = x->x_packet0;
+ x->x_packet0 = packet;
+}
+
+
+
+
+
+/* tick advance CA one timestep */
+static void pdp_ca_bang_thread(t_pdp_ca *x)
+{
+ int encoding;
+ int packet;
+ int i;
+
+ /* invariant: the two packets are allways valid and compatible
+ so a bang is allways possible. this means that in the pdp an
+ invalid packet needs to be converted to a valid one */
+
+ for(i=0; i < x->x_iterations; i++){
+
+ /* process form packet0 -> packet1 and propagate */
+ pdp_ca_process_ca(x);
+
+ /* swap */
+ pdp_ca_swappackets(x);
+
+ }
+
+}
+
+static void pdp_ca_sendpacket(t_pdp_ca *x)
+{
+ /* output the packet */
+ outlet_pdp(x->x_outlet0, x->x_packet0);
+}
+
+static void pdp_ca_bang(t_pdp_ca *x)
+{
+ /* we don't use input packets for testing dropping here
+ but check the queue_id to see if processing is
+ still going on */
+
+ if (-1 == x->x_queue_id){
+ pdp_queue_add(x, pdp_ca_bang_thread, pdp_ca_sendpacket, &x->x_queue_id);
+ }
+
+ else{
+ pdp_control_notify_drop(-1);
+ }
+}
+
+
+/* this method stores the packet into x->x_packet0 (the packet
+ to be processed) if it is valid. x->x_packet1 is not compatible
+ it is regenerated so that it is
+
+ in short, when this routine returns both packets are valid
+ and compatible.
+*/
+
+
+static void pdp_ca_copy_rw_if_valid(t_pdp_ca *x, int packet)
+{
+ t_pdp *header = pdp_packet_header(packet);
+ t_pdp *header1 = pdp_packet_header(x->x_packet1);
+
+
+ int grabpacket;
+ int convertedpacket;
+
+ /* check if header is valid */
+ if (!header) return;
+
+ if (PDP_CA != header->type) return;
+ if (PDP_CA_STANDARD != pdp_type_ca_info(header)->encoding) return;
+
+
+ /* packet is a ca, register it */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = pdp_packet_copy_rw(packet);
+
+
+ /* make sure we have the right header */
+ header = pdp_packet_header(x->x_packet0);
+
+
+ /* make sure that the other packet is compatible */
+ if ((pdp_type_ca_info(header1)->width != pdp_type_ca_info(header)->width) ||
+ (pdp_type_ca_info(header1)->height != pdp_type_ca_info(header)->height)) {
+
+ /* if not, throw away and clone the new one */
+ pdp_packet_mark_unused(x->x_packet1);
+ x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
+ }
+
+
+};
+
+/* hot packet inlet */
+static void pdp_ca_input_0(t_pdp_ca *x, t_symbol *s, t_floatarg f)
+{
+
+ if (s == gensym("register_rw")){
+ pdp_ca_copy_rw_if_valid(x, (int)f);
+ }
+ else if (s == gensym("process")){
+ pdp_ca_bang(x);
+ }
+
+
+}
+
+/* cold packet inlet */
+static void pdp_ca_input_1(t_pdp_ca *x, t_symbol *s, t_floatarg f)
+{
+
+ if (s == gensym("register_rw"))
+ {
+ pdp_ca_copy_rw_if_valid(x, (int)f);
+ }
+
+}
+
+
+static void pdp_ca_rule_string(t_pdp_ca *x, char *c)
+{
+ char tmp[256];
+ void (*prev_routine)(void);
+
+ /* save previous routine ptr */
+ prev_routine = x->x_ca_routine;
+
+ /* check if we can find string */
+ sprintf(tmp, "rule_%s", c);
+ if (!(x->x_ca_routine = dlsym(x->x_ca_libhandle, tmp))){
+ post("pdp_ca: can't fine ca rule %s (symbol: %s)", c, tmp);
+ x->x_ca_routine = x->x_ca_routine;
+ return;
+ }
+
+ /* all seems ok */
+ //post("pdp_ca: using ca rule %s", c);
+
+}
+static void pdp_ca_rule(t_pdp_ca *x, t_symbol *s)
+{
+ /* make sure lib is loaded */
+ if (!x->x_ca_libhandle) return;
+
+ /* set rule by name */
+ pdp_ca_rule_string(x, s->s_name);
+}
+
+static void pdp_ca_rule_index(t_pdp_ca *x, t_float f)
+{
+ int i = (int)f;
+
+ /* make sure lib is loaded */
+ if (!x->x_ca_libhandle) return;
+
+ /* check index */
+ if (i<0) return;
+ if (i>=x->x_ca_nbrules) return;
+
+ /* set rule by index */
+ pdp_ca_rule_string(x, x->x_ca_rulename[i]);
+
+}
+
+
+static void pdp_ca_close(t_pdp_ca *x)
+{
+ if (x->x_ca_libhandle){
+ dlclose(x->x_ca_libhandle);
+ x->x_ca_libhandle = 0;
+ x->x_ca_routine = 0;
+ if (x->x_ca_rulename){
+ free (x->x_ca_rulename);
+ x->x_ca_rulename = 0;
+ }
+
+
+ }
+}
+
+
+static void pdp_ca_printrules(t_pdp_ca *x)
+{
+ int i;
+
+ if (!(x->x_ca_libhandle)) return;
+ post("pdp_ca: found %d rules: ", x->x_ca_nbrules);
+ for(i=0;i<x->x_ca_nbrules; i++) post("%3d: %s ", i, x->x_ca_rulename[i]);
+
+
+}
+
+static void pdp_ca_open(t_pdp_ca *x, t_symbol *s)
+{
+
+ char *c;
+ int words;
+
+ /* close current lib, if one */
+ pdp_ca_close(x);
+
+ /* try to open new lib */
+ if (!(x->x_ca_libhandle = dlopen(s->s_name, RTLD_NOW))){
+ post("pdp_ca: can't open ca library %s, %s", s->s_name, dlerror());
+ x->x_ca_libhandle = 0;
+ }
+
+ /* scan for valid rules */
+ if (!(x->x_ca_rulenames = (char *)dlsym(x->x_ca_libhandle, "rulenames"))){
+ post("pdp_ca: ERROR: %s does not contain a name table. closing.", s->s_name);
+ pdp_ca_close(x);
+ return;
+ }
+
+ /* count rules */
+ words = 0;
+ for(c = (char *)x->x_ca_rulenames; *c;){
+ words++;
+ while(*c++);
+ }
+ x->x_ca_nbrules = words;
+ x->x_ca_rulename = (char **)malloc(sizeof(char *) * words);
+
+ /* build name array */
+ words = 0;
+ for(c = (char *)x->x_ca_rulenames; *c;){
+ x->x_ca_rulename[words] = c;
+ words++;
+ while(*c++);
+ }
+
+ /* ok, we're done */
+ post("pdp_ca: opened rule library %s", s->s_name ,x->x_ca_nbrules);
+
+ /* print rule names */
+ //pdp_ca_printrules(x);
+
+
+
+}
+
+/* init the current packet with random noise */
+static void pdp_ca_rand(t_pdp_ca *x){
+
+ t_pdp *header = pdp_packet_header(x->x_packet0);
+ short int *data = (short int *) pdp_packet_data(x->x_packet0);
+ int i;
+
+ int nbshortints = (pdp_type_ca_info(header)->width >> 4) * pdp_type_ca_info(header)->height;
+
+ for(i=0; i<nbshortints; i++)
+ data[i] = random();
+
+}
+
+
+static void pdp_ca_newca(t_pdp_ca *x, t_float width, t_float height)
+{
+ int w = (int)width;
+ int h = (int)height;
+ int bytesize;
+ t_pdp *header;
+
+ /* ensure with = multiple of 64 */
+ w &= 0xffffffc0;
+
+ /* ensure height = multiple of 4 */
+ w &= 0xfffffffc;
+
+ w = (w<64) ? 64 : w;
+ h = (h<4) ? 4 : h;
+
+ bytesize = (w>>3) * h;
+
+ /* delete old packets */
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+
+
+ /* create new packets */
+ x->x_packet0 = pdp_packet_new(PDP_CA, bytesize);
+ header = pdp_packet_header(x->x_packet0);
+ pdp_type_ca_info(header)->encoding = PDP_CA_STANDARD;
+ pdp_type_ca_info(header)->width = w;
+ pdp_type_ca_info(header)->height = h;
+ pdp_type_ca_info(header)->offset = 0;
+ x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
+
+
+ /* fill with a test pattern */
+ if(0)
+ {
+ unsigned int *d;
+ int i, s;
+
+ s = (w * h) >> 5;
+
+ /* fill the first packet with 01 */
+ d = (unsigned int *)pdp_packet_data(x->x_packet0);
+ for (i=0; i<s; i++){
+ d[i] = i;
+ }
+
+ /* fill the second packet with 10 */
+ d = (unsigned int *)pdp_packet_data(x->x_packet1);
+ for (i=0; i<s; i++){
+ d[i] = i^-1;
+ }
+
+
+
+ }
+
+
+ /* fill with random noise */
+ pdp_ca_rand(x);
+
+}
+
+
+static void pdp_ca_iterations(t_pdp_ca *x, t_float f)
+{
+ int i = (int)f;
+
+ if (i < 0) i = 0;
+
+ x->x_iterations = i;
+}
+
+static void pdp_ca_free(t_pdp_ca *x)
+{
+ pdp_packet_mark_unused(x->x_packet0);
+ pdp_packet_mark_unused(x->x_packet1);
+ pdp_ca_close(x);
+ free(x->x_data);
+}
+
+
+
+void *pdp_ca_new(void)
+{
+ t_pdp_ca *x = (t_pdp_ca *)pd_new(pdp_ca_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("iterations"));
+
+ 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_data = (t_pdp_ca_data *)malloc(sizeof(t_pdp_ca_data));
+ x->x_ca_routine = 0;
+ x->x_ca_libhandle = 0;
+ x->x_ca_rulename = 0;
+
+ pdp_ca_newca(x, 64, 64);
+ pdp_ca_iterations(x, 1);
+
+ x->x_packet_type = gensym("grey");
+
+ return (void *)x;
+}
+
+
+// *********************** CA CONVERTER CLASSES STUFF *********************
+// TODO: move this to a separate file later together with other converters (part of system?)
+
+#define PDP_CA2IMAGE 1
+#define PDP_IMAGE2CA 2
+
+typedef struct pdp_ca_conv_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+
+ int x_threshold;
+
+ int x_packet;
+
+ t_outlet *x_outlet0;
+
+ /* solve identity crisis */
+ int x_whoami;
+
+ /* output packet type */
+ /* only greyscale for now */
+ t_symbol *x_packet_type;
+
+} t_pdp_ca_conv;
+
+/* hot packet inlet */
+static void pdp_ca_conv_input_0(t_pdp_ca_conv *x, t_symbol *s, t_floatarg f)
+{
+ int packet = -1;
+
+ if (s == gensym("register_ro")){
+ pdp_packet_mark_unused(x->x_packet);
+ x->x_packet = pdp_packet_copy_ro((int)f);
+ return;
+ }
+ else if (s == gensym("process")){
+ switch(x->x_whoami){
+ case PDP_CA2IMAGE:
+ packet = pdp_type_ca2grey(x->x_packet);
+ break;
+ case PDP_IMAGE2CA:
+ packet = pdp_type_grey2ca(x->x_packet, x->x_threshold);
+ break;
+ }
+
+ /* throw away the original packet */
+ pdp_packet_mark_unused(x->x_packet);
+ x->x_packet = -1;
+
+ /* unregister the freshly created packet */
+ pdp_packet_mark_unused(packet);
+
+ /* output if valid */
+ if (-1 != packet) outlet_pdp(x->x_outlet0, packet);
+ }
+
+
+}
+
+void pdp_ca_conv_free(t_pdp_ca_conv *x)
+{
+ pdp_packet_mark_unused(x->x_packet);
+}
+
+
+void pdp_image2ca_threshold(t_pdp_ca_conv *x, t_float f)
+{
+ f *= 0x8000;
+
+ if (f < -0x7fff) f = -0x7fff;
+ if (f > 0x7fff) f = 0x7fff;
+
+ x->x_threshold = (short int)f;
+}
+
+void *pdp_ca2image_new(void)
+{
+ t_pdp_ca_conv *x = (t_pdp_ca_conv *)pd_new(pdp_ca2image_class);
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ x->x_packet_type = gensym("grey");
+ x->x_packet = -1;
+ x->x_whoami = PDP_CA2IMAGE;
+ return (void *)x;
+}
+
+void *pdp_image2ca_new(void)
+{
+ t_pdp_ca_conv *x = (t_pdp_ca_conv *)pd_new(pdp_image2ca_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("threshold"));
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ x->x_packet_type = gensym("grey");
+ x->x_packet = -1;
+ x->x_whoami = PDP_IMAGE2CA;
+ x->x_threshold = 0x4000;
+ return (void *)x;
+}
+
+
+// *********************** CLASS SETUP FUNCTIONS *********************
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+void pdp_ca2image_setup(void)
+{
+ pdp_ca2image_class = class_new(gensym("pdp_ca2image"), (t_newmethod)pdp_ca2image_new,
+ (t_method)pdp_ca_conv_free, sizeof(t_pdp_ca), 0, A_NULL);
+ class_addmethod(pdp_ca2image_class, (t_method)pdp_ca_conv_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+}
+
+void pdp_image2ca_setup(void)
+{
+ pdp_image2ca_class = class_new(gensym("pdp_image2ca"), (t_newmethod)pdp_image2ca_new,
+ (t_method)pdp_ca_conv_free, sizeof(t_pdp_ca), 0, A_NULL);
+ class_addmethod(pdp_image2ca_class, (t_method)pdp_ca_conv_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_image2ca_class, (t_method)pdp_image2ca_threshold, gensym("threshold"), A_FLOAT, A_NULL);
+}
+
+void pdp_ca_setup(void)
+{
+
+
+ pdp_ca_class = class_new(gensym("pdp_ca"), (t_newmethod)pdp_ca_new,
+ (t_method)pdp_ca_free, sizeof(t_pdp_ca), 0, A_NULL);
+
+
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_iterations, gensym("iterations"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_bang, gensym("bang"), A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_printrules, gensym("rules"), A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_rand, gensym("random"), A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_newca, gensym("ca"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_close, gensym("close"), A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_open, gensym("open"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_rule, gensym("rule"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_rule_index, gensym("ruleindex"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_ca_class, (t_method)pdp_ca_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/scaf/pdp/pdp_ca_system.c b/scaf/pdp/pdp_ca_system.c
new file mode 100644
index 0000000..0800380
--- /dev/null
+++ b/scaf/pdp/pdp_ca_system.c
@@ -0,0 +1,228 @@
+/*
+ * Cellular Automata Extension Module for pdp - Main system code
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "pdp_ca.h"
+
+/* all symbols are C-style */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+/* check if packet is a valid ca packet */
+int pdp_type_isvalid_ca(int packet)
+{
+ t_pdp *header = pdp_packet_header(packet);
+ if (!header) return 0;
+ if (PDP_CA != header->type) return 0;
+ if (PDP_CA_STANDARD != pdp_type_ca_info(header)->encoding) return 0;
+
+ return 1;
+}
+
+/* convert a CA packet to greyscale */
+
+inline void _pdp_type_ca2grey_convert_word(unsigned short int source, short int *dest)
+{
+
+ int i;
+ for (i = 15; i>=0; i--){
+ dest[i] = ((unsigned short)(((short int)(source & 0x8000)) >> 14)) >> 1;
+ source <<= 1;
+ }
+}
+
+int pdp_type_ca2grey(int packet)
+{
+ int w, h, s, x, y, srcindex;
+ long long offset, xoffset, yoffset;
+ short int *dest;
+ unsigned short int *source;
+ t_pdp *header;
+ t_pdp *newheader;
+ int newpacket;
+ if (!(pdp_type_isvalid_ca(packet))) return -1;
+
+ header = pdp_packet_header(packet);
+ w = pdp_type_ca_info(header)->width;
+ h = pdp_type_ca_info(header)->height;
+ s = w*h;
+ source = (unsigned short int *)pdp_packet_data(packet);
+ offset = pdp_type_ca_info(header)->offset;
+ yoffset = (offset / w) * w;
+ xoffset = offset % w;
+
+ //post("pdp_type_ca2grey: offset: %d, xoffset: %d, yoffset: %d", offset, xoffset, yoffset);
+
+ newpacket = pdp_packet_new(PDP_IMAGE, s<<1);
+ newheader = pdp_packet_header(newpacket);
+ newheader->info.image.width = w;
+ newheader->info.image.height = h;
+ newheader->info.image.encoding = PDP_IMAGE_GREY;
+ dest = (short int *)pdp_packet_data(newpacket);
+
+
+#define check_srcindex \
+if (srcindex >= (s >> 4)) post ("pdp_type_ca2grey: srcindex out of bound");
+
+#define check_dstindex \
+if ((x+y) >= s) post ("pdp_type_ca2grey: dstindex out of bound");
+
+
+ /* dont' shift offset */
+ if (0){
+ for(y=0; y< (h*w); y+=w){
+ for(x=0; x<w; x+=16){
+ _pdp_type_ca2grey_convert_word (source[(x+y)>>4], &dest[x+y]);
+ }
+ }
+ return newpacket;
+ }
+
+
+ /* create top left */
+ for (y=0; y < (h*w) - yoffset; y+=w) {
+ for (x=0; x< (w - xoffset); x+=16) {
+ srcindex = (x+xoffset + y+yoffset) >> 4;
+ //check_srcindex;
+ //check_dstindex;
+ _pdp_type_ca2grey_convert_word (source[srcindex], &dest[x+y]);
+ }
+ }
+
+ /* create top right */
+ for (y=0; y < (h*w) - yoffset; y+=w) {
+ for (x = (w - xoffset); x < w; x+=16) {
+ srcindex = (x+xoffset-w + y+yoffset) >> 4;
+ //check_srcindex;
+ //check_dstindex;
+ _pdp_type_ca2grey_convert_word (source[srcindex], &dest[x+y]);
+ }
+ }
+
+ /* create bottom left */
+ for (y=(h*w) - yoffset; y < h*w; y+=w) {
+ for (x=0; x< (w - xoffset); x+=16) {
+ srcindex = (x+xoffset + y+yoffset-(w*h)) >> 4;
+ //check_srcindex;
+ //check_dstindex;
+ _pdp_type_ca2grey_convert_word (source[srcindex], &dest[x+y]);
+ }
+ }
+
+ /* create bottom right */
+ for (y=(h*w) - yoffset; y < h*w; y+=w) {
+ for (x = (w - xoffset); x < w; x+=16) {
+ srcindex = (x+xoffset-w + y+yoffset-(w*h)) >> 4;
+ //check_srcindex;
+ //check_dstindex;
+ _pdp_type_ca2grey_convert_word (source[srcindex], &dest[x+y]);
+ }
+ }
+
+
+ return newpacket;
+
+}
+
+
+inline unsigned short int _pdp_type_grey2ca_convert_word(short int *src, short int threshold)
+{
+ short int tmp;
+ short int dest = 0;
+ int i;
+
+ for (i = 15; i >= 0; i--){
+ dest <<= 1;
+ dest |= (src[i] > threshold);
+ }
+
+ return dest;
+}
+
+
+
+int pdp_type_grey2ca(int packet, short int threshold)
+{
+ int w, h, s, x, y, srcindex;
+ long long offset, xoffset, yoffset;
+ short int *dest;
+ short int *source;
+ t_pdp *header;
+ t_pdp *newheader;
+ int newpacket;
+ if (!(pdp_type_isvalid_image(packet))) return -1;
+
+ header = pdp_packet_header(packet);
+ w = header->info.image.width;
+ h = header->info.image.height;
+ s = w*h;
+ source = (unsigned short int *)pdp_packet_data(packet);
+
+ if ( (PDP_IMAGE_GREY != header->info.image.encoding)
+ && (PDP_IMAGE_YV12 != header->info.image.encoding)) return -1;
+
+ newpacket = pdp_packet_new(PDP_CA, s>>3);
+ newheader = pdp_packet_header(newpacket);
+ pdp_type_ca_info(newheader)->width = w;
+ pdp_type_ca_info(newheader)->height = h;
+ pdp_type_ca_info(newheader)->encoding = PDP_CA_STANDARD;
+ pdp_type_ca_info(newheader)->offset = 0;
+
+ dest = (short int *)pdp_packet_data(newpacket);
+
+ for(y=0; y< (h*w); y+=w){
+ for(x=0; x<w; x+=16){
+ dest[(x+y)>>4] = _pdp_type_grey2ca_convert_word (&source[x+y], threshold);
+ }
+ }
+ return newpacket;
+
+
+}
+
+/* returns a pointer to the ca subheader given the pdp header */
+t_ca *pdp_type_ca_info(t_pdp *x){return (t_ca *)(&x->info.raw);}
+
+
+void pdp_ca_setup(void);
+void pdp_ca2image_setup(void);
+void pdp_image2ca_setup(void);
+
+
+void pdp_scaf_setup(void)
+{
+ /* babble */
+ post ("PDP: pdp_scaf extension lib (mmx version)");
+
+ /* setup modules */
+ pdp_ca_setup();
+ pdp_ca2image_setup();
+ pdp_image2ca_setup();
+
+}
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/scaf/system/Makefile b/scaf/system/Makefile
new file mode 100644
index 0000000..2a07f4f
--- /dev/null
+++ b/scaf/system/Makefile
@@ -0,0 +1,21 @@
+all: scaf_feeder.o
+
+test: scaf_feeder_test
+
+OBJ = scaf_feeder_test.o scaf_feeder.o
+
+
+scaf_feeder_test: $(OBJ)
+ gcc -o scaf_feeder_test *.o -g -ldl
+
+.s.o:
+ as -o $*.o $*.s
+
+.c.o:
+ gcc -c $*.c -o $*.o -g
+
+clean:
+ rm -f *~
+ rm -f *.o
+ rm -f scaf_feeder_test
+
diff --git a/scaf/system/kernel.scaf b/scaf/system/kernel.scaf
new file mode 100644
index 0000000..0bc2788
--- /dev/null
+++ b/scaf/system/kernel.scaf
@@ -0,0 +1,130 @@
+( Pure Data Packet - scaforth kernel. )
+( Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> )
+( )
+( This program is free software; you can redistribute it and/or modify )
+( it under the terms of the GNU General Public License as published by )
+( the Free Software Foundation; either version 2 of the License, or )
+( [at your option] any later version. )
+( )
+( This program is distributed in the hope that it will be useful, )
+( but WITHOUT ANY WARRANTY; without even the implied warranty of )
+( MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the )
+( GNU General Public License for more details. )
+( )
+( You should have received a copy of the GNU General Public License )
+( along with this program; if not, write to the Free Software )
+( Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. )
+
+
+
+
+
+( this file contains the inline words in the scaforth kernel. )
+( when a file is compiled to asm, it will consist of word )
+( definition asm routines, macros and jmp call ret instructions. )
+( )
+( all words in this file are defined in terms of asm macros )
+( defined in scafmacros.s )
+
+
+
+( stack manip words )
+
+: over dup dropover ;
+
+( neighbourhood cell fetch words )
+
+: @-+ dup dropldTL ;
+: @0+ dup dropldTM ;
+: @++ dup dropldTR ;
+: @-0 dup dropldML ;
+: @00 dup dropldMM ;
+: @+0 dup dropldMR ;
+: @-- dup dropldBL ;
+: @0- dup dropldBM ;
+: @+- dup dropldBR ;
+
+( boolean logic )
+
+: or overor nip ;
+: xor overxor nip ;
+: and overand nip ;
+
+( binary constant loading )
+
+: 1 dup dropone ;
+: 0 dup dropzero ;
+
+( 4,3,2,1 bit add stack to register, leave carry on stack )
+
+: ++++ adb0 adb1 adb2 adb3 ;
+: +++ adb0 adb1 adb2 ;
+: ++ adb0 adb1 ;
+: + adb0 ;
+
+( 4,3,2 bit shifted 1 add )
+
+: ++++<<1 adb1 adb2 adb3 ;
+: +++<<1 adb1 adb2 ;
+: ++<<1 adb1 ;
+
+( 4,3 bit shifted 2 add )
+
+: ++++<<2 adb2 adb3 ;
+: +++<<2 adb2 ;
+
+( 4 bit shifted 3 add )
+
+: ++++<<3 adb3 ;
+
+( 4 bit accumulator access )
+
+: !a0 dupsta0 drop ;
+: !a1 dupsta1 drop ;
+: !a2 dupsta2 drop ;
+: !a3 dupsta3 drop ;
+
+: @a0 dup droplda0 ;
+: @a1 dup droplda1 ;
+: @a2 dup droplda2 ;
+: @a3 dup droplda3 ;
+
+( 4,3,2,1 bit accumulator zero tests )
+
+: ?anz dup dropisnonzero4 ;
+: ?anz4 dup dropisnonzero4 ;
+: ?anz3 dup dropisnonzero3 ;
+: ?anz2 dup dropisnonzero2 ;
+: ?anz1 dup dropisnonzero1 ;
+
+( load constants into accumulator )
+
+: a0 a0000 ;
+: a-0 a0000 ;
+: a+0 a0000 ;
+: a+1 a0001 ;
+: a+2 a0010 ;
+: a+3 a0011 ;
+: a+4 a0100 ;
+: a+5 a0101 ;
+: a+6 a0110 ;
+: a+7 a0111 ;
+
+: a+8 a1000 ;
+: a+9 a1001 ;
+: a+10 a1010 ;
+: a+11 a1011 ;
+: a+12 a1100 ;
+: a+13 a1101 ;
+: a+14 a1110 ;
+: a+15 a1111 ;
+
+: a-8 a1000 ;
+: a-7 a1001 ;
+: a-6 a1010 ;
+: a-5 a1011 ;
+: a-4 a1100 ;
+: a-3 a1101 ;
+: a-2 a1110 ;
+: a-1 a1111 ;
+
diff --git a/scaf/system/optim.rules b/scaf/system/optim.rules
new file mode 100644
index 0000000..282caf4
--- /dev/null
+++ b/scaf/system/optim.rules
@@ -0,0 +1,74 @@
+# Pure Data Packet - scaf optimization rules.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+# this file contains scaf source optimization rules for scaf compiler
+# applied after kernel word inlining and before compilation to asm
+
+# one rule that's not in here, and is the responsability for the
+# final compilation step: "word ;" is "jmp word" instead of "call word ret"
+
+# TODO: think about order!
+
+# no discrimination between pre inline and post inline optimization ops yet
+
+# pre inline optimizations
+
+"over xor" -> "overxor"
+"over and" -> "overand"
+"over or" -> "overor"
+
+"drop 1" -> "dropone"
+"drop 0" -> "dropzero"
+"over add" -> "overadd"
+"over addc" -> "overaddc"
+
+"dup !a0" -> "dupsta0"
+"dup !a1" -> "dupsta1"
+"dup !a2" -> "dupsta2"
+"dup !a3" -> "dupsta3"
+
+"drop @a0" -> "droplda0"
+"drop @a1" -> "droplda1"
+"drop @a2" -> "droplda2"
+"drop @a3" -> "droplda3"
+
+"drop ?anz" -> "dropisnonzero4"
+"drop ?anz4" -> "dropisnonzero4"
+"drop ?anz3" -> "dropisnonzero3"
+"drop ?anz2" -> "dropisnonzero2"
+"drop ?anz1" -> "dropisnonzero1"
+
+"drop @-+" -> "dropldTL"
+"drop @0+" -> "dropldTM"
+"drop @++" -> "dropldTR"
+"drop @-0" -> "dropldML"
+"drop @00" -> "dropldMM"
+"drop @+0" -> "dropldMR"
+"drop @--" -> "dropldBL"
+"drop @0-" -> "dropldBM"
+"drop @+-" -> "dropldBR"
+
+
+# post inline optimizations
+
+"dup drop" -> ""
+"swap drop" -> "nip"
+"dup swap" -> "dup"
+"drop dup" -> "dropdup"
+"drop over" -> "dropover"
+"nip dup" -> "nipdup"
diff --git a/scaf/system/scaf_feeder.s b/scaf/system/scaf_feeder.s
new file mode 100644
index 0000000..1cd8fd3
--- /dev/null
+++ b/scaf/system/scaf_feeder.s
@@ -0,0 +1,49 @@
+# Pure Data Packet - scaf feeder routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+.include "scafmacro.s"
+
+
+# *rg is only used for returning the stack pointer
+# the 4 bit counter is using registers mm4-mm7 now
+# long long scaf_feeder(void *tos, void *rg, *void() ca_rule, void *env)
+.globl scaf_feeder
+.type scaf_feeder, @function
+scaf_feeder:
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+ movl 20(%ebp), %edi # load env ptr
+ movl 8(%ebp), %esi # load TOS2 ptr
+ movl 16(%ebp), %eax # address of ca routine
+ pcmpeqw %mm3, %mm3 # load 1 reg
+
+ call *%eax # TOS = 32x2 cell result
+ dup # push %mm0 to memory
+ movl (%esi), %eax
+ movl 4(%esi), %edx
+ lea 16(%esi), %esi # discard stack
+ movl %esi, (%edi) # store for stack underflow check
+
+ emms
+ pop %edi
+ pop %esi
+ leave
+ ret
diff --git a/scaf/system/scaf_feeder_test.c b/scaf/system/scaf_feeder_test.c
new file mode 100644
index 0000000..23a2661
--- /dev/null
+++ b/scaf/system/scaf_feeder_test.c
@@ -0,0 +1,30 @@
+#include <dlfcn.h>
+
+void scaf_feeder_asm (void *tos, void *reg, void (*ca_rule)(), void *env);
+
+void ca_test() {}
+
+main()
+{
+ int stack[256];
+ int reg[8];
+ int env[8];
+
+ void *libhandle;
+ void *ca_routine;
+
+
+ if (!(libhandle = dlopen("../modules/test.scafo", RTLD_NOW))){
+ printf("error: %s\n", dlerror());
+ exit(1);
+ }
+
+ if (!(ca_routine = dlsym(libhandle, "carule_1"))){
+ printf("error: %s\n", dlerror());
+ exit(1);
+ }
+
+ scaf_feeder_asm(stack+254, reg, ca_routine, env);
+
+ dlclose(libhandle);
+}
diff --git a/scaf/system/scafc.pl b/scaf/system/scafc.pl
new file mode 100755
index 0000000..ee6b969
--- /dev/null
+++ b/scaf/system/scafc.pl
@@ -0,0 +1,269 @@
+#!/usr/bin/perl
+
+# Pure Data Packet - scafc: scaf compiler.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# set this if you want to enable/disable optimizing
+
+$optimize = 1;
+
+
+# this parses a single scaf line
+# it is not very intelligent. only looks for 1 def on a line
+# todo: change later so it can read multiple lines
+
+
+sub remove_illegal_characters {
+ my $line = shift;
+ $$line =~ s/\+/_PLUS_/g;
+ $$line =~ s/-/_MINUS_/g;
+ $$line =~ s/\@/_AT_/g;
+ $$line =~ s/:/_COLON_/g;
+ $$line =~ s/\?/_QMARK_/g;
+ $$line =~ s/<</_SHIFT_/g;
+ $$line =~ s/</_ST_/g;
+ $$line =~ s/>/_GT_/g;
+ $$line =~ s/=/_EQ_/g;
+ $$line =~ s/\(/_OPEN_/g;
+ $$line =~ s/\)/_CLOSE_/g;
+}
+
+sub parse_scaf_line {
+ my $word, $def, $sub;
+ shift;
+
+ # this transforms the source into a parsed assembly like form
+ # a word label: "<word>:<ret>"
+ # a word definition line "<tab><word><ret>"
+ # last def = <ret><ret>
+
+ # dont process if line doesn't have a def
+
+ # first remove comments
+ s/\(\s+(\S+\s+)*?\)//g;
+
+ if (m/:\s+/){
+
+ # separate word and definition
+ m/:\s+(\S+)\s+(.*)/;
+ $word = $1;
+ $def = $2;
+
+ # remove illegal characters;
+ remove_illegal_characters \$word;
+ remove_illegal_characters \$def;
+
+ # format definition in asm style
+ $def =~ s/(\S+)(\s*)/\t$1\n/g;
+
+ # replace ; by r
+ $def =~ s/\s+;\s*/\n\tr\n/;
+
+ # put word: def into one string
+ $sub = "$word:\n$def\n";
+
+ # debug
+ #$sub =~ s/\t/<tab>/g;
+ #$sub =~ s/\n/<ret>\n/g;
+ #print "$sub";
+
+ return $sub;
+
+ }
+
+};
+
+
+
+# load and parse scaf source file
+sub load_source {
+ my $filename = shift;
+ open(SOURCE, $filename) or die "Can't locate source module $filename\n";
+ my @parsedsource;
+ while (<SOURCE>){
+ my $sub = parse_scaf_line $_;
+ if ($sub) {
+ push @parsedsource, ($sub);
+ }
+
+ }
+ close(SOURCE);
+ return @parsedsource;
+
+}
+
+# this routine parses the optimization rules
+sub load_optim {
+ my $filename = shift;
+ open(OPTIM, $filename) or die "Can't locate optimization rule file $filename\n";
+ my @parsedoptim;
+ while (<OPTIM>){
+ unless (m/\A\#/){
+
+ if (m/\"\s*(.*?)\s*\".*?\"\s*(.*?)\s*\"/)
+ {
+ my $source = $1;
+ my $dest = $2;
+
+ $source =~ s/\s+/\n\t/;
+ $dest =~ s/\s+/\n\t/;
+ $source = "\t$source\n";
+ $dest = "\t$dest\n";
+
+ remove_illegal_characters \$source;
+ remove_illegal_characters \$dest;
+
+ push @parsedoptim, ("$source:$dest");
+ }
+ }
+ }
+ close(OPTIM);
+
+ return @parsedoptim;
+
+
+}
+
+
+
+# inline one parsed source's definitions into another parsed source's
+sub inline_defs {
+ my $dest = shift;
+ my $source = shift;
+
+ #print @$dest;
+ #print @$source;
+
+
+ # loop over file with inline defs
+ foreach (@$source) {
+ #print "<SUB>$_</SUB>\n";
+ m/(\S+):\n(.*)\tr\n/s;
+
+ my $def = "\t$1\n";
+ my $body = $2;
+
+ #print "<DEF>$def</DEF>\n";
+ #print "<BODY>$body</BODY>\n";
+
+ foreach (@$dest) {
+ s/$def/$body/g;
+ }
+
+ }
+
+}
+
+# this changes <WORD> to c <WORD> or j <WORD> all defined words
+# the undefined words are supposed to be asm macros
+sub call_defs {
+ my $dest = shift;
+
+ foreach (@$dest){
+ m/(\S+):\n/s;
+ my $word = $1;
+ foreach (@$dest){
+ s/\t$word\n\tr\n/\tj $word\n/sg;
+ s/\t$word\n/\tc $word\n/sg;
+ }
+ }
+}
+
+# substitue word sequences in dest using optim table
+sub subst_optim {
+ my $dest = shift;
+ my $optim = shift;
+ foreach (@$optim){
+ m/(.*?):(.*)/s;
+ my $key = $1;
+ my $subst = $2;
+
+ foreach (@$dest){
+ s/$key/$subst/sg;
+ }
+ }
+}
+
+# add directives to produce global symbols
+# global symbols need to start with carule_
+sub global_syms {
+ my $source = shift;
+ foreach (@$source){
+ s/rule_(\S+):\n/.globl\trule_$1\n.type\trule_$1,\@function\nrule_$1:\n/sg;
+ }
+}
+
+# create an array with names for bookkeeping
+sub name_array {
+ my @namearray;
+ my $source = shift;
+ push @namearray, (".globl rulenames\nrulenames:\n");
+ foreach (@$source){
+ if (m/rule_(\S+):/s){
+ push @namearray, (".asciz\t\"$1\"\n");
+ }
+ }
+ push @namearray, (".byte\t0\n");
+ return @namearray;
+
+}
+
+# main program body
+
+$dir=".";
+
+$source = "-";
+
+
+# parse command line
+foreach (@ARGV){
+ if (m/-I(.*)/) {
+ $dir = $1;
+ }
+ else {
+ $source = $_;
+ }
+}
+
+$kernel = "$dir/kernel.scaf";
+$macro = "$dir/scafmacro.s";
+$rules = "$dir/optim.rules";
+
+
+
+# load files
+@psource = load_source $source;
+@pkernel = load_source $kernel;
+@poptim = load_optim $rules;
+
+
+# substitute kernel defs in source
+if ($optimize) {subst_optim \@psource, \@poptim;}
+inline_defs \@psource, \@pkernel;
+
+if ($optimize) {subst_optim \@psource, \@poptim;}
+
+call_defs \@psource;
+global_syms \@psource;
+@pnames = name_array \@psource;
+
+# print out asm file
+print ".include \"$macro\"\n\n";
+print @psource;
+print @pnames;
+
diff --git a/scaf/system/scafmacro.s b/scaf/system/scafmacro.s
new file mode 100644
index 0000000..04e6537
--- /dev/null
+++ b/scaf/system/scafmacro.s
@@ -0,0 +1,487 @@
+ # Pure Data Packet - scaf assembler macros.
+ # Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+ # the Free Software Foundation; either version 2 of the License, or
+ # (at your option) any later version.
+ #
+ # This program is distributed in the hope that it will be useful,
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ # GNU General Public License for more details.
+ #
+ # You should have received a copy of the GNU General Public License
+ # along with this program; if not, write to the Free Software
+ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ #
+
+
+ # this file contains pure asm macros. it is to be included before assembly
+ # after scaforth.pl has processed the .scaf file
+
+ # *************************** JMP CALL RET **************************************
+ # j c r
+
+ .macro j address
+ jmp \address
+ .endm
+
+ .macro c address
+ call \address
+ .endm
+
+ .macro r
+ ret
+ .endm
+
+
+ # *************************** CA CELL ACCESS MACROS *****************************
+ # dropldTL - dropldBR
+
+ # shift / load rectangle macros:
+
+ # shift rectangle horizontal
+ # result is in reg1
+ .macro shift reg1 reg2 count
+ psllq $(16-\count), \reg1
+ psrlq $(16+\count), \reg2
+ psrlq $32, \reg1
+ psllq $32, \reg2
+ por \reg2, \reg1
+ .endm
+
+ .macro ldtop reg1 reg2
+ movq (%edi), \reg1
+ movq 8(%edi), \reg2
+ .endm
+
+ .macro ldcenter reg1 reg2
+ movq 8(%edi), \reg1
+ movq 16(%edi), \reg2
+ .endm
+
+ .macro ldbottom reg1 reg2
+ movq 16(%edi), \reg1
+ movq 24(%edi), \reg2
+ .endm
+
+
+ # dropld from top row
+
+ # dropld the top left square
+ .macro dropldTL
+ ldtop %mm0, %mm1
+ shift %mm0, %mm1, -1
+ .endm
+
+ # dropld the top mid square
+ .macro dropldTM
+ ldtop %mm0, %mm1
+ shift %mm0, %mm1, 0
+ .endm
+
+ # dropld the top right square
+ .macro dropldTR
+ ldtop %mm0, %mm1
+ shift %mm0, %mm1, 1
+ .endm
+
+
+
+ # dropld from center row
+
+ # dropld the mid left square
+ .macro dropldML
+ ldcenter %mm0, %mm1
+ shift %mm0, %mm1, -1
+ .endm
+
+ # dropld the mid mid square
+ .macro dropldMM
+ ldcenter %mm0, %mm1
+ shift %mm0, %mm1, 0
+ .endm
+
+ # dropld the mid right square
+ .macro dropldMR
+ ldcenter %mm0, %mm1
+ shift %mm0, %mm1, 1
+ .endm
+
+
+
+
+
+ # dropld from bottom row
+
+ # dropld the bottom left square
+ .macro dropldBL
+ ldbottom %mm0, %mm1
+ shift %mm0, %mm1, -1
+ .endm
+
+ # dropld the bottom mid square
+ .macro dropldBM
+ ldbottom %mm0, %mm1
+ shift %mm0, %mm1, 0
+ .endm
+
+ # dropld the bottom right square
+ .macro dropldBR
+ ldbottom %mm0, %mm1
+ shift %mm0, %mm1, 1
+ .endm
+
+
+
+ # *************************** CA STACK MANIP MACROS *****************************
+ # these are the only asm macros that have a stack effect other than
+ # just replacing the TOS
+ #
+ # dup drop dropdup swap nip dropover
+
+ .macro dup
+ lea -8(%esi), %esi
+ movq %mm0, (%esi)
+ .endm
+
+ .macro drop
+ movq (%esi), %mm0
+ lea 8(%esi), %esi
+ .endm
+
+ .macro dropdup
+ movq (%esi), %mm0
+ .endm
+
+ .macro nipdup
+ movq %mm0, (%esi)
+ .endm
+
+ .macro swap
+ movq (%esi), %mm1
+ movq %mm0, (%esi)
+ movq %mm1, %mm0
+ .endm
+
+ .macro nip
+ lea 8(%esi), %esi
+ .endm
+
+ .macro dropover
+ movq 8(%esi), %mm0
+ .endm
+
+
+ # *************************** CA BOOLEAN LOGIC MACROS *****************************
+ # overxor overand overor not
+
+ .macro overxor
+ pxor (%esi), %mm0
+ .endm
+
+ .macro overand
+ pand (%esi), %mm0
+ .endm
+
+ .macro overor
+ por (%esi), %mm0
+ .endm
+
+ .macro not
+ pxor %mm3, %mm0
+ .endm
+
+
+
+ # *************************** CONSTANTS *****************************
+ # dropzero dropone
+
+ .macro dropzero
+ pxor %mm0, %mm0
+ .endm
+
+ .macro dropone
+ pcmpeqw %mm0, %mm0
+ .endm
+
+
+ # *************************** 4 BIT REG ACCESS ******************************
+ # dupsta0 - dupsta4 droplda0 - droplda4
+ # store bit in accumulator
+
+ # bit store
+
+ .macro dupsta0
+ movq %mm0, %mm4
+ .endm
+
+ .macro dupsta1
+ movq %mm0, %mm5
+ .endm
+
+ .macro dupsta2
+ movq %mm0, %mm6
+ .endm
+
+ .macro dupsta3
+ movq %mm0, %mm7
+ .endm
+
+ # load bit from accumulator
+
+ .macro droplda0
+ movq %mm4, %mm0
+ .endm
+
+ .macro droplda1
+ movq %mm5, %mm0
+ .endm
+
+ .macro droplda2
+ movq %mm6, %mm0
+ .endm
+
+ .macro droplda3
+ movq %mm7, %mm0
+ .endm
+
+
+ # *************************** LOAD 4 BIT CONSTANT IN REG ******************************
+ # a0000 - a1111
+
+ .macro ldbit0 value
+ .ifeq \value
+ movq %mm1, %mm4
+ .else
+ movq %mm3, %mm4
+ .endif
+ .endm
+
+ .macro ldbit1 value
+ .ifeq \value
+ movq %mm1, %mm5
+ .else
+ movq %mm3, %mm5
+ .endif
+ .endm
+
+ .macro ldbit2 value
+ .ifeq \value
+ movq %mm1, %mm6
+ .else
+ movq %mm3, %mm6
+ .endif
+ .endm
+
+ .macro ldbit3 value
+ .ifeq \value
+ movq %mm1, %mm7
+ .else
+ movq %mm3, %mm7
+ .endif
+ .endm
+
+ .macro ldbin b3 b2 b1 b0
+ pxor %mm1, %mm1
+ ldbit0 \b0
+ ldbit1 \b1
+ ldbit2 \b2
+ ldbit3 \b3
+ .endm
+
+ .macro a0000
+ ldbin 0 0 0 0
+ .endm
+
+ .macro a0001
+ ldbin 0 0 0 1
+ .endm
+
+ .macro a0010
+ ldbin 0 0 1 0
+ .endm
+
+ .macro a0011
+ ldbin 0 0 1 1
+ .endm
+
+ .macro a0100
+ ldbin 0 1 0 0
+ .endm
+
+ .macro a0101
+ ldbin 0 1 0 1
+ .endm
+
+ .macro a0110
+ ldbin 0 1 1 0
+ .endm
+
+ .macro a0111
+ ldbin 0 1 1 1
+ .endm
+
+ .macro a1000
+ ldbin 1 0 0 0
+ .endm
+
+ .macro a1001
+ ldbin 1 0 0 1
+ .endm
+
+ .macro a1010
+ ldbin 1 0 1 0
+ .endm
+
+ .macro a1011
+ ldbin 1 0 1 1
+ .endm
+
+ .macro a1100
+ ldbin 1 1 0 0
+ .endm
+
+ .macro a1101
+ ldbin 1 1 0 1
+ .endm
+
+ .macro a1110
+ ldbin 1 1 1 0
+ .endm
+
+ .macro a1111
+ ldbin 1 1 1 1
+ .endm
+
+
+
+
+ # *************************** 4 BIT COUNTER ******************************
+ # adds TOS to bit of counter and returns carry in TOS
+ #
+ # adb0 - adb3
+
+
+ .macro adb0
+ movq %mm4, %mm2
+ pxor %mm0, %mm4
+ pand %mm2, %mm0
+ .endm
+
+ .macro adb1
+ movq %mm5, %mm2
+ pxor %mm0, %mm5
+ pand %mm2, %mm0
+ .endm
+
+ .macro adb2
+ movq %mm6, %mm2
+ pxor %mm0, %mm6
+ pand %mm2, %mm0
+ .endm
+
+ .macro adb3
+ movq %mm7, %mm2
+ pxor %mm0, %mm7
+ pand %mm2, %mm0
+ .endm
+
+
+ # *************************** ACCUMULATOR TESTS ***************************
+ # dropisnonzero4 - dropisnonzero1
+
+ .macro dropisnonzero4
+ movq %mm4, %mm0
+ por %mm5, %mm0
+ por %mm6, %mm0
+ por %mm7, %mm0
+ .endm
+
+ .macro dropisnonzero3
+ movq %mm4, %mm0
+ por %mm5, %mm0
+ por %mm6, %mm0
+ .endm
+
+ .macro dropisnonzero2
+ movq %mm4, %mm0
+ por %mm5, %mm0
+ .endm
+
+ .macro dropisnonzero1
+ movq %mm4, %mm0
+ .endm
+
+
+ # *************************** REGISTER SHIFT OPERATIONS **********************
+ # shift and leave shifted out byte on stack
+ # rotate trough top of stack
+
+ .macro dropshiftright
+ movq %mm4, %mm0
+ movq %mm5, %mm4
+ movq %mm6, %mm5
+ movq %mm7, %mm6
+ pxor %mm7, %mm7
+ .endm
+
+ .macro dropshiftleft
+ movq %mm7, %mm0
+ movq %mm6, %mm7
+ movq %mm5, %mm6
+ movq %mm4, %mm5
+ pxor %mm4, %mm4
+ .endm
+
+ .macro dropshiftrighta
+ movq %mm4, %mm0
+ movq %mm5, %mm4
+ movq %mm6, %mm5
+ movq %mm7, %mm6
+ .endm
+
+ .macro rotateright
+ movq %mm4, %mm1
+ movq %mm5, %mm4
+ movq %mm6, %mm5
+ movq %mm7, %mm6
+ movq %mm1, %mm7
+ .endm
+
+ .macro rotateleft
+ movq %mm7, %mm1
+ movq %mm6, %mm7
+ movq %mm5, %mm6
+ movq %mm4, %mm5
+ movq %mm1, %mm4
+ .endm
+
+ .macro rotaterightstack
+ movq %mm0, %mm1
+ movq %mm4, %mm0
+ movq %mm5, %mm4
+ movq %mm6, %mm5
+ movq %mm7, %mm6
+ movq %mm1, %mm7
+ .endm
+
+ .macro rotateleftstack
+ movq %mm0, %mm1
+ movq %mm7, %mm0
+ movq %mm6, %mm7
+ movq %mm5, %mm6
+ movq %mm4, %mm5
+ movq %mm1, %mm4
+ .endm
+
+ # *************************** OTHER REGISTER OPERATIONS **********************
+ # anot : complement reg (can be used to implement subtraction)
+
+ .macro anot
+ pxor %mm3, %mm4
+ pxor %mm3, %mm5
+ pxor %mm3, %mm6
+ pxor %mm3, %mm7
+ .endm
diff --git a/scaf/test/test_pdp_ca.pd b/scaf/test/test_pdp_ca.pd
new file mode 100644
index 0000000..1b84312
--- /dev/null
+++ b/scaf/test/test_pdp_ca.pd
@@ -0,0 +1,132 @@
+#N canvas 650 350 625 557 10;
+#X obj 287 82 openpanel;
+#X msg 287 56 bang;
+#X msg 288 110 open \$1;
+#X obj 230 191 pdp_ca;
+#X obj 193 76 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 223 80 metro 40;
+#X msg 211 56 bang;
+#X msg 247 56 stop;
+#X obj 146 235 pdp_xv;
+#X obj 28 31 t b b b;
+#X obj 11 7 loadbang;
+#X msg 99 80 rule id;
+#X msg 328 155 ca 256 256;
+#X msg 256 296 rule shifttopright;
+#X msg 331 134 ca 64 64;
+#X msg 262 270 rule shiftleft;
+#X msg 298 216 random;
+#X msg 251 321 rule gameoflife;
+#X floatatom 344 52 5 0 0;
+#X msg 331 184 ca 1024 1024;
+#X floatatom 279 154 5 0 0;
+#X msg 357 106 ca 512 512;
+#X msg 363 80 ca 320 240;
+#X obj 211 120 pdp_v4l;
+#X obj 179 99 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 138 53 metro 40;
+#X msg 126 29 bang;
+#X msg 162 29 stop;
+#X floatatom 205 28 5 0 0;
+#X msg 243 348 rule w110;
+#X msg 245 371 rule w110mod;
+#X msg 54 371 rule w110mod2;
+#X msg 387 47 ca 640 394;
+#X obj 481 289 count;
+#X obj 397 248 route 0 1 2 3;
+#X floatatom 517 254 5 0 0;
+#X msg 466 184 bang;
+#X msg 502 184 stop;
+#X floatatom 552 171 5 0 0;
+#X obj 478 208 metro 1000;
+#X msg 258 403 rule golmod;
+#X floatatom 34 129 5 0 0;
+#X obj 90 207 pdp_bqt;
+#X msg 62 107 dim 64 64;
+#X msg 44 167 hpf \$1 0.5;
+#X msg 272 430 rule golmod2;
+#X msg 273 467 rule golmod3;
+#X msg 277 494 rule golmod4;
+#X msg 280 515 rule golmod5;
+#X msg 283 537 rule golmod6;
+#X msg 380 403 rule golmod7;
+#X obj 46 267 pdp_mix;
+#X floatatom 120 297 5 0 0;
+#X msg 61 462 type grey;
+#X msg 112 407 rule w110mod3;
+#X msg 64 490 type yv12;
+#X msg 438 471 dim 512 512;
+#X obj 270 134 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 463 111 ca 1024 512;
+#X msg 105 4 open /home/tom/pd/packet/scaf/modules/carules.scafo;
+#X msg 163 468 rule toomuch;
+#X msg 165 500 rule underflow;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 2 0 3 0;
+#X connect 3 0 8 0;
+#X connect 4 0 3 0;
+#X connect 5 0 3 0;
+#X connect 6 0 5 0;
+#X connect 7 0 5 0;
+#X connect 9 1 11 0;
+#X connect 9 2 59 0;
+#X connect 10 0 9 0;
+#X connect 11 0 3 0;
+#X connect 12 0 3 0;
+#X connect 13 0 3 0;
+#X connect 14 0 3 0;
+#X connect 15 0 3 0;
+#X connect 16 0 3 0;
+#X connect 17 0 3 0;
+#X connect 18 0 5 1;
+#X connect 19 0 3 0;
+#X connect 20 0 3 2;
+#X connect 21 0 3 0;
+#X connect 22 0 3 0;
+#X connect 23 0 51 1;
+#X connect 23 0 3 1;
+#X connect 24 0 23 0;
+#X connect 25 0 24 0;
+#X connect 26 0 25 0;
+#X connect 27 0 25 0;
+#X connect 28 0 25 1;
+#X connect 29 0 3 0;
+#X connect 30 0 3 0;
+#X connect 31 0 3 0;
+#X connect 32 0 3 0;
+#X connect 33 0 34 0;
+#X connect 34 0 30 0;
+#X connect 34 1 17 0;
+#X connect 34 2 40 0;
+#X connect 34 3 17 0;
+#X connect 35 0 33 1;
+#X connect 36 0 39 0;
+#X connect 37 0 39 0;
+#X connect 38 0 39 1;
+#X connect 39 0 33 0;
+#X connect 40 0 3 0;
+#X connect 41 0 44 0;
+#X connect 42 0 8 0;
+#X connect 43 0 23 0;
+#X connect 44 0 42 0;
+#X connect 45 0 3 0;
+#X connect 46 0 3 0;
+#X connect 47 0 3 0;
+#X connect 48 0 3 0;
+#X connect 49 0 3 0;
+#X connect 50 0 3 0;
+#X connect 51 0 8 0;
+#X connect 52 0 51 2;
+#X connect 53 0 23 0;
+#X connect 54 0 3 0;
+#X connect 55 0 23 0;
+#X connect 56 0 8 0;
+#X connect 57 0 20 0;
+#X connect 58 0 3 0;
+#X connect 59 0 3 0;
+#X connect 60 0 3 0;
+#X connect 61 0 3 0;
diff --git a/scaf/test/test_pdp_ca2.pd b/scaf/test/test_pdp_ca2.pd
new file mode 100644
index 0000000..8af44a8
--- /dev/null
+++ b/scaf/test/test_pdp_ca2.pd
@@ -0,0 +1,154 @@
+#N canvas 454 152 625 557 10;
+#X obj 325 83 openpanel;
+#X msg 325 57 bang;
+#X msg 326 111 open \$1;
+#X obj 428 234 pdp_ca;
+#X obj 256 149 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 223 80 metro 40;
+#X msg 211 56 bang;
+#X msg 247 56 stop;
+#X obj 402 407 pdp_xv;
+#X obj 28 31 t b b b;
+#X obj 11 7 loadbang;
+#X msg 391 99 ca 256 256;
+#X msg 394 78 ca 64 64;
+#X msg 298 216 random;
+#X msg 251 321 rule gameoflife;
+#X floatatom 490 187 5 0 0;
+#X msg 420 50 ca 512 512;
+#X obj 107 188 pdp_v4l;
+#X obj 97 127 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 243 348 rule w110;
+#X msg 245 371 rule w110mod;
+#X msg 258 403 rule golmod;
+#X msg 272 430 rule golmod2;
+#X msg 273 467 rule golmod3;
+#X msg 277 494 rule golmod4;
+#X msg 280 515 rule golmod5;
+#X msg 283 537 rule golmod6;
+#X obj 481 167 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 526 55 ca 1024 512;
+#X msg 105 4 open /home/tom/pd/packet/scaf/modules/carules.scafo;
+#X obj 426 294 pdp_ca2image;
+#X obj 104 228 pdp_image2ca;
+#X obj 136 155 metro 40;
+#X msg 124 131 bang;
+#X msg 160 131 stop;
+#X floatatom 510 273 5 0 0;
+#X obj 501 253 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 468 416 rule gameoflife;
+#X msg 450 455 rule golmod6;
+#X msg 380 440 rule golmod3;
+#X msg 159 287 rules;
+#X floatatom 27 213 5 0 0;
+#X msg 40 319 ruleindex \$1;
+#X obj 31 254 t b f;
+#X msg 52 78 rule gameoflife;
+#X floatatom 193 198 5 0 0;
+#X msg 504 143 close;
+#X msg 149 448 rule test1;
+#X obj 181 178 hsl 128 15 0 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X msg 5 129 dim 640 480;
+#X obj 156 51 pdp_qt;
+#X msg 174 23 open /home/ben/MOV/test1.mov;
+#X floatatom 93 31 5 0 0;
+#X msg 65 56 autoplay 1;
+#X obj 144 25 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 22 94 loop 1;
+#X obj 439 483 osc~ 150;
+#X obj 439 508 *~ 0.1;
+#X obj 437 536 dac~;
+#X floatatom 282 57 5 0 0;
+#X msg 503 113 ca 32 32;
+#X obj 428 322 pdp_motion_blur;
+#X obj 488 349 pdp_gradient;
+#X obj 425 382 pdp_mix;
+#X floatatom 508 380 5 0 0;
+#X floatatom 204 128 5 0 0;
+#X obj 39 399 pdp_control;
+#X obj 83 476 pdp_control;
+#X obj 84 519 print two;
+#X obj 39 438 print one;
+#X obj 275 149 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 265 128 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 38 374 thread \$1;
+#X obj 32 349 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 2 0 3 0;
+#X connect 3 0 30 0;
+#X connect 4 0 3 0;
+#X connect 5 0 3 0;
+#X connect 6 0 5 0;
+#X connect 7 0 5 0;
+#X connect 9 1 44 0;
+#X connect 9 2 29 0;
+#X connect 10 0 9 0;
+#X connect 11 0 3 0;
+#X connect 12 0 3 0;
+#X connect 13 0 3 0;
+#X connect 14 0 3 0;
+#X connect 15 0 3 2;
+#X connect 16 0 3 0;
+#X connect 17 0 31 0;
+#X connect 17 0 63 1;
+#X connect 18 0 17 0;
+#X connect 19 0 3 0;
+#X connect 20 0 3 0;
+#X connect 21 0 3 0;
+#X connect 22 0 3 0;
+#X connect 23 0 3 0;
+#X connect 24 0 3 0;
+#X connect 25 0 3 0;
+#X connect 26 0 3 0;
+#X connect 27 0 15 0;
+#X connect 28 0 3 0;
+#X connect 29 0 3 0;
+#X connect 30 0 62 0;
+#X connect 31 0 3 0;
+#X connect 32 0 17 0;
+#X connect 33 0 32 0;
+#X connect 34 0 32 0;
+#X connect 36 0 35 0;
+#X connect 40 0 3 0;
+#X connect 41 0 43 0;
+#X connect 42 0 3 0;
+#X connect 43 0 13 0;
+#X connect 43 1 42 0;
+#X connect 44 0 3 0;
+#X connect 45 0 31 1;
+#X connect 46 0 3 0;
+#X connect 47 0 3 0;
+#X connect 48 0 45 0;
+#X connect 49 0 17 0;
+#X connect 50 0 31 0;
+#X connect 51 0 50 0;
+#X connect 52 0 50 0;
+#X connect 53 0 50 0;
+#X connect 54 0 50 0;
+#X connect 55 0 50 0;
+#X connect 56 0 57 0;
+#X connect 57 0 58 0;
+#X connect 57 0 58 1;
+#X connect 59 0 5 1;
+#X connect 60 0 3 0;
+#X connect 62 0 63 0;
+#X connect 63 0 8 0;
+#X connect 64 0 63 2;
+#X connect 65 0 32 1;
+#X connect 66 0 69 0;
+#X connect 67 0 68 0;
+#X connect 70 0 3 0;
+#X connect 71 0 4 0;
+#X connect 71 0 70 0;
+#X connect 72 0 66 0;
+#X connect 73 0 72 0;
diff --git a/system/Makefile b/system/Makefile
new file mode 100644
index 0000000..acdb944
--- /dev/null
+++ b/system/Makefile
@@ -0,0 +1,20 @@
+target: all_objects
+
+include ../Makefile.config
+include Makefile.$(PDP_TARGET)
+
+
+
+OBJECTS = pdp.o pdp_ut.o pdp_packet.o pdp_type.o pdp_queue.o pdp_comm.o \
+ pdp_control.o pdp_llconv.o pdp_resample.o
+
+pdp_main_clean:
+ rm -f pdp.o
+
+all_objects: pdp_main_clean $(OBJECTS) platform_targets
+
+clean:
+ rm -f *~
+ rm -f *.o
+ make -C mmx clean
+
diff --git a/system/Makefile.linux b/system/Makefile.linux
new file mode 100644
index 0000000..96660f7
--- /dev/null
+++ b/system/Makefile.linux
@@ -0,0 +1,2 @@
+platform_targets: pdp_imageproc_portable.o pdp_llconv_portable.o
+
diff --git a/system/Makefile.linux_mmx b/system/Makefile.linux_mmx
new file mode 100644
index 0000000..a646e5e
--- /dev/null
+++ b/system/Makefile.linux_mmx
@@ -0,0 +1,4 @@
+platform_subtree:
+ make -C mmx
+
+platform_targets: pdp_imageproc_mmx.o pdp_llconv_mmx.o platform_subtree
diff --git a/system/mmx/Makefile b/system/mmx/Makefile
new file mode 100644
index 0000000..0f8f836
--- /dev/null
+++ b/system/mmx/Makefile
@@ -0,0 +1,29 @@
+include ../../Makefile.config
+
+OBJ = \
+pixel_pack_s16u8.o \
+pixel_unpack_u8s16.o \
+pixel_add_s16.o \
+pixel_mul_s16.o \
+pixel_mix_s16.o \
+pixel_randmix_s16.o \
+pixel_conv_hor_s16.o \
+pixel_conv_ver_s16.o \
+pixel_affine_s16.o \
+pixel_biquad_s16.o \
+pixel_ca_s1.o \
+pixel_rand_s16.o \
+pixel_crot_s16.o \
+pixel_gain_s16.o
+
+all: $(OBJ)
+
+test: pdp_mmx_test.o $(OBJ)
+ gcc -o pdp_mmx_test pdp_mmx_test.o $(OBJ) -g
+
+clean:
+ rm -f *.o
+ rm -f *~
+ rm -f pdp_mmx.a
+ rm -f pdp_mmx_test
+
diff --git a/system/mmx/pdp_mmx_test.c b/system/mmx/pdp_mmx_test.c
new file mode 100644
index 0000000..e93539f
--- /dev/null
+++ b/system/mmx/pdp_mmx_test.c
@@ -0,0 +1,62 @@
+#include "pdp_mmx.h"
+
+#define FP(x) ((short int)(((float)(x) * 2 * 256.0f)))
+
+#define nbp 256
+
+ short int a1[4] = {0x0100,0x0100,0x0100,0x0100};
+ short int a2[4] = {0x0100,0x0100,0x0100,0x0100};
+ short int b0[4] = {0x0100,0x0100,0x0100,0x0100};
+ short int b1[4] = {0x0100,0x0100,0x0100,0x0100};
+ short int b2[4] = {0x0100,0x0100,0x0100,0x0100};
+
+ short int u1[4] = {0x0100,0x0100,0x0100,0x0100};
+ short int u2[4] = {0x0100,0x0100,0x0100,0x0100};
+
+ short int x0[4] = {0x0100,0x0100,0x0100,0x0100};
+ short int x1[4] = {0x0100,0x0100,0x0100,0x0100};
+ short int x2[4] = {0x0100,0x0100,0x0100,0x0100};
+ short int x3[4] = {0x0100,0x0100,0x0100,0x0100};
+
+void print_pixel(unsigned int i)
+{
+ if (i) printf("x ");
+ else printf(". ");
+}
+
+void print_line(void)
+{
+ printf("\n");
+}
+
+void print_square(unsigned char *c)
+{
+ int i,j;
+
+ for(j=7; j>=0; j--){
+ for(i=0; i<8; i++) print_pixel(c[j] & (1<<(7-i)));
+ printf("\n");
+ }
+
+}
+
+main()
+{
+
+ unsigned char src[16]={1,2,3,4,5,6,7,8,-1,-2,-3,-4,-5,-6,-7,-8};
+ unsigned char dst[8];
+
+
+ print_square(src);
+ print_line();
+ print_square(src+8);
+ print_line();
+
+ pixel_test_s1(dst,src,1,1);
+
+ print_square(dst);
+ print_line();
+
+
+
+}
diff --git a/system/mmx/pixel_add_s16.s b/system/mmx/pixel_add_s16.s
new file mode 100644
index 0000000..8d4c7df
--- /dev/null
+++ b/system/mmx/pixel_add_s16.s
@@ -0,0 +1,55 @@
+# Pure Data Packet mmx routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+.globl pixel_add_s16
+.type pixel_add_s16,@function
+
+# simple add
+# void pixel_add_s16(int *left, int *right, int nb_4pixel_vectors)
+
+pixel_add_s16:
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+ movl 8(%ebp), %edi # left array
+ movl 12(%ebp), %esi # right array
+ movl 16(%ebp), %ecx # pixel count
+
+
+ .align 16
+ .loop_mix:
+
+# prefetch 128(%esi)
+ movq (%esi), %mm1 # load right 4 pixels from memory
+ movq (%edi), %mm0 # load 4 left pixels from memory
+ paddsw %mm1, %mm0 # mix
+ movq %mm0, (%edi)
+ addl $8, %esi
+ addl $8, %edi
+ decl %ecx
+ jnz .loop_mix # loop
+
+ emms
+
+
+ pop %edi
+ pop %esi
+ leave
+ ret
+
diff --git a/system/mmx/pixel_affine_s16.s b/system/mmx/pixel_affine_s16.s
new file mode 100644
index 0000000..b357de3
--- /dev/null
+++ b/system/mmx/pixel_affine_s16.s
@@ -0,0 +1,59 @@
+# Pure Data Packet mmx routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+.globl pixel_affine_s16
+.type pixel_affine_s16,@function
+
+# void pixel_affine_s16(int *buf, int nb_8pixel_vectors, short int gain[4], short int offset[4])
+
+pixel_affine_s16:
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+ movl 20(%ebp), %edi
+ movq (%edi), %mm6 # get offset vector
+
+ movl 16(%ebp), %edi
+ movq (%edi), %mm7 # get gain vector
+
+ movl 8(%ebp), %esi # input array
+ movl 12(%ebp), %ecx # pixel count
+
+
+ .align 16
+ .loop_affine:
+
+# prefetch 128(%esi)
+ movq (%esi), %mm0 # load 4 pixels from memory
+ pmulhw %mm7, %mm0 # apply gain (s).15 fixed point
+ psllw $1, %mm0 # apply correction shift
+ paddsw %mm6, %mm0 # add offset
+ movq %mm0, (%esi) # store result in memory
+
+ addl $8, %esi # increment source pointer
+ decl %ecx
+ jnz .loop_affine # loop
+
+ emms
+
+ pop %edi
+ pop %esi
+ leave
+ ret
+
diff --git a/system/mmx/pixel_biquad_dirI_s16.s b/system/mmx/pixel_biquad_dirI_s16.s
new file mode 100644
index 0000000..1729502
--- /dev/null
+++ b/system/mmx/pixel_biquad_dirI_s16.s
@@ -0,0 +1,361 @@
+# Pure Data Packet mmx routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+
+ # TODO MOVE TO DIRECT FORM II
+ # y[k] = b0 * x[k] + u1[k-1]
+ # u1[k] = b1 * x[k] + u2[k-1] - a1 * y[k]
+ # u2[k] = b2 * x[k] - a2 * y[k]
+
+ # input in register:
+ # %mm0-mm3: input 4x4 pixels {x0 x1 x2 x3}
+ # %esi: coef memory (a1, a2, b0, b1, b2)
+ # %edi: state memory (u1, u2)
+
+
+ # return in register:
+ # %mm0-mm4: 4x4 pixels result
+
+
+ .biquad_4x4_pixels:
+ .align 16
+ # prescale
+ movq -8(%esi), %mm4
+ pmulhw %mm4, %mm0
+ pmulhw %mm4, %mm1
+ pmulhw %mm4, %mm2
+ pmulhw %mm4, %mm3
+ psllw $1, %mm0
+ psllw $1, %mm1
+ psllw $1, %mm2
+ psllw $1, %mm3
+
+
+ # first vector
+ movq 0(%edi), %mm4 # mm4 <- u[-1]
+ movq 8(%edi), %mm5 # mm5 <- u[-2]
+ movq %mm4, %mm6
+ movq %mm5, %mm7
+
+ pmulhw 0(%esi), %mm6 # multiply by a1
+ pmulhw 8(%esi), %mm7 # multiply by a2
+
+ paddsw %mm6, %mm0 # accumulate
+ paddsw %mm7, %mm0 # accumulate
+ paddsw %mm0, %mm0 # scale by 2 (since all fixed point muls are x*y/2)
+
+ movq %mm0, %mm6 # mm6 <- u[0]
+ movq %mm4, %mm7 # mm7 <- u[-1]
+ pmulhw 16(%esi), %mm0 # multiply by b0
+ pmulhw 24(%esi), %mm4 # multiply by b1
+ pmulhw 32(%esi), %mm5 # multiply by b2
+
+ paddsw %mm4, %mm0 # accumulate
+ paddsw %mm5, %mm0 # accumulate
+
+ # mm0 is result 0
+
+ # second vector
+ movq %mm6, %mm4 # mm4 <- u[0]
+ movq %mm7, %mm5 # mm5 <- u[-1]
+
+ pmulhw 0(%esi), %mm6 # multiply by a1
+ pmulhw 8(%esi), %mm7 # multiply by a2
+
+ paddsw %mm6, %mm1 # accumulate
+ paddsw %mm7, %mm1 # accumulate
+ paddsw %mm1, %mm1 # scale by 2
+
+
+ movq %mm1, %mm6 # mm6 <- u[1]
+ movq %mm4, %mm7 # mm7 <- u[0]
+ pmulhw 16(%esi), %mm1 # multiply by b0
+ pmulhw 24(%esi), %mm4 # multiply by b1
+ pmulhw 32(%esi), %mm5 # multiply by b2
+
+ paddsw %mm4, %mm1 # accumulate
+ paddsw %mm5, %mm1 # accumulate
+
+ # mm1 is result 1
+
+ # third vector
+ movq %mm6, %mm4 # mm4 <- u[1]
+ movq %mm7, %mm5 # mm5 <- u[0]
+
+ pmulhw 0(%esi), %mm6 # multiply by a1
+ pmulhw 8(%esi), %mm7 # multiply by a2
+
+ paddsw %mm6, %mm2 # accumulate
+ paddsw %mm7, %mm2 # accumulate
+ paddsw %mm2, %mm2 # scale by 2
+
+
+ movq %mm2, %mm6 # mm6 <- u[2]
+ movq %mm4, %mm7 # mm7 <- u[1]
+ pmulhw 16(%esi), %mm2 # multiply by b0
+ pmulhw 24(%esi), %mm4 # multiply by b1
+ pmulhw 32(%esi), %mm5 # multiply by b2
+
+ paddsw %mm4, %mm2 # accumulate
+ paddsw %mm5, %mm2 # accumulate
+
+ # mm2 is result 2
+
+ # fourth vector
+ movq %mm6, %mm4 # mm4 <- u[2]
+ movq %mm7, %mm5 # mm5 <- u[1]
+
+ pmulhw 0(%esi), %mm6 # multiply by a1
+ pmulhw 8(%esi), %mm7 # multiply by a2
+
+ paddsw %mm6, %mm3 # accumulate
+ paddsw %mm7, %mm3 # accumulate
+ paddsw %mm3, %mm3 # scale by 2
+
+
+ movq %mm3, 0(%edi) # store u[3]
+ movq %mm4, 8(%edi) # store u[2]
+ pmulhw 16(%esi), %mm3 # multiply by b0
+ pmulhw 24(%esi), %mm4 # multiply by b1
+ pmulhw 32(%esi), %mm5 # multiply by b2
+
+ paddsw %mm4, %mm3 # accumulate
+ paddsw %mm5, %mm3 # accumulate
+
+ # mm3 is result 3
+
+ ret
+
+
+ # in order to use the 4 line parallel biquad routine on horizontal
+ # lines, we need to reorder (rotate or transpose) the matrix, since
+ # images are scanline encoded, and we want to work in parallell
+ # on 4 lines.
+ #
+ # since the 4 lines are independent, it doesnt matter in which order
+ # the the vector elements are present.
+ #
+ # this allows us to use the same routine for left->right and right->left
+ # processing.
+ #
+ # some comments on the non-abelean group of square isometries consisting of
+ # (I) identity
+ # (H) horizontal axis mirror
+ # (V) vertical axis mirror
+ # (T) transpose (diagonal axis mirror)
+ # (A) antitranspose (antidiagonal axis mirror)
+ # (R1) 90deg anticlockwize rotation
+ # (R2) 180deg rotation
+ # (R3) 90deg clockwize rotation
+ #
+ #
+ # we basicly have two options: (R1,R3) or (T,A)
+ # we opt for T and A because they are self inverting, which improves locality
+ #
+ # use antitranspose for right to left an transpose
+ # for left to right (little endian)
+
+
+ # antitranspose 4x4
+
+ # input
+ # %mm3 == {d0 d1 d2 d3}
+ # %mm2 == {c0 c1 c2 c3}
+ # %mm1 == {b0 b1 b2 b3}
+ # %mm0 == {a0 a1 a2 a3}
+
+ # output
+ # %mm3 == {a3 b3 c3 d3}
+ # %mm2 == {a2 b2 c2 d2}
+ # %mm1 == {a1 b1 c1 d1}
+ # %mm0 == {a0 b0 c0 d0}
+
+
+ .antitranspose_4x4:
+ .align 16
+ movq %mm3, %mm4
+ punpcklwd %mm1, %mm4 # mm4 <- {b2 d2 b3 d3}
+ movq %mm3, %mm5
+ punpckhwd %mm1, %mm5 # mm5 <- {b0 d0 b1 d1}
+
+ movq %mm2, %mm6
+ punpcklwd %mm0, %mm6 # mm6 <- {a2 c2 a3 c3}
+ movq %mm2, %mm7
+ punpckhwd %mm0, %mm7 # mm7 <- {a0 c0 a1 c1}
+
+ movq %mm4, %mm3
+ punpcklwd %mm6, %mm3 # mm3 <- {a3 b3 c3 d3}
+ movq %mm4, %mm2
+ punpckhwd %mm6, %mm2 # mm2 <- {a2 b2 c2 d2}
+
+ movq %mm5, %mm1
+ punpcklwd %mm7, %mm1 # mm1 <- {a1 b1 c1 d1}
+ movq %mm5, %mm0
+ punpckhwd %mm7, %mm0 # mm0 <- {a0 b0 c0 d0}
+
+ ret
+
+
+
+ # transpose 4x4
+
+ # input
+ # %mm3 == {d3 d2 d1 d0}
+ # %mm2 == {c3 c2 c1 c0}
+ # %mm1 == {b3 b2 b1 b0}
+ # %mm0 == {a3 a2 a1 a0}
+
+ # output
+ # %mm3 == {d3 c3 b3 a3}
+ # %mm2 == {d2 c2 b2 a2}
+ # %mm1 == {d1 c1 b1 a1}
+ # %mm0 == {d0 c0 b0 a0}
+
+
+ .transpose_4x4:
+ .align 16
+ movq %mm0, %mm4
+ punpcklwd %mm2, %mm4 # mm4 <- {c1 a1 c0 a0}
+ movq %mm0, %mm5
+ punpckhwd %mm2, %mm5 # mm5 <- {c3 a3 c2 a2}
+
+ movq %mm1, %mm6
+ punpcklwd %mm3, %mm6 # mm6 <- {d1 b1 d0 b0}
+ movq %mm1, %mm7
+ punpckhwd %mm3, %mm7 # mm7 <- {d3 b3 d2 b2}
+
+ movq %mm4, %mm0
+ punpcklwd %mm6, %mm0 # mm0 <- {d0 c0 b0 a0}
+ movq %mm4, %mm1
+ punpckhwd %mm6, %mm1 # mm1 <- {d1 c1 b1 a1}
+
+ movq %mm5, %mm2
+ punpcklwd %mm7, %mm2 # mm2 <- {d2 c2 b2 a2}
+ movq %mm5, %mm3
+ punpckhwd %mm7, %mm3 # mm3 <- {d3 c3 b3 a3}
+
+ ret
+
+
+.globl pixel_biquad_vertb_s16
+.type pixel_biquad_vertb_s16,@function
+
+
+# pixel_biquad_vertbr_s16(char *pixel_array, int nb_rows, int linewidth, short int coef[20], short int state[8])
+
+
+pixel_biquad_vertb_s16:
+
+
+ pushl %ebp
+ movl %esp, %ebp
+ push %ebx
+ push %esi
+ push %edi
+
+ movl 8(%ebp), %ebx # pixel array offset
+ movl 12(%ebp), %ecx # nb of 4x4 pixblocks
+ movl 16(%ebp), %edx # line with
+
+ movl 20(%ebp), %esi # coefs
+ movl 24(%ebp), %edi # state
+
+ shll $1, %edx # short int addressing
+ movl %edx, %eax
+ shll $1, %eax
+ addl %edx, %eax # eax = 3 * edx
+
+ .align 16
+ .biquad_vertb_line_loop:
+ movq (%ebx), %mm0
+ movq (%ebx,%edx,1), %mm1
+ movq (%ebx,%edx,2), %mm2
+ movq (%ebx,%eax,1), %mm3
+ call .biquad_4x4_pixels
+ movq %mm0, (%ebx)
+ movq %mm1, (%ebx,%edx,1)
+ movq %mm2, (%ebx,%edx,2)
+ movq %mm3, (%ebx,%eax,1)
+ addl %edx, %ebx
+ addl %eax, %ebx
+ decl %ecx
+ jnz .biquad_vertb_line_loop
+
+ emms
+
+ pop %edi
+ pop %esi
+ pop %ebx
+ leave
+ ret
+
+.globl pixel_biquad_horlr_s16
+.type pixel_biquad_horlr_s16,@function
+
+
+# pixel_biquad_hor_s16(char *pixel_array, int nb_rows, int linewidth, short int coef[20], short int state[8])
+
+
+pixel_biquad_horlr_s16:
+
+
+ pushl %ebp
+ movl %esp, %ebp
+ push %ebx
+ push %esi
+ push %edi
+
+ movl 8(%ebp), %ebx # pixel array offset
+ movl 12(%ebp), %ecx # nb of 4x4 pixblocks
+ movl 16(%ebp), %edx # line with
+
+ movl 20(%ebp), %esi # coefs
+ movl 24(%ebp), %edi # state
+
+ shll $1, %edx # short int addressing
+ movl %edx, %eax
+ shll $1, %eax
+ addl %edx, %eax # eax = 3 * edx
+
+ .align 16
+ .biquad_horlr_line_loop:
+ movq (%ebx), %mm0
+ movq (%ebx,%edx,1), %mm1
+ movq (%ebx,%edx,2), %mm2
+ movq (%ebx,%eax,1), %mm3
+ call .transpose_4x4
+ call .biquad_4x4_pixels
+ call .transpose_4x4
+ movq %mm0, (%ebx)
+ movq %mm1, (%ebx,%edx,1)
+ movq %mm2, (%ebx,%edx,2)
+ movq %mm3, (%ebx,%eax,1)
+ addl $8, %ebx
+ decl %ecx
+ jnz .biquad_horlr_line_loop
+
+ emms
+
+ pop %edi
+ pop %esi
+ pop %ebx
+ leave
+ ret
+
+
+
diff --git a/system/mmx/pixel_biquad_s16.s b/system/mmx/pixel_biquad_s16.s
new file mode 100644
index 0000000..844b041
--- /dev/null
+++ b/system/mmx/pixel_biquad_s16.s
@@ -0,0 +1,451 @@
+# Pure Data Packet mmx routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+
+ # DIRECT FORM II BIQUAD
+ #
+ # y[k] = b0 * x[k] + u1[k-1]
+ # u1[k] = b1 * x[k] + u2[k-1] - a1 * y[k]
+ # u2[k] = b2 * x[k] - a2 * y[k]
+ # MACRO: df2 <reg>
+ #
+ # computes a direct form 2 biquad
+ # does not use {mm0-mm3}\<inreg>
+ #
+ # input: <reg> == input
+ # %mm4 == state 1
+ # %mm5 == state 2
+ # (%esi) == biquad coefs (-a1 -a2 b0 b1 b2) in s1.14
+ # output: <reg> == output
+ # %mm4 == state 1
+ # %mm5 == state 2
+
+ .macro df2 reg
+ movq \reg, %mm6 # mm6 == x[k]
+ movq \reg, %mm7 # mm7 == x[k]
+ pmulhw 16(%esi), %mm6 # mm6 == x[k] * b0
+ pmulhw 24(%esi), %mm7 # mm7 == x[k] * b1
+ paddw %mm4, %mm6 # mm6 == x[k] * b0 + u1[k-1] == y[k]
+ paddw %mm5, %mm7 # mm7 == x[k] * b1 + u2[k-1]
+ paddsw %mm6, %mm6 # compensate for mul = x*y/4 (coefs are s1.14 fixed point)
+ paddsw %mm6, %mm6 # paddsw ensures saturation
+ movq \reg, %mm5 # mm5 == x[k]
+ movq %mm6, %mm4 # mm4 == y[k]
+ movq %mm6, \reg # reg == y[k] --------------------
+ pmulhw 0(%esi), %mm4 # mm4 == y[k] * (-a1)
+ pmulhw 8(%esi), %mm6 # mm6 == y[k] * (-a2)
+ pmulhw 32(%esi), %mm5 # mm5 == x[k] * b2
+ paddw %mm7, %mm4 # mm4 == u1[k] --------------------
+ paddw %mm6, %mm5 # mm5 == u2[k] --------------------
+ .endm
+
+
+ # input in register:
+ # %mm0-mm3: input 4x4 pixels {x0 x1 x2 x3}
+ # %esi: coef memory (-a1, -a2, b0, b1, b2) in s1.14
+ # %edi: state memory (u1, u2)
+
+ # return in register:
+ # %mm0-mm4: 4x4 pixels result
+
+
+
+
+ .macro biquad_4x4_pixels
+ .align 16
+ movq 0(%edi), %mm4 # get state
+ movq 8(%edi), %mm5
+ df2 %mm0 # compute 4 biquads
+ df2 %mm1
+ df2 %mm2
+ df2 %mm3
+ movq %mm4, 0(%edi) # store state
+ movq %mm5, 8(%edi)
+ .endm
+
+
+
+ # in order to use the 4 line parallel biquad routine on horizontal
+ # lines, we need to reorder (rotate or transpose) the matrix, since
+ # images are scanline encoded, and we want to work in parallell
+ # on 4 lines.
+ #
+ # since the 4 lines are independent, it doesnt matter in which order
+ # the the vector elements are present.
+ #
+ # this allows us to use the same routine for left->right and right->left
+ # processing.
+ #
+ # some comments on the non-abelean group of square isometries consisting of
+ # (I) identity
+ # (H) horizontal axis mirror
+ # (V) vertical axis mirror
+ # (T) transpose (diagonal axis mirror)
+ # (A) antitranspose (antidiagonal axis mirror)
+ # (R1) 90deg anticlockwize rotation
+ # (R2) 180deg rotation
+ # (R3) 90deg clockwize rotation
+ #
+ #
+ # we basicly have two options: (R1,R3) or (T,A)
+ # we opt for T and A because they are self inverting, which improves locality
+ #
+ # use antitranspose for right to left an transpose
+ # for left to right (little endian)
+
+
+ # antitranspose 4x4
+
+ # input
+ # %mm3 == {d0 d1 d2 d3}
+ # %mm2 == {c0 c1 c2 c3}
+ # %mm1 == {b0 b1 b2 b3}
+ # %mm0 == {a0 a1 a2 a3}
+
+ # output
+ # %mm3 == {a3 b3 c3 d3}
+ # %mm2 == {a2 b2 c2 d2}
+ # %mm1 == {a1 b1 c1 d1}
+ # %mm0 == {a0 b0 c0 d0}
+
+
+ .macro antitranspose_4x4:
+ movq %mm3, %mm4
+ punpcklwd %mm1, %mm4 # mm4 <- {b2 d2 b3 d3}
+ movq %mm3, %mm5
+ punpckhwd %mm1, %mm5 # mm5 <- {b0 d0 b1 d1}
+
+ movq %mm2, %mm6
+ punpcklwd %mm0, %mm6 # mm6 <- {a2 c2 a3 c3}
+ movq %mm2, %mm7
+ punpckhwd %mm0, %mm7 # mm7 <- {a0 c0 a1 c1}
+
+ movq %mm4, %mm3
+ punpcklwd %mm6, %mm3 # mm3 <- {a3 b3 c3 d3}
+ movq %mm4, %mm2
+ punpckhwd %mm6, %mm2 # mm2 <- {a2 b2 c2 d2}
+
+ movq %mm5, %mm1
+ punpcklwd %mm7, %mm1 # mm1 <- {a1 b1 c1 d1}
+ movq %mm5, %mm0
+ punpckhwd %mm7, %mm0 # mm0 <- {a0 b0 c0 d0}
+
+ .endm
+
+
+ # transpose 4x4
+
+ # input
+ # %mm3 == {d3 d2 d1 d0}
+ # %mm2 == {c3 c2 c1 c0}
+ # %mm1 == {b3 b2 b1 b0}
+ # %mm0 == {a3 a2 a1 a0}
+
+ # output
+ # %mm3 == {d3 c3 b3 a3}
+ # %mm2 == {d2 c2 b2 a2}
+ # %mm1 == {d1 c1 b1 a1}
+ # %mm0 == {d0 c0 b0 a0}
+
+
+ .macro transpose_4x4:
+ movq %mm0, %mm4
+ punpcklwd %mm2, %mm4 # mm4 <- {c1 a1 c0 a0}
+ movq %mm0, %mm5
+ punpckhwd %mm2, %mm5 # mm5 <- {c3 a3 c2 a2}
+
+ movq %mm1, %mm6
+ punpcklwd %mm3, %mm6 # mm6 <- {d1 b1 d0 b0}
+ movq %mm1, %mm7
+ punpckhwd %mm3, %mm7 # mm7 <- {d3 b3 d2 b2}
+
+ movq %mm4, %mm0
+ punpcklwd %mm6, %mm0 # mm0 <- {d0 c0 b0 a0}
+ movq %mm4, %mm1
+ punpckhwd %mm6, %mm1 # mm1 <- {d1 c1 b1 a1}
+
+ movq %mm5, %mm2
+ punpcklwd %mm7, %mm2 # mm2 <- {d2 c2 b2 a2}
+ movq %mm5, %mm3
+ punpckhwd %mm7, %mm3 # mm3 <- {d3 c3 b3 a3}
+
+ .endm
+
+.globl pixel_biquad_vertb_s16
+.type pixel_biquad_vertb_s16,@function
+
+
+# pixel_biquad_vertbr_s16(char *pixel_array, int nb_rows, int linewidth, short int coef[20], short int state[8])
+
+
+pixel_biquad_vertb_s16:
+
+
+ pushl %ebp
+ movl %esp, %ebp
+ push %ebx
+ push %esi
+ push %edi
+
+ movl 8(%ebp), %ebx # pixel array offset
+ movl 12(%ebp), %ecx # nb of 4x4 pixblocks
+ movl 16(%ebp), %edx # line with
+
+ movl 20(%ebp), %esi # coefs
+ movl 24(%ebp), %edi # state
+
+ shll $1, %edx # short int addressing
+ movl %edx, %eax
+ shll $1, %eax
+ addl %edx, %eax # eax = 3 * edx
+
+ .align 16
+ .biquad_vertb_line_loop:
+ movq (%ebx), %mm0
+ movq (%ebx,%edx,1), %mm1
+ movq (%ebx,%edx,2), %mm2
+ movq (%ebx,%eax,1), %mm3
+ biquad_4x4_pixels
+ movq %mm0, (%ebx)
+ movq %mm1, (%ebx,%edx,1)
+ movq %mm2, (%ebx,%edx,2)
+ movq %mm3, (%ebx,%eax,1)
+ addl %edx, %ebx
+ addl %eax, %ebx
+ decl %ecx
+ jnz .biquad_vertb_line_loop
+
+ emms
+
+ pop %edi
+ pop %esi
+ pop %ebx
+ leave
+ ret
+.globl pixel_biquad_verbt_s16
+.type pixel_biquad_verbt_s16,@function
+
+
+# pixel_biquad_vertbt_s16(char *pixel_array, int nb_rows, int linewidth, short int coef[20], short int state[8])
+
+
+pixel_biquad_verbt_s16:
+
+
+ pushl %ebp
+ movl %esp, %ebp
+ push %ebx
+ push %esi
+ push %edi
+
+ movl 8(%ebp), %ebx # pixel array offset
+ movl 12(%ebp), %ecx # nb of 4x4 pixblocks
+ movl 16(%ebp), %eax # line with
+
+ shll $3, %eax # 4 line byte spacing
+ decl %ecx
+ mul %ecx
+ incl %ecx
+ addl %eax, %ebx # ebx points to last pixblock
+
+ movl 16(%ebp), %edx # line with
+
+ movl 20(%ebp), %esi # coefs
+ movl 24(%ebp), %edi # state
+
+ shll $1, %edx # short int addressing
+ movl %edx, %eax
+ shll $1, %eax
+ addl %edx, %eax # eax = 3 * edx
+
+ .align 16
+ .biquad_verbt_line_loop:
+ movq (%ebx), %mm3
+ movq (%ebx,%edx,1), %mm2
+ movq (%ebx,%edx,2), %mm1
+ movq (%ebx,%eax,1), %mm0
+ biquad_4x4_pixels
+ movq %mm3, (%ebx)
+ movq %mm2, (%ebx,%edx,1)
+ movq %mm1, (%ebx,%edx,2)
+ movq %mm0, (%ebx,%eax,1)
+ subl %edx, %ebx
+ subl %eax, %ebx
+ decl %ecx
+ jnz .biquad_verbt_line_loop
+
+ emms
+
+ pop %edi
+ pop %esi
+ pop %ebx
+ leave
+ ret
+
+.globl pixel_biquad_horlr_s16
+.type pixel_biquad_horlr_s16,@function
+# pixel_biquad_hor_s16(char *pixel_array, int nb_rows, int linewidth, short int coef[20], short int state[8])
+
+pixel_biquad_horlr_s16:
+
+
+ pushl %ebp
+ movl %esp, %ebp
+ push %ebx
+ push %esi
+ push %edi
+
+ movl 8(%ebp), %ebx # pixel array offset
+ movl 12(%ebp), %ecx # nb of 4x4 pixblocks
+ movl 16(%ebp), %edx # line with
+
+ movl 20(%ebp), %esi # coefs
+ movl 24(%ebp), %edi # state
+
+ shll $1, %edx # short int addressing
+ movl %edx, %eax
+ shll $1, %eax
+ addl %edx, %eax # eax = 3 * edx
+
+ .align 16
+ .biquad_horlr_line_loop:
+ movq (%ebx), %mm0
+ movq (%ebx,%edx,1), %mm1
+ movq (%ebx,%edx,2), %mm2
+ movq (%ebx,%eax,1), %mm3
+ transpose_4x4
+ biquad_4x4_pixels
+ transpose_4x4
+ movq %mm0, (%ebx)
+ movq %mm1, (%ebx,%edx,1)
+ movq %mm2, (%ebx,%edx,2)
+ movq %mm3, (%ebx,%eax,1)
+ addl $8, %ebx
+ decl %ecx
+ jnz .biquad_horlr_line_loop
+
+ emms
+
+ pop %edi
+ pop %esi
+ pop %ebx
+ leave
+ ret
+
+
+.globl pixel_biquad_horrl_s16
+.type pixel_biquad_horrl_s16,@function
+# pixel_biquad_horrl_s16(char *pixel_array, int nb_rows, int linewidth, short int coef[20], short int state[8])
+
+pixel_biquad_horrl_s16:
+
+ pushl %ebp
+ movl %esp, %ebp
+ push %ebx
+ push %esi
+ push %edi
+
+ movl 8(%ebp), %ebx # pixel array offset
+ movl 12(%ebp), %ecx # nb of 4x4 pixblocks
+ movl 16(%ebp), %edx # line with
+
+
+ movl %ecx, %eax
+ decl %eax
+ shll $3, %eax
+ addl %eax, %ebx # ebx points to last pixblock
+
+
+ movl 20(%ebp), %esi # coefs
+ movl 24(%ebp), %edi # state
+
+ shll $1, %edx # short int addressing
+ movl %edx, %eax
+ shll $1, %eax
+ addl %edx, %eax # eax = 3 * edx
+
+ .align 16
+ .biquad_horrl_line_loop:
+ movq (%ebx), %mm0
+ movq (%ebx,%edx,1), %mm1
+ movq (%ebx,%edx,2), %mm2
+ movq (%ebx,%eax,1), %mm3
+ antitranspose_4x4
+ biquad_4x4_pixels
+ antitranspose_4x4
+ movq %mm0, (%ebx)
+ movq %mm1, (%ebx,%edx,1)
+ movq %mm2, (%ebx,%edx,2)
+ movq %mm3, (%ebx,%eax,1)
+ subl $8, %ebx
+ decl %ecx
+ jnz .biquad_horrl_line_loop
+
+ emms
+
+ pop %edi
+ pop %esi
+ pop %ebx
+ leave
+ ret
+
+
+.globl pixel_biquad_time_s16
+.type pixel_biquad_time_s16,@function
+# pixel_biquad_time_s16(short int *pixel_array, short int *s1, short int *s2, short int *coefs, int nb_4_pix_vectors)
+
+pixel_biquad_time_s16:
+
+ pushl %ebp
+ movl %esp, %ebp
+ push %ebx
+ push %esi
+ push %edi
+
+ movl 8(%ebp), %ebx # pixel array offset
+ movl 12(%ebp), %edx # state 1 array
+ movl 16(%ebp), %edi # state 2 array
+
+ movl 20(%ebp), %esi # coefs
+ movl 24(%ebp), %ecx # nb of 4 pixel vectors
+
+
+ .align 16
+ .biquad_time_loop:
+ movq (%ebx), %mm0 # get input
+ movq (%edx), %mm4 # get state 1
+ movq (%edi), %mm5 # get state 2
+ df2 %mm0 # compute direct form 2
+ movq %mm0, (%ebx) # write output
+ movq %mm5, (%edi) # write state 2
+ movq %mm4, (%edx) # write state 1
+ addl $8, %ebx
+ addl $8, %edi
+ addl $8, %edx
+ decl %ecx
+ jnz .biquad_time_loop
+
+ emms
+
+ pop %edi
+ pop %esi
+ pop %ebx
+ leave
+ ret
+
+
diff --git a/system/mmx/pixel_ca_s1.s b/system/mmx/pixel_ca_s1.s
new file mode 100644
index 0000000..d9c730f
--- /dev/null
+++ b/system/mmx/pixel_ca_s1.s
@@ -0,0 +1,189 @@
+# Pure Data Packet mmx routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+ # this file contains assembler routines for 2D 1 bit cellular automata
+ # processing. it is organized around a feeder kernel and a
+ # stack based bit processor (virtual forth machine)
+ #
+ # the feeder kernel is responsable for loading/storing CA cells
+ # from/to memory. data in memory is organized as a scanline
+ # encoded toroidial bitplane (lsb = left). to simplify the kernel, the top
+ # left corner of the rectangular grid of pixels will shift down
+ # every processing step.
+ #
+ # the stack machine has the following architecture:
+ # CA stack: %esi, TOS: %mm0 (32x2 pixels. lsw = top row)
+ # CA horizon: %mm4-%mm7 (64x4 pixels. %mm4 = top row)
+ #
+ # the stack size / organization is not known to the stack machine.
+ # it can be thought of as operating on a 3x3 cell neightbourhood.
+ # the only purpose of forth program is to determine the CA local update rule.
+ #
+ # the machine is supposed to be very minimal. no looping control.
+ # no adressing modes. no conditional code (hey, this is an experiment!)
+ # so recursion is not allowed (no way to stop it)
+ # there are 9 words to load the cell neigbourhood on the stack.
+ # the rest is just logic and stack manips.
+
+
+ # this file contains pure asm macros. it is to be included before assembly
+ # after scaforth.pl has processed the .scaf file
+
+
+ # *************************** CA CELL ACCESS MACROS *****************************
+ # fetchTL - fetchBR
+
+ # shift / load rectangle macros:
+
+ # shift rectangle horizontal
+ # result is in reg1
+ .macro shift reg1 reg2 count
+ psllq $(32+\count), \reg1
+ psrlq $(32-\count), \reg2
+ psrlq $32, \reg1
+ psllq $32, \reg2
+ por \reg2, \reg1
+ .endm
+
+ .macro ldtop reg1 reg2
+ movq %mm4, \reg1
+ movq %mm5, \reg2
+ .endm
+
+ .macro ldcenter reg1 reg2
+ movq %mm5, \reg1
+ movq %mm6, \reg2
+ .endm
+
+ .macro ldbottom reg1 reg2
+ movq %mm6, \reg1
+ movq %mm7, \reg2
+ .endm
+
+
+ # fetch from top row
+
+ # fetch the top left square
+ .macro fetchTL
+ ldtop %mm0, %mm1
+ shift %mm0, %mm1, -1
+ .endm
+
+ # fetch the top mid square
+ .macro fetchTM
+ ldtop %mm0, %mm1
+ shift %mm0, %mm1, 0
+ .endm
+
+ # fetch the top right square
+ .macro fetchTR
+ ldtop %mm0, %mm1
+ shift %mm0, %mm1, 1
+ .endm
+
+
+
+ # fetch from center row
+
+ # fetch the mid left square
+ .macro fetchML
+ ldcenter %mm0, %mm1
+ shift %mm0, %mm1, -1
+ .endm
+
+ # fetch the mid mid square
+ .macro fetchMM
+ ldcenter %mm0, %mm1
+ shift %mm0, %mm1, 0
+ .endm
+
+ # fetch the mid right square
+ .macro fetchMR
+ ldcenter %mm0, %mm1
+ shift %mm0, %mm1, 1
+ .endm
+
+
+
+
+
+ # fetch from bottom row
+
+ # fetch the bottom left square
+ .macro fetchBL
+ ldbottom %mm0, %mm1
+ shift %mm0, %mm1, -1
+ .endm
+
+ # fetch the bottom mid square
+ .macro fetchBM
+ ldbottom %mm0, %mm1
+ shift %mm0, %mm1, 0
+ .endm
+
+ # fetch the bottom right square
+ .macro fetchBR
+ ldbottom %mm0, %mm1
+ shift %mm0, %mm1, 1
+ .endm
+
+
+
+ # *************************** CA STACK MANIP MACROS *****************************
+ # dup drop dropdup swap nip dropover
+
+ .macro dup
+ lea -8(%esi), %esi
+ movq %mm0, (%esi)
+ .endm
+
+ .macro drop
+ movq (%esi), %mm0
+ lea 8(%esi), %esi
+ .endm
+
+ .macro dropdup
+ movq (%esi), %mm0
+ .endm
+
+ .macro swap
+ movq (%esi), %mm1
+ movq %mm0, (%esi)
+ movq %mm1, %mm0
+ .endm
+
+ .macro nip
+ lea 8(%esi), %esi
+ .endm
+
+ .macro dropover
+ movq 8(%esi), %mm0
+ .endm
+
+
+ # *************************** CA BOOLEAN LOGIC MACROS *****************************
+ # overxor
+
+ .macro overxor
+ pxor (%esi), %mm0
+ .endm
+
+
+
+
+
diff --git a/system/mmx/pixel_cascade_s16.s b/system/mmx/pixel_cascade_s16.s
new file mode 100644
index 0000000..bf88d08
--- /dev/null
+++ b/system/mmx/pixel_cascade_s16.s
@@ -0,0 +1,330 @@
+# Pure Data Packet mmx routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+
+ # TODO: COUPLED CASCADE SECOND ORDER SECTION
+ #
+ # s1[k] = ar * s1[k-1] + ai * s2[k-1] + x[k]
+ # s2[k] = ar * s2[k-1] - ai * s1[k-1]
+ # y[k] = c0 * x[k] + c1 * s1[k-1] + c2 * s2[k-1]
+
+
+ # MACRO: df2
+ #
+ # computes a coupled cascade
+ #
+ # input: %mm0 == input
+ # %mm1 == state 1
+ # %mm2 == state 2
+ # (%esi) == cascade coefs (ar ai c0 c1 c2) in s0.15
+ # output: %mm0 == output
+ # %mm1 == state 1
+ # %mm2 == state 2
+
+
+ .macro coupled
+ pmovq %mm1, %mm3 # mm3 == s1[k-1]
+ pmovq %mm1, %mm4 # mm4 == s1[k-1]
+ pmovq %mm2, %mm5 # mm5 == s2[k-1]
+ pmovq %mm2, %mm6 # mm5 == s2[k-1]
+ pmulhw (%esi), %mm1 # mm1 == s1[k-1] * ar
+ pmulhw 8(%esi), %mm3 # mm3 == s1[k-1] * ai
+ pmulhw 24(%esi), %mm4 # mm4 == s1[k-1] * c1
+ pmulhw (%esi), %mm2 # mm2 == s2[k-1] * ar
+ pmulhw 8(%esi), %mm5 # mm5 == s2[k-1] * ai
+ pmulhw 32(%esi), %mm6 # mm6 == s2[k-1] * c2
+ paddw %mm5, %mm1 # mm1 == s1[k-1] * ar + s2[k-1] * ai
+ psubw %mm3, %mm2 # mm2 == s2[k-1] * ar - s1[k-1] * ai == s2[k]
+ paddw %mm0, %mm1 # mm1 == s1[k]
+ pmulhw 16(%esi), %mm0 # mm0 == x[k] * c0
+ paddw %mm6, %mm4 # mm4 == s1[k-1] * c1 + s2[k-1] * c2
+ paddw %mm4, %mm0 # mm0 == y[k]
+ .endm
+
+
+
+
+ # in order to use the 4 line parallel cascade routine on horizontal
+ # lines, we need to reorder (rotate or transpose) the matrix, since
+ # images are scanline encoded, and we want to work in parallell
+ # on 4 lines.
+ #
+ # since the 4 lines are independent, it doesnt matter in which order
+ # the the vector elements are present.
+ #
+ # this allows us to use the same routine for left->right and right->left
+ # processing.
+ #
+ # some comments on the non-abelean group of square isometries consisting of
+ # (I) identity
+ # (H) horizontal axis mirror
+ # (V) vertical axis mirror
+ # (T) transpose (diagonal axis mirror)
+ # (A) antitranspose (antidiagonal axis mirror)
+ # (R1) 90deg anticlockwize rotation
+ # (R2) 180deg rotation
+ # (R3) 90deg clockwize rotation
+ #
+ #
+ # we basicly have two options: (R1,R3) or (T,A)
+ # we opt for T and A because they are self inverting, which improves locality
+ #
+ # use antitranspose for right to left an transpose
+ # for left to right (little endian)
+
+
+ # antitranspose 4x4
+
+ # input
+ # %mm3 == {d0 d1 d2 d3}
+ # %mm2 == {c0 c1 c2 c3}
+ # %mm1 == {b0 b1 b2 b3}
+ # %mm0 == {a0 a1 a2 a3}
+
+ # output
+ # %mm3 == {a3 b3 c3 d3}
+ # %mm2 == {a2 b2 c2 d2}
+ # %mm1 == {a1 b1 c1 d1}
+ # %mm0 == {a0 b0 c0 d0}
+
+
+ .macro antitranspose_4x4:
+ movq %mm3, %mm4
+ punpcklwd %mm1, %mm4 # mm4 <- {b2 d2 b3 d3}
+ movq %mm3, %mm5
+ punpckhwd %mm1, %mm5 # mm5 <- {b0 d0 b1 d1}
+
+ movq %mm2, %mm6
+ punpcklwd %mm0, %mm6 # mm6 <- {a2 c2 a3 c3}
+ movq %mm2, %mm7
+ punpckhwd %mm0, %mm7 # mm7 <- {a0 c0 a1 c1}
+
+ movq %mm4, %mm3
+ punpcklwd %mm6, %mm3 # mm3 <- {a3 b3 c3 d3}
+ movq %mm4, %mm2
+ punpckhwd %mm6, %mm2 # mm2 <- {a2 b2 c2 d2}
+
+ movq %mm5, %mm1
+ punpcklwd %mm7, %mm1 # mm1 <- {a1 b1 c1 d1}
+ movq %mm5, %mm0
+ punpckhwd %mm7, %mm0 # mm0 <- {a0 b0 c0 d0}
+
+ .endm
+
+
+ # transpose 4x4
+
+ # input
+ # %mm3 == {d3 d2 d1 d0}
+ # %mm2 == {c3 c2 c1 c0}
+ # %mm1 == {b3 b2 b1 b0}
+ # %mm0 == {a3 a2 a1 a0}
+
+ # output
+ # %mm3 == {d3 c3 b3 a3}
+ # %mm2 == {d2 c2 b2 a2}
+ # %mm1 == {d1 c1 b1 a1}
+ # %mm0 == {d0 c0 b0 a0}
+
+
+ .macro transpose_4x4:
+ movq %mm0, %mm4
+ punpcklwd %mm2, %mm4 # mm4 <- {c1 a1 c0 a0}
+ movq %mm0, %mm5
+ punpckhwd %mm2, %mm5 # mm5 <- {c3 a3 c2 a2}
+
+ movq %mm1, %mm6
+ punpcklwd %mm3, %mm6 # mm6 <- {d1 b1 d0 b0}
+ movq %mm1, %mm7
+ punpckhwd %mm3, %mm7 # mm7 <- {d3 b3 d2 b2}
+
+ movq %mm4, %mm0
+ punpcklwd %mm6, %mm0 # mm0 <- {d0 c0 b0 a0}
+ movq %mm4, %mm1
+ punpckhwd %mm6, %mm1 # mm1 <- {d1 c1 b1 a1}
+
+ movq %mm5, %mm2
+ punpcklwd %mm7, %mm2 # mm2 <- {d2 c2 b2 a2}
+ movq %mm5, %mm3
+ punpckhwd %mm7, %mm3 # mm3 <- {d3 c3 b3 a3}
+
+ .endm
+
+.globl pixel_cascade_vertb_s16
+.type pixel_cascade_vertb_s16,@function
+
+
+# pixel_cascade_vertbr_s16(char *pixel_array, int nb_rows, int linewidth, short int coef[20], short int state[8])
+
+
+pixel_cascade_vertb_s16:
+
+
+ pushl %ebp
+ movl %esp, %ebp
+ push %ebx
+ push %esi
+ push %edi
+
+ movl 8(%ebp), %ebx # pixel array offset
+ movl 12(%ebp), %ecx # nb of 4x4 pixblocks
+ movl 16(%ebp), %edx # line with
+
+ movl 20(%ebp), %esi # coefs
+ movl 24(%ebp), %edi # state
+
+ shll $1, %edx # short int addressing
+ subl %edx, %ebx
+
+ movq 0(%edi), %mm1 # s1[k-1]
+ movq 8(%edi), %mm2 # s2[k-1]
+ .align 16
+ .cascade_vertb_line_loop:
+
+ movq (%ebx,%edx,1), %mm3
+ movq %mm3, %mm0
+ addl %edx, %ebx
+ coupled
+ movq %mm0, (%ebx)
+
+ movq (%ebx,%edx,1), %mm3
+ movq %mm3, %mm0
+ addl %edx, %ebx
+ coupled
+ movq %mm0, (%ebx)
+
+ movq (%ebx,%edx,1), %mm3
+ movq %mm3, %mm0
+ addl %edx, %ebx
+ coupled
+ movq %mm0, (%ebx)
+
+ movq (%ebx,%edx,1), %mm3
+ movq %mm3, %mm0
+ addl %edx, %ebx
+ coupled
+ movq %mm0, (%ebx)
+
+ decl %ecx
+ jnz .cascade_vertb_line_loop
+
+ movq %mm1, 0(%edi) # s1[k-1]
+ movq %mm2, 8(%edi) # s2[k-1]
+
+ emms
+
+ pop %edi
+ pop %esi
+ pop %ebx
+ leave
+ ret
+
+.globl pixel_cascade_horlr_s16
+.type pixel_cascade_horlr_s16,@function
+
+
+# pixel_cascade_hor_s16(char *pixel_array, int nb_rows, int linewidth, short int coef[20], short int state[8])
+
+
+pixel_cascade_horlr_s16:
+
+
+ pushl %ebp
+ movl %esp, %ebp
+ push %ebx
+ push %esi
+ push %edi
+
+ movl 8(%ebp), %ebx # pixel array offset
+ movl 12(%ebp), %ecx # nb of 4x4 pixblocks
+ movl 16(%ebp), %edx # line with
+
+ movl 20(%ebp), %esi # coefs
+ movl 24(%ebp), %edi # state
+
+ shll $1, %edx # short int addressing
+ movl %edx, %eax
+ shll $1, %eax
+ addl %edx, %eax # eax = 3 * edx
+
+
+ .align 16
+ .cascade_horlr_line_loop:
+ movq (%edi), %mm1
+ movq 8(%edi), %mm2
+
+ movq (%ebx), %mm0
+ movq (%ebx,%edx,1), %mm1
+ movq (%ebx,%edx,2), %mm2
+ movq (%ebx,%eax,1), %mm3
+
+ transpose_4x4
+
+ movq %mm1, (%ebx,%edx,1)
+ movq %mm2, (%ebx,%edx,2)
+ movq %mm3, (%ebx,%eax,1)
+
+ coupled
+
+ movq %mm0, (%ebx)
+ movq (%ebx,%edx,1), %mm3
+ movq %mm3, %mm0
+
+ coupled
+
+ movq %mm0, (%ebx, %edx,1)
+ movq (%ebx,%edx,2), %mm3
+ movq %mm3, %mm0
+
+ coupled
+
+ movq %mm0, (%ebx, %edx,2)
+ movq (%ebx,%eax,1), %mm3
+ movq %mm3, %mm0
+
+ coupled
+
+ movq %mm1, 0(%edi) # s1[k-1]
+ movq %mm2, 8(%edi) # s2[k-1]
+
+ movq %mm0, %mm3
+ movq (%ebx), %mm0
+ movq (%ebx,%edx,1), %mm1
+ movq (%ebx,%edx,2), %mm2
+
+ transpose_4x4
+
+ movq %mm0, (%ebx)
+ movq %mm1, (%ebx,%edx,1)
+ movq %mm2, (%ebx,%edx,2)
+ movq %mm3, (%ebx,%eax,1)
+
+ addl $8, %ebx
+ decl %ecx
+ jnz .cascade_horlr_line_loop
+
+ emms
+
+ pop %edi
+ pop %esi
+ pop %ebx
+ leave
+ ret
+
+
+
diff --git a/system/mmx/pixel_conv_hor_s16.s b/system/mmx/pixel_conv_hor_s16.s
new file mode 100644
index 0000000..e90a692
--- /dev/null
+++ b/system/mmx/pixel_conv_hor_s16.s
@@ -0,0 +1,134 @@
+# Pure Data Packet mmx routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+ # intermediate function
+
+ # input in register:
+ # %mm0: left 4 pixels
+ # %mm1: middle 4 pixels
+ # %mm2: right 4 pixels
+
+ # %mm5: left 4 pixel masks
+ # %mm6: middle 4 pixel masks
+ # %mm7: right 4 pixel masks
+
+ # return in register:
+ # %mm0: middle 4 pixels result
+
+
+ .conv_hor_4_pixels:
+ .align 16
+
+ # compute quadruplet
+
+ # get left pixels
+ psrlq $48, %mm0 # shift word 3 to byte 0
+ movq %mm1, %mm4
+ psllq $16, %mm4 # shift word 0,1,2 to 1,2,3
+ por %mm4, %mm0 # combine
+ pmulhw %mm5, %mm0
+ psllw $1, %mm0
+
+
+ # get middle pixels
+ movq %mm1, %mm4
+ pmulhw %mm6, %mm4
+ psllw $1, %mm4
+ paddsw %mm4, %mm0
+
+
+ # get right pixels
+ movq %mm2, %mm3
+ psllq $48, %mm3 # shift word 0 to word 3
+ movq %mm1, %mm4
+ psrlq $16, %mm4 # shift word 1,2,3 to 0,1,2
+ por %mm4, %mm3 # combine
+ pmulhw %mm7, %mm3
+ psllw $1, %mm3
+ paddsw %mm3, %mm0 # accumulate
+
+ ret
+
+.globl pixel_conv_hor_s16
+.type pixel_conv_hor_s16,@function
+
+
+# pixel_conv_hor_s16(short int *pixel_array, int nb_4_pixel_vectors, short int border[4], short int mask[12])
+# horizontal unsigned pixel conv (1/4 1/2 1/4) not tested
+# NOT TESTED
+
+
+pixel_conv_hor_s16:
+
+
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+ movl 8(%ebp), %esi # pixel array offset
+ movl 12(%ebp), %ecx # nb of 8 pixel vectors in a row (at least 2)
+
+ movl 20(%ebp), %edi # mask vector
+ movq (%edi), %mm5
+ movq 8(%edi), %mm6
+ movq 16(%edi), %mm7
+
+ movl 16(%ebp), %edi # boundary pixel vector
+
+
+
+ movq (%edi), %mm0 # init regs (left edge, so mm0 is zero)
+ movq (%esi), %mm1
+ movq 8(%esi), %mm2
+
+ decl %ecx # loop has 2 terminator stubs
+ decl %ecx # todo: handle if ecx < 3
+
+ jmp .conv_line_loop
+
+
+ .align 16
+ .conv_line_loop:
+ call .conv_hor_4_pixels # compute conv
+ movq %mm0, (%esi) # store result
+ movq %mm1, %mm0 # mm0 <- prev (%esi)
+ movq %mm2, %mm1 # mm1 <- 8(%esi)
+ movq 16(%esi), %mm2 # mm2 <- 16(%esi)
+
+ addl $8, %esi # increase pointer
+ decl %ecx
+ jnz .conv_line_loop
+
+ call .conv_hor_4_pixels # compute conv
+ movq %mm0, (%esi) # store result
+ movq %mm1, %mm0 # mm0 <- prev (%esi)
+ movq %mm2, %mm1 # mm1 <- 8(%esi)
+ movq (%edi), %mm2 # mm2 <- border
+
+ call .conv_hor_4_pixels # compute last vector
+ movq %mm0, 8(%esi) # store it
+
+ emms
+
+ pop %edi
+ pop %esi
+ leave
+ ret
+
+
+
diff --git a/system/mmx/pixel_conv_ver_s16.s b/system/mmx/pixel_conv_ver_s16.s
new file mode 100644
index 0000000..ae2456f
--- /dev/null
+++ b/system/mmx/pixel_conv_ver_s16.s
@@ -0,0 +1,128 @@
+# Pure Data Packet mmx routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#TODO: fix out of bound acces in conv_ver and conv_hor
+
+ # intermediate function
+
+ # input in register:
+ # %mm0: top 4 pixels
+ # %mm1: middle 4 pixels
+ # %mm2: bottom 4 pixels
+
+ # %mm5: top 4 pixel mask
+ # %mm6: middle 4 pixel mask
+ # %mm7: bottom 4 pixel mask
+
+ # return in register:
+ # %mm0: middle 4 pixels result
+
+
+ .conv_ver_4_pixels:
+ .align 16
+
+ # compute quadruplet
+
+ # get top pixel
+ pmulhw %mm5, %mm0
+ psllw $1, %mm0
+
+ # get middle pixel
+ movq %mm1, %mm4
+ pmulhw %mm6, %mm4
+ psllw $1, %mm4
+ paddsw %mm4, %mm0
+
+ # get bottom pixel
+ movq %mm2, %mm3
+ pmulhw %mm7, %mm3
+ psllw $1, %mm3 # mm3 <- mm3/4
+ paddsw %mm3, %mm0
+
+ ret
+
+.globl pixel_conv_ver_s16
+.type pixel_conv_ver_s16,@function
+
+
+# pixel_conv_ver_s16(short int *pixel_array, int nb_4_pixel_vectors, int row_byte_size, short int border[4])
+# horizontal unsigned pixel conv (1/4 1/2 1/4) not tested
+# NOT TESTED
+
+
+pixel_conv_ver_s16:
+
+
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+ movl 8(%ebp), %esi # pixel array offset
+ movl 12(%ebp), %ecx # nb of 4 pixel vectors in a row (at least 2)
+ movl 16(%ebp), %edx # rowsize in bytes
+
+ movl 24(%ebp), %edi # mask vector
+ movq (%edi), %mm5
+ movq 8(%edi), %mm6
+ movq 16(%edi), %mm7
+
+ movl 20(%ebp), %edi # edge vector
+
+
+ shll $1, %edx
+ decl %ecx # loop has a terminator stub
+ decl %ecx # loop has another terminator stub
+
+
+ movq (%edi), %mm0 # init regs (left edge, so mm0 is zero)
+ movq (%esi), %mm1
+ movq (%esi,%edx,1), %mm2
+ jmp .conv_line_loop
+
+
+ .align 16
+ .conv_line_loop:
+ call .conv_ver_4_pixels # compute conv
+ movq %mm0, (%esi) # store result
+ movq %mm1, %mm0 # mm0 <- prev (%esi)
+ movq %mm2, %mm1 # mm1 <- (%esi,%edx,1)
+ movq (%esi,%edx,2), %mm2 # mm2 <- (%esi,%edx,2)
+
+ addl %edx, %esi # increase pointer
+ decl %ecx
+ jnz .conv_line_loop
+
+ call .conv_ver_4_pixels # compute conv
+ movq %mm0, (%esi) # store result
+ movq %mm1, %mm0 # mm0 <- prev (%esi)
+ movq %mm2, %mm1 # mm1 <- (%esi,%edx,1)
+ movq (%edi), %mm2 # clear invalid edge vector
+
+ addl %edx, %esi # increase pointer
+ call .conv_ver_4_pixels # compute last vector
+ movq %mm0, (%esi) # store it
+
+ emms
+
+ pop %edi
+ pop %esi
+ leave
+ ret
+
+
+
diff --git a/system/mmx/pixel_crot_s16.s b/system/mmx/pixel_crot_s16.s
new file mode 100644
index 0000000..2427869
--- /dev/null
+++ b/system/mmx/pixel_crot_s16.s
@@ -0,0 +1,153 @@
+# Pure Data Packet mmx routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+.globl pixel_crot3d_s16
+.type pixel_crot3d_s16,@function
+
+
+# 3 dimensional colour space rotation
+# 3x3 matrix is column encoded, each coefficient is a 4x16 bit fixed point vector
+
+# void pixel_crot3d_s16(int *buf, int nb_4pixel_vectors_per_plane, short int *matrix)
+
+pixel_crot3d_s16:
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+
+ movl 8(%ebp), %esi # input array
+ movl 12(%ebp), %ecx # pixel count
+ movl 16(%ebp), %edi # rotation matrix
+ movl %ecx, %edx
+ shll $3, %edx # %edx = plane spacing
+
+
+ .align 16
+ .loop_crot3d:
+
+ movq (%esi), %mm0 # get 1st component
+ movq (%esi,%edx,1), %mm6 # get 2nd component
+ movq (%esi,%edx,2), %mm7 # get 3rd component
+
+ movq %mm0, %mm1 # copy 1st component
+ movq %mm0, %mm2
+
+ pmulhw (%edi), %mm0 # mul first column
+ pmulhw 8(%edi), %mm1
+ pmulhw 16(%edi), %mm2
+
+ movq %mm6, %mm5 # copy 2nd component
+ movq %mm6, %mm3
+
+ pmulhw 24(%edi), %mm6 # mul second column
+ pmulhw 32(%edi), %mm5
+ pmulhw 40(%edi), %mm3
+
+ paddsw %mm6, %mm0 # accumulate
+ paddsw %mm5, %mm1
+ paddsw %mm3, %mm2
+
+ movq %mm7, %mm4 # copy 3rd component
+ movq %mm7, %mm6
+
+ pmulhw 48(%edi), %mm4 # mul third column
+ pmulhw 56(%edi), %mm6
+ pmulhw 64(%edi), %mm7
+
+ paddsw %mm4, %mm0 # accumulate
+ paddsw %mm6, %mm1
+ paddsw %mm7, %mm2
+
+ paddsw %mm0, %mm0 # double (fixed point normalization)
+ paddsw %mm1, %mm1
+ paddsw %mm2, %mm2
+
+ movq %mm0, (%esi) # store
+ movq %mm1, (%esi, %edx, 1)
+ movq %mm2, (%esi, %edx, 2)
+
+ addl $8, %esi # increment source pointer
+ decl %ecx
+ jnz .loop_crot3d # loop
+
+ emms
+
+ pop %edi
+ pop %esi
+ leave
+ ret
+
+
+.globl pixel_crot2d_s16
+.type pixel_crot2d_s16,@function
+
+# 2 dimensional colour space rotation
+# 2x2 matrix is column encoded, each coefficient is a 4x16 bit fixed point vector
+
+# void pixel_crot2d_s16(int *buf, int nb_4pixel_vectors_per_plane, short int *matrix)
+
+pixel_crot2d_s16:
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+
+ movl 8(%ebp), %esi # input array
+ movl 12(%ebp), %ecx # pixel count
+ movl 16(%ebp), %edi # rotation matrix
+ movl %ecx, %edx
+ shll $3, %edx # %edx = plane spacing
+
+
+ .align 16
+ .loop_crot2d:
+
+ movq (%esi), %mm0 # get 1st component
+ movq (%esi,%edx,1), %mm2 # get 2nd component
+
+ movq %mm0, %mm1 # copy 1st component
+ movq %mm2, %mm3 # copy 2nd component
+
+ pmulhw (%edi), %mm0 # mul first column
+ pmulhw 8(%edi), %mm1
+
+ pmulhw 16(%edi), %mm2 # mul second column
+ pmulhw 24(%edi), %mm3
+
+ paddsw %mm2, %mm0 # accumulate
+ paddsw %mm3, %mm1
+
+ paddsw %mm0, %mm0 # fixed point gain correction
+ paddsw %mm1, %mm1
+
+ movq %mm0, (%esi) # store
+ movq %mm1, (%esi, %edx, 1)
+
+ addl $8, %esi # increment source pointer
+ decl %ecx
+ jnz .loop_crot2d # loop
+
+ emms
+
+ pop %edi
+ pop %esi
+ leave
+ ret
+
diff --git a/system/mmx/pixel_gain.s b/system/mmx/pixel_gain.s
new file mode 100644
index 0000000..5cd5057
--- /dev/null
+++ b/system/mmx/pixel_gain.s
@@ -0,0 +1,83 @@
+# Pure Data Packet mmx routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+.globl pixel_gain
+.type pixel_gain,@function
+
+# mmx rgba pixel gain
+# void asmtest(char *pixelarray, int32 nbpixels, int *rgba_gain)
+# gains are 7.9 fixed point for rgba
+
+pixel_gain:
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+ movl 8(%ebp), %esi # pixel array offset
+ movl 12(%ebp), %ecx # nb of elements
+ movl 16(%ebp), %edi # int16[4] array of gains
+
+ prefetch (%esi)
+
+ emms
+ sarl $2, %ecx # process 4 pixels per loop iteration
+ jz .exit
+ movq (%edi), %mm7 # read gain array from memory
+ jmp .loop_gain
+
+ .align 16
+ .loop_gain:
+
+ prefetch 128(%esi)
+ movq (%esi), %mm5 # load pixel 1-2 from memory
+ movq 8(%esi), %mm6 # load pixel 3-4 from memory
+ pxor %mm0, %mm0 # zero mm0 - mm3
+ pxor %mm1, %mm1
+ pxor %mm2, %mm2
+ pxor %mm3, %mm3
+ punpcklbw %mm5, %mm0 # unpack 1st pixel into 8.8 bit ints
+ punpckhbw %mm5, %mm1 # unpack 2nd
+ punpcklbw %mm6, %mm2 # unpack 3rd
+ punpckhbw %mm6, %mm3 # unpack 4th
+ psrlw $0x1, %mm0 # shift right to clear sign bit 9.7
+ psrlw $0x1, %mm1
+ psrlw $0x1, %mm2
+ psrlw $0x1, %mm3
+
+ pmulhw %mm7, %mm0 # multiply 1st pixel 9.7 * 7.9 -> 16.0
+ pmulhw %mm7, %mm1 # multiply 2nd
+ pmulhw %mm7, %mm2 # multiply 3rd
+ pmulhw %mm7, %mm3 # multiply 4th
+
+ packuswb %mm1, %mm0 # pack & saturate to 8bit vector
+ movq %mm0, (%esi) # store result in memory
+ packuswb %mm3, %mm2 # pack & saturate to 8bit vector
+ movq %mm2, 8(%esi) # store result in memory
+
+ addl $16, %esi # increment source pointer
+ decl %ecx
+ jnz .loop_gain # loop
+
+ .exit:
+ emms
+
+ pop %edi
+ pop %esi
+ leave
+ ret
+
diff --git a/system/mmx/pixel_gain_s16.s b/system/mmx/pixel_gain_s16.s
new file mode 100644
index 0000000..adcfdf5
--- /dev/null
+++ b/system/mmx/pixel_gain_s16.s
@@ -0,0 +1,71 @@
+# Pure Data Packet mmx routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+.globl pixel_gain_s16
+.type pixel_gain_s16,@function
+
+# gain is integer, shift count is down
+# void pixel_gain_s16(int *buf, int nb_8pixel_vectors, short int gain[4], unsigned long long *shift)
+
+pixel_gain_s16:
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+ movl 20(%ebp), %edi
+ movq (%edi), %mm6 # get shift vector
+
+ movl 16(%ebp), %edi
+ movq (%edi), %mm7 # get gain vector
+
+ movl 8(%ebp), %esi # input array
+ movl 12(%ebp), %ecx # pixel count
+
+
+ .align 16
+ .loop_gain:
+
+ movq (%esi), %mm0 # load 4 pixels from memory
+ movq %mm0, %mm1
+ pmulhw %mm7, %mm1 # apply gain (s15.0) fixed point, high word
+ pmullw %mm7, %mm0 # low word
+
+ movq %mm0, %mm2 # copy
+ movq %mm1, %mm3
+
+ punpcklwd %mm1, %mm0 # unpack lsw components
+ punpckhwd %mm3, %mm2 # unpack msw components
+
+ psrad %mm6, %mm0 # apply signed shift
+ psrad %mm6, %mm2
+
+ packssdw %mm2, %mm0 # pack result & saturate
+ movq %mm0, (%esi) # store result
+
+
+ addl $8, %esi # increment source pointer
+ decl %ecx
+ jnz .loop_gain # loop
+
+ emms
+
+ pop %edi
+ pop %esi
+ leave
+ ret
+
diff --git a/system/mmx/pixel_mix_s16.s b/system/mmx/pixel_mix_s16.s
new file mode 100644
index 0000000..9bf41eb
--- /dev/null
+++ b/system/mmx/pixel_mix_s16.s
@@ -0,0 +1,68 @@
+# Pure Data Packet mmx routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+.globl pixel_mix_s16
+.type pixel_mix_s16,@function
+
+# mmx rgba pixel gain
+# void pixel_mix_s16(int *left, int *right, int nb_4pixel_vectors,
+# short int gain_left[4], short int gain_right[4])
+
+pixel_mix_s16:
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+ movl 20(%ebp), %edi # int16[4] array of gains
+ movq (%edi), %mm6 # get left gain array
+
+ movl 24(%ebp), %edi # int16[4] array of gains
+ movq (%edi), %mm7 # get right gain array
+
+ movl 8(%ebp), %edi # left array
+ movl 12(%ebp), %esi # right array
+ movl 16(%ebp), %ecx # pixel count
+
+
+ .align 16
+ .loop_mix:
+
+# prefetch 128(%esi)
+ movq (%esi), %mm1 # load right 4 pixels from memory
+ pmulhw %mm7, %mm1 # apply right gain
+ movq (%edi), %mm0 # load 4 left pixels from memory
+ pmulhw %mm6, %mm0 # apply left gain
+# pslaw $1, %mm1 # shift left ((s).15 x (s).15 -> (s0).14))
+# pslaw $1, %mm0
+ paddsw %mm0, %mm0 # no shift left arithmic, so use add instead
+ paddsw %mm1, %mm1
+ paddsw %mm1, %mm0 # mix
+ movq %mm0, (%edi)
+ addl $8, %esi
+ addl $8, %edi
+ decl %ecx
+ jnz .loop_mix # loop
+
+ emms
+
+
+ pop %edi
+ pop %esi
+ leave
+ ret
+
diff --git a/system/mmx/pixel_mul_s16.s b/system/mmx/pixel_mul_s16.s
new file mode 100644
index 0000000..240a024
--- /dev/null
+++ b/system/mmx/pixel_mul_s16.s
@@ -0,0 +1,56 @@
+# Pure Data Packet mmx routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+.globl pixel_mul_s16
+.type pixel_mul_s16,@function
+
+# simple add
+# void pixel_mul_s16(int *left, int *right, int nb_4pixel_vectors)
+
+pixel_mul_s16:
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+ movl 8(%ebp), %edi # left array
+ movl 12(%ebp), %esi # right array
+ movl 16(%ebp), %ecx # pixel count
+
+
+ .align 16
+ .loop_mix:
+
+# prefetch 128(%esi)
+ movq (%esi), %mm1 # load right 4 pixels from memory
+ movq (%edi), %mm0 # load 4 left pixels from memory
+ pmulhw %mm1, %mm0 # mul
+ psllw $1, %mm0 # fixed point shift correction
+ movq %mm0, (%edi)
+ addl $8, %esi
+ addl $8, %edi
+ decl %ecx
+ jnz .loop_mix # loop
+
+ emms
+
+
+ pop %edi
+ pop %esi
+ leave
+ ret
+
diff --git a/system/mmx/pixel_pack_s16u8.s b/system/mmx/pixel_pack_s16u8.s
new file mode 100644
index 0000000..57df702
--- /dev/null
+++ b/system/mmx/pixel_pack_s16u8.s
@@ -0,0 +1,126 @@
+# Pure Data Packet mmx routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+.globl pixel_pack_s16u8_y
+.type pixel_pack_s16u8_y,@function
+
+# mmx rgba pixel gain
+# void pixel_pack_s16u8_y(int *input, int *output, int nb_8pixel_vectors)
+
+pixel_pack_s16u8_y:
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+# movl 20(%ebp), %edi # int16[4] array of gains
+# movq (%edi), %mm7 # get gain array
+# psllw $1, %mm7 # adjust for shifted sign bit
+
+ movl 8(%ebp), %esi # input array
+ movl 12(%ebp), %edi # output array
+ movl 16(%ebp), %ecx # pixel count
+
+ pxor %mm6, %mm6
+
+ .align 16
+ .loop_pack_y:
+
+# prefetch 128(%esi)
+ movq (%esi), %mm0 # load 4 pixels from memory
+# pmulhw %mm7, %mm0 # apply gain
+ movq 8(%esi), %mm1 # load 4 pixels from memory
+# pmulhw %mm7, %mm1 # apply gain
+
+# movq %mm0, %mm2
+# pcmpgtw %mm6, %mm2 # mm2 > 0 ? 0xffff : 0
+# pand %mm2, %mm0
+
+# movq %mm1, %mm3
+# pcmpgtw %mm6, %mm3 # mm3 > 0 ? 0xffff : 0
+# pand %mm3, %mm1
+
+# psllw $1, %mm0 # shift out sign bit
+# psllw $1, %mm1 # shift out sign bit
+
+ psraw $7, %mm0 # shift to lsb
+ psraw $7, %mm1 # shift to lsb
+
+ packuswb %mm1, %mm0 # pack & saturate to 8bit vector
+ movq %mm0, (%edi) # store result in memory
+
+ addl $16, %esi # increment source pointer
+ addl $8, %edi # increment dest pointer
+ decl %ecx
+ jnz .loop_pack_y # loop
+
+ emms
+
+ pop %edi
+ pop %esi
+ leave
+ ret
+
+.globl pixel_pack_s16u8_uv
+.type pixel_pack_s16u8_uv,@function
+
+pixel_pack_s16u8_uv:
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+# movl 20(%ebp), %edi # int16[4] array of gains
+# movq (%edi), %mm7 # get gain array
+ movl 8(%ebp), %esi # pixel array offset
+ movl 12(%ebp), %edi # nb of elements
+ movl 16(%ebp), %ecx # pixel count
+
+ pcmpeqw %mm6, %mm6
+ psllw $15, %mm6
+ movq %mm6, %mm5
+ psrlw $8, %mm5
+ por %mm5, %mm6 # mm6 <- 8 times 0x80
+
+ .align 16
+ .loop_pack_uv:
+
+# prefetch 128(%esi)
+ movq (%esi), %mm0 # load 4 pixels from memory
+# pmulhw %mm7, %mm0 # apply gain
+ movq 8(%esi), %mm1 # load 4 pixels from memory
+# pmulhw %mm7, %mm1 # apply gain
+
+ psraw $8, %mm0 # shift to msb
+ psraw $8, %mm1
+
+ packsswb %mm1, %mm0 # pack & saturate to 8bit vector
+ pxor %mm6, %mm0 # flip sign bits
+ movq %mm0, (%edi) # store result in memory
+
+ addl $16, %esi # increment source pointer
+ addl $8, %edi # increment dest pointer
+ decl %ecx
+ jnz .loop_pack_uv # loop
+
+ emms
+
+ pop %edi
+ pop %esi
+ leave
+ ret
+
diff --git a/system/mmx/pixel_rand_s16.s b/system/mmx/pixel_rand_s16.s
new file mode 100644
index 0000000..649400b
--- /dev/null
+++ b/system/mmx/pixel_rand_s16.s
@@ -0,0 +1,76 @@
+# Pure Data Packet mmx routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+.globl pixel_rand_s16
+.type pixel_rand_s16,@function
+
+# mmx rgba pixel gain
+# void pixel_rand_s16(int *dst, nb_4pixel_vectors, short int random_seed[4])
+
+pixel_rand_s16:
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+ movl 16(%ebp), %esi # int16[4] array of random seeds
+ movl 8(%ebp), %edi # dst array
+ movl 12(%ebp), %ecx # pixel count
+
+ movq (%esi), %mm6
+
+
+ pcmpeqw %mm3, %mm3
+ psrlw $15, %mm3 # get bit mask 4 times 0x0001
+
+ .align 16
+ .loop_rand:
+
+# prefetch 128(%esi)
+
+
+ movq %mm6, %mm4 # get random vector
+ psrlw $15, %mm4 # get first component
+ movq %mm6, %mm5
+ psrlw $14, %mm5 # get second component
+ pxor %mm5, %mm4
+ movq %mm6, %mm5
+ psrlw $12, %mm5 # get third component
+ pxor %mm5, %mm4
+ movq %mm6, %mm5
+ psrlw $3, %mm5 # get forth component
+ pxor %mm5, %mm4
+
+ psllw $1, %mm6 # shift left original random vector
+ pand %mm3, %mm4 # isolate new bit
+ por %mm4, %mm6 # combine into new random vector
+
+ movq %mm6, (%edi)
+ addl $8, %edi
+ decl %ecx
+ jnz .loop_rand # loop
+
+
+ movq %mm6, (%esi) # store random seeds
+
+ emms
+
+ pop %edi
+ pop %esi
+ leave
+ ret
+
diff --git a/system/mmx/pixel_randmix_s16.s b/system/mmx/pixel_randmix_s16.s
new file mode 100644
index 0000000..44e1702
--- /dev/null
+++ b/system/mmx/pixel_randmix_s16.s
@@ -0,0 +1,91 @@
+# Pure Data Packet mmx routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+.globl pixel_randmix_s16
+.type pixel_randmix_s16,@function
+
+# mmx rgba pixel gain
+# void pixel_randmix_s16(int *left, int *right, int nb_4pixel_vectors, short int random_seed[4], short int threshold[4])
+
+pixel_randmix_s16:
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+ movl 20(%ebp), %edi # int16[4] array of random seeds
+ movq (%edi), %mm6
+
+ movl 24(%ebp), %edi # int16[4] array of thresholds
+ movq (%edi), %mm7
+
+ movl 8(%ebp), %edi # left array
+ movl 12(%ebp), %esi # right array
+ movl 16(%ebp), %ecx # pixel count
+
+ pcmpeqw %mm3, %mm3
+ psrlw $15, %mm3 # get bit mask 4 times 0x0001
+
+ .align 16
+ .loop_randmix:
+
+# prefetch 128(%esi)
+ movq (%esi), %mm1 # load right 4 pixels from memory
+ movq (%edi), %mm0 # load 4 left pixels from memory
+
+ movq %mm6, %mm2 # get random vector
+ pcmpgtw %mm7, %mm2 # compare random vector with threshold
+ movq %mm2, %mm5
+
+ pand %mm0, %mm2 # get left array's components
+ pandn %mm1, %mm5 # get right array's components
+ por %mm2, %mm5
+
+ movq %mm5, (%edi) # store pixels
+
+ movq %mm6, %mm4 # get random vector
+ psrlw $15, %mm4 # get first component
+ movq %mm6, %mm5
+ psrlw $14, %mm5 # get second component
+ pxor %mm5, %mm4
+ movq %mm6, %mm5
+ psrlw $12, %mm5 # get third component
+ pxor %mm5, %mm4
+ movq %mm6, %mm5
+ psrlw $3, %mm5 # get forth component
+ pxor %mm5, %mm4
+
+ psllw $1, %mm6 # shift left original random vector
+ pand %mm3, %mm4 # isolate new bit
+ por %mm4, %mm6 # combine into new random vector
+
+ addl $8, %esi
+ addl $8, %edi
+ decl %ecx
+ jnz .loop_randmix # loop
+
+
+ movl 20(%ebp), %edi # int16[4] array of random seeds
+ movq %mm6, (%edi) # store random seeds
+
+ emms
+
+ pop %edi
+ pop %esi
+ leave
+ ret
+
diff --git a/system/mmx/pixel_s1.s b/system/mmx/pixel_s1.s
new file mode 100644
index 0000000..d6bc5ca
--- /dev/null
+++ b/system/mmx/pixel_s1.s
@@ -0,0 +1,201 @@
+# Pure Data Packet mmx routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+ # this file contains ops for binary image processing
+ # 8x8 bit tile encoded
+ # low byte = bottom row
+ # low bit = right column
+ # %mm7 = scratch reg for all macros
+
+
+ # ************ load mask *******************
+ # compute bit masks for rows and columns
+ # %mm7: scratch reg
+
+ # load mask top
+ .macro ldmt count reg
+ pcmpeqb \reg, \reg
+ psllq $(64-(\count<<3)), \reg
+ .endm
+
+ # load mask bottom
+ .macro ldmb count reg
+ pcmpeqb \reg, \reg
+ psrlq $(64-(\count<<3)), \reg
+ .endm
+
+ # load mask top and bottom
+ .macro ldmtb count regt regb
+ ldmb \count, \regb
+ ldmt \count, \regt
+ .endm
+
+ # load mask right
+ .macro ldmr count reg
+ pcmpeqb %mm7, %mm7
+ psrlw $(16-\count), %mm7
+ movq %mm7, \reg
+ psllq $8, %mm7
+ por %mm7, \reg
+ .endm
+
+ # load mask left
+ .macro ldml count reg
+ pcmpeqb %mm7, %mm7
+ psllw $(16-\count), %mm7
+ movq %mm7, \reg
+ psrlq $8, %mm7
+ por %mm7, \reg
+ .endm
+
+ # load mask left and right
+ .macro ldmlr count regl regr
+ pcmpeqb %mm7, %mm7
+ psllw $(16-\count), %mm7
+ movq %mm7, \regl
+ psrlq $8, %mm7
+ por %mm7, \regl
+ movq \regl, \regr
+ psrlq $(8-\count), \regr
+ .endm
+
+ # ************* shift square **********
+ # shifts a square in reg, fills with zeros
+
+ # shift square top
+ .macro sst count reg
+ psllq $(\count<<3), \reg
+ .endm
+
+ # shift square bottom
+ .macro ssb count reg
+ psrlq $(\count<<3), \reg
+ .endm
+
+ # not tested
+ # shift square left
+ .macro ssl count reg
+ movq \reg, %mm7
+ pcmpeqb \reg, \reg
+ psllw $(16-\count), \reg
+ psrlw $8, \reg
+ pandn %mm7, \reg
+ psllw $(\count), \reg
+ .endm
+
+ # shift square right
+ .macro ssr count reg
+ movq \reg, %mm7
+ pcmpeqb \reg, \reg
+ psrlw $(16-\count), \reg
+ psllw $8, \reg
+ pandn %mm7, \reg
+ psrlw $(\count), \reg
+ .endm
+
+
+ # ********** combine square *************
+ # combines 2 squares
+
+ # combine right
+ .macro csr count regr reg
+ ssl \count, \reg
+ ssr (8-\count), \regr
+ por \regr, \reg
+ .endm
+
+ # combine left
+ .macro csl count regl reg
+ ssr \count, \reg
+ ssl (8-\count), \regl
+ por \regl, \reg
+ .endm
+
+ # combine top
+ .macro cst count regt reg
+ ssb \count, \reg
+ sst (8-\count), \regt
+ por \regt, \reg
+ .endm
+
+
+ # combine bottom
+ .macro csb count regb reg
+ sst \count, \reg
+ ssb (8-\count), \regb
+ por \regb, \reg
+ .endm
+
+
+ # ********** load combine square *************
+ # loads combined square using mask
+
+ # load combined square left
+ # mask should be count bits set right (i.e. 0x01)
+ .macro lcsml count mask source sourcel dstreg
+ movq \mask, \dstreg
+ movq \mask, %mm7
+ pandn \source, \dstreg
+ pand \sourcel, %mm7
+ psrlq $(\count), \dstreg
+ psllq $(8-\count), %mm7
+ por %mm7, \dstreg
+ .endm
+
+
+
+.globl pixel_test_s1
+.type pixel_test_s1,@function
+
+# simple add
+# void pixel_add_s16(void *dest, void *source, int nb_squares, int spacing)
+
+
+
+ #
+
+
+pixel_test_s1:
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+ movl 8(%ebp), %edi # dest
+ movl 12(%ebp), %esi # source
+ movl 16(%ebp), %ecx # count
+ movl 20(%ebp), %edx # row distance
+
+ ldmr 1, %mm6
+ lcsml 1, %mm6, (%esi), 8(%esi), %mm0
+ movq %mm0, (%edi)
+
+
+# movq (%esi), %mm0
+# movq 8(%esi), %mm1
+# csl 4, %mm1, %mm0
+# movq %mm0, (%edi)
+
+ emms
+
+
+ pop %edi
+ pop %esi
+ leave
+ ret
+
diff --git a/system/mmx/pixel_unpack_u8s16.s b/system/mmx/pixel_unpack_u8s16.s
new file mode 100644
index 0000000..0fc14c2
--- /dev/null
+++ b/system/mmx/pixel_unpack_u8s16.s
@@ -0,0 +1,113 @@
+# Pure Data Packet mmx routine.
+# Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+.globl pixel_unpack_u8s16_y
+.type pixel_unpack_u8s16_y,@function
+
+# mmx rgba pixel gain
+# void pixel_unpack_u8s16_y(char *input, char *output, int32 nb_pixels_div8)
+
+pixel_unpack_u8s16_y:
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+# movl 20(%ebp), %edi # int16[4] array of gains
+# movq (%edi), %mm7 # get gain array
+
+ movl 8(%ebp), %esi # input uint8 pixel array
+ movl 12(%ebp), %edi # output sint16 pixel array
+ movl 16(%ebp), %ecx # nb of elements div 8
+
+
+ .align 16
+ .loop_unpack_y:
+
+ movq (%esi), %mm5 # load 8 pixels from memory
+ pxor %mm0, %mm0 # zero mm0 - mm3
+ pxor %mm1, %mm1
+ punpcklbw %mm5, %mm0 # unpack 1st 4 pixels
+ punpckhbw %mm5, %mm1 # unpack 2nd 4 pixles
+ psrlw $0x1, %mm0 # shift right to clear sign bit 9.7
+ psrlw $0x1, %mm1
+# pmulhw %mm7, %mm0 # apply gain
+# pmulhw %mm7, %mm1
+# paddsw %mm0, %mm0 # correct factor 2
+# paddsw %mm1, %mm1
+ movq %mm0, (%edi) # store
+ movq %mm1, 8(%edi)
+
+ addl $8, %esi # increment source pointer
+ addl $16, %edi # increment dest pointer
+ decl %ecx
+ jnz .loop_unpack_y # loop
+
+ emms
+
+ pop %edi
+ pop %esi
+ leave
+ ret
+
+.globl pixel_unpack_u8s16_uv
+.type pixel_unpack_u8s16_uv,@function
+pixel_unpack_u8s16_uv:
+ pushl %ebp
+ movl %esp, %ebp
+ push %esi
+ push %edi
+
+# movl 20(%ebp), %edi # int16[4] array of gains
+# movq (%edi), %mm7 # get gain array
+
+ movl 8(%ebp), %esi # input uint8 pixel array
+ movl 12(%ebp), %edi # output sint16 pixel array
+ movl 16(%ebp), %ecx # nb of elements div 8
+
+ pcmpeqw %mm6, %mm6
+ psllw $15, %mm6
+
+ .align 16
+ .loop_unpack_uv:
+
+ movq (%esi), %mm5 # load 8 pixels from memory
+ pxor %mm0, %mm0 # zero mm0 - mm3
+ pxor %mm1, %mm1
+ punpcklbw %mm5, %mm0 # unpack 1st 4 pixels
+ punpckhbw %mm5, %mm1 # unpack 2nd 4 pixles
+ pxor %mm6, %mm0 # flip sign bit (Cr and Cb are ofset by 128)
+ pxor %mm6, %mm1
+# pmulhw %mm7, %mm0 # apply gain
+# pmulhw %mm7, %mm1
+# paddsw %mm0, %mm0 # correct factor 2
+# paddsw %mm1, %mm1
+ movq %mm0, (%edi) # store
+ movq %mm1, 8(%edi)
+
+ addl $8, %esi # increment source pointer
+ addl $16, %edi # increment dest pointer
+ decl %ecx
+ jnz .loop_unpack_uv # loop
+
+ emms
+
+ pop %edi
+ pop %esi
+ leave
+ ret
+
diff --git a/system/pdp.c b/system/pdp.c
new file mode 100644
index 0000000..8651971
--- /dev/null
+++ b/system/pdp.c
@@ -0,0 +1,115 @@
+/*
+ * Pure Data Packet system implementation: setup code
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include "pdp.h"
+#include <stdio.h>
+
+/* all symbols are C style */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+/* module setup declarations (all C-style) */
+
+/* pdp system / internal stuff */
+void pdp_packet_setup(void);
+void pdp_ut_setup(void);
+void pdp_queue_setup(void);
+void pdp_control_setup(void);
+
+/* pdp modules */
+void pdp_xv_setup(void);
+void pdp_add_setup(void);
+void pdp_mul_setup(void);
+void pdp_mix_setup(void);
+void pdp_randmix_setup(void);
+void pdp_qt_setup(void);
+void pdp_v4l_setup(void);
+void pdp_reg_setup(void);
+void pdp_conv_setup(void);
+void pdp_bq_setup(void);
+void pdp_affine_setup(void);
+void pdp_del_setup(void);
+void pdp_snap_setup(void);
+void pdp_trigger_setup(void);
+void pdp_route_setup(void);
+void pdp_noise_setup(void);
+void pdp_gradient_setup(void);
+void pdp_gain_setup(void);
+void pdp_grey_setup(void);
+void pdp_chrot_setup(void);
+void pdp_scope_setup(void);
+void pdp_scale_setup(void);
+void pdp_zoom_setup(void);
+
+
+/* library setup routine */
+void pdp_setup(void){
+
+ /* babble */
+ post ("PDP: pure data packet");
+
+#ifdef PDP_VERSION
+ fprintf(stderr, "PDP: version " PDP_VERSION "\n");
+#endif
+
+
+ /* setup pdp system */
+ pdp_packet_setup();
+ pdp_queue_setup();
+ pdp_control_setup();
+
+ /* setup utility toolkit */
+ pdp_ut_setup();
+
+ /* setup pdp modules*/
+ pdp_add_setup();
+ pdp_mul_setup();
+ pdp_mix_setup();
+ pdp_randmix_setup();
+ pdp_xv_setup();
+ pdp_qt_setup();
+ pdp_v4l_setup();
+ pdp_reg_setup();
+ pdp_conv_setup();
+ pdp_bq_setup();
+ pdp_affine_setup();
+ pdp_del_setup();
+ pdp_snap_setup();
+ pdp_trigger_setup();
+ pdp_route_setup();
+ pdp_noise_setup();
+ pdp_gradient_setup();
+ pdp_gain_setup();
+ pdp_grey_setup();
+ pdp_chrot_setup();
+ pdp_scope_setup();
+ pdp_scale_setup();
+ pdp_zoom_setup();
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/system/pdp_comm.c b/system/pdp_comm.c
new file mode 100644
index 0000000..80cbaaa
--- /dev/null
+++ b/system/pdp_comm.c
@@ -0,0 +1,119 @@
+/*
+ * Pure Data Packet system implementation.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* this file contains misc communication methods */
+
+
+#include "pdp.h"
+#include "pdp_internals.h"
+#include <stdio.h>
+
+/* all symbols are C style */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+/************** packet management and communication convenience functions ************/
+
+/* send a packet to an outlet */
+void outlet_pdp(t_outlet *out, int packetid)
+{
+ t_atom atom[2];
+ t_symbol *s = gensym("pdp");
+ t_symbol *rro = gensym("register_ro");
+ t_symbol *rrw = gensym("register_rw");
+ t_symbol *proc = gensym("process");
+
+
+ SETFLOAT(atom+1, (float)packetid);
+
+ SETSYMBOL(atom+0, rro);
+ outlet_anything(out, s, 2, atom);
+
+ SETSYMBOL(atom+0, rrw);
+ outlet_anything(out, s, 2, atom);
+
+ /* this is not really necessary, it can be triggered by the rw message */
+ SETSYMBOL(atom+0, proc);
+ outlet_anything(out, s, 1, atom);
+
+}
+
+
+/* unregister a packet and send it to an outlet */
+void
+pdp_pass_if_valid(t_outlet *outlet, int *packet)
+{
+ if (-1 != *packet){
+ pdp_packet_mark_unused(*packet);
+ outlet_pdp(outlet, *packet);
+ *packet = -1;
+ }
+}
+
+void
+pdp_replace_if_valid(int *dpacket, int *spacket)
+{
+ if (-1 != *spacket){
+ pdp_packet_mark_unused(*dpacket);
+ *dpacket = *spacket;
+ *spacket = -1;
+ }
+
+}
+
+
+int
+pdp_packet_copy_ro_or_drop(int *dpacket, int spacket)
+{
+ int drop = 0;
+ if (*dpacket == -1) *dpacket = pdp_packet_copy_ro(spacket);
+ else {
+ /* send a notification there is a dropped packet */
+ pdp_control_notify_drop(spacket);
+ drop = 1;
+ }
+ return drop;
+}
+
+
+int
+pdp_packet_copy_rw_or_drop(int *dpacket, int spacket)
+{
+ int drop = 0;
+ if (*dpacket == -1) *dpacket = pdp_packet_copy_rw(spacket);
+ else {
+ /* send a notification there is a dropped packet */
+ pdp_control_notify_drop(spacket);
+ drop = 1;
+ }
+ return drop;
+}
+
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/system/pdp_control.c b/system/pdp_control.c
new file mode 100644
index 0000000..a7ee0c7
--- /dev/null
+++ b/system/pdp_control.c
@@ -0,0 +1,162 @@
+/*
+ * Pure Data Packet system implementation: control object
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/* this is an actual pd class that is used for communication with the
+ pdp framework */
+
+#include "pdp.h"
+#include "pdp_internals.h"
+#include <stdio.h>
+
+/* all symbols are C style */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+static long dropped_packets;
+
+static t_class* pdp_control_class;
+
+
+/* pdp control instance data */
+
+struct pdp_control_struct;
+typedef struct pdp_control_struct
+{
+ t_object x_obj;
+ t_outlet *x_outlet0;
+ struct pdp_control_struct *x_next;
+
+} t_pdp_control;
+
+typedef void (t_pdp_control_method_notify)(t_pdp_control *x);
+
+
+static t_pdp_control *pdp_control_list;
+
+static void pdp_control_info(t_pdp_control *x)
+{
+}
+
+static void pdp_control_thread(t_pdp_control *x, t_floatarg f)
+{
+ int t = (int)f;
+
+ if (t){
+ post("pdp_control: switching on processing in thread");
+ pdp_queue_use_thread(1);
+ }
+ else {
+ post("pdp_control: switching off processing in thread");
+ pdp_queue_use_thread(0);
+ }
+}
+
+
+static void pdp_control_send_drop_message(t_pdp_control *x)
+{
+ t_atom atom[1];
+ t_symbol *s = gensym("pdp_drop");
+
+ SETFLOAT(atom+0, (float)dropped_packets);
+ outlet_anything(x->x_outlet0, s, 1, atom);
+}
+
+
+static void pdp_control_free(t_pdp_control *x)
+{
+ /* remove from linked list */
+ t_pdp_control *curr = pdp_control_list;
+ if (pdp_control_list == x) pdp_control_list = x->x_next;
+ else while (curr){
+ if (curr->x_next == x) {
+ curr->x_next = x->x_next;
+ break;
+ }
+ else {
+ curr = curr->x_next;
+ }
+
+ }
+}
+
+
+static void *pdp_control_new(void)
+{
+ t_pdp_control *x = (t_pdp_control *)pd_new(pdp_control_class);
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ /* add to list */
+ x->x_next = pdp_control_list;
+ pdp_control_list = x;
+ return x;
+}
+
+/************************* class methods ***************************************/
+
+
+void pdp_control_setup(void)
+{
+
+ pdp_control_list = 0;
+ dropped_packets = 0;
+
+ /* setup pd class data */
+ pdp_control_class = class_new(gensym("pdp_control"), (t_newmethod)pdp_control_new,
+ (t_method)pdp_control_free, sizeof(t_pdp_control), 0, A_NULL);
+
+
+ class_addmethod(pdp_control_class, (t_method)pdp_control_info, gensym("info"), A_NULL);
+ class_addmethod(pdp_control_class, (t_method)pdp_control_thread, gensym("thread"), A_DEFFLOAT, A_NULL);
+}
+
+
+
+void pdp_control_notify_broadcast(t_pdp_control_method_notify *notify)
+{
+ t_pdp_control *curr = pdp_control_list;
+ while (curr){
+ (*notify)(curr);
+ curr = curr->x_next;
+ }
+}
+
+
+
+/************************* notify class methods *************************/
+
+void pdp_control_notify_drop(int packet)
+{
+ dropped_packets++;
+
+ /* send drop notify to controller class instances */
+ pdp_control_notify_broadcast(pdp_control_send_drop_message);
+ //post("dropped packet");
+}
+
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/system/pdp_imageproc_mmx.c b/system/pdp_imageproc_mmx.c
new file mode 100644
index 0000000..2f32c3f
--- /dev/null
+++ b/system/pdp_imageproc_mmx.c
@@ -0,0 +1,319 @@
+/*
+ * Pure Data Packet. c wrapper for mmx image processing routines.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/* this is a c wrapper around platform specific (mmx) code */
+#include <stdlib.h>
+#include "pdp_mmx.h"
+#include "pdp_imageproc.h"
+
+// utility stuff
+inline static s16 float2fixed(float f)
+{
+ if (f > 1) f = 1;
+ if (f < -1) f = -1;
+ f *= 0x7fff;
+ return (s16)f;
+}
+
+inline static void setvec(s16 *v, float f)
+{
+ s16 a = float2fixed(f);
+ v[0] = a;
+ v[1] = a;
+ v[2] = a;
+ v[3] = a;
+}
+
+
+
+// add two images
+void pdp_imageproc_add_process(s16 *image, s16 *image2, u32 width, u32 height)
+{
+ unsigned int totalnbpixels = width * height;
+ pixel_add_s16(image, image2, totalnbpixels>>2);
+}
+
+// mul two images
+void pdp_imageproc_mul_process(s16 *image, s16 *image2, u32 width, u32 height)
+{
+ unsigned int totalnbpixels = width * height;
+ pixel_mul_s16(image, image2, totalnbpixels>>2);
+}
+
+// mix 2 images
+void *pdp_imageproc_mix_new(void){return malloc(8*sizeof(s16));}
+void pdp_imageproc_mix_delete(void *x) {free (x);}
+void pdp_imageproc_mix_setleftgain(void *x, float gain){setvec((s16 *)x, gain);}
+void pdp_imageproc_mix_setrightgain(void *x, float gain){setvec((s16 *)x + 4, gain);}
+void pdp_imageproc_mix_process(void *x, s16 *image, s16 *image2, u32 width, u32 height)
+{
+ s16 *d = (s16 *)x;
+ unsigned int totalnbpixels = width * height;
+ pixel_mix_s16(image, image2, totalnbpixels>>2, d, d+4);
+}
+
+
+// random mix 2 images
+void *pdp_imageproc_randmix_new(void){return malloc(8*sizeof(s16));}
+void pdp_imageproc_randmix_delete(void *x) {free (x);}
+void pdp_imageproc_randmix_setthreshold(void *x, float threshold){setvec((s16 *)x, 2*threshold-1);}
+void pdp_imageproc_randmix_setseed(void *x, float seed)
+{
+ s16 *d = (s16 *)x;
+ srandom((u32)seed);
+ d[4] = (s16)random();
+ d[5] = (s16)random();
+ d[6] = (s16)random();
+ d[7] = (s16)random();
+
+}
+void pdp_imageproc_randmix_process(void *x, s16 *image, s16 *image2, u32 width, u32 height)
+{
+ s16 *d = (s16 *)x;
+ unsigned int totalnbpixels = width * height;
+ pixel_randmix_s16(image, image2, totalnbpixels>>2, d+4, d);
+}
+
+// affine transformation (applies gain + adds offset)
+void *pdp_imageproc_affine_new(void){return malloc(8*sizeof(s16));}
+void pdp_imageproc_affine_delete(void *x){free(x);}
+void pdp_imageproc_affine_setgain(void *x, float gain){setvec((s16 *)x, gain);}
+void pdp_imageproc_affine_setoffset(void *x, float offset){setvec((s16 *)x+4, offset);}
+void pdp_imageproc_affine_process(void *x, s16 *image, u32 width, u32 height)
+{
+ s16 *d = (s16 *)x;
+ pixel_affine_s16(image, (width*height)>>2, d, d+4);
+}
+
+// 3x1 or 1x3 in place convolution
+// orientation
+void *pdp_imageproc_conv_new(void){return(malloc(16*sizeof(s16)));}
+void pdp_imageproc_conv_delete(void *x){free(x);}
+void pdp_imageproc_conv_setmin1(void *x, float val){setvec((s16 *)x, val);}
+void pdp_imageproc_conv_setzero(void *x, float val){setvec((s16 *)x+4, val);}
+void pdp_imageproc_conv_setplus1(void *x, float val){setvec((s16 *)x+8, val);}
+void pdp_imageproc_conv_setbordercolor(void *x, float val){setvec((s16 *)x+12, val);}
+void pdp_imageproc_conv_process(void *x, s16 *image, u32 width, u32 height, u32 orientation, u32 nbp)
+{
+ s16 *d = (s16 *)x;
+ u32 i,j;
+
+ if (orientation == PDP_IMAGEPROC_CONV_HORIZONTAL)
+ {
+ for(i=0; i<width*height; i+=width)
+ for (j=0; j<nbp; j++)
+ pixel_conv_hor_s16(image+i, width>>2, d+12, d);
+ }
+
+ else
+ {
+ for (j=0; j<nbp; j++)
+ for(i=0; i<width; i +=4) pixel_conv_ver_s16(image+i, height, width, d+12, d);
+ }
+
+
+
+}
+
+// apply a gain to an image
+void *pdp_imageproc_gain_new(void){return(malloc(8*sizeof(s16)));}
+void pdp_imageproc_gain_delete(void *x){free(x);}
+void pdp_imageproc_gain_setgain(void *x, float gain)
+{
+ /* convert float to s16 + shift */
+ s16 *d = (s16 *)x;
+ s16 g;
+ int i;
+ float sign;
+ int shift = 0;
+
+ sign = (gain < 0) ? -1 : 1;
+ gain *= sign;
+
+ /* max shift = 16 */
+ for(i=0; i<=16; i++){
+ if (gain < 0x4000){
+ gain *= 2;
+ shift++;
+ }
+ else break;
+ }
+
+ gain *= sign;
+ g = (s16) gain;
+
+ //g = 0x4000;
+ //shift = 14;
+
+ d[0]=g;
+ d[1]=g;
+ d[2]=g;
+ d[3]=g;
+ d[4]=(s16)shift;
+ d[5]=0;
+ d[6]=0;
+ d[7]=0;
+}
+void pdp_imageproc_gain_process(void *x, s16 *image, u32 width, u32 height)
+{
+ s16 *d = (s16 *)x;
+ pixel_gain_s16(image, (width*height)>>2, d, (u64 *)(d+4));
+}
+
+// colour rotation for 2 colour planes
+void *pdp_imageproc_crot2d_new(void){return malloc(16*sizeof(s16));}
+void pdp_imageproc_crot2d_delete(void *x){free(x);}
+void pdp_imageproc_crot2d_setmatrix(void *x, float *matrix)
+{
+ s16 *d = (s16 *)x;
+ setvec(d, matrix[0]);
+ setvec(d+4, matrix[1]);
+ setvec(d+8, matrix[2]);
+ setvec(d+12, matrix[3]);
+}
+void pdp_imageproc_crot2d_process(void *x, s16 *image, u32 width, u32 height)
+{
+ s16 *d = (s16 *)x;
+ pixel_crot2d_s16(image, width*height >> 2, d);
+}
+
+// biquad and biquad time
+void *pdp_imageproc_bq_new(void){return malloc((5+2+2)*4*sizeof(s16));}//5xcoef, 2xstate, 2xsavestate
+void pdp_imageproc_bq_delete(void *x){free(x);}
+void pdp_imageproc_bq_setcoef(void *x, float *coef) // a0,-a1,-a2,b0,b1,b2,u0,u1
+{
+ s16 *d = (s16 *)x;
+ float ia0 = 1.0f / coef[0];
+
+ /* all coefs are s1.14 fixed point */
+ /* representing values -2 < x < 2 */
+ /* so scale down before using the ordinary s0.15 float->fixed routine */
+
+ ia0 *= 0.5f;
+
+ // coef
+ setvec(d, ia0*coef[1]);
+ setvec(d+4, ia0*coef[2]);
+ setvec(d+8, ia0*coef[3]);
+ setvec(d+12, ia0*coef[4]);
+ setvec(d+16, ia0*coef[5]);
+
+ // state to reset too
+ setvec(d+28, coef[6]);
+ setvec(d+32, coef[7]);
+
+}
+void pdp_imageproc_bqt_process(void *x, s16 *image, s16 *state0, s16 *state1, u32 width, u32 height)
+{
+ s16 *d = (s16 *)x;
+ pixel_biquad_time_s16(image, state0, state1, d, (width*height)>>2);
+}
+
+void pdp_imageproc_bq_process(void *x, s16 *image, u32 width, u32 height, u32 direction, u32 nbp)
+{
+ s16 *d = (s16 *)x;
+ unsigned int i,j;
+
+
+
+ /* VERTICAL */
+
+ if ((direction & PDP_IMAGEPROC_BIQUAD_TOP2BOTTOM)
+ && (direction & PDP_IMAGEPROC_BIQUAD_BOTTOM2TOP)){
+
+ for(i=0; i<width; i +=4){
+ for (j=0; j<nbp; j++){
+ pixel_biquad_vertb_s16(image+i, height>>2, width, d, d + (5*4));
+ pixel_biquad_verbt_s16(image+i, height>>2, width, d, d + (5*4));
+ }
+ }
+ }
+
+ else if (direction & PDP_IMAGEPROC_BIQUAD_TOP2BOTTOM){
+ for(i=0; i<width; i +=4){
+ for (j=0; j<nbp; j++){
+ pixel_biquad_vertb_s16(image+i, height>>2, width, d, d + (5*4));
+ }
+ }
+ }
+
+ else if (direction & PDP_IMAGEPROC_BIQUAD_BOTTOM2TOP){
+ for(i=0; i<width; i +=4){
+ for (j=0; j<nbp; j++){
+ pixel_biquad_verbt_s16(image+i, height>>2, width, d, d + (5*4));
+ }
+ }
+ }
+
+ /* HORIZONTAL */
+
+ if ((direction & PDP_IMAGEPROC_BIQUAD_LEFT2RIGHT)
+ && (direction & PDP_IMAGEPROC_BIQUAD_RIGHT2LEFT)){
+
+ for(i=0; i<(width*height); i +=(width<<2)){
+ for (j=0; j<nbp; j++){
+ pixel_biquad_horlr_s16(image+i, width>>2, width, d, d + (5*4));
+ pixel_biquad_horrl_s16(image+i, width>>2, width, d, d + (5*4));
+ }
+ }
+ }
+
+ else if (direction & PDP_IMAGEPROC_BIQUAD_LEFT2RIGHT){
+ for(i=0; i<(width*height); i +=(width<<2)){
+ for (j=0; j<nbp; j++){
+ pixel_biquad_horlr_s16(image+i, width>>2, width, d, d + (5*4));
+ }
+ }
+ }
+
+ else if (direction & PDP_IMAGEPROC_BIQUAD_RIGHT2LEFT){
+ for(i=0; i<(width*height); i +=(width<<2)){
+ for (j=0; j<nbp; j++){
+ pixel_biquad_horrl_s16(image+i, width>>2, width, d, d + (5*4));
+ }
+ }
+ }
+
+}
+
+// produce a random image
+// note: random number generator can be platform specific
+// however, it should be seeded. (same seed produces the same result)
+void *pdp_imageproc_random_new(void){return malloc(4*sizeof(s16));}
+void pdp_imageproc_random_delete(void *x){free(x);}
+void pdp_imageproc_random_setseed(void *x, float seed)
+{
+ s16 *d = (s16 *)x;
+ srandom((u32)seed);
+ d[0] = (s16)random();
+ d[1] = (s16)random();
+ d[2] = (s16)random();
+ d[3] = (s16)random();
+
+}
+void pdp_imageproc_random_process(void *x, s16 *image, u32 width, u32 height)
+{
+ s16 *d = (s16 *)x;
+ unsigned int totalnbpixels = width * height;
+ pixel_rand_s16(image, totalnbpixels>>2, d);
+}
+
+
diff --git a/system/pdp_imageproc_portable.c b/system/pdp_imageproc_portable.c
new file mode 100644
index 0000000..60062d6
--- /dev/null
+++ b/system/pdp_imageproc_portable.c
@@ -0,0 +1,492 @@
+/*
+ * Pure Data Packet. portable image processing routines.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include <stdlib.h>
+#include "pdp_imageproc.h"
+
+// utility stuff
+inline static s32 float2fixed(float f)
+{
+ if (f > 1) f = 1;
+ if (f < -1) f = -1;
+ f *= 0x7fff;
+ return (s32)f;
+}
+
+
+
+#define CLAMP16(x) (((x) > 0x7fff) ? 0x7fff : (((x) < -0x7fff) ? -0x7fff : (x)))
+
+// add two images
+void pdp_imageproc_add_process(s16 *image, s16 *image2, u32 width, u32 height)
+{
+ int a, b;
+ unsigned int i;
+ for (i=0; i<width*height; i++){
+ a = (int)image[i];
+ b = (int)image2[i];
+ image[i] = (s16)(CLAMP16(a+b));
+ }
+
+}
+
+// mul two images
+void pdp_imageproc_mul_process(s16 *image, s16 *image2, u32 width, u32 height)
+{
+ int a, b;
+ unsigned int i;
+ for (i=0; i<width*height; i++){
+ a = (int)image[i];
+ b = (int)image2[i];
+ image[i] = (s16)((a*b)>>15);
+ }
+
+}
+
+// mix 2 images
+void *pdp_imageproc_mix_new(void){return malloc(2*sizeof(s32));}
+void pdp_imageproc_mix_delete(void *x) {free (x);}
+void pdp_imageproc_mix_setleftgain(void *x, float gain)
+{
+ s32 *d = (s32 *)x;
+ d[0] = float2fixed(gain);
+}
+void pdp_imageproc_mix_setrightgain(void *x, float gain)
+{
+ s32 *d = (s32 *)x;
+ d[1] = float2fixed(gain);
+}
+void pdp_imageproc_mix_process(void *x, s16 *image, s16 *image2, u32 width, u32 height)
+{
+ s32 *d = (s32 *)x;
+ u32 i;
+ s32 a,b;
+
+ for(i=0; i<width*height; i++){
+ a = (s32)image[i];
+ b = (s32)image2[i];
+ a = (a*d[0] + b*d[1]) >> 15;
+ image[i] = (s16)CLAMP16(a);
+ }
+
+}
+
+
+// random mix 2 images
+void *pdp_imageproc_randmix_new(void){return malloc(2*sizeof(s32));;}
+void pdp_imageproc_randmix_delete(void *x) {free(x);}
+void pdp_imageproc_randmix_setthreshold(void *x, float threshold)
+{
+ s32 *d = (s32 *)x;
+ if (threshold > 1.0f) threshold = 1.0f;
+ if (threshold < 0.0f) threshold = 0.0f;
+ d[0] = float2fixed(threshold);
+}
+void pdp_imageproc_randmix_setseed(void *x, float seed)
+{
+ s32 *d = (s32 *)x;
+ d[1] = float2fixed(seed);
+}
+void pdp_imageproc_randmix_process(void *x, s16 *image, s16 *image2, u32 width, u32 height)
+{
+ s32 *d = (s32 *)x;
+ u32 i;
+ s16 r;
+ srandom((u32)d[1]);
+
+
+ for(i=0; i<width*height; i++){
+ // get a random val between 0 and 0x7fff
+ r = (s16)(random() & 0x7fff);
+ if (r < d[0]) image[i] = image2[i];
+ }
+}
+
+// affine transformation (applies gain + adds offset)
+void *pdp_imageproc_affine_new(void){return malloc(2*sizeof(s32));}
+void pdp_imageproc_affine_delete(void *x){free(x);}
+void pdp_imageproc_affine_setgain(void *x, float gain)
+{
+ s32 *d = (s32 *)x;
+ d[0] = float2fixed(gain);
+}
+
+void pdp_imageproc_affine_setoffset(void *x, float offset)
+{
+ s32 *d = (s32 *)x;
+ d[1] = float2fixed(offset);
+}
+void pdp_imageproc_affine_process(void *x, s16 *image, u32 width, u32 height)
+{
+ s32 *d = (s32 *)x;
+ u32 i;
+ s32 a;
+
+ for(i=0; i<width*height; i++){
+ a = (s32)image[i];
+ a = (a*d[0]) >> 15;
+ a += d[1];
+ image[i] = (s16)CLAMP16(a);
+ }
+}
+
+// 3x1 or 1x3 in place convolution
+// orientation
+void *pdp_imageproc_conv_new(void){return(malloc(4*sizeof(s32)));}
+void pdp_imageproc_conv_delete(void *x){free(x);}
+void pdp_imageproc_conv_setmin1(void *x, float val)
+{
+ s32 *d = (s32 *)x;
+ d[0] = float2fixed(val);
+}
+void pdp_imageproc_conv_setzero(void *x, float val)
+{
+ s32 *d = (s32 *)x;
+ d[1] = float2fixed(val);
+}
+void pdp_imageproc_conv_setplus1(void *x, float val)
+{
+ s32 *d = (s32 *)x;
+ d[2] = float2fixed(val);
+}
+void pdp_imageproc_conv_setbordercolor(void *x, float val)
+{
+ s32 *d = (s32 *)x;
+ d[3] = float2fixed(val);
+}
+
+static inline void pdp_imageproc_conv_scanline(void *x, s16 *data, u32 count, s32 stride)
+{
+ s32 *d = (s32 *)x;
+ s32 a,b,c,r;
+ u32 i;
+
+ a = d[3]; //border
+ b = data[0];
+ c = data[stride];
+
+ for(i = 0; i < count-2; i++){
+ r = a*d[0] + b*d[1] + c*d[2];
+ a = data[0];
+ b = data[stride];
+ c = data[stride<<1];
+ data[0] = (s16)CLAMP16(r>>15);
+ data += stride;
+ }
+ r = a*d[0] + b*d[1] + c*d[2];
+ a = data[0];
+ b = data[stride];
+ c = d[3]; //border
+ data[0] = (s16)CLAMP16(r>>15);
+ r = a*d[0] + b*d[1] + c*d[2];
+ data[stride] = (s16)CLAMP16(r>>15);
+
+}
+
+void pdp_imageproc_conv_process(void *x, s16 *image, u32 width, u32 height, u32 orientation, u32 nbp)
+{
+ s32 *d = (s32 *)x;
+ u32 i, j;
+
+ if (orientation == PDP_IMAGEPROC_CONV_HORIZONTAL){
+ for(i=0; i<width*height; i+=width)
+ for(j=0; j<nbp; j++)
+ pdp_imageproc_conv_scanline(x, image+i, width, 1);
+
+ }
+
+ if (orientation == PDP_IMAGEPROC_CONV_VERTICAL){
+ for(i=0; i<width; i++)
+ for(j=0; j<nbp; j++)
+ pdp_imageproc_conv_scanline(x, image+i, height, width);
+
+ }
+
+
+
+
+}
+
+// apply a gain to an image
+void *pdp_imageproc_gain_new(void){return(malloc(2*sizeof(s32)));}
+void pdp_imageproc_gain_delete(void *x){free(x);}
+void pdp_imageproc_gain_setgain(void *x, float gain)
+{
+ /* convert float to s16 + shift */
+ s32 *d = (s32 *)x;
+ s32 g;
+ int i;
+ float sign;
+ s32 shift = 0;
+
+ sign = (gain < 0) ? -1 : 1;
+ gain *= sign;
+
+ /* max shift = 16 */
+ for(i=0; i<=16; i++){
+ if (gain < 0x4000){
+ gain *= 2;
+ shift++;
+ }
+ else break;
+ }
+
+ gain *= sign;
+ g = (s32) gain;
+
+ //g = 0x4000;
+ //shift = 14;
+
+ d[0]=g;
+ d[1]=shift;
+}
+void pdp_imageproc_gain_process(void *x, s16 *image, u32 width, u32 height)
+{
+ s32 *d = (s32 *)x;
+ s32 a;
+ u32 i;
+ for (i=0; i<width*height; i++){
+ a = (s32)image[i];
+ image[i] = (s16)(CLAMP16((a * d[0]) >> d[1]));
+ }
+}
+
+// colour rotation for 2 colour planes
+void *pdp_imageproc_crot2d_new(void){return malloc(4*sizeof(s32));}
+void pdp_imageproc_crot2d_delete(void *x){free(x);}
+void pdp_imageproc_crot2d_setmatrix(void *x, float *matrix)
+{
+ s32 *d = (s32 *)x;
+ d[0] = float2fixed(matrix[0]);
+ d[1] = float2fixed(matrix[1]);
+ d[2] = float2fixed(matrix[2]);
+ d[3] = float2fixed(matrix[3]);
+
+}
+void pdp_imageproc_crot2d_process(void *x, s16 *image, u32 width, u32 height)
+{
+ s32 *d = (s32 *)x;
+ u32 i,j;
+ s32 a1,a2,c1,c2;
+
+ for(i=0, j=width*height; i<width*height; i++, j++){
+ c1 = (s32)image[i];
+ c2 = (s32)image[j];
+
+ a1 = d[0] * c1;
+ a2 = d[1] * c1;
+ a1+= d[2] * c2;
+ a2+= d[3] * c2;
+
+ a1 >>= 15;
+ a2 >>= 15;
+
+ image[i] = (s16)CLAMP16(a1);
+ image[j] = (s16)CLAMP16(a2);
+ }
+}
+
+// biquad and biquad time
+void *pdp_imageproc_bq_new(void){return malloc((5+2+2)*sizeof(s32));}//5xcoef, 2xstate, 2xsavestate
+void pdp_imageproc_bq_delete(void *x){free(x);}
+void pdp_imageproc_bq_setcoef(void *x, float *coef) // a0,-a1,-a2,b0,b1,b2,u0,u1
+{
+ s32 *d = (s32 *)x;
+ float ia0 = 1.0f / coef[0];
+
+ /* all coefs are s1.14 fixed point */
+ /* representing values -2 < x < 2 */
+ /* so scale down before using the ordinary s0.15 float->fixed routine */
+
+ ia0 *= 0.5f;
+
+ // coef
+ d[0] = float2fixed(ia0*coef[1]); // -a1
+ d[1] = float2fixed(ia0*coef[2]); // -a2
+ d[2] = float2fixed(ia0*coef[3]); // b0
+ d[3] = float2fixed(ia0*coef[4]); // b1
+ d[4] = float2fixed(ia0*coef[5]); // b2
+
+
+ // state to reset too
+ d[5] = float2fixed(coef[6]);
+ d[6] = float2fixed(coef[7]);
+
+}
+
+#define A1 d[0]
+#define A2 d[1]
+#define B0 d[2]
+#define B1 d[3]
+#define B2 d[4]
+/*
+ # DIRECT FORM II BIQUAD (from pixel_biquad_s16.s)
+ #
+ # y[k] = b0 * x[k] + u1[k-1]
+ # u1[k] = b1 * x[k] + u2[k-1] - a1 * y[k]
+ # u2[k] = b2 * x[k] - a2 * y[k]
+*/
+
+/* remark A1 and A2 are already negated) */
+
+
+static inline void pdp_imageproc_bq_scanline(void *x, s16 *data, u32 count, s32 stride)
+{
+
+ s32 *d = (s32 *)x;
+ s32 u1,u2, xx, yy;
+
+ u32 i;
+
+ u1 = d[7];
+ u2 = d[8];
+
+ for(i = 0; i < count; i++){
+
+ xx = (s32)data[0];
+
+ yy = ((B0 * xx)>>14) + u1;
+ u1 = ((B1 * xx)>>14) + u2 + ((A1 * yy)>>14);
+ u2 = ((B2 * xx)>>14) + ((A2 * yy)>>14);
+
+ data[0] = (s16)CLAMP16(yy);
+
+ data += stride;
+
+ }
+
+ d[7] = u1;
+ d[8] = u2;
+
+}
+
+void pdp_imageproc_bqt_process(void *x, s16 *image, s16 *state1, s16 *state2, u32 width, u32 height)
+{
+ s32 *d = (s32 *)x;
+ u32 i;
+ s32 u1, u2, xx, yy;
+
+ for (i=0; i<width*height; i++){
+
+ xx = (s32)image[i];
+ u1 = (s32)state1[i];
+ u2 = (s32)state2[i];
+
+ yy = ((B0 * xx)>>14) + u1;
+ u1 = ((B1 * xx)>>14) + u2 + ((A1 * yy)>>14);
+ u2 = ((B2 * xx)>>14) + ((A2 * yy)>>14);
+
+ image[i] = (s16)CLAMP16(yy);
+ state1[i] = (s16)CLAMP16(u1);
+ state2[i] = (s16)CLAMP16(u2);
+ }
+
+
+}
+
+void pdp_imageproc_bq_process(void *x, s16 *data, u32 width, u32 height, u32 direction, u32 nbp)
+{
+ s32 *d = (s32 *)x;
+ unsigned int i,j, offset;
+
+ /* VERTICAL */
+ offset = (height-1)*width;
+
+ if ((direction & PDP_IMAGEPROC_BIQUAD_TOP2BOTTOM)
+ && (direction & PDP_IMAGEPROC_BIQUAD_BOTTOM2TOP)){
+
+ for(i=0; i<width; i++){
+ for (j=0; j<nbp; j++){
+ pdp_imageproc_bq_scanline(x, data+i, height, width); //T->B
+ pdp_imageproc_bq_scanline(x, data+offset+i, height, -width); //B->T
+ }
+ }
+ }
+
+ else if (direction & PDP_IMAGEPROC_BIQUAD_TOP2BOTTOM){
+ for(i=0; i<width; i++){
+ for (j=0; j<nbp; j++){
+ pdp_imageproc_bq_scanline(x, data+i, height, width); //T->B
+ }
+ }
+ }
+
+ else if (direction & PDP_IMAGEPROC_BIQUAD_BOTTOM2TOP){
+ for(i=0; i<width; i++){
+ for (j=0; j<nbp; j++){
+ pdp_imageproc_bq_scanline(x, data+offset+i, height, -width); //B->T
+ }
+ }
+ }
+
+ /* HORIZONTAL */
+
+ offset = width-1;
+ if ((direction & PDP_IMAGEPROC_BIQUAD_LEFT2RIGHT)
+ && (direction & PDP_IMAGEPROC_BIQUAD_RIGHT2LEFT)){
+
+ for(i=0; i<(width*height); i += width){
+ for (j=0; j<nbp; j++){
+ pdp_imageproc_bq_scanline(x, data+i, width, 1); //L->R
+ pdp_imageproc_bq_scanline(x, data+offset+i, width, -1); //R->L
+ }
+ }
+ }
+
+ else if (direction & PDP_IMAGEPROC_BIQUAD_LEFT2RIGHT){
+ for(i=0; i<(width*height); i += width){
+ for (j=0; j<nbp; j++){
+ pdp_imageproc_bq_scanline(x, data+i, width, 1); //L->R
+ }
+ }
+ }
+
+ else if (direction & PDP_IMAGEPROC_BIQUAD_RIGHT2LEFT){
+ for(i=0; i<(width*height); i += width){
+ for (j=0; j<nbp; j++){
+ pdp_imageproc_bq_scanline(x, data+offset+i, width, -1); //R->L
+
+ }
+ }
+ }
+
+}
+
+// produce a random image
+// note: random number generator can be platform specific
+// however, it should be seeded. (same seed produces the same result)
+void *pdp_imageproc_random_new(void){return malloc(sizeof(s32));}
+void pdp_imageproc_random_delete(void *x){free(x);}
+void pdp_imageproc_random_setseed(void *x, float seed)
+{
+ s32 *d = (s32 *)x;
+ d[0] = float2fixed(seed);
+}
+void pdp_imageproc_random_process(void *x, s16 *image, u32 width, u32 height)
+{
+ s32 *d = (s32 *)x;
+ u32 i;
+ srandom((u32)d[0]);
+ for (i=0; i<width*height; i++) image[i] = (s16)(random() & 0xffff);
+
+}
+
diff --git a/system/pdp_llconv.c b/system/pdp_llconv.c
new file mode 100644
index 0000000..93d2934
--- /dev/null
+++ b/system/pdp_llconv.c
@@ -0,0 +1,293 @@
+/*
+ * Pure Data Packet system implementation. : low level format conversion code
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* this file contains low level image conversion code
+ nominated as "the ugliest part of pdp"
+ some code is mmx, most is not. */
+
+#include "pdp_llconv.h"
+#include "pdp_mmx.h"
+
+
+/* all symbols are C style */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+#define CLAMP(x) (((x)<0) ? 0 : ((x>255)? 255 : (x)))
+#define CLAMP16(x) (((x)<-0x7fff) ? -0x7fff : ((x>0x7fff) ? 0x7fff : (x)))
+#define FP(x) ((int)(((float)(x)) * 256.0f))
+
+
+/* some prototypes for functions defined elsewhere */
+void llconv_yvu_planar_s16u8(short int *src, unsigned char *dst, unsigned int nbpixels);
+void llconv_yuv_planar_u8s16(unsigned char* source, short int *dest, int nbpixels);
+void llconv_grey_s16u8(short int *src, unsigned char *dst, unsigned int nbpixels);
+void llconv_yvu_planar_u8s16(unsigned char* source, short int *dest, int nbpixels);
+
+
+static inline int rgb2y(int r, int g, int b){return (FP(0.257) * r) + (FP(0.504) * g) + (FP(0.098) * b) + FP(16);}
+static inline int rgb2v(int r, int g, int b){return (FP(0.439) * r) - (FP(0.368) * g) - (FP(0.071) * b) + FP(128);}
+static inline int rgb2u(int r, int g, int b){return -(FP(0.148) * r) - (FP(0.291) * g) + (FP(0.439) * b) + FP(128);}
+
+
+/* "standard" 8 bit conversion routine */
+static void llconv_rgb2yvu(unsigned char* src, unsigned char* dst, int nbpixels)
+{
+ int r,g,b,y,v,u,i;
+ for (i=0; i<nbpixels; i++){
+ r = src[0];
+ g = src[1];
+ b = src[2];
+
+ y = rgb2y(r,g,b);
+ v = rgb2v(r,g,b);
+ u = rgb2u(r,g,b);
+
+ dst[0] = CLAMP(y>>8);
+ dst[1] = CLAMP(v>>8);
+ dst[2] = CLAMP(u>>8);
+
+ src += 3;
+ dst += 3;
+ }
+}
+
+
+
+/* 8 bit rgb to 16 bit planar subsampled yvu */
+static void llconv_rgb2yvu_planar16sub(unsigned char* src, short int* dst, int w, int h)
+{
+ int r,g,b,y,v,u,i,j,k;
+ int size = w*h;
+
+ int voffset = size;
+ int uoffset = size + (size>>2);
+
+
+ int loffset = w * 3;
+
+ k=0;
+ for (j=0; j<w*h; j+=(w<<1)){
+ k = 3 * j;
+ for (i=0; i<w; i+=2){
+
+
+ // well, this seems to work... strange though
+ b = src[k];
+ g = src[k+1];
+ r = src[k+2];
+
+ y = (FP(0.257) * r) + (FP(0.504) * g) + (FP(0.098) * b) + FP(16);
+ v = (FP(0.439) * r) - (FP(0.368) * g) - (FP(0.071) * b);
+ u = -(FP(0.148) * r) - (FP(0.291) * g) + (FP(0.439) * b);
+
+ dst[i+j] = CLAMP16(y >> 1);
+
+ b = src[k+3];
+ g = src[k+4];
+ r = src[k+5];
+
+ y = (FP(0.257) * r) + (FP(0.504) * g) + (FP(0.098) * b) + FP(16);
+ v += (FP(0.439) * r) - (FP(0.368) * g) - (FP(0.071) * b);
+ u += -(FP(0.148) * r) - (FP(0.291) * g) + (FP(0.439) * b);
+
+ dst[i+j+1] = CLAMP16(y >> 1);
+
+
+
+ b = src[loffset + k];
+ g = src[loffset + k+1];
+ r = src[loffset + k+2];
+
+ y = (FP(0.257) * r) + (FP(0.504) * g) + (FP(0.098) * b) + FP(16);
+ v = (FP(0.439) * r) - (FP(0.368) * g) - (FP(0.071) * b);
+ u = -(FP(0.148) * r) - (FP(0.291) * g) + (FP(0.439) * b);
+
+ dst[w+i+j] = CLAMP16(y >> 1);
+
+ b = src[loffset + k+3];
+ g = src[loffset + k+4];
+ r = src[loffset + k+5];
+
+ k += 6;
+
+ y = (FP(0.257) * r) + (FP(0.504) * g) + (FP(0.098) * b) + FP(16);
+ v += (FP(0.439) * r) - (FP(0.368) * g) - (FP(0.071) * b);
+ u += -(FP(0.148) * r) - (FP(0.291) * g) + (FP(0.439) * b);
+
+ dst[w+i+j+1] = CLAMP16(y >> 1);
+
+ dst[uoffset+ (i>>1) + (j>>2)] = (CLAMP16(u >> 1));
+ dst[voffset+ (i>>1) + (j>>2)] = (CLAMP16(v >> 1));
+ }
+ }
+}
+
+/* these seem to be pretty slow */
+
+static void llconv_yvu2rgb(unsigned char* src, unsigned char* dst, int nbpixels)
+{
+ int r,g,b,y,v,u,i;
+ for (i=0; i<nbpixels; i++){
+ y = src[0];
+ v = src[1];
+ u = src[2];
+
+
+ b = FP(1.164) * (y - 16) + FP(2.018) * (u - 128);
+ g = FP(1.164) * (y - 16) - FP(0.813) * (v - 128) - FP(0.391) * (u - 128);
+ r = FP(1.164) * (y - 16) + FP(1.596) * (v - 128);
+
+ dst[0] = CLAMP(r>>8);
+ dst[1] = CLAMP(g>>8);
+ dst[2] = CLAMP(b>>8);
+
+ src += 3;
+ dst += 3;
+ }
+}
+
+
+
+/* convert yvu to yuyv */
+static void llconv_yvu2yuyv(unsigned char *src, unsigned char *dst, unsigned int nbpixels)
+{
+ unsigned int y1, y2, u, v, i;
+
+ for (i = 0; i < nbpixels/2; i++){
+
+ y1 = src[0];
+ y2 = src[3];
+ v = (src[1] + src[4]) >> 1;
+ u = (src[2] + src[5]) >> 1;
+ dst[0] = y1;
+ dst[1] = u;
+ dst[2] = y2;
+ dst[3] = v;
+
+ src += 6;
+ dst += 4;
+
+ }
+
+}
+
+
+
+/* convert yuvu packed 8 bit unsigned to yv12 planar 16bit signed */
+static void llconv_yuyv_packed_u8s16(unsigned char* ucsource, short int *sidest, unsigned int w, unsigned int h)
+{
+ unsigned int i, j;
+ unsigned int *source = (unsigned int *)ucsource;
+
+ unsigned int *dest = (unsigned int *)sidest;
+ unsigned int uoffset = (w*h)>>1;
+ unsigned int voffset = (w*h + ((w*h) >> 2)) >> 1;
+
+ for(j=0; j < (h*w)>>1; j +=(w)){
+ for(i=0; i< (w>>1); i+=2){
+ unsigned int y,u,v;
+ unsigned int v00, v01, v10, v11;
+ v00 = source[i+j];
+ v01 = source[i+j+1];
+ v10 = source[i+j+(w>>1)];
+ v11 = source[i+j+(w>>1)+1];
+
+ // save luma
+ dest[i+j] = ((v00 & 0x00ff00ff) << 7);
+ dest[i+j+1] = ((v01 & 0x00ff00ff) << 7);
+ dest[i+j+(w>>1)] = ((v10 & 0x00ff00ff) << 7);
+ dest[i+j+(w>>1)+1] = ((v11 & 0x00ff00ff) << 7);
+
+ // compute chroma
+
+ // mask out luma & shift right
+ v00 = (v00 & 0xff00ff00)>>1;
+ v01 = (v01 & 0xff00ff00)>>1;
+ v10 = (v10 & 0xff00ff00)>>1;
+ v11 = (v11 & 0xff00ff00)>>1;
+
+ // average 2 scan lines
+ v00 += v10;
+ v01 += v11;
+
+ // combine
+ v = (v01 << 16) | (v00 & 0x0000ffff);
+ u = (v01 & 0xffff0000) | (v00 >> 16);
+
+ // flip sign bits for u,v
+ u ^= 0x80008000;
+ v ^= 0x80008000;
+
+ // save chroma
+ dest[uoffset + (i>>1) + (j>>2)] = u;
+ dest[voffset + (i>>1) + (j>>2)] = v;
+ }
+ }
+
+
+}
+
+#define CONVERT(x,y) ((x) + ((y)<<16))
+
+void pdp_llconv(void *src, int stype, void *dst, int dtype, int w, int h)
+{
+ int conversion = CONVERT(stype, dtype);
+ void *tmpbuf;
+
+ switch(CONVERT(stype, dtype)){
+
+ case CONVERT( RIF_YVU__P411_U8, RIF_YVU__P411_S16 ):
+ llconv_yvu_planar_u8s16((unsigned char*)src, (short int *)dst, w*h);
+ break;
+
+ case CONVERT( RIF_YUV__P411_U8, RIF_YVU__P411_S16 ):
+ llconv_yuv_planar_u8s16((unsigned char*)src, (short int *)dst, w*h);
+ break;
+
+ case CONVERT( RIF_YUYV_P____U8, RIF_YVU__P411_S16 ):
+ llconv_yuyv_packed_u8s16((unsigned char*)src, (short int *)dst, w, h);
+ break;
+
+ case CONVERT( RIF_RGB__P____U8, RIF_YVU__P411_S16 ):
+ llconv_rgb2yvu_planar16sub((unsigned char*) src, (short int*) dst, w, h);
+ break;
+
+ case CONVERT( RIF_YVU__P411_S16, RIF_YVU__P411_U8 ):
+ llconv_yvu_planar_s16u8((short int*)src, (unsigned char*)dst, w*h);
+ break;
+
+ case CONVERT( RIF_GREY______S16, RIF_GREY______U8 ):
+ llconv_grey_s16u8((short int*)src, (unsigned char*)dst, w*h);
+ break;
+ default:
+ post("pdp_llconv: WARNING: no conversion routine defined for (%d)->(%d)", stype, dtype);
+
+ }
+
+}
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/system/pdp_llconv_mmx.c b/system/pdp_llconv_mmx.c
new file mode 100644
index 0000000..8070bac
--- /dev/null
+++ b/system/pdp_llconv_mmx.c
@@ -0,0 +1,55 @@
+
+/*
+ * Pure Data Packet system implementation. : wrapper for mmx low level format conversion code
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include "pdp_mmx.h"
+
+
+
+/* convert greyscale 8 bit unsigned to 16bit signed */
+void llconv_grey_s16u8(short int *src, unsigned char *dst, unsigned int nbpixels)
+{
+ pixel_pack_s16u8_y(src, dst, nbpixels>>3);
+}
+
+/* convert yvu planar 411 16 bit signed to 8 bit unsigned */
+void llconv_yvu_planar_s16u8(short int *src, unsigned char *dst, unsigned int nbpixels)
+{
+ pixel_pack_s16u8_y(src, dst, nbpixels>>3);
+ pixel_pack_s16u8_uv(src + nbpixels, dst + nbpixels, nbpixels>>4);
+}
+
+
+/* convert yvu planar 411 8 bit unsigned to yv12 planar 16bit signed */
+void llconv_yvu_planar_u8s16(unsigned char* source, short int *dest, int nbpixels)
+{
+ pixel_unpack_u8s16_y(source, dest, nbpixels>>3);
+ pixel_unpack_u8s16_uv(&source[nbpixels], &dest[nbpixels], nbpixels>>4);
+}
+
+/* convert yuv planar 411 8 bit unsigned to yv12 planar 16bit signed */
+void llconv_yuv_planar_u8s16(unsigned char* source, short int *dest, int nbpixels)
+{
+ pixel_unpack_u8s16_y(source, dest, nbpixels>>3);
+ pixel_unpack_u8s16_uv(&source[nbpixels], &dest[nbpixels + (nbpixels>>2)], nbpixels>>5);
+ pixel_unpack_u8s16_uv(&source[nbpixels + (nbpixels>>2)], &dest[nbpixels], nbpixels>>5);
+}
+
diff --git a/system/pdp_llconv_portable.c b/system/pdp_llconv_portable.c
new file mode 100644
index 0000000..de65ef5
--- /dev/null
+++ b/system/pdp_llconv_portable.c
@@ -0,0 +1,81 @@
+
+/*
+ * Pure Data Packet system implementation. : portable low level format conversion code
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#define CLAMP(x) (((x)<0) ? 0 : ((x>255)? 255 : (x)))
+#define FP(x) ((int)(((float)(x)) * 256.0f))
+
+void pixel_unpack_portable_u8s16_y(unsigned char *src ,short int *dst, unsigned int nbpixels)
+{
+ unsigned int i;
+ for (i=0; i<nbpixels; i++) dst[i] = ((short int)(src[i])) << 7;
+}
+
+void pixel_unpack_portable_u8s16_uv(unsigned char *src ,short int *dst, unsigned int nbpixels)
+{
+ unsigned int i;
+ for (i=0; i<nbpixels; i++) dst[i] = (((short int)(src[i])) << 8) ^ 0x8000;
+}
+
+
+void pixel_pack_portable_s16u8_y(short int *src, unsigned char *dst, unsigned int nbpixels)
+{
+ unsigned int i;
+ for (i=0; i<nbpixels; i++) dst[i] = (unsigned char)(CLAMP(src[i]>>7));
+}
+
+void pixel_pack_portable_s16u8_uv(short int *src, unsigned char *dst, unsigned int nbpixels)
+{
+ unsigned int i;
+ for (i=0; i<nbpixels; i++) dst[i] = (unsigned char)((src[i]^0x8000)>>8);
+}
+
+
+/* convert greyscale 8 bit unsigned to 16bit signed */
+void llconv_grey_s16u8(short int *src, unsigned char *dst, unsigned int nbpixels)
+{
+ pixel_pack_portable_s16u8_y(src, dst, nbpixels);
+}
+
+/* convert yvu planar 411 16 bit signed to 8 bit unsigned */
+void llconv_yvu_planar_s16u8(short int *src, unsigned char *dst, unsigned int nbpixels)
+{
+ pixel_pack_portable_s16u8_y(src, dst, nbpixels);
+ pixel_pack_portable_s16u8_uv(src + nbpixels, dst + nbpixels, nbpixels>>1);
+
+}
+
+
+/* convert yvu planar 411 8 bit unsigned to yv12 planar 16bit signed */
+void llconv_yvu_planar_u8s16(unsigned char* source, short int *dest, int nbpixels)
+{
+ pixel_unpack_portable_u8s16_y(source, dest, nbpixels);
+ pixel_unpack_portable_u8s16_uv(&source[nbpixels], &dest[nbpixels], nbpixels>>1);
+}
+
+/* convert yuv planar 411 8 bit unsigned to yv12 planar 16bit signed */
+void llconv_yuv_planar_u8s16(unsigned char* source, short int *dest, int nbpixels)
+{
+ pixel_unpack_portable_u8s16_y(source, dest, nbpixels);
+ pixel_unpack_portable_u8s16_uv(&source[nbpixels], &dest[nbpixels + (nbpixels>>2)], nbpixels>>2);
+ pixel_unpack_portable_u8s16_uv(&source[nbpixels + (nbpixels>>2)], &dest[nbpixels], nbpixels>>2);
+}
+
+
diff --git a/system/pdp_packet.c b/system/pdp_packet.c
new file mode 100644
index 0000000..0c0b2c2
--- /dev/null
+++ b/system/pdp_packet.c
@@ -0,0 +1,239 @@
+/*
+ * Pure Data Packet system implementation:
+ * code for allocation/deallocation/copying/...
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "pdp.h"
+#include <stdio.h>
+
+/* all symbols are C style */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* this needs to be able to grow dynamically, think about it later */
+#define PDP_OBJECT_ARRAY_SIZE 1024
+static t_pdp* pdp_stack[PDP_OBJECT_ARRAY_SIZE];
+
+
+/* some global vars */
+static t_symbol* pdp_sym_register_rw;
+static t_symbol* pdp_sym_register_ro;
+static t_symbol* pdp_sym_process;
+
+
+/* setup methods */
+
+void
+pdp_packet_setup(void)
+{
+ bzero(pdp_stack, PDP_OBJECT_ARRAY_SIZE * sizeof(t_pdp *));
+ pdp_sym_register_rw = gensym("register_rw");
+ pdp_sym_register_ro = gensym("register_ro");
+ pdp_sym_process = gensym("process");
+}
+
+void
+pdp_packet_destroy(void)
+{
+ int i = 0;
+ /* dealloc all the data in object stack */
+ while ((i < PDP_OBJECT_ARRAY_SIZE) && (pdp_stack[i])) free(pdp_stack[i++]);
+}
+
+
+/* private pdp_mem methods */
+
+
+/* public object manips */
+
+
+/* alloc method: alloc time is linear in the number of used packets */
+/* think about a better (tree) method when this number grows large */
+int
+pdp_packet_new(unsigned int datatype, unsigned int datasize /*without header*/)
+{
+ unsigned int totalsize = datasize + PDP_HEADER_SIZE;
+ int i = 0;
+ unsigned int align;
+ t_pdp* p;
+ for (i=0; i < PDP_OBJECT_ARRAY_SIZE; i++){
+ p = pdp_stack[i];
+ /* check if we can reuse this one if it is already allocated */
+ if (p) {
+ /* remark: if p->size >= totalsize we can give away the packet */
+ /* but that would lead to unefficient use if we have a lot of packets */
+ /* of different sizes */
+ if ((p->users == 0) && (p->size == totalsize) && (p->type == datatype)){
+ //post("pdp_new_object: can reuse %d", i);
+ p->users = 1;
+ return i;
+ }
+ else{
+ //post("pdp_new_object: can't reuse %d, (%d users)", i, p->users);
+ //post("size:%d, newsize:%d, type:%d, newtype:%d", p->size, totalsize, p->type, datatype);
+ }
+ }
+ /* allocate new one */
+ else {
+ p = (t_pdp *)malloc(totalsize);
+ align = ((unsigned int)p) & (PDP_ALIGN - 1);
+ if (align) post("pdp_new_object: warning data misaligned by %x", align);
+ pdp_stack[i] = p;
+ p->type = datatype;
+ p->size = totalsize;
+ p->users = 1;
+ //post("pdp_new_object: allocating new (%d)", i);
+ return i;
+ }
+ }
+ post("pdp_new_object: WARNING: out of memory");
+
+ return -1;
+
+}
+
+
+t_pdp*
+pdp_packet_header(int handle)
+{
+ if ((handle >= 0) && (handle < PDP_OBJECT_ARRAY_SIZE)) return pdp_stack[handle];
+ else return 0;
+}
+
+void*
+pdp_packet_data(int handle)
+{
+ if ((handle >= 0) && (handle < PDP_OBJECT_ARRAY_SIZE))
+ return (char *)(pdp_stack[handle]) + PDP_HEADER_SIZE;
+ else return 0;
+}
+
+
+
+int
+pdp_packet_copy_ro(int handle)
+{
+ int out_handle;
+
+ t_pdp* p;
+ if ((handle >= 0)
+ && (handle < PDP_OBJECT_ARRAY_SIZE)
+ && (p = pdp_stack[handle])){
+ /* increase the number of users and return */
+ p->users++;
+ out_handle = handle;
+ }
+ else out_handle = -1;
+
+ //post("pdp_copy_ro: outhandle:%d", out_handle);
+
+ return out_handle;
+}
+
+int
+pdp_packet_copy_rw(int handle)
+{
+ int out_handle;
+
+ t_pdp* p;
+ if ((handle >= 0)
+ && (handle < PDP_OBJECT_ARRAY_SIZE)
+ && (p = pdp_stack[handle])){
+ /* if there are other users, copy the object otherwize return the same handle */
+ if (p->users){
+ int new_handle = pdp_packet_new(p->type, p->size - PDP_HEADER_SIZE);
+ t_pdp* new_p = pdp_packet_header(new_handle);
+ memcpy(new_p, p, p->size);
+ new_p->users = 1;
+ out_handle = new_handle;
+ }
+ else {
+ p->users++;
+ out_handle = handle;
+ }
+ //post("pdp_copy_rw: inhandle:%d outhandle:%d", handle, out_handle);
+
+ }
+ else out_handle = -1;
+
+ return out_handle;
+}
+
+int
+pdp_packet_clone_rw(int handle)
+{
+ int out_handle;
+
+ t_pdp* p;
+ if ((handle >= 0)
+ && (handle < PDP_OBJECT_ARRAY_SIZE)
+ && (p = pdp_stack[handle])){
+
+ /* clone the packet header, don't copy the data */
+ int new_handle = pdp_packet_new(p->type, p->size - PDP_HEADER_SIZE);
+ t_pdp* new_p = pdp_packet_header(new_handle);
+ memcpy(new_p, p, PDP_HEADER_SIZE);
+ new_p->users = 1;
+ out_handle = new_handle;
+ }
+
+ else out_handle = -1;
+
+ return out_handle;
+}
+
+void
+pdp_packet_mark_unused(int handle)
+{
+ t_pdp* p;
+ if ((handle >= 0) && (handle < PDP_OBJECT_ARRAY_SIZE)){
+ if (p = pdp_stack[handle]) {
+ if (p->users) {
+ p->users--;
+ //post("pdp_mark_unused: handle %d, users left %d", handle, p->users);
+ }
+ else {
+ post("pdp_mark_unused: WARNING: handle %d has zero users (duplicate pdp_mark_unused ?)", handle);
+ }
+ }
+ else {
+ post("pdp_mark_unused: WARNING: invalid handle %d: no associated object", handle);
+ }
+ }
+
+ else {
+ /* -1 is the only invalid handle that doesn't trigger a warning */
+ if (handle != -1) post("pdp_mark_unused: WARNING: invalid handle %d: out of bound", handle);
+ }
+
+
+}
+
+/* remark. if an owner frees a rw copy, he can still pass it along to clients.
+the first copy instruction revives the object. maybe free should not be called free but unregister.
+as long as no new_object method is called, or no copy on another object is performed,
+the "undead" copy can be revived. this smells a bit, i know...*/
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/system/pdp_queue.c b/system/pdp_queue.c
new file mode 100644
index 0000000..2932728
--- /dev/null
+++ b/system/pdp_queue.c
@@ -0,0 +1,337 @@
+/*
+ * Pure Data Packet - processor queue module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+/*
+ this is a the processor queue pdp system module
+ it receives tasks from objects that are schedules to
+ be computed in another thread. the object is signalled back
+ when the task is completed.
+
+ this is not a standard pd class. it is a sigleton class
+ using a standard pd clock to poll for compleded methods on
+ every scheduler run. this is a hack to do thread synchronization
+ in a thread unsafe pd.
+
+ */
+
+#include "pdp.h"
+#include <pthread.h>
+#include <unistd.h>
+#include <stdio.h>
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define PDP_QUEUE_SIZE 1024
+#define PDP_QUEUE_DELTIME 1.0f;
+
+
+
+
+/********************* pdp process queue data *********************/
+
+typedef void (*t_pdpmethod)(void *client);
+
+/* the process queue data record */
+typedef struct process_queue_struct
+{
+ void *x_owner; /* the object we are dealing with */
+ t_pdpmethod x_process; /* the process method */
+ t_pdpmethod x_callback; /* the function to be called when finished */
+ int *x_queue_id; /* place to store the queue id for task */
+} t_process_queue;
+
+
+
+/* clock members */
+static t_clock *pdp_clock;
+static double deltime;
+
+/* some bookkeeping vars */
+static long long ticks;
+static long long packets;
+
+/* queue members */
+static t_process_queue *q; /* queue */
+static int mask;
+static int head; /* last entry in queue + 1 */
+static int tail; /* first entry in queque */
+static int curr; /* the object currently processed in other thread */
+
+/* pthread vars */
+static pthread_mutex_t mut;
+static pthread_cond_t cond_dataready;
+static pthread_cond_t cond_processingdone;
+static pthread_t thread_id;
+
+/* synchro pipes */
+static int pipe_fd[2];
+
+/* toggle for thread usage */
+static int use_thread;
+
+
+
+/* the methods */
+void pdp_queue_wait()
+{
+ //post("pdp_pq_wait: waiting for pdp_queue_thread to finish processing");
+ pthread_mutex_lock(&mut);
+ while(((curr - head) & mask) != 0){
+
+ pthread_cond_wait(&cond_processingdone, &mut);
+ }
+ pthread_mutex_unlock(&mut);
+ //post("pdp_pq_wait: pdp_queue_thread has finished processing");
+
+}
+void pdp_queue_finish(int index)
+{
+
+ if (-1 == index) {
+ //post("pdp_pq_remove: index == -1");
+ return;
+ }
+ /* wait for processing thread to finish*/
+ pdp_queue_wait();
+
+ /* invalidate callback at index */
+ q[index & mask].x_callback = 0;
+ q[index & mask].x_queue_id = 0;
+
+}
+
+static void pdp_queue_signal_processor(void)
+{
+
+ pthread_mutex_lock(&mut);
+ //post("signalling process thread");
+ pthread_cond_signal(&cond_dataready);
+ pthread_mutex_unlock(&mut);
+ //post("signalling process thread done");
+
+}
+
+static void pdp_queue_wait_for_feeder(void)
+{
+
+
+ /* only use locking when there is no data */
+ if(((curr - head) & mask) == 0){
+ pthread_mutex_lock(&mut);
+
+ /* signal processing done */
+ //post("pdp_queue_thread: signalling processing is done");
+ pthread_cond_signal(&cond_processingdone);
+
+ /* wait until there is an item in the queue */
+ while(((curr - head) & mask) == 0){
+ //post("waiting for feeder");
+ pthread_cond_wait(&cond_dataready, &mut);
+ //post("waiting for feeder done");
+ }
+
+ pthread_mutex_unlock(&mut);
+
+ }
+}
+
+void pdp_queue_add(void *owner, void *process, void *callback, int *queue_id)
+{
+ int i;
+
+ /* if processing is in not in thread, just call the funcs */
+ if (!use_thread){
+ //post("pdp_queue_add: calling processing routine directly");
+ *queue_id = -1;
+ ((t_pdpmethod) process)(owner);
+ ((t_pdpmethod) callback)(owner);
+ return;
+ }
+
+
+
+ /* schedule method in thread queue */
+ if (1 == ((tail - head) & mask)) {
+ post("pdp_queue_add: WARNING: processing queue is full.\n");
+ post("pdp_queue_add: WARNING: skipping process method, calling callback directly.\n");
+ *queue_id = -1;
+ ((t_pdpmethod) callback)(owner);
+ }
+
+
+
+ i = head & mask;
+ q[i].x_owner = owner;
+ q[i].x_process = process;
+ q[i].x_callback = callback;
+ q[i].x_queue_id = queue_id;
+ *queue_id = i;
+ //post("pdp_queue_add: added method to queue, index %d", i);
+
+
+ // increase the packet count
+ packets++;
+
+ // move head forward
+ head++;
+
+ pdp_queue_signal_processor();
+
+}
+
+
+/* processing thread */
+static void *pdp_queue_thread(void *dummy)
+{
+ while(1){
+
+
+ /* wait until there is data available */
+ pdp_queue_wait_for_feeder();
+
+
+ //post("pdp_queue_thread: processing %d", curr);
+
+
+ /* call the process routine */
+ (q[curr & mask].x_process)(q[curr & mask].x_owner);
+
+ /* advance */
+ curr++;
+
+
+ }
+}
+
+
+/* call back all the callbacks */
+static void pdp_queue_callback (void)
+{
+
+ /* call callbacks for finished packets */
+ while(0 != ((curr - tail) & mask))
+ {
+ int i = tail & mask;
+ /* invalidate queue id */
+ if(q[i].x_queue_id) *q[i].x_queue_id = -1;
+ /* call callback */
+ if(q[i].x_callback) (q[i].x_callback)(q[i].x_owner);
+ //else post("pdp_pq_tick: callback %d is disabled",i );
+ tail++;
+ }
+
+}
+
+/* the clock method */
+static void pdp_queue_tick (void)
+{
+ /* do work */
+ //if (!(ticks % 1000)) post("pdp tick %d", ticks);
+
+ if (!use_thread) return;
+
+ /* call callbacks */
+ pdp_queue_callback();
+
+ /* increase counter */
+ ticks++;
+
+ /* set clock for next update */
+ clock_delay(pdp_clock, deltime);
+}
+
+
+void pdp_queue_use_thread(int t)
+{
+ /* if thread usage is being disabled,
+ wait for thread to finish processing first */
+ if (t == 0) {
+ pdp_queue_wait();
+ use_thread = 0;
+ pdp_queue_callback();
+ clock_unset(pdp_clock);
+ }
+ else {
+ clock_unset(pdp_clock);
+ clock_delay(pdp_clock, deltime);
+ use_thread = 1;
+ }
+
+}
+
+void pdp_queue_setup(void)
+{
+ pthread_attr_t attr;
+
+ /* setup pdp queue processor object */
+ ticks = 0;
+ deltime = PDP_QUEUE_DELTIME;
+
+ /* setup queue data */
+ mask = PDP_QUEUE_SIZE - 1;
+ head = 0;
+ tail = 0;
+ curr = 0;
+ q = getbytes(PDP_QUEUE_SIZE * sizeof(*q));
+
+ /* use threads by default */
+ use_thread = 1;
+
+ /* setup synchro stuff */
+ pthread_mutex_init(&mut, NULL);
+ pthread_cond_init(&cond_dataready, NULL);
+ pthread_cond_init(&cond_processingdone, NULL);
+
+
+ /* allocate the clock */
+ pdp_clock = clock_new(0, (t_method)pdp_queue_tick);
+
+ /* set the clock */
+ clock_delay(pdp_clock, 0);
+
+ /* start processing thread */
+
+ /* glibc doc says SCHED_OTHER is default,
+ but it seems not to be when initiated from a RT thread
+ so we explicitly set it here */
+ pthread_attr_init (&attr);
+ //pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
+ pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
+ pthread_create(&thread_id, &attr, pdp_queue_thread, (void *)0);
+
+
+
+}
+
+
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/system/pdp_resample.c b/system/pdp_resample.c
new file mode 100644
index 0000000..2b5a9de
--- /dev/null
+++ b/system/pdp_resample.c
@@ -0,0 +1,135 @@
+/*
+ * Pure Data Packet system file. - image resampling routines
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include "pdp_resample.h"
+#include "pdp.h"
+
+/*
+
+efficient bilinear resampling ??
+performance: how to eliminate divides? -> virtual coordinates 2^k x 2^k (conf. opengl)
+
+i.e. 16 bit virtual coordinates: easy modular addressing
+
+*/
+
+s32 pdp_resample_bilin(s16 *image, s32 width, s32 height, s32 virt_x, s32 virt_y)
+{
+
+ s32 fp_x, fp_y, frac_x, frac_y, f, offset, r_1, r_2;
+
+ virt_x &= 0xffff;
+ virt_y &= 0xffff;
+
+ fp_x = virt_x * (width - 1);
+ fp_y = virt_y * (height - 1);
+
+ frac_x = fp_x & (0xffff);
+ frac_y = fp_y & (0xffff);
+
+ offset = (fp_x >> 16) + (fp_y >> 16) * width;
+ image += offset;
+
+ f = 0x10000 - frac_x;
+
+ r_1 = ((f * (s32)(image[0]) + frac_x * (s32)(image[1])))>>16;
+
+ image += width;
+
+ r_2 = ((f * (s32)(image[0]) + frac_x * (s32)(image[1])))>>16;
+
+ f = 0x10000 - frac_y;
+
+ return ((f * r_1 + frac_y * r_2)>>16);
+
+}
+
+
+void pdp_resample_scale_bilin(s16 *src_image, s16 *dst_image, s32 src_w, s32 src_h, s32 dst_w, s32 dst_h)
+{
+ s32 i,j;
+ s32 virt_x=0;
+ s32 virt_y=0; /* virtual coordinates in 30 bit */
+ s32 scale_x = 0x40000000 / dst_w;
+ s32 scale_y = 0x40000000 / dst_h;
+
+ for (j=0; j<dst_h; j++){
+ for (i=0; i<dst_w; i++){
+ *dst_image++ = pdp_resample_bilin(src_image, src_w, src_h, virt_x>>14, virt_y>>14);
+ virt_x += scale_x;
+ }
+ virt_x = 0;
+ virt_y += scale_y;
+ }
+
+}
+
+void pdp_resample_scale_nn(s16 *src_image, s16 *dst_image, s32 src_w, s32 src_h, s32 dst_w, s32 dst_h)
+{
+ s32 i,j;
+ s32 x=0;
+ s32 y=0;
+ s32 frac_x=0;
+ s32 frac_y=0;
+ s32 scale_x = (src_w << 20 ) / dst_w;
+ s32 scale_y = (src_h << 20 ) / dst_h;
+
+ for (j=0; j<dst_h; j++){
+ for (i=0; i<dst_w; i++){
+ *dst_image++ = src_image[x+y];
+ frac_x += scale_x;
+ x = frac_x >> 20;
+ }
+ x = 0;
+ frac_x = 0;
+ frac_y += scale_y;
+ y = (frac_y >> 20) * src_w;
+ }
+
+}
+
+void pdp_resample_zoom_tiled_bilin(s16 *src_image, s16 *dst_image, s32 w, s32 h,
+ float zoom_x, float zoom_y, float center_x_relative, float center_y_relative)
+{
+ float izx = 1.0f / zoom_x;
+ float izy = 1.0f / zoom_y;
+ s32 scale_x = (s32)((float)0x100000 * izx / (float)w);
+ s32 scale_y = (s32)((float)0x100000 * izy / (float)h);
+
+ s32 top_virt_x = (s32)((1.0f - izx) * (float)0x100000 * center_x_relative);
+ s32 top_virt_y = (s32)((1.0f - izy) * (float)0x100000 * center_y_relative);
+
+ s32 virt_x = top_virt_x;
+ s32 virt_y = top_virt_y;
+
+ s32 i,j;
+
+ for (j=0; j<h; j++){
+ for (i=0; i<w; i++){
+ *dst_image++ = pdp_resample_bilin(src_image, w, h, virt_x>>4, virt_y>>4);
+ virt_x += scale_x;
+ }
+ virt_x = top_virt_x;
+ virt_y += scale_y;
+ }
+
+}
+
diff --git a/system/pdp_type.c b/system/pdp_type.c
new file mode 100644
index 0000000..b23b9cd
--- /dev/null
+++ b/system/pdp_type.c
@@ -0,0 +1,143 @@
+/*
+ * Pure Data Packet system implementation. : code for handling different packet types
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "pdp.h"
+#include <stdio.h>
+
+/* all symbols are C style */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+/****************** packet type checking methods ********************/
+
+
+/* check if two packets are allocated and of the same type */
+int pdp_type_compat(int packet0, int packet1)
+{
+
+ t_pdp *header0 = pdp_packet_header(packet0);
+ t_pdp *header1 = pdp_packet_header(packet1);
+
+ if (!(header1)){
+ //post("pdp_type_compat: invalid header packet1");
+ return 0;
+ }
+ if (!(header0)){
+ //post("pdp_type_compat: invalid header packet 0");
+ return 0;
+ }
+ if (header0->type != header1->type){
+ //post("pdp_type_compat: types do not match");
+ return 0;
+ }
+
+ return 1;
+}
+
+/* check if two image packets are allocated and of the same type */
+int pdp_type_compat_image(int packet0, int packet1)
+{
+ t_pdp *header0 = pdp_packet_header(packet0);
+ t_pdp *header1 = pdp_packet_header(packet1);
+
+
+ if (!(pdp_type_compat(packet0, packet1))) return 0;
+ if (header0->type != PDP_IMAGE){
+ //post("pdp_type_compat_image: not a PDP_IMAGE");
+ return 0;
+ }
+ if (header0->info.image.encoding != header1->info.image.encoding){
+ //post("pdp_type_compat_image: encodings differ");
+ return 0;
+ }
+ if (header0->info.image.width != header1->info.image.width){
+ //post("pdp_type_compat_image: image withs differ");
+ return 0;
+ }
+ if (header0->info.image.height != header1->info.image.height){
+ //post("pdp_type_compat_image: image heights differ");
+ return 0;
+ }
+ return 1;
+}
+
+/* check if packet is a valid image packet */
+int pdp_type_isvalid_image(int packet)
+{
+ t_pdp *header = pdp_packet_header(packet);
+ if (!header) return 0;
+ if (PDP_IMAGE != header->type) return 0;
+ if ((PDP_IMAGE_YV12 != header->info.image.encoding)
+ && (PDP_IMAGE_GREY != header->info.image.encoding)) return 0;
+
+ return 1;
+
+}
+
+
+
+int pdp_packet_new_image_yv12(u32 w, u32 h)
+{
+ t_pdp *header;
+ int packet;
+
+
+ u32 size = w*h;
+ u32 totalnbpixels = size + (size >> 1);
+ u32 packet_size = totalnbpixels << 1;
+
+ packet = pdp_packet_new(PDP_IMAGE, packet_size);
+ header = pdp_packet_header(packet);
+
+ header->info.image.encoding = PDP_IMAGE_YV12;
+ header->info.image.width = w;
+ header->info.image.height = h;
+
+ return packet;
+}
+
+int pdp_packet_new_image_grey(u32 w, u32 h)
+{
+ t_pdp *header;
+ int packet;
+
+
+ u32 size = w*h;
+ u32 totalnbpixels = size;
+ u32 packet_size = totalnbpixels << 1;
+
+ packet = pdp_packet_new(PDP_IMAGE, packet_size);
+ header = pdp_packet_header(packet);
+
+ header->info.image.encoding = PDP_IMAGE_GREY;
+ header->info.image.width = w;
+ header->info.image.height = h;
+
+ return packet;
+}
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/system/pdp_ut.c b/system/pdp_ut.c
new file mode 100644
index 0000000..83b4cb0
--- /dev/null
+++ b/system/pdp_ut.c
@@ -0,0 +1,195 @@
+/*
+ * Pure Data Packet - Utility toolkit objects.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/* This file contains some small utility pd objects that make working with
+ pdp objects a lot easier. Mainly as glue to be used in the abstractions
+ in the distro. */
+
+#include "pdp.h"
+#include <math.h>
+
+/* this object does an add, scale, clip operation */
+
+t_class *pdp_ut_addscaleclip_class;
+
+typedef struct pdp_ut_addscaleclip_struct
+{
+ t_object x_obj;
+ t_outlet *x_outlet0;
+ t_float x_min;
+ t_float x_max;
+ t_float x_offset;
+ t_float x_scale;
+} t_pdp_ut_addscaleclip;
+
+
+static void pdp_ut_addscaleclip_float(t_pdp_ut_addscaleclip *x, t_floatarg f)
+{
+ f += x->x_offset;
+ f *= x->x_scale;
+ f = (f < x->x_min) ? x->x_min : f;
+ f = (f > x->x_max) ? x->x_max : f;
+ outlet_float(x->x_outlet0, f);
+}
+
+static void pdp_ut_addscaleclip_free(t_pdp_ut_addscaleclip *x){}
+
+void *pdp_ut_addscaleclip_new(t_floatarg offset, t_floatarg scale, t_floatarg min, t_floatarg max)
+{
+ t_pdp_ut_addscaleclip *x = (t_pdp_ut_addscaleclip *)pd_new(pdp_ut_addscaleclip_class);
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_float);
+ x->x_offset = offset;
+ x->x_scale = scale;
+ x->x_min = min;
+ x->x_max = max;
+ return (void *)x;
+}
+
+void pdp_ut_addscaleclip_setup(void)
+{
+ pdp_ut_addscaleclip_class = class_new(gensym("pdp_ut_addscaleclip"), (t_newmethod)pdp_ut_addscaleclip_new,
+ (t_method)pdp_ut_addscaleclip_free, sizeof(t_pdp_ut_addscaleclip), 0,
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addfloat(pdp_ut_addscaleclip_class, pdp_ut_addscaleclip_float);
+}
+
+
+/* pdp_ut_logmap does a logarithmic parameter mapping [0->1] x -> min(max/min)^x max an add, scale, clip operation */
+/* pdp_ut_logmap_comp does x -> min(max/min)^(1-x) */
+/* pdp_ut_linmap dos x -> min + (max - min * x */
+
+t_class *pdp_ut_linmap_class;
+t_class *pdp_ut_logmap_class;
+t_class *pdp_ut_logmap_comp_class;
+
+typedef struct pdp_ut_map_struct
+{
+ t_object x_obj;
+ t_outlet *x_outlet0;
+ t_float x_min;
+ t_float x_max;
+} t_pdp_ut_map;
+
+
+static void pdp_ut_logmap_float(t_pdp_ut_map *x, t_floatarg f)
+{
+ f = (f < 0.0f) ? 0.0f : f;
+ f = (f > 1.0f) ? 1.0f : f;
+
+ f = x->x_min * pow((x->x_max / x->x_min), f);
+
+ outlet_float(x->x_outlet0, f);
+}
+
+static void pdp_ut_linmap_float(t_pdp_ut_map *x, t_floatarg f)
+{
+ f = (f < 0.0f) ? 0.0f : f;
+ f = (f > 1.0f) ? 1.0f : f;
+
+ f = x->x_min + ((x->x_max - x->x_min) * f);
+
+ outlet_float(x->x_outlet0, f);
+}
+
+static void pdp_ut_logmap_comp_float(t_pdp_ut_map *x, t_floatarg f)
+{
+ f = (f < 0.0f) ? 0.0f : f;
+ f = (f > 1.0f) ? 1.0f : f;
+
+ f = x->x_min * pow((x->x_max / x->x_min), (1.0f - f));
+
+ outlet_float(x->x_outlet0, f);
+}
+
+static void pdp_ut_map_free(t_pdp_ut_map *x){}
+
+
+void pdp_ut_map_init(t_pdp_ut_map *x, t_floatarg min, t_floatarg max)
+{
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_float);
+ x->x_min = min;
+ x->x_max = max;
+}
+
+void *pdp_ut_logmap_new(t_floatarg min, t_floatarg max)
+{
+ t_pdp_ut_map *x = (t_pdp_ut_map *)pd_new(pdp_ut_logmap_class);
+ pdp_ut_map_init(x, min, max);
+ return (void *)x;
+}
+
+void *pdp_ut_linmap_new(t_floatarg min, t_floatarg max)
+{
+ t_pdp_ut_map *x = (t_pdp_ut_map *)pd_new(pdp_ut_linmap_class);
+ pdp_ut_map_init(x, min, max);
+ return (void *)x;
+}
+
+void *pdp_ut_logmap_comp_new(t_floatarg min, t_floatarg max)
+{
+ t_pdp_ut_map *x = (t_pdp_ut_map *)pd_new(pdp_ut_logmap_comp_class);
+ pdp_ut_map_init(x, min, max);
+ return (void *)x;
+}
+
+void pdp_ut_logmap_setup(void)
+{
+ pdp_ut_logmap_class = class_new(gensym("pdp_ut_logmap"), (t_newmethod)pdp_ut_logmap_new,
+ (t_method)pdp_ut_map_free, sizeof(t_pdp_ut_map), 0,
+ A_FLOAT, A_FLOAT, A_NULL);
+ class_addfloat(pdp_ut_logmap_class, pdp_ut_logmap_float);
+}
+
+void pdp_ut_logmap_comp_setup(void)
+{
+ pdp_ut_logmap_comp_class = class_new(gensym("pdp_ut_logmap_comp"), (t_newmethod)pdp_ut_logmap_comp_new,
+ (t_method)pdp_ut_map_free, sizeof(t_pdp_ut_map), 0,
+ A_FLOAT, A_FLOAT, A_NULL);
+ class_addfloat(pdp_ut_logmap_comp_class, pdp_ut_logmap_comp_float);
+}
+
+void pdp_ut_linmap_setup(void)
+{
+ pdp_ut_linmap_class = class_new(gensym("pdp_ut_linmap"), (t_newmethod)pdp_ut_linmap_new,
+ (t_method)pdp_ut_map_free, sizeof(t_pdp_ut_map), 0,
+ A_FLOAT, A_FLOAT, A_NULL);
+ class_addfloat(pdp_ut_linmap_class, pdp_ut_linmap_float);
+}
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+void pdp_ut_setup(void)
+{
+ pdp_ut_addscaleclip_setup();
+ pdp_ut_logmap_setup();
+ pdp_ut_logmap_comp_setup();
+ pdp_ut_linmap_setup();
+}
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/test/pdp_abstractions.pd b/test/pdp_abstractions.pd
new file mode 100644
index 0000000..27a5d48
--- /dev/null
+++ b/test/pdp_abstractions.pd
@@ -0,0 +1,22 @@
+#N canvas 606 93 450 300 10;
+#X obj 68 71 pdp_v4l;
+#X obj 69 163 pdp_xv;
+#X obj 71 11 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 184 13 stop;
+#X obj 143 44 metro 20;
+#X msg 133 13 bang;
+#X floatatom 189 103 5 0 0;
+#X floatatom 243 102 5 0 0;
+#X msg 17 47 type grey;
+#X obj 388 25 vsl 15 128 -1 1 0 0 empty empty empty 0 -8 0 8 -262144
+-1 -1 4500 1;
+#X obj 69 125 pdp_phase_hor;
+#X connect 0 0 10 0;
+#X connect 2 0 0 0;
+#X connect 3 0 4 0;
+#X connect 4 0 0 0;
+#X connect 5 0 4 0;
+#X connect 8 0 0 0;
+#X connect 9 0 10 1;
+#X connect 10 0 1 0;
diff --git a/test/test_oscil.pd b/test/test_oscil.pd
new file mode 100644
index 0000000..4455732
--- /dev/null
+++ b/test/test_oscil.pd
@@ -0,0 +1,69 @@
+#N canvas 144 73 626 492 10;
+#X obj 86 75 pdp_v4l;
+#X obj 69 268 pdp_xv;
+#X obj 186 40 metro 40;
+#X obj 185 13 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 85 24 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 258 148 1;
+#X obj 296 180 hsl 128 15 -1 1 0 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 12700 1;
+#X obj 240 229 pdp_mix2;
+#X obj 302 203 hsl 128 15 -1 1 0 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 800 1;
+#X floatatom 146 237 5 0 0;
+#X floatatom 236 122 5 0 0;
+#X obj 211 177 pdp_del 50;
+#X obj 257 261 pdp_conv;
+#X msg 290 34 dim 160 120;
+#X floatatom 310 229 5 0 0;
+#X floatatom 177 107 5 0 0;
+#X obj 194 81 hsl 128 15 0 1 0 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 10800 1;
+#X msg 211 10 stop;
+#X obj 126 140 pdp_randmix;
+#X obj 312 289 hsl 128 15 -1 1 0 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 12700 1;
+#X obj 318 312 hsl 128 15 -1 1 0 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 800 1;
+#X obj 319 343 hsl 128 15 -1 1 0 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 12700 1;
+#X obj 325 366 hsl 128 15 -1 1 0 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 800 1;
+#X obj 219 421 pdp_affine;
+#X obj 328 394 hsl 128 15 -1 1 0 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 12700 1;
+#X obj 334 417 hsl 128 15 -1 1 0 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 800 1;
+#X obj 217 325 pdp_affine 1;
+#X obj 217 368 pdp_affine 2;
+#X connect 0 0 18 0;
+#X connect 2 0 0 0;
+#X connect 3 0 2 0;
+#X connect 4 0 0 0;
+#X connect 5 0 11 1;
+#X connect 6 0 7 2;
+#X connect 7 0 12 0;
+#X connect 7 0 18 1;
+#X connect 8 0 7 3;
+#X connect 9 0 1 1;
+#X connect 10 0 11 1;
+#X connect 11 0 7 1;
+#X connect 12 0 11 0;
+#X connect 12 0 26 0;
+#X connect 13 0 0 0;
+#X connect 14 0 12 1;
+#X connect 15 0 18 2;
+#X connect 16 0 15 0;
+#X connect 17 0 2 0;
+#X connect 18 0 7 0;
+#X connect 19 0 26 1;
+#X connect 20 0 26 2;
+#X connect 21 0 27 1;
+#X connect 22 0 27 2;
+#X connect 23 0 1 0;
+#X connect 24 0 23 1;
+#X connect 25 0 23 2;
+#X connect 26 0 27 0;
+#X connect 27 0 23 0;
diff --git a/test/test_pdp_add.pd b/test/test_pdp_add.pd
new file mode 100644
index 0000000..e44df2d
--- /dev/null
+++ b/test/test_pdp_add.pd
@@ -0,0 +1,96 @@
+#N canvas 180 63 814 601 10;
+#X obj 152 101 pdp_qt;
+#X msg 173 63 bang;
+#X floatatom 92 60 5 0 0;
+#X msg 258 62 open /home/ben/MOV/test1.mov;
+#X obj 164 8 i 0;
+#X obj 220 19 + 1;
+#X obj 303 24 metro 40;
+#X obj 300 -1 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X msg 63 29 0;
+#X msg 102 31 9999;
+#X msg 63 131 loop \$1;
+#X obj 59 105 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 178 136 5 0 0;
+#X floatatom 235 137 5 0 0;
+#X obj 413 229 pdp_qt;
+#X msg 446 190 bang;
+#X floatatom 365 187 5 0 0;
+#X msg 531 189 open /home/ben/MOV/test1.mov;
+#X obj 437 135 i 0;
+#X obj 493 146 + 1;
+#X obj 576 151 metro 40;
+#X obj 573 126 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X msg 336 156 0;
+#X msg 375 158 9999;
+#X msg 336 258 loop \$1;
+#X obj 332 232 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0
+1;
+#X floatatom 451 263 5 0 0;
+#X floatatom 508 264 5 0 0;
+#X floatatom 383 3 5 0 0;
+#X floatatom 634 128 5 0 0;
+#X msg 327 106 0;
+#X obj 181 222 pdp_add;
+#X obj 196 550 pdp_xv;
+#X obj 76 200 print p1;
+#X obj 411 286 print p2;
+#X obj 180 301 print p;
+#X obj 201 453 pdp_v4l;
+#X obj 176 399 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 261 381 metro 40;
+#X obj 263 352 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 244 480 5 0 0;
+#X obj 332 546 pdp_del 8;
+#X floatatom 305 479 5 0 0;
+#X obj 191 519 pdp_affine;
+#X connect 0 0 31 0;
+#X connect 0 0 33 0;
+#X connect 0 1 12 0;
+#X connect 0 2 13 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 5 0;
+#X connect 4 0 1 0;
+#X connect 5 0 4 1;
+#X connect 6 0 0 0;
+#X connect 7 0 6 0;
+#X connect 8 0 2 0;
+#X connect 9 0 2 0;
+#X connect 10 0 0 0;
+#X connect 11 0 10 0;
+#X connect 14 0 31 1;
+#X connect 14 0 34 0;
+#X connect 14 1 26 0;
+#X connect 14 2 27 0;
+#X connect 15 0 14 0;
+#X connect 16 0 14 0;
+#X connect 17 0 14 0;
+#X connect 18 0 19 0;
+#X connect 18 0 15 0;
+#X connect 19 0 18 1;
+#X connect 20 0 14 0;
+#X connect 21 0 20 0;
+#X connect 22 0 16 0;
+#X connect 23 0 16 0;
+#X connect 24 0 14 0;
+#X connect 25 0 24 0;
+#X connect 28 0 6 1;
+#X connect 29 0 20 1;
+#X connect 30 0 22 0;
+#X connect 30 0 8 0;
+#X connect 31 0 35 0;
+#X connect 36 0 41 0;
+#X connect 36 0 43 0;
+#X connect 37 0 36 0;
+#X connect 38 0 36 0;
+#X connect 39 0 38 0;
+#X connect 40 0 43 2;
+#X connect 42 0 43 1;
+#X connect 43 0 32 0;
diff --git a/test/test_pdp_affine.pd b/test/test_pdp_affine.pd
new file mode 100644
index 0000000..3e4afc9
--- /dev/null
+++ b/test/test_pdp_affine.pd
@@ -0,0 +1,80 @@
+#N canvas 278 50 629 562 10;
+#X obj 130 454 pdp_xv;
+#X obj 265 42 metro 40;
+#X obj 262 17 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X floatatom 309 9 5 0 0;
+#X obj 115 119 pdp_v4l;
+#X msg 220 80 open /dev/video0;
+#X msg 83 57 close;
+#X obj 142 56 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 233 127 dim 160 120;
+#X msg 238 162 dim 320 240;
+#X floatatom 177 418 5 0 0;
+#X msg 350 123 dim 640 480;
+#X obj 264 341 hsl 128 15 -1 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 6350 1;
+#X obj 404 340 hsl 128 15 -1 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 7750 1;
+#X obj 265 365 hsl 128 15 -1 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 6350 1;
+#X obj 405 364 hsl 128 15 -1 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 2650 1;
+#X obj 263 316 hsl 128 15 -1 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 12700 1;
+#X obj 403 315 hsl 128 15 -1 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 5250 1;
+#X obj 136 332 pdp_affine 1;
+#X obj 137 357 pdp_affine 2;
+#X obj 138 381 pdp_affine 3;
+#X msg 260 278 1;
+#X msg 399 275 0;
+#X msg 236 409 1;
+#X obj 415 223 sin;
+#X obj 448 223 cos;
+#X obj 346 192 f 0;
+#X obj 346 223 +;
+#X floatatom 382 188 5 0 0;
+#X obj 463 259 *;
+#X obj 427 258 *;
+#X floatatom 496 230 5 0 0;
+#X connect 1 0 7 0;
+#X connect 1 0 26 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 1;
+#X connect 4 0 18 0;
+#X connect 5 0 4 0;
+#X connect 6 0 4 0;
+#X connect 7 0 4 0;
+#X connect 8 0 4 0;
+#X connect 9 0 4 0;
+#X connect 10 0 0 1;
+#X connect 11 0 4 0;
+#X connect 12 0 19 1;
+#X connect 13 0 19 2;
+#X connect 14 0 20 1;
+#X connect 15 0 20 2;
+#X connect 16 0 18 1;
+#X connect 17 0 18 2;
+#X connect 18 0 19 0;
+#X connect 19 0 20 0;
+#X connect 20 0 0 0;
+#X connect 21 0 16 0;
+#X connect 21 0 12 0;
+#X connect 21 0 14 0;
+#X connect 22 0 17 0;
+#X connect 22 0 13 0;
+#X connect 22 0 15 0;
+#X connect 23 0 10 0;
+#X connect 24 0 30 0;
+#X connect 25 0 29 0;
+#X connect 26 0 27 0;
+#X connect 27 0 26 1;
+#X connect 27 0 24 0;
+#X connect 27 0 25 0;
+#X connect 28 0 27 1;
+#X connect 29 0 14 0;
+#X connect 30 0 12 0;
+#X connect 31 0 29 1;
+#X connect 31 0 30 1;
diff --git a/test/test_pdp_bq.pd b/test/test_pdp_bq.pd
new file mode 100644
index 0000000..c7b48d4
--- /dev/null
+++ b/test/test_pdp_bq.pd
@@ -0,0 +1,136 @@
+#N canvas 8 69 765 701 10;
+#X obj 128 85 pdp_v4l;
+#X obj 127 53 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 178 30 stop;
+#X msg 216 29 bang;
+#X msg 291 64 dim 160 120;
+#X msg 289 29 dim 32 32;
+#X msg 283 5 dim 80 60;
+#X msg 313 94 dim 320 240;
+#X msg 334 117 dim 768 576;
+#X floatatom 222 3 5 0 0;
+#X msg 253 144 dim 640 240;
+#X msg 364 45 dim 640 480;
+#X msg 32 38 type grey;
+#X msg 31 14 type yv12;
+#X floatatom 193 228 5 0 0;
+#X msg 36 218 ver \$1;
+#X msg 91 219 hor \$1;
+#X obj 38 193 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 95 192 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 168 319 pdp_bq;
+#X floatatom 243 346 5 0 0;
+#X floatatom 130 10 5 0 0;
+#X obj 196 58 metro 5;
+#X floatatom 313 209 5 0 0;
+#X msg 312 233 onep \$1;
+#X obj 318 178 hsl 128 15 0.01 1 1 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 4900 1;
+#X floatatom 389 244 5 0 0;
+#X obj 394 213 hsl 128 15 0.03 1 1 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 9400 1;
+#X msg 388 267 twop \$1;
+#X floatatom 203 155 5 0 0;
+#X msg 18 303 u1 \$1;
+#X msg 20 334 u2 \$1;
+#X floatatom 51 273 5 0 0;
+#X floatatom 90 306 5 0 0;
+#X obj 44 156 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 102 154 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 30 100 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 87 99 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X msg 28 125 lr \$1;
+#X msg 83 126 rl \$1;
+#X msg 32 172 tb \$1;
+#X msg 87 173 bt \$1;
+#X obj 461 368 hsl 128 15 0.05 0.5 1 1 empty empty empty -2 -6 0 8
+-262144 -1 -1 0 1;
+#X obj 537 403 hsl 128 15 0.1 10 1 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 5200 1;
+#X obj 490 477 t b f;
+#X floatatom 556 438 5 0 0;
+#X floatatom 393 426 5 0 0;
+#X obj 495 529 pack s 0 0;
+#X msg 492 562 \$1 \$2 \$3;
+#X obj 548 482 t b f;
+#X msg 402 505 lpf;
+#X msg 402 484 hpf;
+#X msg 400 533 apf;
+#X msg 397 566 bsf;
+#X obj 157 181 pdp_mix;
+#X obj 545 98 random 2;
+#X obj 610 98 random 2;
+#X obj 548 61 pdp_trigger;
+#X obj 543 135 random 2;
+#X obj 608 135 random 2;
+#X connect 0 0 54 0;
+#X connect 0 0 57 0;
+#X connect 1 0 0 0;
+#X connect 2 0 22 0;
+#X connect 3 0 22 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
+#X connect 8 0 0 0;
+#X connect 9 0 22 1;
+#X connect 10 0 0 0;
+#X connect 11 0 0 0;
+#X connect 12 0 0 0;
+#X connect 13 0 0 0;
+#X connect 14 0 19 1;
+#X connect 15 0 19 0;
+#X connect 16 0 19 0;
+#X connect 17 0 15 0;
+#X connect 18 0 16 0;
+#X connect 19 0 54 1;
+#X connect 22 0 0 0;
+#X connect 23 0 24 0;
+#X connect 24 0 19 0;
+#X connect 25 0 23 0;
+#X connect 26 0 28 0;
+#X connect 27 0 26 0;
+#X connect 28 0 19 0;
+#X connect 29 0 54 2;
+#X connect 30 0 19 0;
+#X connect 31 0 19 0;
+#X connect 32 0 30 0;
+#X connect 33 0 31 0;
+#X connect 34 0 40 0;
+#X connect 35 0 41 0;
+#X connect 36 0 38 0;
+#X connect 37 0 39 0;
+#X connect 38 0 19 0;
+#X connect 39 0 19 0;
+#X connect 40 0 19 0;
+#X connect 41 0 19 0;
+#X connect 42 0 46 0;
+#X connect 43 0 45 0;
+#X connect 44 0 47 0;
+#X connect 44 1 47 1;
+#X connect 45 0 49 0;
+#X connect 46 0 44 0;
+#X connect 47 0 48 0;
+#X connect 48 0 19 0;
+#X connect 49 0 47 0;
+#X connect 49 1 47 2;
+#X connect 50 0 47 0;
+#X connect 51 0 47 0;
+#X connect 52 0 47 0;
+#X connect 53 0 47 0;
+#X connect 54 0 19 0;
+#X connect 55 0 36 0;
+#X connect 56 0 37 0;
+#X connect 57 0 55 0;
+#X connect 57 0 56 0;
+#X connect 57 0 58 0;
+#X connect 57 0 59 0;
+#X connect 58 0 34 0;
+#X connect 59 0 35 0;
diff --git a/test/test_pdp_bq2.pd b/test/test_pdp_bq2.pd
new file mode 100644
index 0000000..a13b11b
--- /dev/null
+++ b/test/test_pdp_bq2.pd
@@ -0,0 +1,146 @@
+#N canvas 116 11 765 631 10;
+#X obj 128 85 pdp_v4l;
+#X obj 127 53 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 178 30 stop;
+#X msg 216 29 bang;
+#X msg 291 64 dim 160 120;
+#X msg 289 29 dim 32 32;
+#X msg 283 5 dim 80 60;
+#X msg 313 94 dim 320 240;
+#X msg 334 117 dim 768 576;
+#X floatatom 222 3 5 0 0;
+#X msg 253 144 dim 640 240;
+#X msg 364 45 dim 640 480;
+#X obj 90 507 pdp_xv;
+#X msg 32 38 type grey;
+#X msg 31 14 type yv12;
+#X floatatom 193 228 5 0 0;
+#X msg 36 218 ver \$1;
+#X msg 91 219 hor \$1;
+#X obj 38 193 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 95 192 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 168 319 pdp_bq;
+#X floatatom 243 346 5 0 0;
+#X floatatom 130 10 5 0 0;
+#X obj 196 58 metro 5;
+#X floatatom 313 209 5 0 0;
+#X msg 312 233 onep \$1;
+#X obj 318 178 hsl 128 15 0.01 1 1 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 2800 1;
+#X floatatom 389 244 5 0 0;
+#X obj 394 213 hsl 128 15 0.03 1 1 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 6900 1;
+#X msg 388 267 twop \$1;
+#X floatatom 203 155 5 0 0;
+#X msg 18 303 u1 \$1;
+#X msg 20 334 u2 \$1;
+#X floatatom 51 273 5 0 0;
+#X floatatom 90 306 5 0 0;
+#X obj 44 156 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X obj 102 154 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X obj 30 100 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 87 99 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X msg 28 125 lr \$1;
+#X msg 83 126 rl \$1;
+#X msg 32 172 tb \$1;
+#X msg 87 173 bt \$1;
+#X obj 461 368 hsl 128 15 0.05 0.5 1 1 empty empty empty -2 -6 0 8
+-262144 -1 -1 2400 1;
+#X obj 537 403 hsl 128 15 0.1 10 1 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 2700 1;
+#X obj 490 477 t b f;
+#X floatatom 556 438 5 0 0;
+#X floatatom 393 426 5 0 0;
+#X obj 495 529 pack s 0 0;
+#X msg 492 562 \$1 \$2 \$3;
+#X obj 548 482 t b f;
+#X msg 402 505 lpf;
+#X msg 402 484 hpf;
+#X msg 400 533 apf;
+#X msg 397 566 bsf;
+#X obj 157 181 pdp_mix;
+#X obj 545 98 random 2;
+#X obj 610 98 random 2;
+#X obj 548 61 pdp_trigger;
+#X obj 543 135 random 2;
+#X obj 608 135 random 2;
+#X obj 155 128 pdp_reg;
+#X msg 201 511 create :0;
+#X msg 204 475 close;
+#X connect 0 0 58 0;
+#X connect 0 0 61 0;
+#X connect 1 0 0 0;
+#X connect 2 0 23 0;
+#X connect 3 0 23 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
+#X connect 8 0 0 0;
+#X connect 9 0 23 1;
+#X connect 10 0 0 0;
+#X connect 11 0 0 0;
+#X connect 13 0 0 0;
+#X connect 14 0 0 0;
+#X connect 15 0 20 1;
+#X connect 16 0 20 0;
+#X connect 17 0 20 0;
+#X connect 18 0 16 0;
+#X connect 19 0 17 0;
+#X connect 20 0 55 1;
+#X connect 20 0 12 0;
+#X connect 21 0 12 1;
+#X connect 22 0 0 1;
+#X connect 23 0 0 0;
+#X connect 24 0 25 0;
+#X connect 25 0 20 0;
+#X connect 26 0 24 0;
+#X connect 27 0 29 0;
+#X connect 28 0 27 0;
+#X connect 29 0 20 0;
+#X connect 30 0 55 2;
+#X connect 31 0 20 0;
+#X connect 32 0 20 0;
+#X connect 33 0 31 0;
+#X connect 34 0 32 0;
+#X connect 35 0 41 0;
+#X connect 36 0 42 0;
+#X connect 37 0 39 0;
+#X connect 38 0 40 0;
+#X connect 39 0 20 0;
+#X connect 40 0 20 0;
+#X connect 41 0 20 0;
+#X connect 42 0 20 0;
+#X connect 43 0 47 0;
+#X connect 44 0 46 0;
+#X connect 45 0 48 0;
+#X connect 45 1 48 1;
+#X connect 46 0 50 0;
+#X connect 47 0 45 0;
+#X connect 48 0 49 0;
+#X connect 49 0 20 0;
+#X connect 50 0 48 0;
+#X connect 50 1 48 2;
+#X connect 51 0 48 0;
+#X connect 52 0 48 0;
+#X connect 53 0 48 0;
+#X connect 54 0 48 0;
+#X connect 55 0 20 0;
+#X connect 56 0 37 0;
+#X connect 57 0 38 0;
+#X connect 58 0 56 0;
+#X connect 58 0 57 0;
+#X connect 58 0 59 0;
+#X connect 58 0 60 0;
+#X connect 59 0 35 0;
+#X connect 60 0 36 0;
+#X connect 61 0 55 0;
+#X connect 62 0 12 0;
+#X connect 63 0 12 0;
diff --git a/test/test_pdp_bqt.pd b/test/test_pdp_bqt.pd
new file mode 100644
index 0000000..b52edf1
--- /dev/null
+++ b/test/test_pdp_bqt.pd
@@ -0,0 +1,91 @@
+#N canvas 28 181 765 631 10;
+#X obj 128 85 pdp_v4l;
+#X obj 127 53 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 178 30 stop;
+#X msg 216 29 bang;
+#X msg 291 64 dim 160 120;
+#X msg 289 29 dim 32 32;
+#X msg 283 5 dim 80 60;
+#X msg 313 94 dim 320 240;
+#X msg 334 117 dim 768 576;
+#X floatatom 222 3 5 0 0;
+#X msg 253 144 dim 640 240;
+#X msg 364 45 dim 640 480;
+#X obj 90 507 pdp_xv;
+#X msg 32 38 type grey;
+#X msg 31 14 type yv12;
+#X floatatom 141 464 5 0 0;
+#X floatatom 130 10 5 0 0;
+#X obj 196 58 metro 5;
+#X floatatom 313 209 5 0 0;
+#X msg 312 233 onep \$1;
+#X obj 318 178 hsl 128 15 0.01 1 1 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 4900 1;
+#X floatatom 389 244 5 0 0;
+#X obj 394 213 hsl 128 15 0.03 1 1 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 9400 1;
+#X msg 388 267 twop \$1;
+#X msg 18 303 u1 \$1;
+#X msg 20 334 u2 \$1;
+#X floatatom 51 273 5 0 0;
+#X floatatom 90 306 5 0 0;
+#X obj 461 368 hsl 128 15 0.001 0.5 1 1 empty empty empty -2 -6 0 8
+-262144 -1 -1 100 1;
+#X obj 537 403 hsl 128 15 0.1 10 1 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 9800 1;
+#X obj 490 477 t b f;
+#X floatatom 556 438 5 0 0;
+#X floatatom 393 426 5 0 0;
+#X obj 495 529 pack s 0 0;
+#X msg 492 562 \$1 \$2 \$3;
+#X obj 548 482 t b f;
+#X msg 402 505 lpf;
+#X msg 402 484 hpf;
+#X msg 400 533 apf;
+#X msg 397 566 bsf;
+#X obj 168 319 pdp_bqt;
+#X msg 171 237 reset;
+#X connect 0 0 40 0;
+#X connect 1 0 0 0;
+#X connect 2 0 17 0;
+#X connect 3 0 17 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
+#X connect 8 0 0 0;
+#X connect 9 0 17 1;
+#X connect 10 0 0 0;
+#X connect 11 0 0 0;
+#X connect 13 0 0 0;
+#X connect 14 0 0 0;
+#X connect 15 0 12 1;
+#X connect 16 0 0 1;
+#X connect 17 0 0 0;
+#X connect 18 0 19 0;
+#X connect 19 0 40 0;
+#X connect 20 0 18 0;
+#X connect 21 0 23 0;
+#X connect 22 0 21 0;
+#X connect 23 0 40 0;
+#X connect 24 0 40 0;
+#X connect 25 0 40 0;
+#X connect 26 0 24 0;
+#X connect 27 0 25 0;
+#X connect 28 0 32 0;
+#X connect 29 0 31 0;
+#X connect 30 0 33 0;
+#X connect 30 1 33 1;
+#X connect 31 0 35 0;
+#X connect 32 0 30 0;
+#X connect 33 0 34 0;
+#X connect 34 0 40 0;
+#X connect 35 0 33 0;
+#X connect 35 1 33 2;
+#X connect 36 0 33 0;
+#X connect 37 0 33 0;
+#X connect 38 0 33 0;
+#X connect 39 0 33 0;
+#X connect 40 0 12 0;
+#X connect 41 0 40 0;
diff --git a/test/test_pdp_chrot.pd b/test/test_pdp_chrot.pd
new file mode 100644
index 0000000..308b21e
--- /dev/null
+++ b/test/test_pdp_chrot.pd
@@ -0,0 +1,32 @@
+#N canvas 7 0 629 658 10;
+#X obj 169 525 pdp_xv;
+#X obj 265 42 metro 40;
+#X obj 262 17 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X floatatom 309 9 5 0 0;
+#X obj 158 156 pdp_v4l;
+#X msg 83 57 close;
+#X obj 142 56 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 119 430 pdp_add;
+#X obj 156 305 pdp_gain;
+#X msg 266 272 y \$1;
+#X msg 315 272 v \$1;
+#X msg 363 271 u \$1;
+#X floatatom 265 235 5 0 0;
+#X floatatom 315 235 5 0 0;
+#X floatatom 367 235 5 0 0;
+#X connect 1 0 6 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 1;
+#X connect 4 0 8 0;
+#X connect 5 0 4 0;
+#X connect 6 0 4 0;
+#X connect 7 0 0 0;
+#X connect 8 0 7 0;
+#X connect 9 0 8 0;
+#X connect 10 0 8 0;
+#X connect 11 0 8 0;
+#X connect 12 0 9 0;
+#X connect 13 0 10 0;
+#X connect 14 0 11 0;
diff --git a/test/test_pdp_conv.pd b/test/test_pdp_conv.pd
new file mode 100644
index 0000000..2de317a
--- /dev/null
+++ b/test/test_pdp_conv.pd
@@ -0,0 +1,115 @@
+#N canvas 255 202 713 686 10;
+#X obj 152 101 pdp_qt;
+#X msg 173 63 bang;
+#X floatatom 92 60 5 0 0;
+#X msg 258 62 open /home/ben/MOV/test1.mov;
+#X obj 164 8 i 0;
+#X obj 220 19 + 1;
+#X obj 303 24 metro 40;
+#X obj 300 -1 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X msg 63 29 0;
+#X msg 102 31 9999;
+#X msg 63 131 loop \$1;
+#X obj 59 105 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 178 136 5 0 0;
+#X floatatom 235 137 5 0 0;
+#X floatatom 383 3 5 0 0;
+#X obj 179 488 pdp_xv;
+#X obj 263 331 pdp_conv;
+#X msg 348 92 open /home/ben/MOV/neuskoter90.mov;
+#X obj 267 206 pdp_mix;
+#X floatatom 313 174 5 0 0;
+#X floatatom 234 454 5 0 0;
+#X msg 530 54 open \$1;
+#X obj 526 28 openpanel;
+#X obj 520 8 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X obj 408 164 * -1;
+#X obj 406 192 + 1;
+#X obj 405 137 hsl 128 15 1e-04 1 1 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 1;
+#X floatatom 317 299 5 0 0;
+#X msg 119 257 hor \$1;
+#X msg 173 257 ver \$1;
+#X obj 123 231 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0
+1;
+#X obj 176 228 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0
+1;
+#X obj 212 395 pdp_mix;
+#X obj 463 283 pack 0 0;
+#X obj 485 253 t b f;
+#X floatatom 462 222 5 0 0;
+#X floatatom 511 223 5 0 0;
+#X msg 462 310 mix2 \$1 \$2;
+#X obj 357 417 pdp_xv;
+#X floatatom 399 387 5 0 0;
+#X msg 323 2 stop;
+#X msg 40 416 size 1024 768;
+#X floatatom 272 367 5 0 0;
+#X msg 305 250 vmask 0.25 0.5 0.25;
+#X msg 306 272 hmask 0.25 0.5 0.25;
+#X msg 300 226 vmask 0.25 -0.5 0.25;
+#X obj 476 654 pdp_xv;
+#X floatatom 531 620 5 0 0;
+#X obj 446 535 pdp_v4l;
+#X obj 446 499 metro 40;
+#X obj 443 471 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 514 554 5 0 0;
+#X obj 450 585 pdp_chrot;
+#X connect 0 0 18 0;
+#X connect 0 0 32 0;
+#X connect 0 1 12 0;
+#X connect 0 2 13 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 5 0;
+#X connect 4 0 1 0;
+#X connect 5 0 4 1;
+#X connect 6 0 1 0;
+#X connect 7 0 6 0;
+#X connect 8 0 2 0;
+#X connect 9 0 2 0;
+#X connect 10 0 0 0;
+#X connect 11 0 10 0;
+#X connect 14 0 6 1;
+#X connect 16 0 32 1;
+#X connect 17 0 0 0;
+#X connect 18 0 16 0;
+#X connect 19 0 18 2;
+#X connect 20 0 15 1;
+#X connect 21 0 0 0;
+#X connect 22 0 21 0;
+#X connect 23 0 22 0;
+#X connect 24 0 25 0;
+#X connect 25 0 19 0;
+#X connect 26 0 24 0;
+#X connect 27 0 16 1;
+#X connect 28 0 16 0;
+#X connect 29 0 16 0;
+#X connect 30 0 28 0;
+#X connect 31 0 29 0;
+#X connect 32 0 15 0;
+#X connect 32 0 18 1;
+#X connect 33 0 37 0;
+#X connect 34 0 33 0;
+#X connect 34 1 33 1;
+#X connect 35 0 33 0;
+#X connect 36 0 34 0;
+#X connect 37 0 32 0;
+#X connect 39 0 38 1;
+#X connect 40 0 6 0;
+#X connect 41 0 15 0;
+#X connect 42 0 32 2;
+#X connect 43 0 16 0;
+#X connect 44 0 16 0;
+#X connect 45 0 16 0;
+#X connect 47 0 46 1;
+#X connect 48 0 52 0;
+#X connect 49 0 48 0;
+#X connect 50 0 49 0;
+#X connect 51 0 52 1;
+#X connect 52 0 46 0;
diff --git a/test/test_pdp_debug.pd b/test/test_pdp_debug.pd
new file mode 100644
index 0000000..54ccb66
--- /dev/null
+++ b/test/test_pdp_debug.pd
@@ -0,0 +1,18 @@
+#N canvas 649 12 317 300 10;
+#X obj 102 33 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 94 208 pdp_xv;
+#X floatatom 173 149 5 0 0;
+#X floatatom 199 64 5 0 0;
+#X obj 93 112 pdp_mix;
+#X obj 34 35 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 29 59 pdp_noise;
+#X obj 105 59 pdp_noise;
+#X connect 0 0 7 0;
+#X connect 2 0 1 1;
+#X connect 3 0 4 2;
+#X connect 4 0 1 0;
+#X connect 5 0 6 0;
+#X connect 6 0 4 0;
+#X connect 7 0 4 1;
diff --git a/test/test_pdp_del.pd b/test/test_pdp_del.pd
new file mode 100644
index 0000000..b363936
--- /dev/null
+++ b/test/test_pdp_del.pd
@@ -0,0 +1,41 @@
+#N canvas 0 0 498 481 10;
+#X obj 163 121 pdp_v4l;
+#X obj 115 58 metro 40;
+#X obj 118 25 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 75 454 pdp_xv;
+#X obj 94 106 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 283 93 5 0 0;
+#X floatatom 163 21 5 0 0;
+#X msg 232 25 2000;
+#X floatatom 220 198 5 0 0;
+#X floatatom 132 406 5 0 0;
+#X obj 133 248 pdp_mix2 0.5 -0.5;
+#X obj 291 308 pdp_conv;
+#X obj 73 360 pdp_mul;
+#X floatatom 283 337 5 0 0;
+#X floatatom 354 273 5 0 0;
+#X obj 186 359 pdp_mix;
+#X obj 181 175 pdp_del 100;
+#X msg 295 215 mask 0.33333 0.33333 0.33333;
+#X connect 0 0 10 0;
+#X connect 0 0 15 0;
+#X connect 0 0 16 0;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X connect 4 0 0 0;
+#X connect 5 0 16 1;
+#X connect 6 0 1 1;
+#X connect 7 0 1 1;
+#X connect 8 0 10 2;
+#X connect 9 0 3 1;
+#X connect 10 0 11 0;
+#X connect 11 0 15 1;
+#X connect 12 0 3 0;
+#X connect 13 0 15 2;
+#X connect 14 0 11 1;
+#X connect 15 0 12 0;
+#X connect 15 0 12 1;
+#X connect 16 0 10 1;
+#X connect 17 0 11 0;
diff --git a/test/test_pdp_gain.pd b/test/test_pdp_gain.pd
new file mode 100644
index 0000000..4387b7e
--- /dev/null
+++ b/test/test_pdp_gain.pd
@@ -0,0 +1,46 @@
+#N canvas 7 0 629 658 10;
+#X obj 169 525 pdp_xv;
+#X obj 265 42 metro 40;
+#X obj 262 17 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X floatatom 309 9 5 0 0;
+#X obj 158 156 pdp_v4l;
+#X msg 83 57 close;
+#X obj 142 56 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 119 430 pdp_add;
+#X obj 156 305 pdp_gain;
+#X msg 266 272 y \$1;
+#X msg 315 272 v \$1;
+#X msg 363 271 u \$1;
+#X floatatom 265 235 5 0 0;
+#X floatatom 315 235 5 0 0;
+#X floatatom 367 235 5 0 0;
+#X floatatom 327 184 5 0 0;
+#X floatatom 212 259 5 0 0;
+#X obj 266 212 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 332 213 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X obj 372 208 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X connect 1 0 6 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 1;
+#X connect 4 0 8 0;
+#X connect 5 0 4 0;
+#X connect 6 0 4 0;
+#X connect 7 0 0 0;
+#X connect 8 0 7 0;
+#X connect 9 0 8 0;
+#X connect 10 0 8 0;
+#X connect 11 0 8 0;
+#X connect 12 0 9 0;
+#X connect 13 0 10 0;
+#X connect 14 0 11 0;
+#X connect 15 0 13 0;
+#X connect 15 0 14 0;
+#X connect 16 0 8 1;
+#X connect 17 0 12 0;
+#X connect 18 0 13 0;
+#X connect 19 0 14 0;
diff --git a/test/test_pdp_gradient.pd b/test/test_pdp_gradient.pd
new file mode 100644
index 0000000..831fd4d
--- /dev/null
+++ b/test/test_pdp_gradient.pd
@@ -0,0 +1,52 @@
+#N canvas 0 0 592 507 10;
+#X obj 128 85 pdp_v4l;
+#X obj 127 53 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 178 30 stop;
+#X msg 216 29 bang;
+#X msg 307 9 dim 160 120;
+#X msg 305 64 dim 320 240;
+#X floatatom 222 3 5 0 0;
+#X msg 303 36 dim 640 480;
+#X obj 126 360 pdp_xv;
+#X obj 196 58 metro 20;
+#X msg 32 38 type grey;
+#X msg 31 14 type yv12;
+#X obj 129 268 pdp_gradient;
+#X obj 224 174 pack s 0 0 0;
+#X msg 171 142 rgb;
+#X floatatom 337 105 5 0 0;
+#X msg 222 209 \$1 \$2 \$3 \$4;
+#X obj 339 139 t b f;
+#X floatatom 287 105 5 0 0;
+#X obj 289 139 t b f;
+#X floatatom 232 106 5 0 0;
+#X obj 234 140 t b f;
+#X obj 125 118 pdp_trigger;
+#X msg 170 179 yuv;
+#X connect 0 0 22 0;
+#X connect 1 0 0 0;
+#X connect 2 0 9 0;
+#X connect 3 0 9 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 9 1;
+#X connect 7 0 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 0 0;
+#X connect 11 0 0 0;
+#X connect 12 0 8 0;
+#X connect 13 0 16 0;
+#X connect 14 0 13 0;
+#X connect 15 0 17 0;
+#X connect 16 0 12 0;
+#X connect 17 0 13 0;
+#X connect 17 1 13 3;
+#X connect 18 0 19 0;
+#X connect 19 0 13 0;
+#X connect 19 1 13 2;
+#X connect 20 0 21 0;
+#X connect 21 0 13 0;
+#X connect 21 1 13 1;
+#X connect 22 0 12 0;
+#X connect 23 0 13 0;
diff --git a/test/test_pdp_mix.pd b/test/test_pdp_mix.pd
new file mode 100644
index 0000000..8f9599e
--- /dev/null
+++ b/test/test_pdp_mix.pd
@@ -0,0 +1,114 @@
+#N canvas 341 641 822 286 10;
+#X obj 152 101 pdp_qt;
+#X msg 173 63 bang;
+#X floatatom 92 60 5 0 0;
+#X msg 258 62 open /home/ben/MOV/test1.mov;
+#X obj 164 8 i 0;
+#X obj 220 19 + 1;
+#X obj 303 24 metro 40;
+#X obj 300 -1 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X msg 63 29 0;
+#X msg 102 31 9999;
+#X msg 63 131 loop \$1;
+#X obj 59 105 toggle 15 0 empty empty empty 20 8 0 8 -262144 -1 -1
+1 1;
+#X floatatom 178 136 5 0 0;
+#X floatatom 235 137 5 0 0;
+#X obj 413 229 pdp_qt;
+#X msg 446 190 bang;
+#X floatatom 365 187 5 0 0;
+#X msg 531 189 open /home/ben/MOV/test1.mov;
+#X obj 437 135 i 0;
+#X obj 493 146 + 1;
+#X obj 576 151 metro 40;
+#X obj 573 126 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X msg 336 156 0;
+#X msg 375 158 9999;
+#X msg 336 258 loop \$1;
+#X obj 332 232 toggle 15 0 empty empty empty 20 8 0 8 -262144 -1 -1
+1 1;
+#X floatatom 451 263 5 0 0;
+#X floatatom 508 264 5 0 0;
+#X floatatom 383 3 5 0 0;
+#X floatatom 634 128 5 0 0;
+#X msg 327 106 0;
+#X obj 289 565 pdp_xv;
+#X obj 232 390 pdp_mix;
+#X floatatom 313 352 5 0 0;
+#X obj 356 326 hslider 300 15 0 1 0 0 empty empty empty 20 8 0 8 -241291
+-1 -1 27200 1;
+#X obj 236 437 pdp_reg;
+#X obj 297 519 pdp_mix;
+#X obj 397 437 hslider 300 15 0 1 0 0 empty empty empty 20 8 0 8 -241291
+-1 -1 10100 1;
+#X msg 396 517 mix2 \$1 \$2;
+#X obj 394 410 hslider 300 15 0 1 0 0 empty empty empty 20 8 0 8 -241291
+-1 -1 8900 1;
+#X obj 437 465 t b f;
+#X obj 417 493 pack 0 0;
+#X floatatom 241 215 5 0 0;
+#X floatatom 350 541 5 0 0;
+#X floatatom 549 226 5 0 0;
+#X msg 470 33 open /home/ben/MOV/neuskoter90.mov;
+#X msg 555 80 open /home/ben/MOV/neuskoter90.mov;
+#X msg 480 101 open \$1;
+#X obj 479 79 openpanel;
+#X obj 480 59 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X connect 0 0 32 0;
+#X connect 0 1 12 0;
+#X connect 0 2 13 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 5 0;
+#X connect 4 0 1 0;
+#X connect 5 0 4 1;
+#X connect 6 0 0 0;
+#X connect 7 0 6 0;
+#X connect 8 0 2 0;
+#X connect 9 0 2 0;
+#X connect 10 0 0 0;
+#X connect 11 0 10 0;
+#X connect 14 0 36 1;
+#X connect 14 1 26 0;
+#X connect 14 2 27 0;
+#X connect 15 0 14 0;
+#X connect 16 0 14 0;
+#X connect 17 0 14 0;
+#X connect 18 0 19 0;
+#X connect 18 0 15 0;
+#X connect 19 0 18 1;
+#X connect 20 0 15 0;
+#X connect 21 0 20 0;
+#X connect 22 0 16 0;
+#X connect 23 0 16 0;
+#X connect 24 0 14 0;
+#X connect 25 0 24 0;
+#X connect 28 0 6 1;
+#X connect 29 0 20 1;
+#X connect 30 0 22 0;
+#X connect 30 0 8 0;
+#X connect 32 0 35 0;
+#X connect 32 0 36 0;
+#X connect 33 0 32 2;
+#X connect 34 0 33 0;
+#X connect 35 0 32 1;
+#X connect 36 0 31 0;
+#X connect 37 0 40 0;
+#X connect 38 0 36 0;
+#X connect 39 0 41 0;
+#X connect 40 0 41 0;
+#X connect 40 1 41 1;
+#X connect 41 0 38 0;
+#X connect 42 0 0 1;
+#X connect 43 0 31 1;
+#X connect 44 0 14 1;
+#X connect 45 0 0 0;
+#X connect 46 0 14 0;
+#X connect 47 0 14 0;
+#X connect 47 0 0 0;
+#X connect 48 0 47 0;
+#X connect 49 0 48 0;
diff --git a/test/test_pdp_mul.pd b/test/test_pdp_mul.pd
new file mode 100644
index 0000000..3fc0902
--- /dev/null
+++ b/test/test_pdp_mul.pd
@@ -0,0 +1,44 @@
+#N canvas 0 0 450 373 10;
+#X obj 128 85 pdp_v4l;
+#X obj 128 215 pdp_xv;
+#X obj 127 53 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 340 167 pdp_reg;
+#X obj 211 93 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 178 195 5 0 0;
+#X obj 95 167 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 178 30 stop;
+#X obj 196 58 metro 40;
+#X msg 216 29 bang;
+#X obj 291 193 pdp_mul;
+#X msg 291 64 dim 160 120;
+#X msg 289 29 dim 32 32;
+#X msg 283 5 dim 80 60;
+#X msg 313 94 dim 320 240;
+#X msg 334 117 dim 768 576;
+#X floatatom 222 3 5 0 0;
+#X obj 262 245 timer;
+#X floatatom 261 271 5 0 0;
+#X obj 148 121 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X connect 0 0 1 0;
+#X connect 0 0 19 0;
+#X connect 2 0 0 0;
+#X connect 3 0 10 1;
+#X connect 4 0 3 0;
+#X connect 5 0 1 1;
+#X connect 6 0 1 0;
+#X connect 7 0 8 0;
+#X connect 8 0 0 0;
+#X connect 9 0 8 0;
+#X connect 11 0 0 0;
+#X connect 12 0 0 0;
+#X connect 13 0 0 0;
+#X connect 14 0 0 0;
+#X connect 15 0 0 0;
+#X connect 16 0 8 1;
+#X connect 17 0 18 0;
+#X connect 19 0 17 1;
+#X connect 19 0 17 0;
diff --git a/test/test_pdp_noise.pd b/test/test_pdp_noise.pd
new file mode 100644
index 0000000..7302692
--- /dev/null
+++ b/test/test_pdp_noise.pd
@@ -0,0 +1,40 @@
+#N canvas 0 0 450 300 10;
+#X obj 132 150 pdp_noise;
+#X obj 128 258 pdp_xv;
+#X obj 133 21 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 171 92 type grey;
+#X msg 173 114 type yv12;
+#X msg 243 35 dim 32 32;
+#X msg 244 10 dim 320 240;
+#X msg 246 61 dim 640 480;
+#X msg 243 216 lpf \$1 \$2;
+#X obj 242 179 pack 0 0;
+#X floatatom 247 117 5 0 0;
+#X floatatom 299 123 5 0 0;
+#X obj 264 150 t b f;
+#X floatatom 174 184 5 0 0;
+#X msg 340 33 dim 512 256;
+#X obj 134 57 metro 100;
+#X msg 205 158 2;
+#X msg 358 71 dim 1024 1024;
+#X obj 132 212 pdp_bq;
+#X connect 0 0 18 0;
+#X connect 2 0 15 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
+#X connect 8 0 18 0;
+#X connect 9 0 8 0;
+#X connect 10 0 9 0;
+#X connect 11 0 12 0;
+#X connect 12 0 9 0;
+#X connect 12 1 9 1;
+#X connect 13 0 18 1;
+#X connect 14 0 0 0;
+#X connect 15 0 0 0;
+#X connect 16 0 13 0;
+#X connect 17 0 0 0;
+#X connect 18 0 1 0;
diff --git a/test/test_pdp_pctv.pd b/test/test_pdp_pctv.pd
new file mode 100644
index 0000000..379a8e0
--- /dev/null
+++ b/test/test_pdp_pctv.pd
@@ -0,0 +1,47 @@
+#N canvas 0 0 458 400 10;
+#X obj 128 85 pdp_v4l;
+#X obj 127 53 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 178 30 stop;
+#X msg 216 29 bang;
+#X msg 291 64 dim 160 120;
+#X msg 289 29 dim 32 32;
+#X msg 283 5 dim 80 60;
+#X msg 313 94 dim 320 240;
+#X msg 334 117 dim 768 576;
+#X floatatom 222 3 5 0 0;
+#X msg 253 144 dim 640 240;
+#X msg 364 45 dim 640 480;
+#X obj 126 360 pdp_xv;
+#X obj 196 58 metro 20;
+#X msg 32 38 type grey;
+#X msg 31 14 type yv12;
+#X obj 129 268 pdp_conv;
+#X floatatom 193 228 5 0 0;
+#X msg 36 218 ver \$1;
+#X msg 91 219 hor \$1;
+#X obj 38 193 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X obj 95 192 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X connect 0 0 16 0;
+#X connect 1 0 0 0;
+#X connect 2 0 13 0;
+#X connect 3 0 13 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
+#X connect 8 0 0 0;
+#X connect 9 0 13 1;
+#X connect 10 0 0 0;
+#X connect 11 0 0 0;
+#X connect 13 0 0 0;
+#X connect 14 0 0 0;
+#X connect 15 0 0 0;
+#X connect 16 0 12 0;
+#X connect 17 0 16 1;
+#X connect 18 0 16 0;
+#X connect 19 0 16 0;
+#X connect 20 0 18 0;
+#X connect 21 0 19 0;
diff --git a/test/test_pdp_portable.pd b/test/test_pdp_portable.pd
new file mode 100644
index 0000000..5da41be
--- /dev/null
+++ b/test/test_pdp_portable.pd
@@ -0,0 +1,41 @@
+#N canvas 281 443 562 448 10;
+#X obj 60 370 pdp_xv;
+#X obj 76 103 pdp_v4l;
+#X obj 78 76 metro 20;
+#X obj 78 41 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 211 158 5 0 0;
+#X obj 71 238 pdp_gain;
+#X floatatom 146 219 5 0 0;
+#X msg 18 79 close;
+#X msg 22 156 channel \$1;
+#X floatatom 24 123 5 0 0;
+#X msg 190 97 freqMHz \$1;
+#X obj 167 8 hsl 201 15 -100 100 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X floatatom 215 36 5 0 0;
+#X obj 331 90 +;
+#X obj 333 61 t b f;
+#X obj 169 37 * 8;
+#X floatatom 330 33 5 0 0;
+#X msg 86 336 cursor \$1;
+#X obj 98 315 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X connect 1 0 5 0;
+#X connect 2 0 1 0;
+#X connect 3 0 2 0;
+#X connect 5 0 0 0;
+#X connect 6 0 5 1;
+#X connect 7 0 1 0;
+#X connect 8 0 1 0;
+#X connect 9 0 8 0;
+#X connect 10 0 1 0;
+#X connect 11 0 12 0;
+#X connect 11 0 15 0;
+#X connect 13 0 10 0;
+#X connect 14 0 13 0;
+#X connect 14 1 13 1;
+#X connect 15 0 13 0;
+#X connect 16 0 14 0;
+#X connect 17 0 0 0;
+#X connect 18 0 17 0;
diff --git a/test/test_pdp_qt_read.pd b/test/test_pdp_qt_read.pd
new file mode 100644
index 0000000..b4bb088
--- /dev/null
+++ b/test/test_pdp_qt_read.pd
@@ -0,0 +1,164 @@
+#N canvas 190 294 862 660 10;
+#X obj 122 506 pdp_xv;
+#X msg 135 81 bang;
+#X floatatom 54 78 5 0 0;
+#X msg 222 90 open /home/ben/MOV/test1.mov;
+#X msg 418 369 open /home/ben/MOV/eye.mov;
+#X obj 126 26 i 0;
+#X obj 182 37 + 1;
+#X obj 217 47 metro 40;
+#X obj 262 17 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X msg 25 47 0;
+#X msg 64 49 9999;
+#X msg 25 149 loop \$1;
+#X obj 21 123 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 264 231 5 0 0;
+#X floatatom 538 184 5 0 0;
+#X msg 370 44 open \$1;
+#X obj 369 20 openpanel;
+#X obj 354 3 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X floatatom 192 459 5 0 0;
+#X floatatom 309 9 5 0 0;
+#X msg 298 135 open /home/ben/MOV/nogeseenfilmke.mov;
+#X obj 346 406 table tab1;
+#X msg 56 23 close;
+#X obj 250 542 dac~;
+#X msg 315 390 0;
+#X obj 316 427 tabplay~ tab1;
+#X msg 332 325 importaudio tab1;
+#X obj 26 185 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 180 83 5 0 0;
+#X msg 215 7 stop;
+#X obj 478 213 i;
+#X obj 490 276 mod;
+#X obj 494 244 + 1;
+#X floatatom 558 226 5 0 0;
+#X msg 30 211 autoplay \$1;
+#X floatatom 501 321 5 0 0;
+#X obj 119 331 pdp_del 10;
+#X floatatom 194 289 5 0 0;
+#X obj 384 221 *;
+#X obj 288 159 hsl 300 15 0 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 305 44 hsl 300 15 0 1000 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X msg 329 254 loop \$1;
+#X obj 325 228 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0
+1;
+#X obj 236 258 pdp_trigger;
+#X obj 117 421 pdp_mix;
+#X floatatom 182 390 5 0 0;
+#X obj 278 349 hsl 300 15 0 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X msg 434 394 open /home/ben/MOV/nogeseenfilmke.mov;
+#X obj 241 175 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0
+1;
+#X msg 245 201 autoplay \$1;
+#X obj 408 254 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 65 281 close;
+#X obj 352 484 vol~;
+#X obj 221 497 vol~;
+#X floatatom 252 470 5 0 0;
+#X floatatom 382 460 5 0 0;
+#X msg 418 281 close;
+#X msg 121 145 play;
+#X msg 347 229 play;
+#X msg 447 13 bang;
+#X msg 564 13 stop;
+#X msg 540 97 \; pd dsp 1;
+#X msg 616 98 \; pd dsp 0;
+#X floatatom 608 13 5 0 0;
+#X msg 732 104 close;
+#X msg 778 105 close;
+#X obj 470 66 route 0 1 2 3 4 5 6 7;
+#X msg 675 13 140;
+#X obj 489 42 random 6;
+#X obj 483 12 metro 140;
+#X obj 715 46 loadbang;
+#X msg 750 76 \; pd dsp 1;
+#X obj 133 205 pdp_qt~;
+#X obj 322 283 pdp_qt~;
+#X obj 207 71 random 250;
+#X connect 1 0 72 0;
+#X connect 2 0 72 0;
+#X connect 3 0 72 0;
+#X connect 4 0 73 0;
+#X connect 5 0 6 0;
+#X connect 5 0 1 0;
+#X connect 6 0 5 1;
+#X connect 7 0 74 0;
+#X connect 8 0 7 0;
+#X connect 9 0 2 0;
+#X connect 10 0 2 0;
+#X connect 11 0 72 0;
+#X connect 12 0 11 0;
+#X connect 14 0 31 1;
+#X connect 14 0 38 1;
+#X connect 15 0 72 0;
+#X connect 16 0 15 0;
+#X connect 17 0 16 0;
+#X connect 18 0 0 1;
+#X connect 19 0 7 1;
+#X connect 20 0 72 0;
+#X connect 22 0 72 0;
+#X connect 24 0 25 0;
+#X connect 26 0 72 0;
+#X connect 27 0 34 0;
+#X connect 28 0 72 1;
+#X connect 29 0 7 0;
+#X connect 30 0 32 0;
+#X connect 31 0 35 0;
+#X connect 32 0 31 0;
+#X connect 33 0 32 1;
+#X connect 34 0 72 0;
+#X connect 36 0 44 0;
+#X connect 37 0 36 1;
+#X connect 38 0 28 0;
+#X connect 39 0 38 0;
+#X connect 40 0 19 0;
+#X connect 41 0 73 0;
+#X connect 42 0 41 0;
+#X connect 44 0 0 0;
+#X connect 45 0 44 2;
+#X connect 46 0 45 0;
+#X connect 47 0 73 0;
+#X connect 48 0 49 0;
+#X connect 49 0 73 0;
+#X connect 50 0 73 0;
+#X connect 51 0 72 0;
+#X connect 56 0 73 0;
+#X connect 57 0 72 0;
+#X connect 58 0 73 0;
+#X connect 59 0 69 0;
+#X connect 59 0 58 0;
+#X connect 59 0 57 0;
+#X connect 60 0 69 0;
+#X connect 63 0 69 1;
+#X connect 64 0 72 0;
+#X connect 65 0 73 0;
+#X connect 66 0 3 0;
+#X connect 66 1 20 0;
+#X connect 66 2 4 0;
+#X connect 66 3 47 0;
+#X connect 66 6 64 0;
+#X connect 66 7 65 0;
+#X connect 67 0 63 0;
+#X connect 68 0 66 0;
+#X connect 69 0 68 0;
+#X connect 70 0 59 0;
+#X connect 70 0 71 0;
+#X connect 72 0 43 0;
+#X connect 72 0 36 0;
+#X connect 72 1 13 0;
+#X connect 72 2 14 0;
+#X connect 72 3 23 1;
+#X connect 72 4 23 0;
+#X connect 73 0 44 1;
+#X connect 73 3 23 0;
+#X connect 73 4 23 1;
+#X connect 74 0 28 0;
diff --git a/test/test_pdp_qt_read2.pd b/test/test_pdp_qt_read2.pd
new file mode 100644
index 0000000..0071f4b
--- /dev/null
+++ b/test/test_pdp_qt_read2.pd
@@ -0,0 +1,45 @@
+#N canvas 388 475 450 300 10;
+#X msg 120 29 open /home/ben/MOV/nogeseenfilmke.mov;
+#X obj 79 52 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 119 156 pdp_xv;
+#X obj 222 166 dac~;
+#X obj 200 137 *~ 0.2;
+#X obj 253 135 *~ 0.2;
+#X obj 122 100 pdp_qt~;
+#X msg 50 98 stop;
+#X msg 119 7 open /home/ben/MOV/test1.mov;
+#X floatatom 322 77 5 0 0;
+#X obj 362 139 osc~ 1000;
+#X msg 56 215 thread \$1;
+#X obj 58 185 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 271 51 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X obj 289 75 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X msg 205 73 autoplay \$1;
+#X msg 205 47 loop \$1;
+#X obj 14 25 metro;
+#X obj 11 1 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 -1
+;
+#X floatatom 47 2 5 0 0;
+#X connect 0 0 6 0;
+#X connect 1 0 6 0;
+#X connect 4 0 3 0;
+#X connect 5 0 3 1;
+#X connect 6 0 2 0;
+#X connect 6 3 4 0;
+#X connect 6 4 5 0;
+#X connect 7 0 6 0;
+#X connect 8 0 6 0;
+#X connect 9 0 6 1;
+#X connect 11 0 6 0;
+#X connect 12 0 11 0;
+#X connect 13 0 16 0;
+#X connect 14 0 15 0;
+#X connect 15 0 6 0;
+#X connect 16 0 6 0;
+#X connect 17 0 1 0;
+#X connect 18 0 17 0;
+#X connect 19 0 17 1;
diff --git a/test/test_pdp_randmix.pd b/test/test_pdp_randmix.pd
new file mode 100644
index 0000000..c3c3023
--- /dev/null
+++ b/test/test_pdp_randmix.pd
@@ -0,0 +1,31 @@
+#N canvas 0 0 569 226 10;
+#X obj 137 194 pdp_randmix;
+#X obj 135 98 pdp_v4l;
+#X obj 167 151 pdp_reg;
+#X obj 225 113 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 135 70 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 137 241 pdp_xv;
+#X floatatom 232 167 5 0 0;
+#X msg 130 30 stop;
+#X obj 182 15 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 181 43 metro 40;
+#X obj 260 134 hsl 128 15 0 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 9800 1;
+#X obj 254 214 pdp_conv;
+#X floatatom 316 184 5 0 0;
+#X connect 0 0 5 0;
+#X connect 0 0 11 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 1;
+#X connect 3 0 2 0;
+#X connect 4 0 1 0;
+#X connect 6 0 0 2;
+#X connect 7 0 9 0;
+#X connect 8 0 9 0;
+#X connect 9 0 4 0;
+#X connect 10 0 6 0;
+#X connect 11 0 2 0;
+#X connect 12 0 11 1;
diff --git a/test/test_pdp_reg.pd b/test/test_pdp_reg.pd
new file mode 100644
index 0000000..6e5424b
--- /dev/null
+++ b/test/test_pdp_reg.pd
@@ -0,0 +1,21 @@
+#N canvas 0 0 450 300 10;
+#X obj 152 123 pdp_reg;
+#X obj 152 180 pdp_xv;
+#X obj 108 89 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X obj 149 64 pdp_qt;
+#X msg 180 34 open /home/ben/MOV/test1.mov;
+#X obj 119 21 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X msg 300 71 loop 1;
+#X obj 301 126 metro 40;
+#X obj 299 101 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X connect 0 0 1 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 1;
+#X connect 4 0 3 0;
+#X connect 5 0 3 0;
+#X connect 6 0 3 0;
+#X connect 7 0 3 0;
+#X connect 8 0 7 0;
diff --git a/test/test_pdp_scale.pd b/test/test_pdp_scale.pd
new file mode 100644
index 0000000..41a16ee
--- /dev/null
+++ b/test/test_pdp_scale.pd
@@ -0,0 +1,38 @@
+#N canvas 103 210 562 448 10;
+#X obj 60 370 pdp_xv;
+#X obj 78 76 metro 20;
+#X obj 78 41 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 211 158 5 0 0;
+#X floatatom 206 277 5 0 0;
+#X msg 18 79 close;
+#X msg 22 156 channel \$1;
+#X floatatom 24 123 5 0 0;
+#X msg 86 336 cursor \$1;
+#X obj 98 315 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X msg 109 178 dim 256 256;
+#X msg 113 202 dim 320 240;
+#X obj 71 238 pdp_scale 320 240;
+#X obj 152 78 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 76 103 pdp_v4l;
+#X msg 121 144 dim 32 32;
+#X msg 280 221 quality \$1;
+#X obj 282 193 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X connect 1 0 14 0;
+#X connect 2 0 1 0;
+#X connect 5 0 14 0;
+#X connect 6 0 14 0;
+#X connect 7 0 6 0;
+#X connect 8 0 0 0;
+#X connect 9 0 8 0;
+#X connect 10 0 12 0;
+#X connect 11 0 12 0;
+#X connect 12 0 0 0;
+#X connect 13 0 14 0;
+#X connect 14 0 12 0;
+#X connect 15 0 12 0;
+#X connect 16 0 12 0;
+#X connect 17 0 16 0;
diff --git a/test/test_pdp_scope.pd b/test/test_pdp_scope.pd
new file mode 100644
index 0000000..d441ebb
--- /dev/null
+++ b/test/test_pdp_scope.pd
@@ -0,0 +1,21 @@
+#N canvas 504 346 450 300 10;
+#X obj 107 108 pdp_scope~;
+#X obj 81 45 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 109 161 pdp_xv;
+#X msg 118 23 type grey;
+#X obj 253 58 metro 40;
+#X obj 249 37 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 198 29 5 0 0;
+#X obj 127 55 noise~ 50;
+#X obj 248 175 r~ scope;
+#X msg 270 113 dim 1024 512;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 4 0;
+#X connect 6 0 7 0;
+#X connect 8 0 0 0;
+#X connect 9 0 0 0;
diff --git a/test/test_pdp_snap.pd b/test/test_pdp_snap.pd
new file mode 100644
index 0000000..b8b5e8b
--- /dev/null
+++ b/test/test_pdp_snap.pd
@@ -0,0 +1,16 @@
+#N canvas 0 0 450 300 10;
+#X obj 130 211 pdp_xv;
+#X obj 74 97 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X obj 189 38 metro 40;
+#X obj 187 13 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X obj 118 131 pdp_snap;
+#X msg 103 96 snap;
+#X obj 185 72 pdp_v4l;
+#X connect 1 0 4 0;
+#X connect 2 0 6 0;
+#X connect 3 0 2 0;
+#X connect 4 0 0 0;
+#X connect 5 0 4 0;
+#X connect 6 0 4 1;
diff --git a/test/test_pdp_thread.pd b/test/test_pdp_thread.pd
new file mode 100644
index 0000000..2110c12
--- /dev/null
+++ b/test/test_pdp_thread.pd
@@ -0,0 +1,33 @@
+#N canvas 512 101 579 567 10;
+#X msg 86 6 stop;
+#X obj 61 6 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 -1
+;
+#X floatatom 130 3 5 0 0;
+#X obj 88 30 metro 40;
+#X obj 174 125 pdp_v4l;
+#X floatatom 207 93 5 0 0;
+#X obj 93 407 pdp_xv;
+#X msg 162 66 type grey;
+#X msg 242 63 type yv12;
+#X obj 332 322 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 346 413 pdp_control;
+#X msg 332 363 thread \$1;
+#X obj 153 408 pdp_xv;
+#X obj 212 408 pdp_xv;
+#X floatatom 213 289 5 0 0;
+#X obj 124 329 pdp_route 3;
+#X connect 0 0 3 0;
+#X connect 1 0 3 0;
+#X connect 2 0 3 1;
+#X connect 3 0 4 0;
+#X connect 4 0 15 0;
+#X connect 5 0 4 1;
+#X connect 7 0 4 0;
+#X connect 8 0 4 0;
+#X connect 9 0 11 0;
+#X connect 11 0 10 0;
+#X connect 14 0 15 1;
+#X connect 15 0 6 0;
+#X connect 15 1 12 0;
+#X connect 15 2 13 0;
diff --git a/test/test_pdp_trigger.pd b/test/test_pdp_trigger.pd
new file mode 100644
index 0000000..877d7eb
--- /dev/null
+++ b/test/test_pdp_trigger.pd
@@ -0,0 +1,13 @@
+#N canvas 661 462 467 193 10;
+#X obj 33 137 pdp_xv;
+#X obj 33 57 pdp_v4l;
+#X msg 33 12 bang;
+#X obj 33 92 pdp_trigger;
+#X obj 33 35 metro 1000;
+#X obj 105 138 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X connect 1 0 3 0;
+#X connect 2 0 4 0;
+#X connect 3 0 0 0;
+#X connect 3 1 5 0;
+#X connect 4 0 1 0;
diff --git a/test/test_pdp_v4l.pd b/test/test_pdp_v4l.pd
new file mode 100644
index 0000000..0bff99b
--- /dev/null
+++ b/test/test_pdp_v4l.pd
@@ -0,0 +1,91 @@
+#N canvas 7 0 629 658 10;
+#X obj 130 454 pdp_xv;
+#X obj 265 42 metro 40;
+#X obj 262 17 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X floatatom 309 9 5 0 0;
+#X obj 115 119 pdp_v4l;
+#X msg 220 80 open /dev/video0;
+#X msg 83 57 close;
+#X obj 142 56 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 233 127 dim 160 120;
+#X msg 238 162 dim 320 240;
+#X floatatom 177 418 5 0 0;
+#X obj 161 239 pdp_conv;
+#X floatatom 228 237 5 0 0;
+#X obj 157 325 pdp_mix2;
+#X floatatom 191 293 5 0 0;
+#X floatatom 241 293 5 0 0;
+#X obj 315 259 hsl 128 15 -1 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 316 280 hsl 128 15 -1 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X msg 350 123 dim 640 480;
+#X obj 252 372 pdp_mix;
+#X obj 257 435 pdp_reg;
+#X floatatom 307 340 5 0 0;
+#X obj 253 405 pdp_conv;
+#X floatatom 319 388 5 0 0;
+#X obj 313 314 hsl 128 15 0 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X msg 64 391 size 1024 768;
+#X msg 62 363 size 320 240;
+#X obj 357 453 hsl 128 15 -1 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 358 474 hsl 128 15 -1 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 357 500 hsl 128 15 -1 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 358 521 hsl 128 15 -1 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 230 528 pdp_affine 2;
+#X obj 357 544 hsl 128 15 -1 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 358 565 hsl 128 15 -1 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 228 570 pdp_affine 3;
+#X obj 228 479 pdp_affine 1;
+#X obj 499 372 osc~;
+#X obj 490 408 dac~;
+#X floatatom 486 335 5 0 0;
+#X connect 1 0 7 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 1;
+#X connect 4 0 11 0;
+#X connect 4 0 13 0;
+#X connect 5 0 4 0;
+#X connect 6 0 4 0;
+#X connect 7 0 4 0;
+#X connect 8 0 4 0;
+#X connect 9 0 4 0;
+#X connect 10 0 0 1;
+#X connect 11 0 13 1;
+#X connect 12 0 11 1;
+#X connect 13 0 19 0;
+#X connect 14 0 13 2;
+#X connect 15 0 13 3;
+#X connect 16 0 14 0;
+#X connect 17 0 15 0;
+#X connect 18 0 4 0;
+#X connect 19 0 22 0;
+#X connect 20 0 19 1;
+#X connect 20 0 35 0;
+#X connect 21 0 19 2;
+#X connect 22 0 20 0;
+#X connect 23 0 22 1;
+#X connect 24 0 21 0;
+#X connect 25 0 0 0;
+#X connect 26 0 0 0;
+#X connect 27 0 35 1;
+#X connect 28 0 35 2;
+#X connect 29 0 31 1;
+#X connect 30 0 31 2;
+#X connect 31 0 34 0;
+#X connect 32 0 34 1;
+#X connect 33 0 34 2;
+#X connect 34 0 0 0;
+#X connect 35 0 31 0;
+#X connect 36 0 37 0;
+#X connect 36 0 37 1;
+#X connect 38 0 36 0;
diff --git a/test/test_pdp_v4l_2.pd b/test/test_pdp_v4l_2.pd
new file mode 100644
index 0000000..905e850
--- /dev/null
+++ b/test/test_pdp_v4l_2.pd
@@ -0,0 +1,26 @@
+#N canvas 207 394 450 300 10;
+#X obj 112 96 pdp_v4l;
+#X obj 111 177 pdp_xv;
+#X obj 111 48 metro 40;
+#X obj 110 21 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 232 76 channel \$1;
+#X floatatom 227 45 5 0 0;
+#X msg 135 22 stop;
+#X msg 52 78 close;
+#X msg 222 147 dim 1280 1024;
+#X obj 63 35 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 223 120 dim 320 240;
+#X obj 110 121 pdp_grey;
+#X connect 0 0 11 0;
+#X connect 2 0 0 0;
+#X connect 3 0 2 0;
+#X connect 4 0 0 0;
+#X connect 5 0 4 0;
+#X connect 6 0 2 0;
+#X connect 7 0 0 0;
+#X connect 8 0 1 0;
+#X connect 9 0 0 0;
+#X connect 10 0 1 0;
+#X connect 11 0 1 0;
diff --git a/test/test_pdp_xv.pd b/test/test_pdp_xv.pd
new file mode 100644
index 0000000..ebd2258
--- /dev/null
+++ b/test/test_pdp_xv.pd
@@ -0,0 +1,44 @@
+#N canvas 451 201 473 511 10;
+#X obj 57 83 pdp_xv;
+#X msg 51 35 create;
+#X msg 105 41 bang;
+#X floatatom 195 37 5 0 0;
+#X msg 151 30 bang;
+#X obj 155 78 metro 40;
+#X obj 75 248 pdp_xv;
+#X msg 69 200 create;
+#X msg 123 206 bang;
+#X obj 237 244 pdp_xv;
+#X msg 231 196 create;
+#X msg 285 202 bang;
+#X floatatom 188 134 5 0 0;
+#X msg 144 127 bang;
+#X obj 148 175 metro 40;
+#X floatatom 330 121 5 0 0;
+#X msg 286 114 bang;
+#X obj 290 162 metro 40;
+#X msg 76 8 destroy;
+#X msg 283 27 size 300 300;
+#X msg 285 58 size 320 240;
+#X msg 227 326 size 1280 1024;
+#X msg 147 7 random;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 5 1;
+#X connect 4 0 5 0;
+#X connect 5 0 0 0;
+#X connect 7 0 6 0;
+#X connect 8 0 6 0;
+#X connect 10 0 9 0;
+#X connect 11 0 9 0;
+#X connect 12 0 14 1;
+#X connect 13 0 14 0;
+#X connect 14 0 8 0;
+#X connect 15 0 17 1;
+#X connect 16 0 17 0;
+#X connect 17 0 11 0;
+#X connect 18 0 0 0;
+#X connect 19 0 0 0;
+#X connect 20 0 0 0;
+#X connect 21 0 0 0;
+#X connect 22 0 0 0;
diff --git a/test/test_pdp_zoom.pd b/test/test_pdp_zoom.pd
new file mode 100644
index 0000000..eab3826
--- /dev/null
+++ b/test/test_pdp_zoom.pd
@@ -0,0 +1,73 @@
+#N canvas 58 235 562 448 10;
+#X obj 104 418 pdp_xv;
+#X obj 78 76 metro 20;
+#X obj 78 41 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 18 79 close;
+#X msg 22 156 channel \$1;
+#X floatatom 24 123 5 0 0;
+#X msg 129 344 cursor \$1;
+#X obj 129 325 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 152 78 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 76 103 pdp_v4l;
+#X obj 108 301 pdp_zoom;
+#X floatatom 157 257 5 0 0;
+#X obj 134 193 pdp_mix;
+#X floatatom 195 130 5 0 0;
+#X obj 245 179 hsl 300 15 0.01 100 1 1 empty empty empty -2 -6 0 8
+-262144 -1 -1 17104 1;
+#X floatatom 211 304 5 0 0;
+#X obj 235 244 hsl 300 15 0.01 100 1 1 empty empty empty -2 -6 0 8
+-262144 -1 -1 14200 1;
+#X msg 254 279 zoomx \$1;
+#X msg 253 305 zoomy \$1;
+#X floatatom 213 280 5 0 0;
+#X obj 239 217 hsl 300 15 0.01 100 1 1 empty empty empty -2 -6 0 8
+-262144 -1 -1 17200 1;
+#X obj 238 91 hsl 300 15 0 1 0 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 22600 1;
+#X msg 367 345 centerx \$1;
+#X floatatom 370 319 5 0 0;
+#X floatatom 452 317 5 0 0;
+#X msg 449 343 centery \$1;
+#X obj 378 265 hsl 128 15 -1 1 0 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 7700 1;
+#X obj 396 284 hsl 128 15 -1 1 0 1 empty empty empty -2 -6 0 8 -262144
+-1 -1 7700 1;
+#X msg 381 386 center 0 0;
+#X obj 129 148 pdp_grey;
+#X obj 108 382 pdp_saturation;
+#X floatatom 212 359 5 0 0;
+#X connect 1 0 9 0;
+#X connect 2 0 1 0;
+#X connect 3 0 9 0;
+#X connect 4 0 9 0;
+#X connect 5 0 4 0;
+#X connect 7 0 6 0;
+#X connect 8 0 9 0;
+#X connect 9 0 29 0;
+#X connect 9 0 12 0;
+#X connect 10 0 12 1;
+#X connect 10 0 30 0;
+#X connect 11 0 10 1;
+#X connect 12 0 10 0;
+#X connect 13 0 12 2;
+#X connect 14 0 11 0;
+#X connect 15 0 18 0;
+#X connect 16 0 15 0;
+#X connect 17 0 10 0;
+#X connect 18 0 10 0;
+#X connect 19 0 17 0;
+#X connect 20 0 19 0;
+#X connect 21 0 13 0;
+#X connect 22 0 10 0;
+#X connect 23 0 22 0;
+#X connect 24 0 25 0;
+#X connect 25 0 10 0;
+#X connect 26 0 23 0;
+#X connect 27 0 24 0;
+#X connect 28 0 10 0;
+#X connect 30 0 0 0;
+#X connect 31 0 30 1;
diff --git a/test/test_warpfeedback.pd b/test/test_warpfeedback.pd
new file mode 100644
index 0000000..4ae32ef
--- /dev/null
+++ b/test/test_warpfeedback.pd
@@ -0,0 +1,49 @@
+#N canvas 723 178 450 461 10;
+#X obj 107 108 pdp_scope~;
+#X obj 81 45 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 120 374 pdp_xv;
+#X msg 118 23 type grey;
+#X obj 253 58 metro 40;
+#X obj 249 37 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 198 29 5 0 0;
+#X obj 127 55 noise~ 50;
+#X obj 248 175 r~ scope;
+#X msg 270 113 dim 1024 512;
+#X obj 162 215 pdp_gain;
+#X floatatom 224 192 5 0 0;
+#X floatatom 121 157 5 0 0;
+#X obj 216 264 pdp_warp;
+#X obj 77 197 pdp_mix;
+#X floatatom 266 320 5 0 0;
+#X floatatom 293 287 5 0 0;
+#X obj 32 135 pdp_v4l;
+#X floatatom 230 367 5 0 0;
+#X obj 320 226 pdp_control;
+#X msg 321 194 thread 0;
+#X obj 193 303 pdp_phase;
+#X floatatom 247 213 5 0 0;
+#X obj 183 243 pdp_blur;
+#X connect 1 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 4 0 17 0;
+#X connect 5 0 4 0;
+#X connect 6 0 7 0;
+#X connect 8 0 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 23 0;
+#X connect 11 0 10 1;
+#X connect 12 0 14 2;
+#X connect 13 0 21 0;
+#X connect 14 0 10 0;
+#X connect 15 0 13 1;
+#X connect 16 0 21 1;
+#X connect 17 0 14 0;
+#X connect 18 0 2 1;
+#X connect 20 0 19 0;
+#X connect 21 0 14 1;
+#X connect 21 0 2 0;
+#X connect 22 0 23 1;
+#X connect 23 0 13 0;