diff options
author | Tom Schouten <doelie@users.sourceforge.net> | 2003-01-21 10:27:33 +0000 |
---|---|---|
committer | Tom Schouten <doelie@users.sourceforge.net> | 2003-01-21 10:27:33 +0000 |
commit | 9b8745d5250c9d0b60c9aa5a77f58a3fcddf1076 (patch) | |
tree | 8372b6a414a7124cec57efc9c80845e2bc1b157d |
This commit was generated by cvs2svn to compensate for changes in r352,svn2git-root
which included commits to RCS files with non-trunk default branches.
svn path=/trunk/externals/pdp/; revision=353
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 @@ -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 @@ -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 @@ -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; |