aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorN.N. <sevyves@users.sourceforge.net>2005-01-02 06:02:50 +0000
committerN.N. <sevyves@users.sourceforge.net>2005-01-02 06:02:50 +0000
commit304d25a2828076188afbd32757f5a67009ed866b (patch)
treeafce5fc762fee332916fb5cb4d9e874c95860c52
parenta9cfc5852d75ca1c62e4c97e3334c99ee2f2f9a8 (diff)
PiDiP 0.12.18
svn path=/trunk/externals/pidip/; revision=2440
-rw-r--r--CHANGES.LOG14
-rw-r--r--Makefile4
-rw-r--r--acinclude.m42
-rw-r--r--aclocal.m42
-rw-r--r--charmaps/acuadrosypuntos.map91
-rw-r--r--charmaps/allone.map1290
-rw-r--r--charmaps/cuadros-basic.map32
-rw-r--r--charmaps/tati.map91
-rwxr-xr-xconfigure2
-rw-r--r--configure.ac2
-rw-r--r--configure.in2
-rw-r--r--doc/help-pdp_icedthe~.pd14
-rw-r--r--doc/help-pdp_mapper.pd292
-rw-r--r--doc/help-pdp_theonice~.pd20
-rw-r--r--doc/help-pdp_theorout~.pd4
-rw-r--r--doc/rs_pdp_icedthe~.pd61
-rw-r--r--doc/rs_pdp_theonice~.pd175
-rw-r--r--doc/rs_pdp_theorin~.pd110
-rw-r--r--modules/Makefile1
-rw-r--r--modules/Makefile.in1
-rw-r--r--modules/pdp_ascii.c1
-rw-r--r--modules/pdp_binary.c2
-rw-r--r--modules/pdp_ffmpeg~.c11
-rw-r--r--modules/pdp_i.c2
-rw-r--r--modules/pdp_icedthe~.c1369
-rw-r--r--modules/pdp_live~.c82
-rw-r--r--modules/pdp_mapper.c280
-rw-r--r--modules/pdp_theonice~.c1333
-rw-r--r--modules/pdp_theorin~.c188
-rw-r--r--modules/pdp_theorout~.c89
-rw-r--r--patches/collage.pd6
-rw-r--r--patches/morphology/help-closing.pd8
-rw-r--r--patches/morphology/help-opening.pd6
-rw-r--r--patches/morphology/help-thickening.pd6
-rw-r--r--patches/morphology/help-thinning.pd6
-rw-r--r--system/pidip.c6
36 files changed, 5423 insertions, 182 deletions
diff --git a/CHANGES.LOG b/CHANGES.LOG
index d76102e..956f4ec 100644
--- a/CHANGES.LOG
+++ b/CHANGES.LOG
@@ -1,4 +1,18 @@
+0.12.18 ( codename Benisensi )
+ added pdp_icedthe~ : a threaded theora stream reader ( from flumotion or icecast )
+ added pdp_theonice~ : a theora a/v streamer ( to flumotion or icecast )
+ the icecast server can be found here : http://mediacast1.com/~karl/
+ added pdp_mapper : a pixel mapper ( copying regions and single pixels )
+
+ modified pdp_theorin~ : removed loop option ( was crashing ), added mutexes
+ modified pdp_live~ : added mutexes
+ modified pdp_ascii : added T. de la O. charmaps
+
+ fixed pdp_ffmpeg~ : fixed framerate control
+ fixed pdp_binary : fixed wrong diff calculation
+
0.12.17 ( codename No pasa nada )
+ fixed pdp_shape : a unitializded cursor caused some crashes
added pdp_theorout~ : theora file recorder
fixed pdp_theorin~ : fixed buggy end of file detection
fixed pdp_theorin~ : now, it's able to read files without sound
diff --git a/Makefile b/Makefile
index fa0eac9..0ea14fe 100644
--- a/Makefile
+++ b/Makefile
@@ -7,9 +7,9 @@ IMLIB_CFLAGS = -I/usr/local/include -I/usr/X11R6/include
IMLIB_LIBS = -L/usr/local/lib -lImlib2 -lfreetype -lz -lm -ldl -lXext -lXext -lX11 -L/usr/X11R6/lib
MAGICK_CFLAGS = -I/usr/X11R6/include -O2 -g -pipe -m32 -march=i386 -mtune=pentium4 -Wall -pthread
MAGICK_LIBS = -L/usr/X11R6/lib -lMagick -lMagick -ltiff -lfreetype -ljpeg -lpng -ldpstk -ldps -lXext -lXt -lSM -lICE -lX11 -lbz2 -lxml2 -lz -lpthread -lm -lpthread -L/usr/lib -L/usr/X11R6/lib -lfreetype -lz -L/usr/lib
-THEORA_LIBS = /usr/lib/libtheora.a /usr/lib/libogg.a /usr/lib/libvorbis.a /usr/lib/libvorbisenc.a
+THEORA_LIBS = /usr/lib/libtheora.a /usr/local/lib/libtheora.a /usr/lib/libogg.a /usr/local/lib/libvorbis.a /usr/local/lib/libvorbisenc.a
PDP_PIDIP_INCLUDES = -I/usr/local/pd/src -I. -I/usr/local/pd/pdp/include -I../include -I../charmaps -I/SOURCES/ffmpeg-cvs-2003-03-04/libavcodec -I/SOURCES/ffmpeg-cvs-2003-03-04/libavformat
-PDP_PIDIP_VERSION = 0.12.17
+PDP_PIDIP_VERSION = 0.12.18
MPEG4IP_CFLAGS =
PDP_PIDIP_DISTRO = /mnt/c/ydegoyon.free.fr/pidip-$(PDP_PIDIP_VERSION)
diff --git a/acinclude.m4 b/acinclude.m4
index 2eaf6f0..d8b255d 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -24,7 +24,7 @@ dnl At present there is no support for additional "MODULES" (see AM_PATH_GTK)
dnl (shamelessly stolen from gtk.m4 and then hacked around a fair amount)
dnl
dnl @author Angus Lees <gusl@cse.unsw.edu.au>
-dnl @version $Id: acinclude.m4,v 1.8 2004-11-14 22:52:19 sevyves Exp $
+dnl @version $Id: acinclude.m4,v 1.9 2005-01-02 06:02:47 sevyves Exp $
AC_DEFUN(AC_PATH_GENERIC,
[dnl
diff --git a/aclocal.m4 b/aclocal.m4
index 439dd2b..9abb6bb 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -36,7 +36,7 @@ dnl At present there is no support for additional "MODULES" (see AM_PATH_GTK)
dnl (shamelessly stolen from gtk.m4 and then hacked around a fair amount)
dnl
dnl @author Angus Lees <gusl@cse.unsw.edu.au>
-dnl @version $Id: aclocal.m4,v 1.8 2004-11-14 22:52:19 sevyves Exp $
+dnl @version $Id: aclocal.m4,v 1.9 2005-01-02 06:02:47 sevyves Exp $
AC_DEFUN(AC_PATH_GENERIC,
[dnl
diff --git a/charmaps/acuadrosypuntos.map b/charmaps/acuadrosypuntos.map
new file mode 100644
index 0000000..856690a
--- /dev/null
+++ b/charmaps/acuadrosypuntos.map
@@ -0,0 +1,91 @@
+#ifndef __default_h__
+#define __default_h__
+
+#define CHARWIDTH 5
+#define CHARHEIGHT 8
+#define NBCHARS 128
+
+static char charmaps[NBCHARS][CHARWIDTH*CHARHEIGHT] = {
+{
+0,1,0,0,0,
+1,0,1,0,0,
+0,1,0,0,0,
+1,0,1,0,0,
+1,0,1,0,0,
+1,1,0,0,0,
+0,1,1,0,0,
+0,0,0,0,0,
+},
+{
+0,0,0,0,0,
+0,1,0,0,0,
+0,1,0,0,0,
+0,0,0,0,0,
+0,0,0,0,0,
+0,0,0,0,0,
+0,0,0,0,0,
+0,0,0,0,0,
+},
+{
+0,1,0,1,0,
+0,1,0,1,0,
+0,1,1,1,0,
+0,1,0,1,0,
+0,1,0,1,0,
+0,0,1,1,0,
+0,0,0,1,0,
+0,0,0,1,0,
+},
+{
+0,0,0,0,0,
+0,1,1,0,0,
+0,1,1,1,0,
+1,1,1,1,0,
+0,1,1,1,0,
+0,0,1,0,0,
+0,0,0,0,0,
+0,0,0,0,0,
+},
+{
+0,1,1,0,0,
+1,0,0,0,0,
+0,1,1,0,0,
+0,0,0,0,0,
+0,0,1,1,0,
+0,0,1,0,0,
+0,0,1,1,0,
+0,0,1,0,0,
+},
+{
+0,0,0,0,0,
+0,0,0,0,0,
+1,1,0,0,0,
+0,1,1,0,0,
+0,0,0,0,0,
+0,0,0,0,0,
+0,0,0,0,0,
+0,0,0,0,0,
+},
+{
+0,0,0,0,0,
+0,0,0,0,0,
+1,1,0,0,0,
+0,1,1,0,0,
+0,0,0,0,0,
+0,0,0,0,0,
+0,0,0,0,0,
+0,0,0,0,0,
+},
+{
+0,0,0,0,0,
+0,0,0,0,0,
+0,1,0,0,0,
+0,0,0,0,0,
+0,0,0,0,0,
+0,1,0,0,0,
+1,0,0,0,0,
+0,0,0,0,0,
+},
+};
+
+#endif
diff --git a/charmaps/allone.map b/charmaps/allone.map
new file mode 100644
index 0000000..b09de06
--- /dev/null
+++ b/charmaps/allone.map
@@ -0,0 +1,1290 @@
+#ifndef __default_h__
+#define __default_h__
+
+#define CHARWIDTH 5
+#define CHARHEIGHT 8
+#define NBCHARS 128
+
+static char charmaps[NBCHARS][CHARWIDTH*CHARHEIGHT] = {
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+},
+{
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+1,1,1,1,1,
+}
+};
+
+#endif
diff --git a/charmaps/cuadros-basic.map b/charmaps/cuadros-basic.map
new file mode 100644
index 0000000..66d80b5
--- /dev/null
+++ b/charmaps/cuadros-basic.map
@@ -0,0 +1,32 @@
+#ifndef __default_h__
+#define __default_h__
+
+#define CHARWIDTH 5
+#define CHARHEIGHT 8
+#define NBCHARS 128
+
+static char charmaps[NBCHARS][CHARWIDTH*CHARHEIGHT] = {
+
+{
+0,0,0,0,0,
+0,0,0,0,0,
+1,1,0,0,0,
+1,0,1,0,0,
+1,0,1,0,0,
+1,1,0,0,0,
+1,0,0,0,0,
+1,0,0,0,0,
+},
+{
+0,0,0,0,0,
+0,0,0,0,0,
+0,1,0,0,0,
+0,0,0,0,0,
+0,0,0,0,0,
+0,1,0,0,0,
+1,0,0,0,0,
+0,0,0,0,0,
+},
+};
+
+#endif
diff --git a/charmaps/tati.map b/charmaps/tati.map
new file mode 100644
index 0000000..e607300
--- /dev/null
+++ b/charmaps/tati.map
@@ -0,0 +1,91 @@
+#ifndef __default_h__
+#define __default_h__
+
+#define CHARWIDTH 5
+#define CHARHEIGHT 8
+#define NBCHARS 128
+
+static char charmaps[NBCHARS][CHARWIDTH*CHARHEIGHT] = {
+{
+0,0,0,0,0,
+0,0,0,0,0,
+1,0,1,0,0,
+1,0,1,0,0,
+1,0,1,0,0,
+1,1,1,1,0,
+1,0,1,0,0,
+0,0,0,0,0,
+},
+{
+0,0,0,0,0,
+0,0,0,0,0,
+1,0,1,0,0,
+1,0,1,0,0,
+0,1,0,0,0,
+1,0,1,0,0,
+1,0,1,0,0,
+0,0,0,0,0,
+},
+{
+0,0,0,0,0,
+0,0,0,0,0,
+1,0,1,0,0,
+1,0,1,0,0,
+1,0,1,0,0,
+0,1,1,0,0,
+0,0,1,0,0,
+1,1,0,0,0,
+},
+{
+0,0,0,0,0,
+0,0,0,0,0,
+1,1,1,1,0,
+0,0,1,0,0,
+0,1,0,0,0,
+1,0,0,0,0,
+1,1,1,1,0,
+0,0,0,0,0,
+},
+{
+0,0,1,0,0,
+0,1,0,0,0,
+0,1,0,0,0,
+1,0,0,0,0,
+0,1,0,0,0,
+0,1,0,0,0,
+0,0,1,0,0,
+0,0,0,0,0,
+},
+{
+0,0,0,0,0,
+0,0,0,0,0,
+0,1,1,0,0,
+1,0,1,0,0,
+1,0,1,0,0,
+0,1,1,0,0,
+0,0,1,0,0,
+0,0,1,0,0,
+},
+{
+0,0,0,0,0,
+0,0,0,0,0,
+1,1,0,0,0,
+1,0,1,0,0,
+1,0,1,0,0,
+1,1,0,0,0,
+1,0,0,0,0,
+1,0,0,0,0,
+},
+{
+0,0,0,0,0,
+0,0,0,0,0,
+0,1,0,0,0,
+0,0,0,0,0,
+0,0,0,0,0,
+0,1,0,0,0,
+1,0,0,0,0,
+0,0,0,0,0,
+},
+};
+
+#endif
diff --git a/configure b/configure
index 9058c00..ecc0918 100755
--- a/configure
+++ b/configure
@@ -1267,7 +1267,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
ac_config_headers="$ac_config_headers include/pidip_config.h"
-PDP_PIDIP_VERSION="0.12.17"
+PDP_PIDIP_VERSION="0.12.18"
PD_DIR=/usr/local/pd
PDP_DIR=/usr/local/pd/pdp
FFMPEG_SOURCE_DIR=/SOURCES/ffmpeg
diff --git a/configure.ac b/configure.ac
index 9bf0afb..d55d80c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3,7 +3,7 @@ dnl Process this file with autoconf to produce a configure script.
AC_INIT
AC_CONFIG_HEADER(include/pidip_config.h)
-PDP_PIDIP_VERSION="0.12.17"
+PDP_PIDIP_VERSION="0.12.18"
PD_DIR=/usr/local/pd
PDP_DIR=/usr/local/pd/pdp
FFMPEG_SOURCE_DIR=/SOURCES/ffmpeg
diff --git a/configure.in b/configure.in
index 9bf0afb..d55d80c 100644
--- a/configure.in
+++ b/configure.in
@@ -3,7 +3,7 @@ dnl Process this file with autoconf to produce a configure script.
AC_INIT
AC_CONFIG_HEADER(include/pidip_config.h)
-PDP_PIDIP_VERSION="0.12.17"
+PDP_PIDIP_VERSION="0.12.18"
PD_DIR=/usr/local/pd
PDP_DIR=/usr/local/pd/pdp
FFMPEG_SOURCE_DIR=/SOURCES/ffmpeg
diff --git a/doc/help-pdp_icedthe~.pd b/doc/help-pdp_icedthe~.pd
new file mode 100644
index 0000000..d8cfb70
--- /dev/null
+++ b/doc/help-pdp_icedthe~.pd
@@ -0,0 +1,14 @@
+#N canvas 259 178 509 391 10;
+#X obj 156 158 dac~;
+#X text 51 309 written by Yves Degoyon (ydegoyon@free.fr);
+#X text 236 112 <-- everything is in this box;
+#X text 265 127 where the block size is redefined;
+#X text 265 141 this is necessary for an;
+#X text 266 154 ( acceptable? ) audio decoding;
+#X obj 395 221 loadbang;
+#X msg 395 251 \; pd dsp 1;
+#X obj 129 113 rs_pdp_icedthe~;
+#X text 51 295 pdp_icedthe~ : theora threaded stream decoder;
+#X connect 6 0 7 0;
+#X connect 8 0 0 0;
+#X connect 8 1 0 1;
diff --git a/doc/help-pdp_mapper.pd b/doc/help-pdp_mapper.pd
new file mode 100644
index 0000000..bf90482
--- /dev/null
+++ b/doc/help-pdp_mapper.pd
@@ -0,0 +1,292 @@
+#N canvas 237 21 712 664 10;
+#X obj 268 64 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X msg 123 136 loop \$1;
+#X obj 124 114 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1
+1;
+#X msg 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 316 99 5 0 0 0 - - -;
+#X msg 225 65 stop;
+#X obj 323 68 hsl 300 15 0 1000 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 282 213 dac~;
+#X obj 257 135 metro 70;
+#X obj 252 167 pdp_yqt;
+#X obj 421 166 pdp_v4l;
+#X obj 430 135 metro 70;
+#X obj 475 101 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X msg 432 102 stop;
+#X msg 517 133 open /dev/video;
+#X obj 548 463 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 548 515 pdp_control;
+#X msg 548 488 thread \$1;
+#X floatatom 548 576 5 0 0 0 - - -;
+#X obj 548 547 route pdp_drop;
+#X text 108 497 pdp_mapper : a pixel mapper;
+#X text 108 511 enabling some cut and paste;
+#X text 108 524 written by Yves Degoyon ( ydegoyon@free.fr );
+#X msg 369 299 copy \$1 \$2 \$3 \$4;
+#X obj 369 273 pack f f f f;
+#X obj 364 244 t b f;
+#X obj 404 244 t b f;
+#X obj 444 244 t b f;
+#X floatatom 502 245 5 0 0 0 - - -;
+#X floatatom 554 245 5 0 0 0 - - -;
+#X floatatom 603 244 5 0 0 0 - - -;
+#X floatatom 650 244 5 0 0 0 - - -;
+#X text 501 229 fromX;
+#X text 553 228 fromY;
+#X text 609 227 toX;
+#X text 652 226 toY;
+#X obj 373 364 pack f f f f;
+#X obj 368 335 t b f;
+#X obj 408 335 t b f;
+#X obj 448 335 t b f;
+#X floatatom 506 336 5 0 0 0 - - -;
+#X floatatom 558 336 5 0 0 0 - - -;
+#X floatatom 607 335 5 0 0 0 - - -;
+#X floatatom 654 335 5 0 0 0 - - -;
+#X text 505 320 fromX;
+#X text 557 319 fromY;
+#X text 613 318 toX;
+#X text 656 317 toY;
+#X msg 373 392 swap \$1 \$2 \$3 \$4;
+#X msg 373 426 reset;
+#N canvas 365 107 634 551 cutandpaste 0;
+#X obj 52 438 outlet;
+#X obj 121 76 f;
+#X obj 121 105 + 1;
+#X floatatom 121 137 5 0 0 0 - - -;
+#X msg 121 29 bang;
+#X obj 122 190 select 1;
+#X msg 167 104 34;
+#X msg 164 30 stop;
+#X obj 167 80 loadbang;
+#X obj 272 78 f;
+#X obj 272 107 + 1;
+#X floatatom 272 139 5 0 0 0 - - -;
+#X obj 273 192 select 1;
+#X obj 318 82 loadbang;
+#X msg 318 106 56;
+#X msg 272 54 bang;
+#X floatatom 169 269 5 0 0 0 - - -;
+#X floatatom 239 269 5 0 0 0 - - -;
+#X text 166 284 fromX;
+#X text 234 285 fromY;
+#X floatatom 315 268 5 0 0 0 - - -;
+#X text 321 285 toX;
+#X floatatom 395 269 5 0 0 0 - - -;
+#X text 400 284 toY;
+#X obj 168 358 pack f f f f;
+#X obj 191 327 t b f;
+#X obj 237 327 t b f;
+#X obj 286 327 t b f;
+#X obj 121 161 > 117;
+#X obj 314 243 + 100;
+#X obj 272 163 > 140;
+#X obj 395 243 + 80;
+#X obj 122 52 metro 1;
+#X obj 121 6 inlet;
+#X msg 52 406 copy \$1 \$2 \$3 \$4;
+#X connect 1 0 2 0;
+#X connect 2 0 1 1;
+#X connect 2 0 3 0;
+#X connect 3 0 16 0;
+#X connect 3 0 28 0;
+#X connect 4 0 32 0;
+#X connect 5 0 6 0;
+#X connect 5 0 15 0;
+#X connect 6 0 1 1;
+#X connect 7 0 32 0;
+#X connect 8 0 6 0;
+#X connect 9 0 10 0;
+#X connect 10 0 9 1;
+#X connect 10 0 11 0;
+#X connect 11 0 17 0;
+#X connect 11 0 30 0;
+#X connect 12 0 14 0;
+#X connect 13 0 14 0;
+#X connect 14 0 9 1;
+#X connect 14 0 7 0;
+#X connect 15 0 9 0;
+#X connect 16 0 24 0;
+#X connect 16 0 29 0;
+#X connect 17 0 25 0;
+#X connect 17 0 31 0;
+#X connect 20 0 26 0;
+#X connect 22 0 27 0;
+#X connect 24 0 34 0;
+#X connect 25 0 24 0;
+#X connect 25 1 24 1;
+#X connect 26 0 24 0;
+#X connect 26 1 24 2;
+#X connect 27 0 24 0;
+#X connect 27 1 24 3;
+#X connect 28 0 5 0;
+#X connect 29 0 20 0;
+#X connect 30 0 12 0;
+#X connect 31 0 22 0;
+#X connect 32 0 1 0;
+#X connect 33 0 4 0;
+#X connect 34 0 0 0;
+#X restore 375 455 pd cutandpaste;
+#N canvas 0 193 634 551 circleswap 0;
+#X obj 53 493 outlet;
+#X msg 121 29 bang;
+#X msg 164 30 stop;
+#X floatatom 204 328 5 0 0 0 - - -;
+#X text 131 343 fromX;
+#X text 199 344 fromY;
+#X floatatom 280 327 5 0 0 0 - - -;
+#X text 286 344 toX;
+#X floatatom 360 328 5 0 0 0 - - -;
+#X text 365 343 toY;
+#X obj 133 417 pack f f f f;
+#X obj 156 386 t b f;
+#X obj 202 386 t b f;
+#X obj 251 386 t b f;
+#X obj 279 302 + 100;
+#X obj 360 302 + 80;
+#X obj 123 78 f;
+#X obj 123 105 + 1;
+#X obj 124 156 select 1;
+#X floatatom 123 182 5 0 0 0 - - -;
+#X text 298 181 alpha;
+#X obj 124 130 > 359;
+#X obj 172 180 / 360;
+#X msg 153 79 0;
+#X obj 184 78 loadbang;
+#X obj 221 181 * 6.2832;
+#X obj 134 303 + 100;
+#X floatatom 134 328 5 0 0 0 - - -;
+#X obj 204 302 + 100;
+#X obj 126 274 expr $f1*cos($f2);
+#X obj 256 273 expr $f1*sin($f2);
+#X obj 438 77 loadbang;
+#X msg 439 103 50;
+#X obj 423 130 f;
+#X obj 423 154 - 1;
+#X obj 424 180 < 0;
+#X obj 424 206 select 1;
+#X msg 400 104 bang;
+#X floatatom 424 233 5 0 0 0 - - -;
+#X obj 243 227 t b f;
+#X obj 122 52 metro 1;
+#X obj 121 6 inlet;
+#X msg 53 461 copy \$1 \$2 \$3 \$4;
+#X connect 1 0 40 0;
+#X connect 2 0 40 0;
+#X connect 3 0 11 0;
+#X connect 3 0 15 0;
+#X connect 6 0 12 0;
+#X connect 8 0 13 0;
+#X connect 10 0 42 0;
+#X connect 11 0 10 0;
+#X connect 11 1 10 1;
+#X connect 12 0 10 0;
+#X connect 12 1 10 2;
+#X connect 13 0 10 0;
+#X connect 13 1 10 3;
+#X connect 14 0 6 0;
+#X connect 15 0 8 0;
+#X connect 16 0 17 0;
+#X connect 17 0 16 1;
+#X connect 17 0 19 0;
+#X connect 17 0 21 0;
+#X connect 18 0 23 0;
+#X connect 19 0 22 0;
+#X connect 21 0 18 0;
+#X connect 22 0 25 0;
+#X connect 23 0 16 1;
+#X connect 23 0 37 0;
+#X connect 24 0 23 0;
+#X connect 25 0 39 0;
+#X connect 26 0 27 0;
+#X connect 27 0 10 0;
+#X connect 27 0 14 0;
+#X connect 28 0 3 0;
+#X connect 29 0 26 0;
+#X connect 30 0 28 0;
+#X connect 31 0 32 0;
+#X connect 32 0 33 1;
+#X connect 32 0 30 0;
+#X connect 32 0 29 0;
+#X connect 33 0 34 0;
+#X connect 34 0 33 1;
+#X connect 34 0 35 0;
+#X connect 34 0 38 0;
+#X connect 35 0 36 0;
+#X connect 36 0 2 0;
+#X connect 36 0 32 0;
+#X connect 37 0 33 0;
+#X connect 38 0 30 0;
+#X connect 38 0 29 0;
+#X connect 39 0 30 0;
+#X connect 39 0 29 0;
+#X connect 39 1 30 1;
+#X connect 39 1 29 1;
+#X connect 40 0 16 0;
+#X connect 41 0 1 0;
+#X connect 42 0 0 0;
+#X restore 376 478 pd circleswap;
+#X obj 153 430 pdp_xv;
+#X msg 481 454 bang;
+#X msg 481 477 bang;
+#X obj 153 388 pdp_mapper;
+#X connect 0 0 10 0;
+#X connect 1 0 11 0;
+#X connect 2 0 1 0;
+#X connect 3 0 11 0;
+#X connect 4 0 3 0;
+#X connect 5 0 4 0;
+#X connect 6 0 10 1;
+#X connect 7 0 10 0;
+#X connect 8 0 6 0;
+#X connect 10 0 11 0;
+#X connect 11 0 57 0;
+#X connect 11 4 9 0;
+#X connect 11 5 9 1;
+#X connect 12 0 57 0;
+#X connect 13 0 12 0;
+#X connect 14 0 13 0;
+#X connect 15 0 13 0;
+#X connect 16 0 12 0;
+#X connect 17 0 19 0;
+#X connect 18 0 21 0;
+#X connect 19 0 18 0;
+#X connect 21 0 20 0;
+#X connect 25 0 57 0;
+#X connect 26 0 25 0;
+#X connect 27 0 26 0;
+#X connect 27 1 26 1;
+#X connect 28 0 26 0;
+#X connect 28 1 26 2;
+#X connect 29 0 26 0;
+#X connect 29 1 26 3;
+#X connect 30 0 26 0;
+#X connect 31 0 27 0;
+#X connect 32 0 28 0;
+#X connect 33 0 29 0;
+#X connect 38 0 50 0;
+#X connect 39 0 38 0;
+#X connect 39 1 38 1;
+#X connect 40 0 38 0;
+#X connect 40 1 38 2;
+#X connect 41 0 38 0;
+#X connect 41 1 38 3;
+#X connect 42 0 38 0;
+#X connect 43 0 39 0;
+#X connect 44 0 40 0;
+#X connect 45 0 41 0;
+#X connect 50 0 57 0;
+#X connect 51 0 57 0;
+#X connect 52 0 57 0;
+#X connect 53 0 57 0;
+#X connect 55 0 52 0;
+#X connect 56 0 53 0;
+#X connect 57 0 54 0;
diff --git a/doc/help-pdp_theonice~.pd b/doc/help-pdp_theonice~.pd
new file mode 100644
index 0000000..cec7bf2
--- /dev/null
+++ b/doc/help-pdp_theonice~.pd
@@ -0,0 +1,20 @@
+#N canvas 131 125 861 556 10;
+#X obj 156 158 dac~;
+#X text 246 113 <-- everything is in this box;
+#X text 275 128 where the block size is redefined;
+#X text 275 142 this is necessary for an;
+#X msg 395 251 \; pd dsp 1;
+#X obj 128 113 rs_pdp_theonice~;
+#X text 52 282 written by Yves Degoyon ( ydegoyon@free.fr );
+#X text 55 229 pdp_theonice~ : streams theora a/v to a;
+#X text 52 242 (patched) icecast server;
+#X text 53 269 http://mediacast1.com/~karl;
+#X text 52 256 the icecast server can be found here :;
+#X text 276 155 ( acceptable? ) theora audio decoding;
+#X obj 395 221 loadbang;
+#X obj 160 55 adc~;
+#X connect 5 0 0 0;
+#X connect 5 1 0 1;
+#X connect 12 0 4 0;
+#X connect 13 0 5 0;
+#X connect 13 1 5 1;
diff --git a/doc/help-pdp_theorout~.pd b/doc/help-pdp_theorout~.pd
index 0fe1b31..e6cb579 100644
--- a/doc/help-pdp_theorout~.pd
+++ b/doc/help-pdp_theorout~.pd
@@ -66,6 +66,8 @@
#X text 682 310 before starting the recording;
#X text 682 324 ( or restart it );
#X obj 159 504 pdp_theorout~;
+#X msg 452 82 loop 1;
+#X obj 452 55 loadbang;
#X connect 0 0 8 0;
#X connect 1 0 19 0;
#X connect 2 0 1 0;
@@ -116,3 +118,5 @@
#X connect 56 0 49 0;
#X connect 57 0 50 0;
#X connect 60 0 18 0;
+#X connect 61 0 38 0;
+#X connect 62 0 61 0;
diff --git a/doc/rs_pdp_icedthe~.pd b/doc/rs_pdp_icedthe~.pd
new file mode 100644
index 0000000..f6fc439
--- /dev/null
+++ b/doc/rs_pdp_icedthe~.pd
@@ -0,0 +1,61 @@
+#N canvas 127 47 872 636 10;
+#X text 452 600 written by Yves Degoyon (ydegoyon@free.fr);
+#X floatatom 245 506 7 0 0 0 - - -;
+#X text 301 507 Number of video frames decoded;
+#X msg 248 352 priority \$1;
+#X floatatom 337 353 5 0 0 0 - - -;
+#X text 383 376 ( optional \, if you know what you're doing );
+#X text 388 348 Set the priority of decoding thread;
+#X msg 248 322 audio \$1;
+#X obj 317 324 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X floatatom 261 483 5 0 0 0 - - -;
+#X floatatom 285 463 5 0 0 0 - - -;
+#X obj 72 543 outlet~;
+#X text 385 361 ([0 \, 20 ] default : 1 );
+#X text 442 323 Activate decoding of audio ( default : on );
+#X obj 375 323 loadbang;
+#X msg 340 323 1;
+#X obj 67 60 block~ 512;
+#X obj 39 496 pdp_xv;
+#X obj 691 39 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 691 91 pdp_control;
+#X msg 691 64 thread \$1;
+#X floatatom 691 152 5 0 0 0 - - -;
+#X obj 691 123 route pdp_drop;
+#X msg 248 291 disconnect;
+#X text 332 291 Disconnect from a stream;
+#X text 538 263 Connect to a stream;
+#X text 332 463 End of stream reached;
+#X text 308 485 Stream framerate;
+#X floatatom 232 530 5 0 0 0 - - -;
+#X text 281 531 Connection status;
+#X text 452 586 pdp_icedthe~ : threaded theora stream decoder;
+#X msg 248 263 connect http://localhost:8000/theora.ogg;
+#X floatatom 306 443 20 0 0 0 - - -;
+#X text 458 442 Video/Audio lag;
+#X msg 248 232 connect http://mirror.fluendo.com:8801/;
+#X obj 134 543 outlet~;
+#X obj 133 396 pdp_icedthe~;
+#X connect 3 0 36 0;
+#X connect 4 0 3 0;
+#X connect 7 0 36 0;
+#X connect 8 0 7 0;
+#X connect 14 0 15 0;
+#X connect 15 0 8 0;
+#X connect 18 0 20 0;
+#X connect 19 0 22 0;
+#X connect 20 0 19 0;
+#X connect 22 0 21 0;
+#X connect 23 0 36 0;
+#X connect 31 0 36 0;
+#X connect 34 0 36 0;
+#X connect 36 0 17 0;
+#X connect 36 1 11 0;
+#X connect 36 2 35 0;
+#X connect 36 3 28 0;
+#X connect 36 4 1 0;
+#X connect 36 5 9 0;
+#X connect 36 6 10 0;
+#X connect 36 7 32 0;
diff --git a/doc/rs_pdp_theonice~.pd b/doc/rs_pdp_theonice~.pd
new file mode 100644
index 0000000..31602de
--- /dev/null
+++ b/doc/rs_pdp_theonice~.pd
@@ -0,0 +1,175 @@
+#N canvas 5 16 986 661 10;
+#X obj 255 34 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X msg 117 65 loop \$1;
+#X obj 117 40 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 1
+;
+#X msg 278 48 open \$1;
+#X obj 278 24 openpanel;
+#X obj 278 3 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X floatatom 293 75 5 0 0 0 - - -;
+#X msg 212 35 stop;
+#X obj 215 91 metro 70;
+#X obj 5 155 pdp_v4l;
+#X obj 14 124 metro 70;
+#X obj 59 90 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X msg 16 91 stop;
+#X msg 79 125 open /dev/video;
+#X text 647 79 written by Yves Degoyon ( ydegoyon@free.fr );
+#X obj 215 124 pdp_yqt;
+#X obj 860 516 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 860 568 pdp_control;
+#X msg 860 541 thread \$1;
+#X floatatom 860 629 5 0 0 0 - - -;
+#X obj 860 600 route pdp_drop;
+#X text 388 144 <---- audio connections;
+#X text 381 161 ==== ACTIONS ========;
+#X text 382 382 ==== VIDEOS SETTINGS ========;
+#X text 381 483 ==== AUDIO SETTINGS ========;
+#X obj 23 329 pdp_xv;
+#X obj 74 178 pdp_affine;
+#X floatatom 106 152 5 0 0 0 - - -;
+#X obj 356 19 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 356 69 open \$1;
+#X obj 356 41 openpanel;
+#X text 509 571 Warning : change audio and video settings;
+#X msg 383 431 videoquality \$1;
+#X msg 385 455 videobitrate \$1;
+#X text 558 457 Video bitrate ( kbps ) : [45 \, 2000];
+#X text 723 471 default 48;
+#X msg 383 504 audioquality \$1;
+#X msg 384 532 audiobitrate \$1;
+#X text 725 547 default 32;
+#X text 561 533 Audio bitrate ( kbps ) : [8 \, 2000];
+#X text 560 506 Audio quality : [-0.1 \, 1.0] \, default 0.5;
+#X floatatom 502 432 5 0 0 0 - - -;
+#X floatatom 503 454 5 0 0 0 - - -;
+#X floatatom 504 504 5 0 0 0 - - -;
+#X floatatom 504 533 5 0 0 0 - - -;
+#X text 650 26 pdp_theonice~ : streams theora a/v to a;
+#X text 647 39 (patched) icecast server;
+#X text 648 66 http://mediacast1.com/~karl;
+#X text 647 53 the icecast server can be found here :;
+#X msg 384 237 passwd letmein;
+#X text 579 585 before connecting;
+#X msg 384 210 disconnect;
+#X text 494 237 Setting up the password;
+#X text 627 184 Connect to an icecast server;
+#X text 466 212 Disconnect;
+#X text 577 598 ( or reconnect to the server );
+#X msg 384 263 title the aesthetics of our anger;
+#X msg 384 362 genre angrrrry;
+#X msg 383 335 description images from infowar;
+#X msg 384 309 url http://www.indymedia.org;
+#X msg 384 285 artist recuerdos de luchas;
+#X msg 384 182 connect localhost theora.ogg 8000;
+#X obj 356 98 pdp_theorin~;
+#X floatatom 41 530 5 0 0 0 - - -;
+#X text 83 531 Streaming status;
+#X floatatom 68 551 7 0 0 0 - - -;
+#X text 126 551 Number of video frames emitted;
+#X floatatom 96 571 7 0 0 0 - - -;
+#X text 147 571 Number of video frames dropped;
+#X floatatom 124 594 5 0 0 0 - - -;
+#X text 168 593 Emission framerate;
+#X obj 23 304 pdp_spigot;
+#X obj 94 282 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X text 556 433 Video quality : [0 \, 63] \, default 2!;
+#X floatatom 502 406 5 0 0 0 - - -;
+#X msg 383 405 framerate \$1;
+#X obj 156 268 pdp_scale 192 160;
+#X floatatom 145 617 7 0 0 0 - - -;
+#X text 201 618 Audio stream time;
+#X floatatom 165 639 7 0 0 0 - - -;
+#X text 220 639 Video stream time;
+#X msg 76 329 close;
+#X obj 265 172 spigot~;
+#X obj 311 143 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 463 97 route 1;
+#X msg 464 70 bang;
+#X obj 416 69 symbol;
+#X obj 229 213 outlet~;
+#X obj 294 214 outlet~;
+#X obj 518 622 block~ 512;
+#X obj 142 366 inlet~;
+#X obj 216 366 inlet~;
+#X text 556 406 Framerate : [1 \, 100] \, default 7;
+#X obj 159 490 pdp_theonice~;
+#X connect 0 0 8 0;
+#X connect 1 0 15 0;
+#X connect 2 0 1 0;
+#X connect 3 0 15 0;
+#X connect 4 0 3 0;
+#X connect 5 0 4 0;
+#X connect 6 0 8 1;
+#X connect 7 0 8 0;
+#X connect 8 0 15 0;
+#X connect 9 0 26 0;
+#X connect 10 0 9 0;
+#X connect 11 0 10 0;
+#X connect 12 0 10 0;
+#X connect 13 0 9 0;
+#X connect 15 0 76 0;
+#X connect 15 4 82 0;
+#X connect 15 4 93 0;
+#X connect 15 5 82 0;
+#X connect 15 5 93 1;
+#X connect 16 0 18 0;
+#X connect 17 0 20 0;
+#X connect 18 0 17 0;
+#X connect 20 0 19 0;
+#X connect 26 0 76 0;
+#X connect 27 0 26 1;
+#X connect 28 0 30 0;
+#X connect 29 0 62 0;
+#X connect 30 0 29 0;
+#X connect 30 0 86 1;
+#X connect 32 0 93 0;
+#X connect 33 0 93 0;
+#X connect 36 0 93 0;
+#X connect 37 0 93 0;
+#X connect 41 0 32 0;
+#X connect 42 0 33 0;
+#X connect 43 0 36 0;
+#X connect 44 0 37 0;
+#X connect 49 0 93 0;
+#X connect 51 0 93 0;
+#X connect 56 0 93 0;
+#X connect 57 0 93 0;
+#X connect 58 0 93 0;
+#X connect 59 0 93 0;
+#X connect 60 0 93 0;
+#X connect 61 0 93 0;
+#X connect 62 0 93 0;
+#X connect 62 1 82 0;
+#X connect 62 1 93 0;
+#X connect 62 2 82 0;
+#X connect 62 2 93 1;
+#X connect 62 5 84 0;
+#X connect 71 1 25 0;
+#X connect 72 0 71 1;
+#X connect 74 0 75 0;
+#X connect 75 0 93 0;
+#X connect 76 0 71 0;
+#X connect 76 0 93 0;
+#X connect 81 0 25 0;
+#X connect 82 1 88 0;
+#X connect 82 1 87 0;
+#X connect 83 0 82 1;
+#X connect 84 0 85 0;
+#X connect 85 0 86 0;
+#X connect 86 0 29 0;
+#X connect 90 0 93 0;
+#X connect 91 0 93 1;
+#X connect 93 0 63 0;
+#X connect 93 1 65 0;
+#X connect 93 2 67 0;
+#X connect 93 3 69 0;
+#X connect 93 4 77 0;
+#X connect 93 5 79 0;
diff --git a/doc/rs_pdp_theorin~.pd b/doc/rs_pdp_theorin~.pd
index cc1a74b..100f137 100644
--- a/doc/rs_pdp_theorin~.pd
+++ b/doc/rs_pdp_theorin~.pd
@@ -7,7 +7,7 @@
#X text 385 433 ( optional \, if you know what you're doing );
#X obj 134 543 outlet~;
#X text 390 405 Set the priority of decoding thread;
-#X obj 247 143 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+#X obj 247 174 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
-1;
#X msg 250 379 audio \$1;
#X obj 319 381 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
@@ -20,41 +20,34 @@
#X text 446 350 Activate threading ( default : on );
#X floatatom 256 526 5 0 0 0 - - -;
#X floatatom 280 506 5 0 0 0 - - -;
-#X obj 339 257 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+#X obj 339 288 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
1;
-#X obj 395 255 loadbang;
-#X msg 360 255 1;
-#X msg 248 256 autoplay \$1;
-#X text 463 255 Activate auto play mode ( default : on );
-#X msg 248 287 bang;
-#X msg 388 289 bang;
-#X floatatom 429 290 5 0 0 0 - - -;
-#X text 481 288 In manual mode \, read next frame ( autoplay = off
+#X obj 395 286 loadbang;
+#X msg 360 286 1;
+#X msg 248 287 autoplay \$1;
+#X text 463 286 Activate auto play mode ( default : on );
+#X msg 248 318 bang;
+#X msg 388 318 bang;
+#X floatatom 429 319 5 0 0 0 - - -;
+#X text 481 319 In manual mode \, read next frame ( autoplay = off
);
-#X obj 324 289 metro 70;
-#X msg 249 318 loop \$1;
-#X obj 311 319 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
-1;
-#X obj 367 317 loadbang;
-#X msg 332 317 1;
-#X text 435 317 Activate loop mode for files ( default : on );
-#X msg 285 288 stop;
+#X obj 324 318 metro 70;
+#X msg 285 318 stop;
#X obj 111 430 pdp_theorin~;
-#X msg 248 222 close;
-#X text 326 224 Close the current file;
-#X text 325 164 Open a theora video file;
-#X msg 247 193 open \$1;
+#X msg 248 253 close;
+#X text 326 255 Close the current file;
+#X text 325 195 Open a theora video file;
+#X msg 247 224 open \$1;
#X text 303 528 File framerate;
#X text 327 507 End of file reached;
#X text 452 586 pdp_theorin~ : threaded theora file reader;
#X text 11 163 Seek file ( in kilobytes );
#X obj 72 543 outlet~;
#X text 387 418 ([0 \, 20 ] default : 1 );
-#X obj 247 165 openpanel;
+#X obj 247 196 openpanel;
#X text 444 380 Activate decoding of audio ( default : on );
#X obj 377 380 loadbang;
#X msg 342 380 1;
-#X obj 67 60 block~ 512;
#X text 12 179 warning : there's a big delay;
#X text 11 192 and risks of desynchronisation;
#X text 25 220 seekable for now );
@@ -62,7 +55,7 @@
#X floatatom 309 455 5 0 0 0 - - -;
#X text 354 455 File size ( in kbs );
#X obj 39 496 pdp_xv;
-#X obj 78 259 vsl 15 128 0 2083 0 0 empty filesize empty 0 -8 0 8 -262144
+#X obj 78 259 vsl 15 128 0 510 0 0 empty filesize empty 0 -8 0 8 -262144
-1 -1 0 1;
#X msg 310 473 \; filesize range 0 \$1;
#X floatatom 59 411 5 0 0 0 - - -;
@@ -72,44 +65,49 @@
#X msg 691 64 thread \$1;
#X floatatom 691 152 5 0 0 0 - - -;
#X obj 691 123 route pdp_drop;
-#X connect 3 0 34 0;
+#X obj 129 294 route 1;
+#X obj 152 265 symbol;
+#X msg 115 265 bang;
+#X obj 241 582 block~ 512;
+#X connect 3 0 29 0;
#X connect 4 0 3 0;
-#X connect 8 0 45 0;
-#X connect 9 0 34 0;
+#X connect 8 0 40 0;
+#X connect 9 0 29 0;
#X connect 10 0 9 0;
#X connect 11 0 12 0;
-#X connect 12 0 34 0;
+#X connect 12 0 29 0;
#X connect 13 0 14 0;
#X connect 14 0 11 0;
#X connect 18 0 21 0;
#X connect 19 0 20 0;
#X connect 20 0 18 0;
-#X connect 21 0 34 0;
-#X connect 23 0 34 0;
+#X connect 21 0 29 0;
+#X connect 23 0 29 0;
#X connect 24 0 27 0;
#X connect 25 0 27 1;
-#X connect 27 0 34 0;
-#X connect 28 0 34 0;
-#X connect 29 0 28 0;
-#X connect 30 0 31 0;
-#X connect 31 0 29 0;
-#X connect 33 0 27 0;
-#X connect 34 0 56 0;
-#X connect 34 1 43 0;
-#X connect 34 2 6 0;
-#X connect 34 3 1 0;
-#X connect 34 4 16 0;
-#X connect 34 5 17 0;
-#X connect 34 6 54 0;
-#X connect 35 0 34 0;
-#X connect 38 0 34 0;
-#X connect 45 0 38 0;
-#X connect 47 0 48 0;
-#X connect 48 0 10 0;
-#X connect 54 0 58 0;
-#X connect 57 0 34 1;
-#X connect 57 0 59 0;
-#X connect 60 0 62 0;
-#X connect 61 0 64 0;
-#X connect 62 0 61 0;
-#X connect 64 0 63 0;
+#X connect 27 0 29 0;
+#X connect 28 0 27 0;
+#X connect 29 0 50 0;
+#X connect 29 1 38 0;
+#X connect 29 2 6 0;
+#X connect 29 3 1 0;
+#X connect 29 4 16 0;
+#X connect 29 5 17 0;
+#X connect 29 5 59 0;
+#X connect 29 6 48 0;
+#X connect 30 0 29 0;
+#X connect 33 0 29 0;
+#X connect 40 0 33 0;
+#X connect 40 0 60 1;
+#X connect 42 0 43 0;
+#X connect 43 0 10 0;
+#X connect 48 0 52 0;
+#X connect 51 0 29 1;
+#X connect 51 0 53 0;
+#X connect 54 0 56 0;
+#X connect 55 0 58 0;
+#X connect 56 0 55 0;
+#X connect 58 0 57 0;
+#X connect 59 0 61 0;
+#X connect 60 0 33 0;
+#X connect 61 0 60 0;
diff --git a/modules/Makefile b/modules/Makefile
index 66847ff..c9bd447 100644
--- a/modules/Makefile
+++ b/modules/Makefile
@@ -19,6 +19,7 @@ OBJECTS = pdp_intrusion.o pdp_yqt.o pdp_simura.o pdp_underwatch.o \
pdp_binary.o pdp_erode.o pdp_dilate.o pdp_hitandmiss.o \
pdp_disintegration.o pdp_distance.o pdp_theorin~.o \
pdp_theorout~.o pdp_cropper.o pdp_background.o \
+ pdp_mapper.o pdp_theonice~.o pdp_icedthe~.o\
pdp_live~.o pdp_ffmpeg~.o # pdp_xcanvas.o pdp_aa.o
all_modules: $(OBJECTS)
diff --git a/modules/Makefile.in b/modules/Makefile.in
index 56fe02b..88c8bc0 100644
--- a/modules/Makefile.in
+++ b/modules/Makefile.in
@@ -19,6 +19,7 @@ OBJECTS = pdp_intrusion.o pdp_yqt.o pdp_simura.o pdp_underwatch.o \
pdp_binary.o pdp_erode.o pdp_dilate.o pdp_hitandmiss.o \
pdp_disintegration.o pdp_distance.o pdp_theorin~.o \
pdp_theorout~.o pdp_cropper.o pdp_background.o \
+ pdp_mapper.o pdp_theonice~.o pdp_icedthe~.o\
@PDP_STREAMING_OBJECTS@ # pdp_xcanvas.o pdp_aa.o
all_modules: $(OBJECTS)
diff --git a/modules/pdp_ascii.c b/modules/pdp_ascii.c
index e81d3f2..34f9e96 100644
--- a/modules/pdp_ascii.c
+++ b/modules/pdp_ascii.c
@@ -315,6 +315,7 @@ static void pdp_ascii_load(t_pdp_ascii *x, t_symbol *sfile)
{
case '0':
case '1':
+ // post( "pdp_ascii : read %c", charread );
*pdata++ = ( charread == '0' )?0:1;
nbexpdata--;
break;
diff --git a/modules/pdp_binary.c b/modules/pdp_binary.c
index 5ce943c..c0ddb10 100644
--- a/modules/pdp_binary.c
+++ b/modules/pdp_binary.c
@@ -198,7 +198,7 @@ static void pdp_binary_process_yv12(t_pdp_binary *x)
diff = 0;
if ( x->x_colorY >= 0 )
{
- diff += abs(y-x->x_colorY );
+ diff = abs(y-x->x_colorY );
}
if ( x->x_colorV >= 0 )
{
diff --git a/modules/pdp_ffmpeg~.c b/modules/pdp_ffmpeg~.c
index 3e229af..fec1c35 100644
--- a/modules/pdp_ffmpeg~.c
+++ b/modules/pdp_ffmpeg~.c
@@ -322,6 +322,7 @@ static void pdp_ffmpeg_process_yv12(t_pdp_ffmpeg *x)
t_int framebytes;
t_int owidth, oheight;
short *pencbuf;
+ t_int framerate, atime, ttime;
/* allocate all ressources */
if ( ((int)header->info.image.width != x->x_vwidth) ||
@@ -391,12 +392,12 @@ static void pdp_ffmpeg_process_yv12(t_pdp_ffmpeg *x)
x->x_secondcount[ j ] = 0;
}
}
- if ( x->x_secondcount[ svideoindex ] >= (x->x_avcontext->streams[i]->codec.frame_rate/10000) )
+ framerate = x->x_avcontext->streams[i]->codec.frame_rate/10000;
+ ttime = ( ( x->x_nbframes + 1 ) % framerate ) * ( 1000 / framerate );
+ atime = ( etime.tv_usec / 1000 );
+ // post("pdp_theonice~ : actual : %d, theoretical : %d", atime, ttime );
+ if ( atime < ttime )
{
- // post("pdp_ffmpeg : index=%d actual : %d, nominal : %d",
- // svideoindex,
- // x->x_secondcount[ svideoindex ],
- // (x->x_avcontext->streams[i]->codec.frame_rate/10000) );
x->x_nbframes_dropped++;
continue;
}
diff --git a/modules/pdp_i.c b/modules/pdp_i.c
index a89a56c..f1a47c1 100644
--- a/modules/pdp_i.c
+++ b/modules/pdp_i.c
@@ -155,7 +155,7 @@ static void pdp_i_free_ressources(t_pdp_i *x)
{
if ( x->x_ddata ) freebytes( x->x_ddata, x->x_psize );
if ( x->x_hdata ) freebytes( x->x_hdata, x->x_hsize );
- if ( x->x_bdata ) freebytes( x->x_hdata, x->x_bsize );
+ if ( x->x_bdata ) freebytes( x->x_bdata, x->x_bsize );
}
static void pdp_i_allocate(t_pdp_i *x)
diff --git a/modules/pdp_icedthe~.c b/modules/pdp_icedthe~.c
new file mode 100644
index 0000000..2a07f96
--- /dev/null
+++ b/modules/pdp_icedthe~.c
@@ -0,0 +1,1369 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@free.fr)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* This object is a theora stream reader from icecast2
+ * It uses libtheora and some of it code samples ( copyright xiph.org )
+ * Written by Yves Degoyon ( ydegoyon@free.fr )
+ */
+
+
+#include "pdp.h"
+#include "yuv.h"
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <math.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <signal.h>
+
+#include <theora/theora.h> /* theora stuff */
+#include <vorbis/codec.h> /* vorbis stuff */
+
+#define STRBUF_SIZE 4096
+#define NET_BUFFER_SIZE (4*1024)
+#define VIDEO_BUFFER_SIZE (1024*1024)
+#define MAX_AUDIO_PACKET_SIZE (64 * 1024)
+#define MIN_AUDIO_SIZE (64*1024)
+
+#define DEFAULT_CHANNELS 1
+#define DEFAULT_WIDTH 320
+#define DEFAULT_HEIGHT 240
+#define DEFAULT_FRAME_RATE 25
+#define END_OF_STREAM 20
+#define MIN_PRIORITY 0
+#define DEFAULT_PRIORITY 1
+#define MAX_PRIORITY 20
+#define MAX_NO_STREAM 50
+#define THEORA_NUM_HEADER_PACKETS 3
+#define MAX_WRONG_PACKETS 10
+
+static char *pdp_icedthe_version = "pdp_icedthe~: version 0.1, a theora stream reader ( ydegoyon@free.fr).";
+
+typedef struct pdp_icedthe_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_dropped;
+
+ t_pdp *x_header;
+ unsigned char *x_data;
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+
+ t_outlet *x_pdp_out; // output decoded pdp packets
+ t_outlet *x_outlet_left; // left audio output
+ t_outlet *x_outlet_right; // right audio output
+ t_outlet *x_outlet_state; // for informing of the connection state
+ t_outlet *x_outlet_nbframes; // number of frames emitted
+ t_outlet *x_outlet_framerate; // real framerate
+ t_outlet *x_outlet_endofstream;// for signaling the end of the stream
+ t_outlet *x_outlet_time; // outputing the video/audio delay
+
+ pthread_t x_decodechild; // stream decoding thread
+ pthread_t x_connectchild; // connecting thread
+ pthread_mutex_t x_audiolock; // audio mutex
+ pthread_mutex_t x_videolock; // video mutex
+ t_int x_priority; // priority of decoding thread
+
+ char *x_url; // url to connect to
+ char *x_hostname; // hostname of the server ( or IP )
+ char *x_mountpoint; // mountpoint requested
+ t_int x_bitrate; // bitrate of stream read at connection time
+ char *x_name; // name of stream
+ char *x_genre; // genre of stream
+ t_int x_portnum; // port number
+ t_int x_insock; // socket file descriptor
+ t_int x_decoding; // decoding flag
+ t_int x_theorainit; // flag for indicating that theora is initialized
+ t_int x_videoready; // video ready flag
+ t_int x_newpicture; // new picture flag
+ t_int x_notpackets; // number of theora packets decoded
+ t_int x_novpackets; // number of vorbis packets decoded
+ t_int x_nbnostream; // number of cycles without a video stream
+ t_int x_endofstream; // end of the stream reached
+ t_int x_nbframes; // number of frames emitted
+ t_float x_framerate; // framerate
+ t_int x_samplerate; // audio sample rate
+ t_int x_audiochannels; // audio channels
+ t_int x_blocksize; // audio block size
+ t_int x_audioon; // audio buffer filling flag
+ t_int x_connected; // connection flag
+ t_int x_pconnected; // previous state
+ t_int x_cursec; // current second
+ t_int x_secondcount; // number of frames received in the current second
+ struct timeval x_starttime; // reading starting time
+ char x_request[STRBUF_SIZE]; // string to be send to server
+
+ /* vorbis/theora structures */
+ ogg_sync_state x_sync_state; // ogg sync state
+ ogg_page x_ogg_page; // ogg page
+ ogg_packet x_ogg_packet; // ogg packet
+ ogg_stream_state x_statev; // vorbis stream state
+ ogg_stream_state x_statet; // theora stream state
+ theora_info x_theora_info; // theora info
+ theora_comment x_theora_comment; // theora comment
+ theora_state x_theora_state; // theora state
+ vorbis_info x_vorbis_info; // vorbis info
+ vorbis_dsp_state x_dsp_state; // vorbis dsp state
+ vorbis_block x_vorbis_block; // vorbis block
+ vorbis_comment x_vorbis_comment; // vorbis comment
+ yuv_buffer x_yuvbuffer; // yuv buffer
+
+ double x_videotime; // video logical time of last packet
+ double x_audiotime; // audio logical time of last packet
+ double x_ptime; // previous state
+
+ /* audio structures */
+ t_int x_audio; // flag to activate the decoding of audio
+ t_float x_audio_inl[4*MAX_AUDIO_PACKET_SIZE]; /* buffer for float audio decoded from ogg */
+ t_float x_audio_inr[4*MAX_AUDIO_PACKET_SIZE]; /* buffer for float audio decoded from ogg */
+ t_int x_audioin_position; // writing position for incoming audio
+
+} t_pdp_icedthe;
+
+static void pdp_icedthe_priority(t_pdp_icedthe *x, t_floatarg fpriority )
+{
+ if ( ( x->x_priority >= MIN_PRIORITY ) && ( x->x_priority <= MAX_PRIORITY ) )
+ {
+ x->x_priority = (int)fpriority;
+ }
+}
+
+static void pdp_icedthe_audio(t_pdp_icedthe *x, t_floatarg faudio )
+{
+ if ( ( faudio == 0. ) || ( faudio == 1. ) )
+ {
+ x->x_audio = (int)faudio;
+ }
+}
+
+static int strip_ice_header(char *head, int n)
+{
+ int i;
+ for (i = 0; i < (n - 2); i++)
+ {
+ if ((head[i] == '\n') && (head[i + 1] == '\n'))
+ break;
+ }
+ head[i + 1] = '\0';
+ return n - (i + 1);
+}
+
+static void pdp_icedthe_disconnect(t_pdp_icedthe *x)
+{
+ t_int ret, i, count=0;
+ struct timespec twait;
+
+ twait.tv_sec = 0;
+ twait.tv_nsec = 100000000; // 100 ms
+
+ if ( x->x_insock == -1 )
+ {
+ post("pdp_icedthe~ : close request but no stream is played ... ignored" );
+ return;
+ }
+
+ if ( x->x_connected )
+ {
+ x->x_connected = 0;
+ // post("pdp_icedthe~ : waiting end of decoding..." );
+ // while ( x->x_decoding ) nanosleep( &twait, NULL );
+
+ if ( close( x->x_insock ) < 0 )
+ {
+ post( "pdp_icedthe~ : could not close input stream" );
+ perror( "fclose" );
+ }
+ x->x_insock = -1;
+
+ if ( x->x_notpackets > 0 )
+ {
+ ogg_stream_clear(&x->x_statet);
+ theora_clear(&x->x_theora_state);
+ theora_comment_clear(&x->x_theora_comment);
+ theora_info_clear(&x->x_theora_info);
+ }
+
+ if ( x->x_novpackets > 0 )
+ {
+ ogg_stream_clear(&x->x_statev);
+ vorbis_block_clear(&x->x_vorbis_block);
+ vorbis_dsp_clear(&x->x_dsp_state);
+ vorbis_comment_clear(&x->x_vorbis_comment);
+ vorbis_info_clear(&x->x_vorbis_info);
+ }
+
+ }
+
+ x->x_notpackets = 0;
+ x->x_novpackets = 0;
+ x->x_nbnostream = 0;
+ x->x_nbframes = 0;
+ x->x_decoding = 0;
+ x->x_theorainit = 0;
+ x->x_videoready = 0;
+ x->x_newpicture = 0;
+
+ x->x_nbframes = 0;
+ x->x_framerate = 0.;
+ x->x_videotime = 0.;
+ x->x_audiotime = 0.;
+ x->x_endofstream = 1;
+}
+
+static t_int pdp_icedthe_get_buffer_from_network(t_int socket, ogg_sync_state *oy)
+{
+ char *buffer;
+ t_int bytes;
+
+ buffer=ogg_sync_buffer(oy, NET_BUFFER_SIZE);
+ if ( ( bytes = read( socket, buffer, NET_BUFFER_SIZE ) ) < 0 )
+ {
+ post( "pdp_icedthe~ : could not read data from the server" );
+ perror( "read" );
+ return -1;
+ }
+ ogg_sync_wrote(oy,bytes);
+ return(bytes);
+}
+
+static t_int pdp_icedthe_queue_page(t_pdp_icedthe *x)
+{
+
+ if(x->x_notpackets)
+ {
+ if ( x->x_connected && ( ogg_page_serialno(&x->x_ogg_page) == x->x_statet.serialno ) )
+ {
+ // post( "pdp_icedthe~ : got a video page (#=%ld)", x->x_statet.pageno );
+ x->x_videotime = theora_granule_time(&x->x_theora_state, ogg_page_granulepos(&x->x_ogg_page));
+ }
+ ogg_stream_pagein(&x->x_statet, &x->x_ogg_page);
+ }
+ if(x->x_novpackets)
+ {
+ if ( x->x_connected && ( ogg_page_serialno(&x->x_ogg_page) == x->x_statev.serialno ) )
+ {
+ // post( "pdp_icedthe~ : got an audio page (#=%ld)", x->x_statev.pageno );
+ x->x_audiotime = vorbis_granule_time(&x->x_dsp_state, ogg_page_granulepos(&x->x_ogg_page));
+ }
+ ogg_stream_pagein(&x->x_statev, &x->x_ogg_page);
+ }
+ return 0;
+}
+
+static t_int pdp_icedthe_decode_stream(t_pdp_icedthe *x)
+{
+ int ret, count, maxsamples, samples, si=0, sj=0;
+ float **pcm;
+ struct timespec mwait;
+ struct timeval ctime;
+ long long tplaying;
+ long long ttheoretical;
+ unsigned char *pY, *pU, *pV;
+ unsigned char *psY, *psU, *psV;
+ t_int px, py;
+
+ // post( "pdp_icedthe~ : decode packet" );
+
+ while ( x->x_novpackets && !x->x_audioon && x->x_connected )
+ {
+ /* if there's pending, decoded audio, grab it */
+ if((ret=vorbis_synthesis_pcmout(&x->x_dsp_state, &pcm))>0)
+ {
+ if ( x->x_audio && x->x_connected )
+ {
+ if ( pthread_mutex_lock( &x->x_audiolock ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to lock audio mutex" );
+ perror( "pthread_mutex_lock" );
+ }
+ maxsamples=(4*MAX_AUDIO_PACKET_SIZE-x->x_audioin_position);
+ samples=(ret<maxsamples)?ret:maxsamples;
+
+ memcpy( (void*)&x->x_audio_inl[x->x_audioin_position], pcm[0], samples*sizeof(t_float) );
+ memcpy( (void*)&x->x_audio_inr[x->x_audioin_position], pcm[1], samples*sizeof(t_float) );
+ x->x_audioin_position = ( x->x_audioin_position + samples ) % (4*MAX_AUDIO_PACKET_SIZE);
+
+ if ( ( x->x_audioin_position > MIN_AUDIO_SIZE ) && (!x->x_audioon) )
+ {
+ x->x_audioon = 1;
+ // post( "pdp_icedthe~ : audio on (audioin=%d)", x->x_audioin_position );
+ }
+ // tell vorbis how many samples were read
+ // post( "pdp_icedthe~ : got %d audio samples (audioin=%d)", samples, x->x_audioin_position );
+ vorbis_synthesis_read(&x->x_dsp_state, samples);
+ if ( pthread_mutex_unlock( &x->x_audiolock ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to audio unlock mutex" );
+ perror( "pthread_mutex_unlock" );
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ // no pending audio: is there a pending packet to decode?
+ if( ogg_stream_packetout(&x->x_statev, &x->x_ogg_packet)>0 )
+ {
+ if(vorbis_synthesis(&x->x_vorbis_block, &x->x_ogg_packet)==0)
+ {
+ vorbis_synthesis_blockin(&x->x_dsp_state, &x->x_vorbis_block);
+ }
+ }
+ else /* we need more data; suck in another page */
+ {
+ break;
+ }
+ }
+ }
+
+ if ( !x->x_newpicture && x->x_connected )
+ {
+ while(x->x_notpackets && !x->x_videoready && x->x_connected )
+ {
+ // theora is one in, one out...
+ if(ogg_stream_packetout(&x->x_statet, &x->x_ogg_packet)>0)
+ {
+ theora_decode_packetin(&x->x_theora_state, &x->x_ogg_packet);
+ // post( "pdp_icedthe~ : got one video frame" );
+ x->x_videoready=1;
+ x->x_nbnostream=0;
+ }
+ else
+ {
+ if ( x->x_nbframes > 0 )
+ {
+ x->x_nbnostream++;
+ }
+
+ if ( x->x_nbnostream > MAX_NO_STREAM )
+ {
+ post ( "pdp_icedthe~ : receiving too few frames... disconnecting." );
+ x->x_endofstream = 1;
+ x->x_nbframes = 0;
+ x->x_audioin_position = 0; // reset audio
+ x->x_audioon = 0;
+ x->x_connected = 0;
+ x->x_notpackets = 0;
+ x->x_novpackets = 0;
+ }
+ break;
+ }
+ }
+
+ if ( x->x_videoready )
+ {
+ if ( pthread_mutex_lock( &x->x_videolock ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to lock video mutex" );
+ perror( "pthread_mutex_lock" );
+ }
+ theora_decode_YUVout(&x->x_theora_state, &x->x_yuvbuffer);
+
+ // create a new pdp packet from PIX_FMT_YUV420P image format
+ x->x_vwidth = x->x_yuvbuffer.y_width;
+ x->x_vheight = x->x_yuvbuffer.y_height;
+ x->x_vsize = x->x_vwidth*x->x_vheight;
+ x->x_packet0 = pdp_packet_new_bitmap_yv12( x->x_vwidth, x->x_vheight );
+ // post( "pdp_icedthe~ : allocated packet %d", x->x_packet0 );
+ x->x_header = pdp_packet_header(x->x_packet0);
+ x->x_data = (unsigned char*) pdp_packet_data(x->x_packet0);
+
+ x->x_header->info.image.encoding = PDP_BITMAP_YV12;
+ x->x_header->info.image.width = x->x_vwidth;
+ x->x_header->info.image.height = x->x_vheight;
+
+ pY = x->x_data;
+ pV = x->x_data+x->x_vsize;
+ pU = x->x_data+x->x_vsize+(x->x_vsize>>2);
+
+ psY = x->x_yuvbuffer.y;
+ psU = x->x_yuvbuffer.u;
+ psV = x->x_yuvbuffer.v;
+
+ for ( py=0; py<x->x_vheight; py++)
+ {
+ memcpy( (void*)pY, (void*)psY, x->x_vwidth );
+ pY += x->x_vwidth;
+ psY += x->x_yuvbuffer.y_stride;
+ if ( py%2==0 )
+ {
+ memcpy( (void*)pU, (void*)psU, (x->x_vwidth>>1) );
+ memcpy( (void*)pV, (void*)psV, (x->x_vwidth>>1) );
+ pU += (x->x_vwidth>>1);
+ pV += (x->x_vwidth>>1);
+ psU += x->x_yuvbuffer.uv_stride;
+ psV += x->x_yuvbuffer.uv_stride;
+ }
+ }
+ x->x_newpicture = 1;
+ // post( "pdp_icedthe~ : new picture decoded" );
+ if ( pthread_mutex_unlock( &x->x_videolock ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to unlock video mutex" );
+ perror( "pthread_mutex_unlock" );
+ }
+ }
+ }
+
+ // read more data in
+ if( ( x->x_audioin_position < MIN_AUDIO_SIZE ) || ( !x->x_newpicture ) )
+ {
+ if ( ( ret=pdp_icedthe_get_buffer_from_network(x->x_insock, &x->x_sync_state) ) < 0 )
+ {
+ pdp_icedthe_disconnect(x);
+ return -1;
+ }
+
+ // post( "pdp_icedthe~ : read %d bytes from network", ret );
+ while( ogg_sync_pageout(&x->x_sync_state, &x->x_ogg_page)>0 )
+ {
+ pdp_icedthe_queue_page(x);
+ }
+ }
+
+ x->x_videoready = 0;
+
+ return 0;
+
+}
+
+static void *pdp_icedthe_decode(void *tdata)
+{
+ t_pdp_icedthe *x = (t_pdp_icedthe*)tdata;
+ struct sched_param schedprio;
+ t_int pmin, pmax, p1;
+ struct timespec twait;
+
+ twait.tv_sec = 0;
+ twait.tv_nsec = 25000000; // 25 ms
+
+ schedprio.sched_priority = sched_get_priority_min(SCHED_FIFO) + x->x_priority;
+ if ( sched_setscheduler(0, SCHED_FIFO, &schedprio) == -1)
+ {
+ post("pdp_icedthe~ : couldn't set priority for decoding thread.");
+ }
+
+ while ( x->x_decodechild )
+ {
+ if ( x->x_connected )
+ {
+ if ( x->x_decoding == 0 )
+ {
+ post( "pdp_icedthe~ : child started decoding" );
+ x->x_decoding = 1;
+ }
+ // decode incoming packets
+ pdp_icedthe_decode_stream( x );
+ nanosleep( &twait, NULL );
+ }
+ else
+ {
+ if ( x->x_decoding == 1 )
+ {
+ post( "pdp_icedthe~ : child stopped decoding" );
+ x->x_decoding = 0;
+ }
+ nanosleep( &twait, NULL ); // nothing to do, just wait
+ }
+ }
+
+ x->x_decodechild = 0;
+ post("pdp_icedthe~ : decoding child exiting." );
+ return NULL;
+}
+
+static void pdp_icedthe_connect(t_pdp_icedthe *x, t_symbol *s);
+
+static void *pdp_icedthe_do_connect(void *tdata)
+{
+ pthread_attr_t decode_child_attr;
+ ogg_stream_state o_tempstate;
+ t_pdp_icedthe *x = (t_pdp_icedthe*)tdata;
+ t_int sockfd;
+ struct sockaddr_in server;
+ struct hostent *hp;
+ fd_set fdset;
+ struct timeval tv;
+ t_int numrelocs = 0;
+ t_int i, ret, rest, nanswers=0;
+ char *cpoint = NULL;
+ t_int offset = 0, endofheaders = 0, wpackets = 0;
+ char *sptr = NULL;
+ char *url; /* used for relocation */
+
+ if ( x->x_insock != -1 )
+ {
+ post("pdp_icedthe~ : connect request but a stream is open ... disconnecting" );
+ pdp_icedthe_disconnect(x);
+ }
+
+ sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if ( ( sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) ) <= 0 )
+ {
+ error("pdp_icedthe~: couldn't obtain a socket");
+ x->x_connectchild = 0;
+ return NULL;
+ }
+
+ server.sin_family = AF_INET;
+ hp = gethostbyname(x->x_hostname);
+ if (hp == 0)
+ {
+ post("pdp_icedthe~: your server is unresolved here.");
+ if ( close(sockfd) < 0 ) post("pdp_icedthe~: could not close socket" );
+ x->x_connectchild = 0;
+ return NULL;
+ }
+ memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
+
+ /* assign client port number */
+ server.sin_port = htons((unsigned short)x->x_portnum);
+
+ /* try to connect. */
+ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
+ {
+ error("pdp_icedthe~: connection failed!\n");
+ if ( close(sockfd) < 0 ) post("pdp_icedthe~: could not close socket" );
+ x->x_connectchild = 0;
+ return NULL;
+ }
+ post("pdp_icedthe~: connected : socket opened" );
+
+ /* check if we can read from socket */
+ FD_ZERO( &fdset);
+ FD_SET( sockfd, &fdset);
+ tv.tv_sec = 0; /* seconds */
+ tv.tv_usec = 500; /* microseconds */
+
+ ret = select(sockfd + 1, &fdset, NULL, NULL, &tv);
+ if(ret != 0)
+ {
+ error("pdp_icedthe~: can not read from socket");
+ if ( close(sockfd) < 0 ) post("pdp_icedthe~: could not close socket" );
+ x->x_connectchild = 0;
+ return NULL;
+ }
+
+ /* build up stuff we need to send to server */
+ sprintf(x->x_request, "GET /%s HTTP/1.0 \r\nHost: %s\r\nUser-Agent: pdp_icedthe~ 0.1\r\nAccept: */*\r\n\r\n",
+ x->x_mountpoint, x->x_hostname);
+
+ if ( send(sockfd, x->x_request, strlen(x->x_request), 0) < 0 ) /* say hello to server */
+ {
+ post( "pdp_icedthe~: could not contact server... " );
+ perror( "send" );
+ x->x_connectchild = 0;
+ return NULL;
+ }
+ post("pdp_icedthe~: send done" );
+
+ memset( x->x_request, 0x00, STRBUF_SIZE );
+
+ // read all the answer
+ endofheaders=0;
+ while ( !endofheaders )
+ {
+ if( ( ret = recv(sockfd, x->x_request+offset, 1, MSG_NOSIGNAL) ) <0)
+ {
+ error("pdp_icedthe~: no response from server");
+ perror( "recv" );
+ x->x_connectchild = 0;
+ return NULL;
+ }
+ // post ( "pdp_icedthe~ : received %d bytes at %d", ret, offset );
+ for ( i=0; i<=offset; i++ )
+ {
+ if ( ( x->x_request[i] == '\n' && x->x_request[i+1] == '\n' ) ||
+ ( x->x_request[i] == 10 && x->x_request[i+1] == 13 ) )
+ {
+ endofheaders=1;
+ }
+ }
+ if ( offset+ret < STRBUF_SIZE )
+ {
+ offset+=ret;
+ }
+ else
+ {
+ post( "pdp_icedthe~ : headers too long." );
+ x->x_connectchild = 0;
+ return NULL;
+ }
+ }
+
+ // post( "pdp_icedthe~ : read HTTP headers : %s", x->x_request );
+ post( "pdp_icedthe~ : got HTTP answer" );
+
+ strip_ice_header(x->x_request, STRBUF_SIZE);
+ if(sptr = strstr(x->x_request, "302"))
+ {
+ cpoint = NULL;
+ cpoint = strstr(x->x_request, "Location:");
+ if ( cpoint == NULL )
+ {
+ post( "pdp_icedthe~ : stream has moved but couldn't find new location out of this :" );
+ post("pdp_icedthe~: %s", x->x_request );
+ x->x_connectchild = 0;
+ return NULL;
+ }
+ url = strdup(cpoint + 10);
+ post("pdp_icedthe~: relocating to %s", url);
+ if ( close(sockfd) < 0 ) post("pdp_icedthe~: could not close socket" );
+ x->x_connectchild = 0;
+ pdp_icedthe_connect(x, gensym(url));
+ return NULL;
+ }
+ if ( !(sptr = strstr(x->x_request, "200")) )
+ {
+ error("pdp_icedthe~: cannot connect to the stream");
+ error("pdp_icedthe~: server answered : %s", x->x_request);
+ x->x_connectchild = 0;
+ return NULL;
+ }
+
+ // check what we got
+ if( cpoint = strstr(x->x_request, "x-audiocast-mount:"))
+ {
+ if ( x->x_mountpoint ) free( x->x_mountpoint );
+ x->x_mountpoint = strdup(cpoint + 18);
+ for ( i=0; i<(int)strlen(x->x_mountpoint); i++ )
+ {
+ if ( x->x_mountpoint[i] == '\n' )
+ {
+ x->x_mountpoint[i] = '\0';
+ break;
+ }
+ }
+ post(" mountpoint: %s", x->x_mountpoint);
+ }
+ if( cpoint = strstr(x->x_request, "x-audiocast-server-url:"))
+ {
+ sptr = strdup( cpoint + 24);
+ for ( i=0; i<(int)strlen(sptr); i++ )
+ {
+ if ( sptr[i] == '\n' )
+ {
+ sptr[i] = '\0';
+ break;
+ }
+ }
+ post(" server-url: %s", sptr);
+ }
+ if( cpoint = strstr(x->x_request, "x-audiocast-location:"))
+ {
+ sptr = strdup( cpoint + 22);
+ for ( i=0; i<(int)strlen(sptr); i++ )
+ {
+ if ( sptr[i] == '\n' )
+ {
+ sptr[i] = '\0';
+ break;
+ }
+ }
+ post(" location: %s", sptr);
+ }
+ if( cpoint = strstr(x->x_request, "x-audiocast-admin:"))
+ {
+ sptr = strdup( cpoint + 19);
+ for ( i=0; i<(int)strlen(sptr); i++ )
+ {
+ if ( sptr[i] == '\n' )
+ {
+ sptr[i] = '\0';
+ break;
+ }
+ }
+ post(" admin: %s", sptr);
+ }
+ if( cpoint = strstr(x->x_request, "x-audiocast-name:"))
+ {
+ x->x_name = strdup( cpoint + 17);
+ for ( i=0; i<(int)strlen(x->x_name); i++ )
+ {
+ if ( x->x_name[i] == '\n' )
+ {
+ x->x_name[i] = '\0';
+ break;
+ }
+ }
+ post(" name: %s", x->x_name);
+ }
+ if( cpoint = strstr(x->x_request, "x-audiocast-genre:"))
+ {
+ x->x_genre = strdup( cpoint + 18);
+ for ( i=0; i<(int)strlen(x->x_genre); i++ )
+ {
+ if ( x->x_genre[i] == '\n' )
+ {
+ x->x_genre[i] = '\0';
+ break;
+ }
+ }
+ post(" genre: %s", x->x_genre);
+ }
+ if( cpoint = strstr(x->x_request, "x-audiocast-url:"))
+ {
+ if ( x->x_url ) free( x->x_url );
+ x->x_url = strdup( cpoint + 16);
+ for ( i=0; i<(int)strlen(x->x_url); i++ )
+ {
+ if ( x->x_url[i] == '\n' )
+ {
+ x->x_url[i] = '\0';
+ break;
+ }
+ }
+ post(" url: %s", x->x_url);
+ }
+ if( cpoint = strstr(x->x_request, "x-audiocast-public:1"))
+ {
+ post(" broadcast is public");
+ }
+ else if( cpoint = strstr(x->x_request, "x-audiocast-public:0"))
+ {
+ post(" broadcast is NOT public");
+ }
+ if( cpoint = strstr(x->x_request, "x-audiocast-bitrate:"))
+ {
+ sptr = strdup( cpoint + 20);
+ for ( i=0; i<(int)strlen(sptr); i++ )
+ {
+ if ( sptr[i] == '\n' )
+ {
+ sptr[i] = '\0';
+ break;
+ }
+ }
+ if(!strncmp(sptr, "320", 3))x->x_bitrate = 320;
+ else if(!strncmp(sptr, "256", 3))x->x_bitrate = 256;
+ else if(!strncmp(sptr, "224", 3))x->x_bitrate = 224;
+ else if(!strncmp(sptr, "192", 3))x->x_bitrate = 192;
+ else if(!strncmp(sptr, "160", 3))x->x_bitrate = 160;
+ else if(!strncmp(sptr, "144", 3))x->x_bitrate = 144;
+ else if(!strncmp(sptr, "128", 3))x->x_bitrate = 128;
+ else if(!strncmp(sptr, "112", 3))x->x_bitrate = 112;
+ else if(!strncmp(sptr, "96", 2))x->x_bitrate = 96;
+ else if(!strncmp(sptr, "80", 2))x->x_bitrate = 80;
+ else if(!strncmp(sptr, "64", 2))x->x_bitrate = 64;
+ else if(!strncmp(sptr, "56", 2))x->x_bitrate = 56;
+ else if(!strncmp(sptr, "48", 2))x->x_bitrate = 48;
+ else if(!strncmp(sptr, "40", 2))x->x_bitrate = 40;
+ else if(!strncmp(sptr, "32", 2))x->x_bitrate = 32;
+ else if(!strncmp(sptr, "24", 2))x->x_bitrate = 24;
+ else if(!strncmp(sptr, "16", 2))x->x_bitrate = 16;
+ else if(!strncmp(sptr, "8", 1))x->x_bitrate = 8;
+ else
+ {
+ post("pdp_icedthe~: unsupported bitrate! : %s", sptr);
+ x->x_connectchild = 0;
+ return NULL;
+ }
+ post(" bitrate: %d", x->x_bitrate);
+ }
+
+ ogg_sync_init(&x->x_sync_state);
+ x->x_notpackets=0;
+ x->x_novpackets=0;
+
+ // init supporting Vorbis structures needed in header parsing
+ vorbis_info_init(&x->x_vorbis_info);
+ vorbis_comment_init(&x->x_vorbis_comment);
+
+ // init supporting Theora structures needed in header parsing
+ theora_comment_init(&x->x_theora_comment);
+ theora_info_init(&x->x_theora_info);
+
+ // parse headers
+ while( !x->x_theorainit )
+ {
+ ret = pdp_icedthe_get_buffer_from_network(sockfd, &x->x_sync_state);
+ if ( ret==0) break;
+ if ( ret<0)
+ {
+ post( "pdp_icedthe~ : unable to read from server" );
+ pdp_icedthe_disconnect( x );
+ x->x_theorainit = 0;
+ x->x_connectchild = 0;
+ return NULL;
+ }
+
+ while( ogg_sync_pageout(&x->x_sync_state, &x->x_ogg_page) > 0 )
+ {
+ pdp_icedthe_queue_page(x);
+
+ ogg_stream_init(&o_tempstate, ogg_page_serialno(&x->x_ogg_page));
+ ogg_stream_pagein(&o_tempstate, &x->x_ogg_page);
+ ogg_stream_packetout(&o_tempstate, &x->x_ogg_packet);
+
+ /* identify the codec: try theora */
+ if(!x->x_notpackets &&
+ theora_decode_header(&x->x_theora_info, &x->x_theora_comment, &x->x_ogg_packet)>=0)
+ {
+ // it is theora
+ // post( "pdp_icedthe~ : got one theora header.");
+ memcpy(&x->x_statet, &o_tempstate, sizeof(o_tempstate));
+ x->x_notpackets=1;
+ x->x_theorainit = 1;
+ }else
+ if(!x->x_novpackets &&
+ vorbis_synthesis_headerin(&x->x_vorbis_info, &x->x_vorbis_comment, &x->x_ogg_packet)>=0)
+ {
+ // post( "pdp_icedthe~ : got one vorbis header.");
+ memcpy(&x->x_statev, &o_tempstate, sizeof(o_tempstate));
+ x->x_novpackets=1;
+ }
+ else
+ {
+ // post( "pdp_icedthe~ : got something else.");
+ wpackets++;
+ ogg_stream_clear(&o_tempstate);
+ if ( wpackets > MAX_WRONG_PACKETS )
+ {
+ post( "pdp_icedthe~ : couldn't read any headers.");
+ x->x_theorainit = 0;
+ x->x_connectchild = 0;
+ return NULL;
+ }
+ }
+ }
+ }
+
+ // we're expecting more header packets.
+ while( (x->x_notpackets && x->x_notpackets<THEORA_NUM_HEADER_PACKETS) || (x->x_novpackets && x->x_novpackets<THEORA_NUM_HEADER_PACKETS) )
+ {
+ // look for further theora headers
+ while(x->x_notpackets && (x->x_notpackets<THEORA_NUM_HEADER_PACKETS) &&
+ (ret=ogg_stream_packetout(&x->x_statet, &x->x_ogg_packet)))
+ {
+ if( ret<0 )
+ {
+ post("pdp_icedthe~ : error parsing theora stream headers\n");
+ x->x_theorainit = 0;
+ x->x_connectchild = 0;
+ return NULL;
+ }
+ if( theora_decode_header(&x->x_theora_info, &x->x_theora_comment, &x->x_ogg_packet) )
+ {
+ post("pdp_icedthe~ : error parsing theora stream headers\n");
+ x->x_theorainit = 0;
+ x->x_connectchild = 0;
+ return NULL;
+ }
+ x->x_notpackets++;
+ if(x->x_notpackets==THEORA_NUM_HEADER_PACKETS) break;
+ }
+
+ /* look for more vorbis header packets */
+ while(x->x_novpackets && (x->x_novpackets<THEORA_NUM_HEADER_PACKETS) &&
+ (ret=ogg_stream_packetout(&x->x_statev, &x->x_ogg_packet)))
+ {
+ if(ret<0)
+ {
+ post("pdp_icedthe~ : error parsing theora stream headers\n");
+ x->x_theorainit = 0;
+ x->x_connectchild = 0;
+ return NULL;
+ }
+ if( vorbis_synthesis_headerin(&x->x_vorbis_info, &x->x_vorbis_comment, &x->x_ogg_packet) )
+ {
+ post("pdp_icedthe~ : error parsing theora stream headers\n");
+ x->x_theorainit = 0;
+ x->x_connectchild = 0;
+ return NULL;
+ }
+ x->x_novpackets++;
+ if(x->x_novpackets==THEORA_NUM_HEADER_PACKETS) break;
+ }
+
+ if(ogg_sync_pageout(&x->x_sync_state, &x->x_ogg_page)>0)
+ {
+ pdp_icedthe_queue_page(x);
+ }
+ else
+ {
+ ret=pdp_icedthe_get_buffer_from_network(sockfd, &x->x_sync_state);
+ if( ret==0 )
+ {
+ post("pdp_icedthe~ : end of stream while parsing headers\n");
+ x->x_theorainit = 0;
+ x->x_connectchild = 0;
+ return NULL;
+ }
+ if( ret<0 )
+ {
+ post("pdp_icedthe~ : error reading from server\n");
+ x->x_theorainit = 0;
+ x->x_connectchild = 0;
+ return NULL;
+ }
+ }
+ }
+ post( "pdp_icedthe~ : parsed headers ok (not=%d) (nov=%d)", x->x_notpackets, x->x_novpackets );
+
+ // initialize decoders
+ if( x->x_notpackets )
+ {
+ theora_decode_init(&x->x_theora_state, &x->x_theora_info);
+ if ( x->x_theora_info.fps_denominator != 0 )
+ {
+ x->x_framerate = x->x_theora_info.fps_numerator/x->x_theora_info.fps_denominator;
+ }
+ else
+ {
+ x->x_framerate = DEFAULT_FRAME_RATE;
+ }
+ post("pdp_icedthe~ : stream %x is theora %dx%d %f fps video.",
+ x->x_statet.serialno,
+ x->x_theora_info.width,x->x_theora_info.height,
+ x->x_framerate);
+ if(x->x_theora_info.width!=x->x_theora_info.frame_width ||
+ x->x_theora_info.height!=x->x_theora_info.frame_height)
+ {
+ post("pdp_icedthe~ : frame content is %dx%d with offset (%d,%d).",
+ x->x_theora_info.frame_width, x->x_theora_info.frame_height,
+ x->x_theora_info.offset_x, x->x_theora_info.offset_y);
+ }
+ x->x_vwidth = x->x_theora_info.width;
+ x->x_vheight = x->x_theora_info.height;
+ x->x_vsize = x->x_vwidth*x->x_vheight;
+
+ switch(x->x_theora_info.colorspace)
+ {
+ case OC_CS_UNSPECIFIED:
+ /* nothing to report */
+ break;;
+ case OC_CS_ITU_REC_470M:
+ post("pdp_icedthe~ : encoder specified ITU Rec 470M (NTSC) color.");
+ break;;
+ case OC_CS_ITU_REC_470BG:
+ post("pdp_icedthe~ : encoder specified ITU Rec 470BG (PAL) color.");
+ break;;
+ default:
+ post("pdp_icedthe~ : warning: encoder specified unknown colorspace (%d).",
+ x->x_theora_info.colorspace);
+ break;;
+ }
+ }
+ else
+ {
+ // tear down the partial theora setup
+ theora_info_clear(&x->x_theora_info);
+ theora_comment_clear(&x->x_theora_comment);
+ post("pdp_icedthe~ : could not initialize theora decoder (theora packets=%d).", x->x_notpackets);
+ x->x_theorainit = 0;
+ x->x_connectchild = 0;
+ return NULL;
+ }
+
+ if( x->x_novpackets )
+ {
+ vorbis_synthesis_init(&x->x_dsp_state, &x->x_vorbis_info);
+ vorbis_block_init(&x->x_dsp_state, &x->x_vorbis_block);
+ x->x_audiochannels = x->x_vorbis_info.channels;
+ x->x_samplerate = x->x_vorbis_info.rate;
+ post("pdp_icedthe~ : ogg logical stream %x is vorbis %d channel %d Hz audio.",
+ x->x_statev.serialno,
+ x->x_audiochannels, x->x_samplerate);
+ }
+ else
+ {
+ /* tear down the partial vorbis setup */
+ vorbis_info_clear(&x->x_vorbis_info);
+ vorbis_comment_clear(&x->x_vorbis_comment);
+ post("pdp_icedthe~ : could not initialize vorbis decoder (vorbis packets=%d).", x->x_novpackets);
+ // x->x_theorainit = 0;
+ // return NULL;
+ x->x_audio = 0;
+ }
+ // everything seems to be ready
+ x->x_insock = sockfd;
+ x->x_connected = 1;
+
+ if ( x->x_decodechild == 0 )
+ {
+ x->x_decodechild = 1; // trick & treets
+ // launch decoding thread
+ if ( pthread_attr_init( &decode_child_attr ) < 0 )
+ {
+ post( "pdp_icedthe~ : could not launch decoding thread" );
+ perror( "pthread_attr_init" );
+ pthread_exit(NULL);
+ }
+ if ( pthread_create( &x->x_decodechild, &decode_child_attr, pdp_icedthe_decode, x ) < 0 )
+ {
+ post( "pdp_icedthe~ : could not launch decoding thread" );
+ perror( "pthread_create" );
+ pthread_exit(NULL);
+ }
+ else
+ {
+ post( "pdp_icedthe~ : decoding thread %d launched", (int)x->x_decodechild );
+ }
+ }
+
+ if ( gettimeofday(&x->x_starttime, NULL) == -1)
+ {
+ post("pdp_icedthe~ : could not set start time" );
+ }
+
+ x->x_nbframes = 0;
+ x->x_endofstream = -1;
+ x->x_connectchild = 0;
+ post("pdp_icedthe~ : connect child exiting." );
+
+ return NULL;
+}
+
+static void pdp_icedthe_connect(t_pdp_icedthe *x, t_symbol *s)
+{
+ t_int ret, i, length;
+ pthread_attr_t connect_child_attr;
+ char *hostptr = NULL, *p, *endhost = NULL, *pathptr = NULL;
+
+ if ( x->x_connectchild != 0 )
+ {
+ post("pdp_icedthe~ : connection request but a connection is pending ... ignored." );
+ return;
+ }
+
+ if ( x->x_connected )
+ {
+ post("pdp_icedthe~ : connection request but a connection is established ... disconnecting." );
+ pdp_icedthe_disconnect(x);
+ }
+
+ if ( x->x_url ) free( x->x_url );
+ x->x_url = (char*) malloc( strlen( s->s_name ) + 1 );
+ strcpy( x->x_url, s->s_name );
+
+ post ("pdp_icedthe~ : connecting to url=%s", x->x_url );
+
+ /* strip http:// or ftp:// */
+ p = x->x_url;
+ if (strncmp(p, "http://", 7) == 0) p+=7;
+
+ hostptr = p;
+ while (*p && *p != '/' && *p != ':') /* look for end of hostname: */ p++;
+
+ endhost = p;
+ switch ( *p )
+ {
+ case ':' :
+ x->x_portnum = atoi( p+1 );
+ while (*p && *p != '/') p++;
+ pathptr = p+1;
+ break;
+ case '/' :
+ x->x_portnum = 8000;
+ pathptr = p+1;
+ break;
+ default :
+ if ( ( p - x->x_url ) != (int)strlen( x->x_url ) )
+ {
+ post( "pdp_icedthe~ : wrong url : %s", hostptr );
+ return;
+ }
+ pathptr = "";
+ break;
+ }
+
+ length = (t_int)(endhost - hostptr);
+ if ( x->x_hostname )
+ {
+ post ("pdp_icedthe~ : freeing hostname" );
+ free( x->x_hostname );
+ }
+ x->x_hostname=(char*)malloc( length + 1);
+ strncpy( x->x_hostname, hostptr, length );
+ x->x_hostname[ length ] = '\0';
+
+ if ( x->x_mountpoint ) free( x->x_mountpoint );
+ x->x_mountpoint=(char*)malloc( strlen( pathptr ) + 1);
+ strncpy( x->x_mountpoint, pathptr, strlen( pathptr ) );
+ x->x_mountpoint[ strlen( pathptr ) ] = '\0';
+
+ post ("pdp_icedthe~ : connecting to host=%s port=%d mountpoint=%s", x->x_hostname, x->x_portnum, x->x_mountpoint );
+
+ // launch connection thread
+ if ( pthread_attr_init( &connect_child_attr ) < 0 ) {
+ post( "pdp_icedthe~ : could not launch connection thread" );
+ perror( "pthread_attr_init" );
+ return;
+ }
+ if ( pthread_attr_setdetachstate( &connect_child_attr, PTHREAD_CREATE_DETACHED ) < 0 ) {
+ post( "pdp_icedthe~ : could not launch connection thread" );
+ perror( "pthread_attr_setdetachstate" );
+ return;
+ }
+ if ( pthread_create( &x->x_connectchild, &connect_child_attr, pdp_icedthe_do_connect, x ) < 0 ) {
+ post( "pdp_icedthe~ : could not launch connection thread" );
+ perror( "pthread_create" );
+ return;
+ }
+ else
+ {
+ post( "pdp_icedthe~ : connection thread %d launched", (int)x->x_connectchild );
+ }
+
+ return;
+}
+
+ /* decode the audio buffer */
+static t_int *pdp_icedthe_perform(t_int *w)
+{
+ t_float *out1 = (t_float *)(w[1]); // left audio inlet
+ t_float *out2 = (t_float *)(w[2]); // right audio inlet
+ t_pdp_icedthe *x = (t_pdp_icedthe *)(w[3]);
+ int n = (int)(w[4]); // number of samples
+ struct timeval etime;
+ t_int sn;
+
+ x->x_blocksize = n;
+
+ // just read the buffer
+ if ( x->x_audioon && x->x_connected )
+ {
+ if ( pthread_mutex_lock( &x->x_audiolock ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to lock audio mutex" );
+ perror( "pthread_mutex_lock" );
+ }
+ sn=0;
+ while (n--)
+ {
+ *(out1)=x->x_audio_inl[ sn ];
+ if ( x->x_audiochannels == 1 )
+ {
+ *(out2) = *(out1);
+ sn++;
+ }
+ if ( x->x_audiochannels == 2 )
+ {
+ *(out2)=x->x_audio_inr[ sn++ ];
+ }
+ out1++;
+ out2++;
+ }
+ memcpy( &x->x_audio_inl[0], &x->x_audio_inl[sn], (x->x_audioin_position-sn)*sizeof(t_float) );
+ memcpy( &x->x_audio_inr[0], &x->x_audio_inr[sn], (x->x_audioin_position-sn)*sizeof(t_float) );
+ x->x_audioin_position-=sn;
+ // post( "pdp_icedthe~ : audio in position : %d", x->x_audioin_position );
+ if ( x->x_audioin_position <= sn )
+ {
+ x->x_audioon = 0;
+ // post( "pdp_icedthe~ : audio off ( audioin : %d, channels=%d )",
+ // x->x_audioin_position, x->x_audiochannels );
+ }
+ if ( pthread_mutex_unlock( &x->x_audiolock ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to unlock audio mutex" );
+ perror( "pthread_mutex_unlock" );
+ }
+ }
+ else
+ {
+ // post("pdp_icedthe~ : no available audio" );
+ while (n--)
+ {
+ *(out1++) = 0.0;
+ *(out2++) = 0.0;
+ }
+ }
+
+ // update framerate
+ if ( gettimeofday(&etime, NULL) == -1)
+ {
+ post("pdp_icedthe~ : could not read time" );
+ }
+ if ( etime.tv_sec != x->x_cursec )
+ {
+ x->x_cursec = etime.tv_sec;
+ if (x->x_connected) outlet_float( x->x_outlet_framerate, x->x_secondcount );
+ x->x_secondcount = 0;
+ }
+
+ // output image if there's a new one decoded
+ if ( x->x_newpicture )
+ {
+ if ( pthread_mutex_lock( &x->x_videolock ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to lock video mutex" );
+ perror( "pthread_mutex_lock" );
+ }
+ pdp_packet_pass_if_valid(x->x_pdp_out, &x->x_packet0);
+ x->x_newpicture = 0;
+
+ // update streaming status
+ x->x_nbframes++;
+ x->x_secondcount++;
+ outlet_float( x->x_outlet_nbframes, x->x_nbframes );
+ if ( pthread_mutex_unlock( &x->x_videolock ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to unlock video mutex" );
+ perror( "pthread_mutex_unlock" );
+ }
+ }
+ if ( x->x_endofstream == 1 ) // only once
+ {
+ outlet_float( x->x_outlet_endofstream, x->x_endofstream );
+ outlet_float( x->x_outlet_time, 0. );
+ x->x_endofstream = 0;
+ }
+ if ( x->x_endofstream == -1 ) // reset
+ {
+ x->x_endofstream = 0;
+ outlet_float( x->x_outlet_endofstream, x->x_endofstream );
+ }
+ if ( x->x_connected != x->x_pconnected )
+ {
+ x->x_pconnected = x->x_connected;
+ outlet_float( x->x_outlet_state, x->x_connected );
+ }
+ if ( ( x->x_videotime != -1) && ( x->x_audiotime != -1 ) &&
+ ( (x->x_videotime-x->x_audiotime) != x->x_ptime ) )
+ {
+ x->x_ptime = x->x_videotime-x->x_audiotime;
+ outlet_float( x->x_outlet_time, (t_float)(x->x_videotime-x->x_audiotime) );
+ }
+
+ return (w+5);
+}
+
+static void pdp_icedthe_dsp(t_pdp_icedthe *x, t_signal **sp)
+{
+ dsp_add(pdp_icedthe_perform, 4, sp[0]->s_vec, sp[1]->s_vec, x, sp[0]->s_n);
+}
+
+static void pdp_icedthe_free(t_pdp_icedthe *x)
+{
+ int i;
+
+ if ( x->x_decodechild )
+ {
+ x->x_decodechild = 0;
+ }
+
+ if ( x->x_connected )
+ {
+ pdp_icedthe_disconnect(x);
+ x->x_connected = 0;
+ }
+
+ post( "pdp_icedthe~ : freeing object" );
+}
+
+t_class *pdp_icedthe_class;
+
+void *pdp_icedthe_new(void)
+{
+ int i;
+
+ t_pdp_icedthe *x = (t_pdp_icedthe *)pd_new(pdp_icedthe_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("frame_cold"));
+
+ x->x_pdp_out = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_outlet_left = outlet_new(&x->x_obj, &s_signal);
+ x->x_outlet_right = outlet_new(&x->x_obj, &s_signal);
+
+ x->x_outlet_state = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet_nbframes = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet_framerate = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet_endofstream = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet_time = outlet_new(&x->x_obj, &s_float);
+
+ x->x_packet0 = -1;
+ x->x_decodechild = 0;
+ x->x_connectchild = 0;
+ x->x_decoding = 0;
+ x->x_theorainit = 0;
+ x->x_priority = DEFAULT_PRIORITY;
+ x->x_framerate = DEFAULT_FRAME_RATE;
+ x->x_nbframes = 0;
+ x->x_samplerate = 0;
+ x->x_audio = 1;
+ x->x_audiochannels = 0;
+ x->x_audioin_position = 0;
+ x->x_videoready = 0;
+ x->x_newpicture = 0;
+ x->x_endofstream = 0;
+ x->x_notpackets = 0;
+ x->x_novpackets = 0;
+ x->x_blocksize = MIN_AUDIO_SIZE;
+ x->x_insock = -1;
+ x->x_connected = 0;
+ x->x_pconnected = 0;
+ x->x_url = NULL;
+ x->x_hostname = NULL;
+ x->x_mountpoint = NULL;
+ x->x_portnum = 8000;
+ x->x_nbnostream = 0;
+ x->x_videotime = -1.0;
+ x->x_audiotime = -1.0;
+ x->x_ptime = 0.;
+
+ memset( &x->x_audio_inl[0], 0x0, 4*MAX_AUDIO_PACKET_SIZE*sizeof(t_float) );
+ memset( &x->x_audio_inr[0], 0x0, 4*MAX_AUDIO_PACKET_SIZE*sizeof(t_float) );
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_icedthe_tilde_setup(void)
+{
+ // post( pdp_icedthe_version );
+ pdp_icedthe_class = class_new(gensym("pdp_icedthe~"), (t_newmethod)pdp_icedthe_new,
+ (t_method)pdp_icedthe_free, sizeof(t_pdp_icedthe), 0, A_NULL);
+
+ class_addmethod(pdp_icedthe_class, (t_method)pdp_icedthe_dsp, gensym("dsp"), A_NULL);
+ class_addmethod(pdp_icedthe_class, (t_method)pdp_icedthe_connect, gensym("connect"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_icedthe_class, (t_method)pdp_icedthe_disconnect, gensym("disconnect"), A_NULL);
+ class_addmethod(pdp_icedthe_class, (t_method)pdp_icedthe_priority, gensym("priority"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_icedthe_class, (t_method)pdp_icedthe_audio, gensym("audio"), A_FLOAT, A_NULL);
+ class_sethelpsymbol( pdp_icedthe_class, gensym("pdp_icedthe~.pd") );
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_live~.c b/modules/pdp_live~.c
index c403a15..2404aba 100644
--- a/modules/pdp_live~.c
+++ b/modules/pdp_live~.c
@@ -83,6 +83,8 @@ typedef struct pdp_live_struct
pthread_t x_connectchild; // thread used for connecting to a stream
pthread_t x_decodechild; // stream decoding thread
+ pthread_mutex_t x_audiolock; // audio mutex
+ pthread_mutex_t x_videolock; // video mutex
t_int x_usethread; // flag to activate decoding in a thread
t_int x_autoplay; // flag to autoplay the file ( default = true )
t_int x_nextimage; // flag to play next image in manual mode
@@ -178,8 +180,8 @@ static void pdp_live_bang(t_pdp_live *x)
static void pdp_live_frame_cold(t_pdp_live *x, t_floatarg frameindex)
{
- int frame = (int)frameindex;
- int ret;
+ t_int frame = (int)frameindex;
+ t_int ret, flags=0;
uint64_t newpts;
if (!(x->x_streaming)) return;
@@ -196,7 +198,8 @@ static void pdp_live_frame_cold(t_pdp_live *x, t_floatarg frameindex)
post( "pdp_live~ : couldn't seek requested frame ( framerate = %d )", x->x_framerate );
return;
}
- if ( ( ret = av_seek_frame(x->x_avcontext, x->x_videoindex, newpts) ) < 0 )
+ if ( frame < x->x_nbframes ) flags = AVSEEK_FLAG_BACKWARD;
+ if ( ( ret = av_seek_frame(x->x_avcontext, x->x_videoindex, newpts, flags) ) < 0 )
{
post( "pdp_live~ : couldn't seek the requested frame (ret=%d)", ret );
}
@@ -242,7 +245,7 @@ static t_int pdp_live_decode_packet(t_pdp_live *x)
if ( ( x->x_avcontext->iformat->flags & AVFMT_NOFILE ) == 0 )
{
post( "pdp_live~ : looping file reading..." );
- if ( ( ret = av_seek_frame(x->x_avcontext, x->x_videoindex, 0) ) < 0 )
+ if ( ( ret = av_seek_frame(x->x_avcontext, x->x_videoindex, 0, 0) ) < 0 )
{
post( "pdp_live~ : couldn't seek the requested frame (ret=%d)", ret );
}
@@ -301,6 +304,12 @@ static t_int pdp_live_decode_packet(t_pdp_live *x)
continue;
}
+ if ( pthread_mutex_lock( &x->x_audiolock ) < 0 )
+ {
+ post( "pdp_live~ : unable to lock audio mutex" );
+ perror( "pthread_mutex_lock" );
+ }
+
// resample received audio
// post( "pdp_live~ : resampling from %dHz-%dch to %dHz-%dch (in position=%d)",
// x->x_avcontext->streams[x->x_pkt.stream_index]->codec.sample_rate,
@@ -336,6 +345,11 @@ static t_int pdp_live_decode_packet(t_pdp_live *x)
x->x_audioon = 1;
// post( "pdp_live~ : audio on" );
}
+ if ( pthread_mutex_unlock( &x->x_audiolock ) < 0 )
+ {
+ post( "pdp_live~ : unable to unlock audio mutex" );
+ perror( "pthread_mutex_unlock" );
+ }
break;
case CODEC_TYPE_VIDEO:
@@ -383,6 +397,11 @@ static t_int pdp_live_decode_packet(t_pdp_live *x)
}
else
{
+ if ( pthread_mutex_lock( &x->x_videolock ) < 0 )
+ {
+ post( "pdp_live~ : unable to lock video mutex" );
+ perror( "pthread_mutex_lock" );
+ }
x->x_newpicture=1;
x->x_vwidth = x->x_avcontext->streams[x->x_pkt.stream_index]->codec.width;
x->x_vheight = x->x_avcontext->streams[x->x_pkt.stream_index]->codec.height;
@@ -429,13 +448,13 @@ static t_int pdp_live_decode_packet(t_pdp_live *x)
{
if ( gettimeofday(&ctime, NULL) == -1)
{
- post("pdp_theorin~ : could not read time" );
+ post("pdp_live~ : could not read time" );
}
tplaying = ( ctime.tv_sec-x->x_starttime.tv_sec )*1000 +
( ctime.tv_usec-x->x_starttime.tv_usec )/1000;
ttheoretical = ((x->x_nbframes)*1000 )/x->x_framerate;
- // post( "pdp-theorin~ : %d playing since : %lldms ( theory : %lldms )",
+ // post( "pdp_live~ : %d playing since : %lldms ( theory : %lldms )",
// x->x_nbframes, tplaying, ttheoretical );
if ( tplaying < ttheoretical )
@@ -447,6 +466,11 @@ static t_int pdp_live_decode_packet(t_pdp_live *x)
if ( x->x_autoplay ) nanosleep( &mwait, NULL );
}
}
+ if ( pthread_mutex_unlock( &x->x_videolock ) < 0 )
+ {
+ post( "pdp_live~ : unable to unlock video mutex" );
+ perror( "pthread_mutex_unlock" );
+ }
}
break;
}
@@ -473,7 +497,7 @@ static void *pdp_decode_stream_from_url(void *tdata)
schedprio.sched_priority = sched_get_priority_min(SCHED_FIFO) + x->x_priority;
if ( sched_setscheduler(0,SCHED_FIFO,&schedprio) == -1)
{
- post("pdp_theorin~ : couldn't set priority for decoding thread.");
+ post("pdp_live~ : couldn't set priority for decoding thread.");
}
if ( ! (x->x_avcontext->iformat->flags & AVFMT_NOHEADER ) )
@@ -764,6 +788,11 @@ static t_int *pdp_live_perform(t_int *w)
// just read the buffer
if ( x->x_audioon )
{
+ if ( pthread_mutex_lock( &x->x_audiolock ) < 0 )
+ {
+ post( "pdp_live~ : unable to lock audio mutex" );
+ perror( "pthread_mutex_lock" );
+ }
sn=0;
while (n--)
{
@@ -789,6 +818,11 @@ static t_int *pdp_live_perform(t_int *w)
x->x_audioon = 0;
// post( "pdp_live~ : audio off" );
}
+ if ( pthread_mutex_unlock( &x->x_audiolock ) < 0 )
+ {
+ post( "pdp_live~ : unable to audio unlock mutex" );
+ perror( "pthread_mutex_unlock" );
+ }
}
else
{
@@ -819,6 +853,11 @@ static t_int *pdp_live_perform(t_int *w)
// output image if there's a new one decoded
if ( x->x_newpicture )
{
+ if ( pthread_mutex_lock( &x->x_videolock ) < 0 )
+ {
+ post( "pdp_live~ : unable to lock video mutex" );
+ perror( "pthread_mutex_lock" );
+ }
pdp_packet_pass_if_valid(x->x_pdp_out, &x->x_packet0);
x->x_newpicture = 0;
@@ -826,6 +865,11 @@ static t_int *pdp_live_perform(t_int *w)
x->x_nbframes++;
x->x_secondcount++;
outlet_float( x->x_outlet_nbframes, x->x_nbframes );
+ if ( pthread_mutex_unlock( &x->x_videolock ) < 0 )
+ {
+ post( "pdp_live~ : unable to unlock video mutex" );
+ perror( "pthread_mutex_unlock" );
+ }
}
outlet_float( x->x_outlet_streaming, x->x_streaming );
outlet_float( x->x_outlet_endofstream, x->x_endofstream );
@@ -856,6 +900,17 @@ static void pdp_live_free(t_pdp_live *x)
post( "pdp_live~ : freeing object" );
pdp_packet_mark_unused(x->x_packet0);
av_free_static();
+
+ if ( pthread_mutex_destroy( &x->x_audiolock ) < 0 )
+ {
+ post( "pdp_live~ : unable to destroy audio mutex" );
+ perror( "pthread_mutex_destroy" );
+ }
+ if ( pthread_mutex_destroy( &x->x_videolock ) < 0 )
+ {
+ post( "pdp_live~ : unable to destroy video mutex" );
+ perror( "pthread_mutex_destroy" );
+ }
}
t_class *pdp_live_class;
@@ -907,6 +962,19 @@ void *pdp_live_new(void)
x->x_previouspts = -1;
x->x_firstpts = -1;
+ if ( pthread_mutex_init( &x->x_audiolock, NULL ) < 0 )
+ {
+ post( "pdp_live~ : unable to initialize audio mutex" );
+ perror( "pthread_mutex_init" );
+ return NULL;
+ }
+ if ( pthread_mutex_init( &x->x_videolock, NULL ) < 0 )
+ {
+ post( "pdp_live~ : unable to initialize video mutex" );
+ perror( "pthread_mutex_init" );
+ return NULL;
+ }
+
x->x_avcontext = av_mallocz(sizeof(AVFormatContext));
if ( !x->x_avcontext )
{
diff --git a/modules/pdp_mapper.c b/modules/pdp_mapper.c
new file mode 100644
index 0000000..9d6fe55
--- /dev/null
+++ b/modules/pdp_mapper.c
@@ -0,0 +1,280 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@free.fr)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* This object is a pixels mapper enabling to do some cut and paste
+ * Written by Yves Degoyon
+ */
+
+#include "pdp.h"
+#include <math.h>
+
+static char *pdp_mapper_version = "pdp_mapper: version 0.1, a pixels mapper, written by Yves Degoyon (ydegoyon@free.fr)";
+
+typedef struct pdp_mapper_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+ t_int x_packet0;
+ t_int x_packet1;
+ t_int x_dropped;
+ t_int x_queue_id;
+
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+ unsigned int x_encoding;
+ t_int *x_pixelmap;
+
+} t_pdp_mapper;
+
+static void pdp_mapper_copy(t_pdp_mapper *x, t_floatarg fromX, t_floatarg fromY, t_floatarg toX, t_floatarg toY)
+{
+ if ( ( fromX >= 0 ) && ( fromX < x->x_vwidth ) &&
+ ( toX >= 0 ) && ( toX < x->x_vwidth ) &&
+ ( fromY >= 0 ) && ( fromY < x->x_vheight ) &&
+ ( toY >= 0 ) && ( toY < x->x_vheight ) )
+ {
+ x->x_pixelmap[ (t_int)toY*x->x_vwidth+(t_int)toX ] = x->x_pixelmap[ (t_int)fromY*x->x_vwidth+(t_int)fromX ];
+ }
+}
+
+static void pdp_mapper_reset(t_pdp_mapper *x)
+{
+ t_int px, py;
+
+ if ( x->x_vsize > 0 )
+ {
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ x->x_pixelmap[py*x->x_vwidth+px] = py*x->x_vwidth+px;
+ }
+ }
+ }
+}
+
+static void pdp_mapper_swap(t_pdp_mapper *x, t_floatarg fromX, t_floatarg fromY, t_floatarg toX, t_floatarg toY)
+{
+
+ t_int tval;
+
+ if ( ( fromX >= 0 ) && ( fromX < x->x_vwidth ) &&
+ ( toX >= 0 ) && ( toX < x->x_vwidth ) &&
+ ( fromY >= 0 ) && ( fromY < x->x_vheight ) &&
+ ( toY >= 0 ) && ( toY < x->x_vheight ) )
+ {
+ tval = x->x_pixelmap[ (t_int)toY*x->x_vwidth+(t_int)toX ];
+ x->x_pixelmap[ (t_int)toY*x->x_vwidth+(t_int)toX ] = x->x_pixelmap[ (t_int)fromY*x->x_vwidth+(t_int)fromX ];
+ x->x_pixelmap[ (t_int)fromY*x->x_vwidth+(t_int)fromX ] = tval;
+ }
+}
+
+static void pdp_mapper_allocate(t_pdp_mapper *x, t_int newsize)
+{
+ int i, px, py;
+
+ if ( x->x_pixelmap != NULL )
+ {
+ freebytes( x->x_pixelmap, x->x_vsize*sizeof(t_int) );
+ }
+
+ x->x_vsize = newsize;
+ x->x_pixelmap = (t_int*) getbytes( x->x_vsize*sizeof(t_int) );
+
+ for ( py=0; py<x->x_vheight; py++ )
+ {
+ for ( px=0; px<x->x_vwidth; px++ )
+ {
+ x->x_pixelmap[py*x->x_vwidth+px] = py*x->x_vwidth+px;
+ }
+ }
+}
+
+static void pdp_mapper_process_yv12(t_pdp_mapper *x)
+{
+ t_pdp *header = pdp_packet_header(x->x_packet0);
+ short int *data = (short int *)pdp_packet_data(x->x_packet0);
+ t_pdp *newheader = pdp_packet_header(x->x_packet1);
+ short int *newdata = (short int *)pdp_packet_data(x->x_packet1);
+ int i;
+
+ t_int px, py, ppx, ppy, offset;
+ short int *sy, *su, *sv, t;
+ t_int *spy;
+ short int *sny, *snu, *snv;
+
+ /* allocate all ressources */
+ if ( ((t_int)header->info.image.width != x->x_vwidth ) ||
+ ((t_int)header->info.image.height != x->x_vheight ) )
+ {
+ x->x_vwidth = header->info.image.width;
+ x->x_vheight = header->info.image.height;
+ post( "pdp_mapper : reallocating buffers" );
+ pdp_mapper_allocate(x, header->info.image.width*header->info.image.height );
+ }
+
+ x->x_encoding = header->info.image.encoding;
+
+ newheader->info.image.encoding = x->x_encoding;
+ newheader->info.image.width = x->x_vwidth;
+ newheader->info.image.height = x->x_vheight;
+
+ /* copy images if necessary */
+ // memcpy( newdata, data, (( x->x_vsize + (x->x_vsize>>1))<<1));
+
+ sy = data;
+ su = (data+x->x_vsize);
+ sv = (data+x->x_vsize+(x->x_vsize>>2));
+ spy = x->x_pixelmap;
+ sny = newdata;
+ snu = (newdata+x->x_vsize);
+ snv = (newdata+x->x_vsize+(x->x_vsize>>2));
+
+ for(py=1; py<x->x_vheight; py++)
+ {
+ for(px=0; px<x->x_vwidth; px++)
+ {
+ ppy = (*(spy)/x->x_vwidth);
+ ppx = (*(spy)%x->x_vwidth);
+ *(sny) = *(sy+ppy*x->x_vwidth+ppx);
+ *(snu) = *(su+(ppy>>1)*(x->x_vwidth>>1)+(ppx>>1));
+ *(snv) = *(sv+(ppy>>1)*(x->x_vwidth>>1)+(ppx>>1));
+ sny++; spy++;
+ if ( ( px%2 == 0 ) && ( py%2 == 0 ) )
+ {
+ snu++; snv++;
+ }
+ }
+ }
+
+ return;
+}
+
+static void pdp_mapper_sendpacket(t_pdp_mapper *x)
+{
+ /* release the packet */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = -1;
+
+ /* unregister and propagate if valid dest packet */
+ pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet1);
+}
+
+static void pdp_mapper_process(t_pdp_mapper *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_mapper_process inputs and write into active inlet */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding){
+
+ case PDP_IMAGE_YV12:
+ x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
+ pdp_queue_add(x, pdp_mapper_process_yv12, pdp_mapper_sendpacket, &x->x_queue_id);
+ break;
+
+ case PDP_IMAGE_GREY:
+ // pdp_mapper_process_packet(x);
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_mapper_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_mapper_input_0(t_pdp_mapper *x, t_symbol *s, t_floatarg f)
+{
+ /* if this is a register_ro message or register_rw message, register with packet factory */
+
+ if (s== gensym("register_rw"))
+ {
+ x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("image/YCrCb/*") );
+ }
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped))
+ {
+ /* add the process method and callback to the process queue */
+ pdp_mapper_process(x);
+ }
+}
+
+static void pdp_mapper_free(t_pdp_mapper *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+
+ if ( x->x_pixelmap ) freebytes( x->x_pixelmap, x->x_vsize*sizeof(t_int) );
+
+}
+
+t_class *pdp_mapper_class;
+
+void *pdp_mapper_new(void)
+{
+ int i;
+
+ t_pdp_mapper *x = (t_pdp_mapper *)pd_new(pdp_mapper_class);
+
+ 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_vsize = -1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_mapper_setup(void)
+{
+// post( pdp_mapper_version );
+ pdp_mapper_class = class_new(gensym("pdp_mapper"), (t_newmethod)pdp_mapper_new,
+ (t_method)pdp_mapper_free, sizeof(t_pdp_mapper), 0, A_NULL);
+
+ class_addmethod(pdp_mapper_class, (t_method)pdp_mapper_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mapper_class, (t_method)pdp_mapper_copy, gensym("copy"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mapper_class, (t_method)pdp_mapper_swap, gensym("swap"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mapper_class, (t_method)pdp_mapper_reset, gensym("reset"), A_NULL);
+ class_sethelpsymbol( pdp_mapper_class, gensym("pdp_mapper.pd") );
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_theonice~.c b/modules/pdp_theonice~.c
new file mode 100644
index 0000000..42552bf
--- /dev/null
+++ b/modules/pdp_theonice~.c
@@ -0,0 +1,1333 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon <ydegoyon@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* This object is a theora a/v streaming object to an icecast server
+ * The patched icecast server can be found here : http://mediacast1.com/~karl/
+ * Written by Yves Degoyon ( ydegoyon@free.fr )
+ *
+ */
+
+
+#include "pdp.h"
+#include <pthread.h>
+#include <unistd.h>
+#include <math.h>
+#include <time.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <theora/theora.h>
+#include <vorbis/codec.h>
+#include <vorbis/vorbisenc.h>
+
+#define MIN_FRAMERATE 1
+#define MAX_FRAMERATE 100
+#define DEFAULT_FRAME_RATE 7
+#define MIN_VIDEO_QUALITY 0
+#define MAX_VIDEO_QUALITY 63
+#define DEFAULT_VIDEO_QUALITY 2
+#define MIN_VIDEO_BITRATE 45
+#define MAX_VIDEO_BITRATE 2000
+#define DEFAULT_VIDEO_BITRATE 48
+#define MIN_AUDIO_QUALITY -0.1
+#define MAX_AUDIO_QUALITY 1.0
+#define DEFAULT_AUDIO_QUALITY 0.5
+#define MIN_AUDIO_BITRATE 8
+#define MAX_AUDIO_BITRATE 2000
+#define DEFAULT_AUDIO_BITRATE 32
+
+#define DEFAULT_CHANNELS 2
+#define DEFAULT_DRIFT 100
+#define DEFAULT_BITS 8
+#define MAX_AUDIO_PACKET_SIZE (128 * 1024)
+// streams hard-coded serial numbers
+#define STREAMV_SNO 0x987654
+#define STREAMA_SNO 0x456789
+
+#define MAX_COMMENT_LENGTH 1024
+#define STRBUF_SIZE 32
+#define OGG_AUDIO_SIZE 1024
+
+static char base64table[65] = {
+ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
+ 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
+ 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
+ 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/',
+};
+
+static char *pdp_theonice_version = "pdp_theonice~: version 0.1, a theora a/v streaming object, written by ydegoyon@free.fr";
+
+typedef struct pdp_theonice_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_int x_packet0;
+ t_int x_packet1;
+ t_int x_dropped;
+ t_int x_queue_id;
+
+ t_int x_vwidth;
+ t_int x_tvwidth; // theora 16 pixels aligned width value
+ t_int x_vheight;
+ t_int x_tvheight; // theora 16 pixels aligned height value
+ t_int x_vsize;
+
+ pthread_t x_connectchild; // thread used for connecting to a stream
+ int x_socketfd; // connection socket
+ t_int x_streaming; // streaming on : connected and all
+ t_int x_pstreaming; // previous state
+ char *x_passwd; // password
+ char x_title[MAX_COMMENT_LENGTH]; // title of the stream
+ char x_url[MAX_COMMENT_LENGTH]; // url of the stream
+ char x_genre[MAX_COMMENT_LENGTH]; // genre of the stream
+ char x_description[MAX_COMMENT_LENGTH]; // description
+ char x_artist[MAX_COMMENT_LENGTH]; // artist
+ char x_copyright[MAX_COMMENT_LENGTH];
+ char x_date[MAX_COMMENT_LENGTH]; // starting system date
+ char x_hostname[MAX_COMMENT_LENGTH]; // name or IP of host to connect to
+ char x_mountpoint[MAX_COMMENT_LENGTH]; // mountpoint
+ t_int x_port; // port number
+ t_int x_public; // publish on www.oggcast.com
+ t_int x_framerate;
+ t_int x_mframerate; // measured framerate
+ t_int x_pmframerate; // previous state
+ t_int x_einit;
+ t_int x_frameswritten;
+ t_int x_pframeswritten;
+ t_int x_frameslate;
+ t_int x_nbframes_dropped;
+ t_int x_pnbframes_dropped;
+ t_int x_frames;
+ t_float x_maxdrift; /* maximum delay between audio and video */
+ struct timeval x_tstart;
+ struct timeval x_tzero;
+ struct timeval x_tcurrent;
+ struct timeval x_tprevstream;
+ t_int x_cursec; // current second
+ t_int x_secondcount; // number of frames emitted in the current second
+
+ /* vorbis/theora structures */
+ ogg_page x_ogg_page; // ogg page for headers
+ ogg_page x_apage; // ogg audio page
+ ogg_page x_vpage; // ogg video page
+ ogg_packet x_ogg_packet; // ogg packet
+ ogg_stream_state x_statev; // vorbis stream state
+ ogg_stream_state x_statet; // theora stream state
+ theora_info x_theora_info; // theora info
+ theora_comment x_theora_comment; // theora comment
+ theora_state x_theora_state; // theora state
+ vorbis_info x_vorbis_info; // vorbis info
+ vorbis_dsp_state x_dsp_state; // vorbis dsp state
+ vorbis_block x_vorbis_block; // vorbis block
+ vorbis_comment x_vorbis_comment; // vorbis comment
+ yuv_buffer x_yuvbuffer; // yuv buffer
+ t_int x_eos; // end of stream
+
+ t_int x_akbps; // audio bit rate
+ t_int x_vkbps; // video bit rate
+ t_float x_aquality; // audio quality
+ t_int x_vquality; // video quality
+ t_int x_abytesout; // audio bytes written
+ t_int x_vbytesout; // video bytes written
+ double x_audiotime; // audio stream time
+ double x_paudiotime; // previous value
+ double x_videotime; // video stream time
+ double x_pvideotime; // previous value
+
+ /* audio structures */
+ t_float x_audio_buf[DEFAULT_CHANNELS][MAX_AUDIO_PACKET_SIZE]; // buffer for incoming audio
+ t_int x_audioin_position; // writing position for incoming audio
+ t_int x_channels; // audio channels
+ t_int x_samplerate; // audio sample rate
+ t_int x_bits; // audio bits
+
+ t_outlet *x_outlet_streaming; // indicates the action of streaming
+ t_outlet *x_outlet_nbframes; // number of frames emitted
+ t_outlet *x_outlet_framerate; // real framerate
+ t_outlet *x_outlet_nbframes_dropped; // number of frames dropped
+ t_outlet *x_outlet_atime; // audio time
+ t_outlet *x_outlet_vtime; // video time
+ t_float **x_vbuffer; // buffer from vorbis
+
+} t_pdp_theonice;
+
+ /* allocate internal ressources */
+static void pdp_theonice_allocate(t_pdp_theonice *x)
+{
+ int ret;
+
+ x->x_yuvbuffer.y_width=x->x_vwidth;
+ x->x_yuvbuffer.y_height=x->x_vheight;
+ x->x_yuvbuffer.y_stride=x->x_vwidth;
+
+ x->x_yuvbuffer.uv_width=x->x_vwidth>>1;
+ x->x_yuvbuffer.uv_height=x->x_vheight>>1;
+ x->x_yuvbuffer.uv_stride=x->x_vwidth>>1;
+
+ x->x_yuvbuffer.y = (char *)malloc( x->x_yuvbuffer.y_width * x->x_yuvbuffer.y_height );
+ x->x_yuvbuffer.u = (char *)malloc( x->x_yuvbuffer.uv_width * x->x_yuvbuffer.uv_height );
+ x->x_yuvbuffer.v = (char *)malloc( x->x_yuvbuffer.uv_width * x->x_yuvbuffer.uv_height );
+}
+
+ /* free internal ressources */
+static void pdp_theonice_free_ressources(t_pdp_theonice *x)
+{
+ if ( x->x_yuvbuffer.y ) free( x->x_yuvbuffer.y );
+ if ( x->x_yuvbuffer.u ) free( x->x_yuvbuffer.u );
+ if ( x->x_yuvbuffer.v ) free( x->x_yuvbuffer.v );
+}
+
+ /* initialize the encoder */
+static void pdp_theonice_init_encoder(t_pdp_theonice *x)
+{
+ t_int ret;
+
+ x->x_einit=0;
+
+ // init streams
+ ogg_stream_init(&x->x_statet, STREAMA_SNO);
+ ogg_stream_init(&x->x_statev, STREAMV_SNO);
+
+ theora_info_init(&x->x_theora_info);
+ x->x_theora_info.width=x->x_tvwidth;
+ x->x_theora_info.height=x->x_tvheight;
+ x->x_theora_info.frame_width=x->x_vwidth;
+ x->x_theora_info.frame_height=x->x_vheight;
+ x->x_theora_info.offset_x=(x->x_tvwidth-x->x_vwidth)>>1;
+ x->x_theora_info.offset_y=(x->x_tvheight-x->x_vheight)>>1;
+ x->x_theora_info.fps_numerator=x->x_framerate;
+ x->x_theora_info.fps_denominator=1;
+ x->x_theora_info.aspect_numerator=1;
+ x->x_theora_info.aspect_denominator=1;
+ x->x_theora_info.colorspace=OC_CS_UNSPECIFIED;
+ x->x_theora_info.target_bitrate=x->x_vkbps;
+ x->x_theora_info.quality=x->x_vquality;
+
+ x->x_theora_info.dropframes_p=0;
+ x->x_theora_info.quick_p=1;
+ x->x_theora_info.keyframe_auto_p=1;
+ x->x_theora_info.keyframe_frequency=64;
+ x->x_theora_info.keyframe_frequency_force=64;
+ x->x_theora_info.keyframe_data_target_bitrate=x->x_vkbps*1.5;
+ x->x_theora_info.keyframe_auto_threshold=80;
+ x->x_theora_info.keyframe_mindistance=8;
+ x->x_theora_info.noise_sensitivity=1;
+
+ theora_encode_init(&x->x_theora_state,&x->x_theora_info);
+
+ vorbis_info_init(&x->x_vorbis_info);
+
+ if(x->x_aquality > -0.1)
+ {
+ ret = vorbis_encode_init_vbr(&x->x_vorbis_info, x->x_channels, x->x_samplerate, x->x_aquality);
+ }
+ else
+ {
+ ret = vorbis_encode_init(&x->x_vorbis_info, x->x_channels, x->x_samplerate, -1, x->x_akbps, -1);
+ }
+
+ if (ret)
+ {
+ post( "pdp_theonice~ : could not initialize vorbis encoder" );
+ x->x_einit=0;
+ return;
+ }
+
+ vorbis_comment_init(&x->x_vorbis_comment);
+ vorbis_comment_add_tag(&(x->x_vorbis_comment),"TITLE", x->x_title);
+ vorbis_comment_add_tag(&(x->x_vorbis_comment),"ARTIST", x->x_artist);
+ vorbis_comment_add_tag(&(x->x_vorbis_comment),"GENRE",x->x_genre);
+ vorbis_comment_add_tag(&(x->x_vorbis_comment),"DESCRIPTION", x->x_description);
+ vorbis_comment_add_tag(&(x->x_vorbis_comment),"LOCATION",x->x_url);
+ vorbis_comment_add_tag(&(x->x_vorbis_comment),"PERFORMER",x->x_artist);
+ vorbis_comment_add_tag(&(x->x_vorbis_comment),"COPYRIGHT",x->x_copyright);
+ vorbis_comment_add_tag(&(x->x_vorbis_comment),"DATE",x->x_date);
+ vorbis_comment_add_tag(&(x->x_vorbis_comment),"ENCODER","pdp_theonice~ v0.1");
+ vorbis_analysis_init(&x->x_dsp_state,&x->x_vorbis_info);
+ vorbis_block_init(&x->x_dsp_state,&x->x_vorbis_block);
+
+ post( "pdp_theonice~ : encoder initialized." );
+ x->x_einit=1;
+
+}
+
+ /* terminate the encoding process */
+static void pdp_theonice_shutdown_encoder(t_pdp_theonice *x)
+{
+ t_int ret;
+
+ if ( x->x_streaming )
+ {
+ post( "pdp_theonice~ : shutting down encoder");
+ vorbis_analysis_wrote(&x->x_dsp_state,0);
+ // get rid of remaining data in encoder, if any
+ while(vorbis_analysis_blockout( &x->x_dsp_state, &x->x_vorbis_block )==1)
+ {
+ vorbis_analysis( &x->x_vorbis_block, NULL );
+ vorbis_bitrate_addblock( &x->x_vorbis_block );
+
+ while(vorbis_bitrate_flushpacket( &x->x_dsp_state, &x->x_ogg_packet ))
+ {
+ ogg_stream_packetin( &x->x_statev, &x->x_ogg_packet );
+ }
+ }
+ while( ( ret = ogg_stream_pageout( &x->x_statev, &x->x_apage) ) > 0 )
+ {
+ x->x_audiotime = vorbis_granule_time(&x->x_dsp_state, ogg_page_granulepos(&x->x_apage));
+
+ // post("pdp_theonice~ : writing audio : %d samples, header : %d, body : %d", nbsamples, x->x_apage.header_len, x->x_apage.body_len);
+ if ( ( ret = send(x->x_socketfd, (void*)x->x_apage.header, x->x_apage.header_len, MSG_NOSIGNAL) ) < 0 )
+ {
+ post( "pdp_theonice~ : could not write audio packet (ret=%d).", ret );
+ perror( "send" );
+ }
+ if ( ( ret = send(x->x_socketfd, (void*)x->x_apage.body, x->x_apage.body_len, MSG_NOSIGNAL) ) < 0 )
+ {
+ post( "pdp_theonice~ : could not write audio packet (ret=%d).", ret );
+ perror( "send" );
+ }
+ }
+
+ ogg_stream_clear(&x->x_statev);
+ vorbis_block_clear(&x->x_vorbis_block);
+ vorbis_dsp_clear(&x->x_dsp_state);
+ vorbis_comment_clear(&x->x_vorbis_comment);
+ vorbis_info_clear(&x->x_vorbis_info);
+ ogg_stream_clear(&x->x_statet);
+ theora_clear(&x->x_theora_state);
+ }
+}
+
+ /* disconnect from an icecast server */
+static void pdp_theonice_disconnect(t_pdp_theonice *x)
+{
+ int ret;
+
+ pdp_theonice_shutdown_encoder( x );
+ x->x_streaming = 0;
+
+ if ( x->x_socketfd > 0 )
+ {
+ if ( close( x->x_socketfd ) < 0 )
+ {
+ post( "pdp_theonice~ : could not disconnect" );
+ perror( "close" );
+ }
+ x->x_socketfd = -1;
+ }
+}
+
+static int pdp_theonice_write_headers(t_pdp_theonice *x)
+{
+ t_int ret;
+ ogg_packet aheader, aheadercomm, aheadercode;
+
+ if ( !x->x_einit )
+ {
+ post( "pdp_theonice~ : trying to write headers but encoder is not initialized." );
+ return -1;
+ }
+
+ theora_encode_header(&x->x_theora_state, &x->x_ogg_packet);
+ ogg_stream_packetin(&x->x_statet, &x->x_ogg_packet);
+ if(ogg_stream_pageout(&x->x_statet, &x->x_ogg_page)!=1)
+ {
+ post( "pdp_theonice~ : ogg encoding error." );
+ return -1;
+ }
+ if ( ( ret = send(x->x_socketfd, (void*)x->x_ogg_page.header, x->x_ogg_page.header_len, MSG_NOSIGNAL) ) < 0 )
+ {
+ post( "pdp_theonice~ : could not write headers (ret=%d).", ret );
+ perror( "send" );
+ pdp_theonice_disconnect(x);
+ return -1;
+ }
+ if ( ( ret = send(x->x_socketfd, (void*)x->x_ogg_page.body, x->x_ogg_page.body_len, MSG_NOSIGNAL) ) < 0 )
+ {
+ post( "pdp_theonice~ : could not write headers (ret=%d).", ret );
+ perror( "send" );
+ pdp_theonice_disconnect(x);
+ return -1;
+ }
+
+ theora_comment_init(&x->x_theora_comment);
+ theora_comment_add_tag(&(x->x_theora_comment),"TITLE", x->x_title);
+ theora_comment_add_tag(&(x->x_theora_comment),"ARTIST", x->x_artist);
+ theora_comment_add_tag(&(x->x_theora_comment),"GENRE",x->x_genre);
+ theora_comment_add_tag(&(x->x_theora_comment),"DESCRIPTION", x->x_description);
+ theora_comment_add_tag(&(x->x_theora_comment),"LOCATION",x->x_url);
+ theora_comment_add_tag(&(x->x_theora_comment),"PERFORMER",x->x_artist);
+ theora_comment_add_tag(&(x->x_theora_comment),"COPYRIGHT",x->x_copyright);
+ theora_comment_add_tag(&(x->x_theora_comment),"DATE",x->x_date);
+ theora_comment_add_tag(&(x->x_theora_comment),"ENCODER","pdp_theonice~ v0.1");
+ theora_encode_comment(&x->x_theora_comment, &x->x_ogg_packet);
+ ogg_stream_packetin(&x->x_statet, &x->x_ogg_packet);
+ theora_encode_tables(&x->x_theora_state, &x->x_ogg_packet);
+ ogg_stream_packetin(&x->x_statet, &x->x_ogg_packet);
+
+ vorbis_analysis_headerout(&x->x_dsp_state, &x->x_vorbis_comment,
+ &aheader,&aheadercomm,&aheadercode);
+ ogg_stream_packetin(&x->x_statev,&aheader);
+
+ if(ogg_stream_pageout(&x->x_statev, &x->x_ogg_page)!=1)
+ {
+ post( "pdp_theonice~ : ogg encoding error." );
+ return -1;
+ }
+ if ( ( ret = send(x->x_socketfd, (void*)x->x_ogg_page.header, x->x_ogg_page.header_len, MSG_NOSIGNAL) ) < 0 )
+ {
+ post( "pdp_theonice~ : could not write headers (ret=%d).", ret );
+ perror( "send" );
+ pdp_theonice_disconnect(x);
+ return -1;
+ }
+ if ( ( ret = send(x->x_socketfd, (void*)x->x_ogg_page.body, x->x_ogg_page.body_len, MSG_NOSIGNAL) ) < 0 )
+ {
+ post( "pdp_theonice~ : could not write headers (ret=%d).", ret );
+ perror( "send" );
+ pdp_theonice_disconnect(x);
+ return -1;
+ }
+
+ // remaining vorbis header packets
+ ogg_stream_packetin(&x->x_statev, &aheadercomm);
+ ogg_stream_packetin(&x->x_statev, &aheadercode);
+
+ // flush all the headers
+ while(1)
+ {
+ ret = ogg_stream_flush(&x->x_statet, &x->x_ogg_page);
+ if(ret<0){
+ post( "pdp_theonice~ : ogg encoding error." );
+ return -1;
+ }
+ if(ret==0)break;
+ if ( ( ret = send(x->x_socketfd, (void*)x->x_ogg_page.header, x->x_ogg_page.header_len, MSG_NOSIGNAL) ) < 0 )
+ {
+ post( "pdp_theonice~ : could not write headers (ret=%d).", ret );
+ perror( "send" );
+ pdp_theonice_disconnect(x);
+ return -1;
+ }
+ if ( ( ret = send(x->x_socketfd, (void*)x->x_ogg_page.body, x->x_ogg_page.body_len, MSG_NOSIGNAL) ) < 0 )
+ {
+ post( "pdp_theonice~ : could not write headers (ret=%d).", ret );
+ perror( "send" );
+ pdp_theonice_disconnect(x);
+ return -1;
+ }
+ }
+
+ while(1)
+ {
+ ret = ogg_stream_flush(&x->x_statev, &x->x_ogg_page);
+ if(ret<0){
+ post( "pdp_theonice~ : ogg encoding error." );
+ return -1;
+ }
+ if(ret==0)break;
+ if ( ( ret = send(x->x_socketfd, (void*)x->x_ogg_page.header, x->x_ogg_page.header_len, MSG_NOSIGNAL) ) < 0 )
+ {
+ post( "pdp_theonice~ : could not write headers (ret=%d).", ret );
+ perror( "send" );
+ pdp_theonice_disconnect(x);
+ return -1;
+ }
+ if ( ( ret = send(x->x_socketfd, (void*)x->x_ogg_page.body, x->x_ogg_page.body_len, MSG_NOSIGNAL) ) < 0 )
+ {
+ post( "pdp_theonice~ : could not write headers (ret=%d).", ret );
+ perror( "send" );
+ pdp_theonice_disconnect(x);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+ /* start streaming */
+static int pdp_theonice_start(t_pdp_theonice *x)
+{
+ time_t start_t;
+ t_int ret;
+
+ if ( gettimeofday(&x->x_tstart, NULL) == -1)
+ {
+ post("pdp_theonice~ : could not set start time" );
+ }
+
+ if ( gettimeofday(&x->x_tzero, NULL) == -1)
+ {
+ post("pdp_theonice~ : could get initial time" );
+ }
+
+ time( &start_t );
+ strcpy( x->x_date, ctime( &start_t ));
+ post("pdp_theonice~ : initializing encoder...");
+ pdp_theonice_init_encoder( x );
+ post("pdp_theonice~ : writing headers...");
+ if ( ( ret = pdp_theonice_write_headers( x ) ) < 0 )
+ {
+ return ret;
+ }
+ post("pdp_theonice~ : start streaming at %d frames/second", x->x_framerate);
+}
+
+ /* set password */
+static void pdp_theonice_passwd(t_pdp_theonice *x, t_symbol *passwd)
+{
+ post("pdp_theonice~ : setting password to %s", passwd->s_name );
+ x->x_passwd = passwd->s_name;
+}
+
+ /* set url */
+static void pdp_theonice_url(t_pdp_theonice *x, t_symbol *url)
+{
+ post("pdp_theonice~ : setting location to %s", url->s_name );
+ strcpy(x->x_url, url->s_name);
+}
+
+ /* set title */
+static void pdp_theonice_title(t_pdp_theonice *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_int i;
+
+ strcpy( x->x_title, "" );
+ for ( i=0; i<argc; i++ )
+ {
+ // typechecking
+ if (argv[i].a_type == A_SYMBOL)
+ {
+ sprintf( x->x_title, "%s %s", x->x_title, argv[i].a_w.w_symbol->s_name );
+ }
+ if (argv[i].a_type == A_FLOAT)
+ {
+ sprintf( x->x_title, "%s %d", x->x_title, (t_int)argv[i].a_w.w_float );
+ }
+ }
+ sprintf( x->x_title, "%s", x->x_title+1 );
+ post("pdp_theonice~ : setting title to %s", x->x_title );
+}
+
+ /* set artist */
+static void pdp_theonice_artist(t_pdp_theonice *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_int i;
+
+ strcpy( x->x_artist, "" );
+ for ( i=0; i<argc; i++ )
+ {
+ // typechecking
+ if (argv[i].a_type == A_SYMBOL)
+ {
+ sprintf( x->x_artist, "%s %s", x->x_artist, argv[i].a_w.w_symbol->s_name );
+ }
+ if (argv[i].a_type == A_FLOAT)
+ {
+ sprintf( x->x_artist, "%s %d", x->x_artist, (t_int)argv[i].a_w.w_float );
+ }
+ }
+ sprintf( x->x_artist, "%s", x->x_artist+1 );
+ post("pdp_theonice~ : setting artist to %s", x->x_artist );
+}
+
+ /* set description */
+static void pdp_theonice_description(t_pdp_theonice *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_int i;
+
+ strcpy( x->x_description, "" );
+ for ( i=0; i<argc; i++ )
+ {
+ // typechecking
+ if (argv[i].a_type == A_SYMBOL)
+ {
+ sprintf( x->x_description, "%s %s", x->x_description, argv[i].a_w.w_symbol->s_name );
+ }
+ if (argv[i].a_type == A_FLOAT)
+ {
+ sprintf( x->x_description, "%s %d", x->x_description, (t_int)argv[i].a_w.w_float );
+ }
+ }
+ sprintf( x->x_description, "%s", x->x_description+1 );
+ post("pdp_theonice~ : setting description to %s", x->x_description );
+}
+
+ /* set genre */
+static void pdp_theonice_genre(t_pdp_theonice *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_int i;
+
+ strcpy( x->x_genre, "" );
+ for ( i=0; i<argc; i++ )
+ {
+ // typechecking
+ if (argv[i].a_type == A_SYMBOL)
+ {
+ sprintf( x->x_genre, "%s %s", x->x_genre, argv[i].a_w.w_symbol->s_name );
+ }
+ if (argv[i].a_type == A_FLOAT)
+ {
+ sprintf( x->x_genre, "%s %d", x->x_genre, (t_int)argv[i].a_w.w_float );
+ }
+ }
+ sprintf( x->x_genre, "%s", x->x_genre+1 );
+ post("pdp_theonice~ : setting genre to %s", x->x_genre );
+}
+
+char *pdp_theonice_base64_encode(char *data)
+{
+ int len = strlen(data);
+ char *out = t_getbytes(len*4/3 + 4);
+ char *result = out;
+ int chunk;
+
+ while(len > 0) {
+ chunk = (len >3)?3:len;
+ *out++ = base64table[(*data & 0xFC)>>2];
+ *out++ = base64table[((*data & 0x03)<<4) | ((*(data+1) & 0xF0) >> 4)];
+
+ switch(chunk) {
+ case 3:
+ *out++ = base64table[((*(data+1) & 0x0F)<<2) | ((*(data+2) & 0xC0)>>6)];
+ *out++ = base64table[(*(data+2)) & 0x3F];
+ break;
+ case 2:
+ *out++ = base64table[((*(data+1) & 0x0F)<<2)];
+ *out++ = '=';
+ break;
+ case 1:
+ *out++ = '=';
+ *out++ = '=';
+ break;
+ }
+ data += chunk;
+ len -= chunk;
+ }
+ *out = 0;
+
+ return result;
+}
+
+static void sendsock( t_int sockfd, char *buf, size_t buflen )
+{
+ if ( send( sockfd, buf, buflen, MSG_NOSIGNAL ) != (t_int)buflen )
+ {
+ post( "pdp_theonice~ : could not send message to the server" );
+ post( "pdp_theonice~ : message : %s", buf );
+ }
+}
+
+ /* connect to an icecast server */
+static void *pdp_theonice_do_connect(void *tdata)
+{
+ char buf[MAX_COMMENT_LENGTH]; /* buffer to hold commands sent to the server */
+ char *base64; /* buffer to hold 64bit encoded strings */
+ char resp[STRBUF_SIZE];
+ unsigned int len;
+ fd_set fdset;
+ struct timeval tv;
+ t_int sockfd, ret;
+ struct sockaddr_in sinfo;
+ struct hostent *hp;
+ t_pdp_theonice *x;
+
+ x = (t_pdp_theonice *)tdata;
+
+ sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sockfd < 0)
+ {
+ error("pdp_theonice~: internal error while attempting to open socket");
+ return NULL;
+ }
+
+ /* connect socket using hostname provided in command line */
+ sinfo.sin_family = AF_INET;
+ hp = gethostbyname(x->x_hostname);
+ if (hp == 0)
+ {
+ post("pdp_theonice~: wrong server name or IP.");
+ close(sockfd);
+ return NULL;
+ }
+ memcpy((char *)&sinfo.sin_addr, (char *)hp->h_addr, hp->h_length);
+
+ /* assign client port number */
+ sinfo.sin_port = htons((unsigned short)x->x_port);
+
+ /* try to connect. */
+ post("pdp_theonice~: connecting to port %d", x->x_port);
+ if (connect(sockfd, (struct sockaddr *) &sinfo, sizeof (sinfo)) < 0)
+ {
+ error("pdp_theonice~: connection failed!\n");
+ close(sockfd);
+ return NULL;
+ }
+
+ /* check if we can read/write from/to the socket */
+ FD_ZERO( &fdset);
+ FD_SET( sockfd, &fdset);
+ tv.tv_sec = 0; /* seconds */
+ tv.tv_usec = 500; /* microseconds */
+
+ ret = select(sockfd + 1, &fdset, NULL, NULL, &tv);
+ if(ret < 0)
+ {
+ error("pdp_theonice~: can not read from socket.");
+ close(sockfd);
+ return NULL;
+ }
+ ret = select(sockfd + 1, NULL, &fdset, NULL, &tv);
+ if(ret < 0)
+ {
+ error("pdp_theonice~: can not write to socket.");
+ close(sockfd);
+ return NULL;
+ }
+
+ /* send the request, a string like: "SOURCE /<mountpoint> HTTP/1.0\r\n" */
+ sprintf(buf, "SOURCE /%s", x->x_mountpoint);
+ sendsock(sockfd, buf, strlen(buf));
+ strcpy( buf, " HTTP/1.0\r\n");
+ sendsock(sockfd, buf, strlen(buf));
+ /* send basic authorization as base64 encoded string */
+ sprintf(resp, "source:%s", x->x_passwd);
+ len = strlen(resp);
+ base64 = pdp_theonice_base64_encode(resp);
+ sprintf(resp, "Authorization: Basic %s\r\n", base64);
+ sendsock(sockfd, resp, strlen(resp));
+ t_freebytes(base64, len*4/3 + 4);
+ /* send application name */
+ strcpy( buf, "User-Agent: pdp_theonice~");
+ sendsock(sockfd, buf, strlen(buf));
+ /* send content type: vorbis */
+ strcpy( buf, "\r\nContent-Type: application/ogg");
+ sendsock(sockfd, buf, strlen(buf));
+ /* send the ice headers */
+ /* name */
+ sprintf( buf, "\r\nice-name: %s", x->x_title );
+ sendsock(sockfd, buf, strlen(buf));
+ /* url */
+ sprintf( buf, "\r\nice-url: %s", x->x_url );
+ sendsock(sockfd, buf, strlen(buf));
+ /* genre */
+ sprintf( buf, "\r\nice-genre: %s", x->x_genre );
+ sendsock(sockfd, buf, strlen(buf));
+ /* public */
+ strcpy( buf, "\r\nice-public: 1" );
+ sendsock(sockfd, buf, strlen(buf));
+ /* bitrate */
+ sprintf(buf, "\r\nice-audio-info: bitrate=%d", x->x_akbps);
+ sendsock(sockfd, buf, strlen(buf));
+ /* description */
+ sprintf(buf, "\r\nice-description: %s", x->x_description);
+ sendsock(sockfd, buf, strlen(buf));
+ /* end of header: write an empty line */
+ strcpy( buf, "\r\n\r\n");
+ sendsock(sockfd, buf, strlen(buf));
+
+ /* read the anticipated response: "OK" */
+ len = recv(sockfd, resp, STRBUF_SIZE, MSG_NOSIGNAL);
+ if ( strstr( resp, "OK" ) == NULL )
+ {
+ post("pdp_theonice~: login failed!");
+ if ( len>0 ) post("pdp_theonice~: server answered : %s", resp);
+ close(sockfd);
+ return NULL;
+ }
+ post("pdp_theonice~: logged in to %s", x->x_hostname);
+
+ post("pdp_theonice~: connecting child %d exiting....", x->x_connectchild);
+ x->x_connectchild = 0;
+
+ x->x_socketfd = sockfd;
+ if ( ( ret = pdp_theonice_start( x ) ) < 0 )
+ {
+ x->x_socketfd = -1;
+ return NULL;
+ }
+ else
+ {
+ x->x_streaming = 1;
+ x->x_frameswritten = 0;
+ x->x_videotime = 0.;
+ x->x_audiotime = 0.;
+ x->x_frameslate = 0;
+ x->x_nbframes_dropped = 0;
+ x->x_secondcount = 0;
+ x->x_frames = 0;
+ }
+
+ return NULL;
+
+}
+
+ /* launch a connection thread */
+static void pdp_theonice_connect(t_pdp_theonice *x, t_symbol *shost, t_symbol *smountpoint, t_floatarg fport)
+{
+ t_int ret=0;
+ pthread_attr_t connect_child_attr;
+
+ // check parameters
+ if ( gethostbyname( shost->s_name ) == NULL )
+ {
+ post("pdp_theonice~ : it looks like your server is unknown here.." );
+ return;
+ }
+ else
+ {
+ strcpy( x->x_hostname, shost->s_name);
+ }
+
+ if ( ( (t_int)fport < 0 ) || ( (t_int)fport > 65535 ) )
+ {
+ post("pdp_theonice~ : wrong port number." );
+ return;
+ }
+ else
+ {
+ x->x_port = (t_int)fport;
+ }
+
+ strcpy( x->x_mountpoint, smountpoint->s_name );
+ sprintf( x->x_url, "http://%s:%d/%s", x->x_hostname, x->x_port, x->x_mountpoint );
+ post("pdp_theonice~ : connecting to %s", x->x_url );
+
+ if ( ( x->x_streaming ) || ( x->x_connectchild != 0 ) )
+ {
+ post("pdp_theonice~ : connection request but a connection is pending ... disconnecting" );
+ pdp_theonice_disconnect(x);
+ }
+
+ // launch connection thread
+ if ( pthread_attr_init( &connect_child_attr ) < 0 ) {
+ post( "pdp_theonice~ : could not launch connection thread" );
+ perror( "pthread_attr_init" );
+ return;
+ }
+ if ( pthread_attr_setdetachstate( &connect_child_attr, PTHREAD_CREATE_DETACHED ) < 0 ) {
+ post( "pdp_theonice~ : could not launch connection thread" );
+ perror( "pthread_attr_setdetachstate" );
+ return;
+ }
+ if ( pthread_create( &x->x_connectchild, &connect_child_attr, pdp_theonice_do_connect, x ) < 0 ) {
+ post( "pdp_theonice~ : could not launch connection thread" );
+ perror( "pthread_create" );
+ return;
+ }
+ else
+ {
+ post( "pdp_theonice~ : connection thread %d launched", x->x_connectchild );
+ }
+
+ return;
+
+}
+
+ /* set video bitrate */
+static void pdp_theonice_vbitrate(t_pdp_theonice *x, t_floatarg vbitrate )
+{
+ if ( ( (t_int) vbitrate < MIN_VIDEO_BITRATE ) || ( (t_int) vbitrate > MAX_VIDEO_BITRATE ) )
+ {
+ post( "pdp_theonice~ : wrong video bitrate %d : should be in [%d,%d] kbps",
+ (t_int) vbitrate, MIN_VIDEO_BITRATE, MAX_VIDEO_BITRATE );
+ return;
+ }
+ x->x_vkbps = (t_int) vbitrate;
+}
+
+ /* set audio bitrate */
+static void pdp_theonice_abitrate(t_pdp_theonice *x, t_floatarg abitrate )
+{
+ if ( ( (t_int) abitrate < MIN_AUDIO_BITRATE ) || ( (t_int) abitrate > MAX_AUDIO_BITRATE ) )
+ {
+ post( "pdp_theonice~ : wrong audio bitrate %d : should be in [%d,%d] kbps",
+ (t_int) abitrate, MIN_AUDIO_BITRATE, MAX_AUDIO_BITRATE );
+ return;
+ }
+ x->x_akbps = (t_int) abitrate;
+}
+
+ /* set video quality */
+static void pdp_theonice_vquality(t_pdp_theonice *x, t_floatarg vquality )
+{
+ if ( ( (t_int) vquality < MIN_VIDEO_QUALITY ) || ( (t_int) vquality > MAX_VIDEO_QUALITY ) )
+ {
+ post( "pdp_theonice~ : wrong video quality %d : should be in [%d,%d]",
+ (t_int) vquality, MIN_VIDEO_QUALITY, MAX_VIDEO_QUALITY );
+ return;
+ }
+ x->x_vquality = (t_int) vquality;
+}
+
+ /* set audio quality */
+static void pdp_theonice_aquality(t_pdp_theonice *x, t_floatarg aquality )
+{
+ if ( ( (t_int) aquality < MIN_AUDIO_QUALITY ) || ( (t_int) aquality > MAX_AUDIO_QUALITY ) )
+ {
+ post( "pdp_theonice~ : wrong audio quality %d : should be in [%d,%d]",
+ (t_int) aquality, MIN_AUDIO_QUALITY, MAX_AUDIO_QUALITY );
+ return;
+ }
+ x->x_aquality = (t_int) aquality;
+}
+
+ /* set framerate */
+static void pdp_theonice_framerate(t_pdp_theonice *x, t_floatarg fframerate )
+{
+ if ( ( (t_int) fframerate < MIN_FRAMERATE ) || ( (t_int) fframerate > MAX_FRAMERATE ) )
+ {
+ post( "pdp_theonice~ : wrong framerate %d : should be in [%d,%d]",
+ (t_int) fframerate, MIN_FRAMERATE, MAX_FRAMERATE );
+ return;
+ }
+ x->x_framerate = (t_int) fframerate;
+}
+
+ /* store audio data in PCM format in a buffer for now */
+static t_int *pdp_theonice_perform(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]); // left audio inlet
+ t_float *in2 = (t_float *)(w[2]); // right audio inlet
+ t_pdp_theonice *x = (t_pdp_theonice *)(w[3]);
+ int n = (int)(w[4]); // number of samples
+ t_float fsample;
+ t_int isample, i;
+
+ if ( x->x_streaming )
+ {
+ // just fills the buffer
+ while (n--)
+ {
+ fsample=*(in1++);
+ if (fsample > 1.0) { fsample = 1.0; }
+ if (fsample < -1.0) { fsample = -1.0; }
+ x->x_audio_buf[0][x->x_audioin_position]=fsample;
+ fsample=*(in2++);
+ if (fsample > 1.0) { fsample = 1.0; }
+ if (fsample < -1.0) { fsample = -1.0; }
+ x->x_audio_buf[1][x->x_audioin_position]=fsample;
+ x->x_audioin_position=(x->x_audioin_position+1)%(MAX_AUDIO_PACKET_SIZE);
+ if ( x->x_audioin_position >= MAX_AUDIO_PACKET_SIZE-1 )
+ {
+ post( "pdp_theonice~ : reaching end of audio buffer" );
+ }
+ }
+ }
+
+ if ( x->x_streaming != x->x_pstreaming )
+ {
+ x->x_pstreaming = x->x_streaming;
+ outlet_float(x->x_outlet_streaming, x->x_streaming);
+ }
+ if ( x->x_frameswritten != x->x_pframeswritten )
+ {
+ x->x_pframeswritten = x->x_frameswritten;
+ outlet_float(x->x_outlet_nbframes, x->x_frameswritten);
+ }
+ if ( x->x_nbframes_dropped != x->x_pnbframes_dropped )
+ {
+ x->x_pnbframes_dropped = x->x_nbframes_dropped;
+ outlet_float(x->x_outlet_nbframes_dropped, x->x_nbframes_dropped);
+ }
+ if ( x->x_mframerate != x->x_pmframerate )
+ {
+ x->x_pmframerate = x->x_mframerate;
+ outlet_float(x->x_outlet_framerate, x->x_mframerate);
+ }
+ if ( x->x_audiotime != x->x_paudiotime )
+ {
+ x->x_paudiotime = x->x_audiotime;
+ if ( x->x_audiotime >= 0. ) outlet_float(x->x_outlet_atime, x->x_audiotime);
+ }
+ if ( x->x_videotime != x->x_pvideotime )
+ {
+ x->x_pvideotime = x->x_videotime;
+ if ( x->x_videotime >= 0. ) outlet_float(x->x_outlet_vtime, x->x_videotime);
+ }
+
+ return (w+5);
+}
+
+static void pdp_theonice_dsp(t_pdp_theonice *x, t_signal **sp)
+{
+ dsp_add(pdp_theonice_perform, 4, sp[0]->s_vec, sp[1]->s_vec, x, sp[0]->s_n);
+}
+
+static void pdp_theonice_process_yv12(t_pdp_theonice *x)
+{
+ t_pdp *header = pdp_packet_header(x->x_packet0);
+ unsigned char *data = (unsigned char *)pdp_packet_data(x->x_packet0);
+ t_int i, ret;
+ t_int px, py;
+ char *pY, *pU, *pV;
+ struct timeval tstream;
+ struct timeval etime;
+ t_int nbaudiosamples, nbusecs, nbsamples;
+ t_float fframerate=0.0;
+ t_int ttime, atime;
+
+ if ( ( (int)(header->info.image.width) != x->x_vwidth ) ||
+ ( (int)(header->info.image.height) != x->x_vheight ) )
+ {
+ post( "pdp_theonice~: reallocating ressources" );
+ pdp_theonice_free_ressources( x );
+ pdp_theonice_shutdown_encoder( x );
+ x->x_vwidth = header->info.image.width;
+ x->x_vheight = header->info.image.height;
+ x->x_vsize = x->x_vwidth*x->x_vheight;
+ x->x_tvwidth=((x->x_vwidth + 15) >>4)<<4;
+ x->x_tvheight=((x->x_vheight + 15) >>4)<<4;
+ pdp_theonice_allocate( x );
+ if ( x->x_tzero.tv_sec != 0 )
+ {
+ pdp_theonice_init_encoder( x );
+ pdp_theonice_write_headers( x );
+ }
+ }
+
+ x->x_frames++;
+
+ if ( x->x_frameswritten == 0 )
+ {
+ if ( gettimeofday(&x->x_tprevstream, NULL) == -1)
+ {
+ post("pdp_theonice~ : could set start time" );
+ }
+ }
+
+ // check if it's time to emit a frame
+ if ( gettimeofday(&etime, NULL) == -1)
+ {
+ post("pdp_theonice~ : could not read time" );
+ }
+ if ( etime.tv_sec != x->x_cursec )
+ {
+ x->x_cursec = etime.tv_sec;
+ x->x_mframerate = x->x_secondcount;
+ if ( x->x_mframerate < x->x_framerate )
+ {
+ x->x_frameslate += x->x_framerate-x->x_mframerate;
+ }
+ x->x_secondcount = 0;
+ }
+ ttime = ( ( x->x_frameswritten ) % x->x_framerate ) * ( 1000 / x->x_framerate );
+ atime = ( etime.tv_usec / 1000 );
+ // post("pdp_theonice~ : actual : %d, theoretical : %d", atime, ttime );
+ if ( ( atime < ttime ) && ( x->x_frameslate <= 0 ) )
+ {
+ x->x_nbframes_dropped++;
+ return;
+ }
+
+ pY = x->x_yuvbuffer.y;
+ memcpy( (void*)pY, (void*)&data[0], x->x_vsize );
+ pV = x->x_yuvbuffer.v;
+ memcpy( (void*)pV, (void*)&data[x->x_vsize], (x->x_vsize>>2) );
+ pU = x->x_yuvbuffer.u;
+ memcpy( (void*)pU, (void*)&data[x->x_vsize+(x->x_vsize>>2)], (x->x_vsize>>2) );
+
+ if ( x->x_socketfd > 0 && x->x_streaming )
+ {
+ // calculate the number of audio samples to output
+ if ( gettimeofday(&tstream, NULL) == -1)
+ {
+ post("pdp_theonice~ : could set stop time" );
+ }
+ // calculate time diff in micro seconds
+ nbusecs = ( tstream.tv_usec - x->x_tprevstream.tv_usec ) +
+ ( tstream.tv_sec - x->x_tprevstream.tv_sec )*1000000;
+ nbaudiosamples = (sys_getsr()*1000000)/nbusecs;
+ memcpy( &x->x_tprevstream, &tstream, sizeof( struct timeval) );
+
+ if ( x->x_audioin_position > nbaudiosamples )
+ {
+ nbsamples = nbaudiosamples;
+ }
+ else
+ {
+ nbsamples = x->x_audioin_position;
+ }
+ // if ( x->x_audiotime > x->x_videotime ) nbsamples = -1;
+
+ if ( ( ret = theora_encode_YUVin( &x->x_theora_state, &x->x_yuvbuffer ) ) != 0 )
+ {
+ post( "pdp_theonice~ : could not encode yuv image (ret=%d).", ret );
+ }
+ else
+ {
+ // stream one packet
+ theora_encode_packetout(&x->x_theora_state, 0, &x->x_ogg_packet);
+ ogg_stream_packetin(&x->x_statet, &x->x_ogg_packet);
+ // post( "pdp_theonice~ : new (theora) ogg packet : bytes:%ld, bos:%ld, eos:%ld, no:%lld",
+ // x->x_ogg_packet.bytes, x->x_ogg_packet.b_o_s,
+ // x->x_ogg_packet.e_o_s, x->x_ogg_packet.packetno );
+
+ while( ( ret = ogg_stream_pageout(&x->x_statet, &x->x_vpage) ) >0 )
+ {
+ x->x_videotime = theora_granule_time(&x->x_theora_state, ogg_page_granulepos(&x->x_vpage));
+ // post("pdp_theonice~ : writing video : header : %d, body : %d", x->x_vpage.header_len, x->x_vpage.body_len);
+ if ( ( ret = send(x->x_socketfd, (void*)x->x_vpage.header, x->x_vpage.header_len, MSG_NOSIGNAL) ) < 0 )
+ {
+ post( "pdp_theonice~ : could not write video packet (ret=%d).", ret );
+ perror( "send" );
+ pdp_theonice_disconnect(x);
+ return;
+ }
+ if ( ( ret = send(x->x_socketfd, (void*)x->x_vpage.body, x->x_vpage.body_len, MSG_NOSIGNAL) ) < 0 )
+ {
+ post( "pdp_theonice~ : could not write video packet (ret=%d).", ret );
+ perror( "send" );
+ pdp_theonice_disconnect(x);
+ return;
+ }
+ }
+ x->x_frameswritten++;
+ if ( x->x_frameslate > 0 ) x->x_frameslate--;
+ x->x_secondcount++;
+ }
+
+ // audio is ahead, don't send no audio
+ if ( nbsamples < 0 ) return;
+
+ x->x_vbuffer=vorbis_analysis_buffer( &x->x_dsp_state, nbsamples );
+ if ( !x->x_vbuffer ) return;
+
+ memcpy( (void*)&x->x_vbuffer[0][0], (void*)&x->x_audio_buf[0][0], nbsamples*sizeof( t_float ) );
+ memcpy( (void*)&x->x_vbuffer[1][0], (void*)&x->x_audio_buf[1][0], nbsamples*sizeof( t_float ) );
+
+ vorbis_analysis_wrote( &x->x_dsp_state, nbsamples);
+
+ while(vorbis_analysis_blockout( &x->x_dsp_state, &x->x_vorbis_block )==1)
+ {
+
+ // analysis, assume we want to use bitrate management
+ vorbis_analysis( &x->x_vorbis_block, NULL);
+ vorbis_bitrate_addblock( &x->x_vorbis_block );
+
+ // weld packets into the bitstream
+ while(vorbis_bitrate_flushpacket( &x->x_dsp_state, &x->x_ogg_packet ))
+ {
+ ogg_stream_packetin( &x->x_statev, &x->x_ogg_packet);
+ }
+
+ }
+
+ x->x_eos=0;
+ while( !x->x_eos )
+ {
+ ret = ogg_stream_pageout( &x->x_statev, &x->x_apage);
+ if ( ret == 0 ) break;
+ x->x_audiotime = vorbis_granule_time(&x->x_dsp_state, ogg_page_granulepos(&x->x_apage));
+
+ // post("pdp_theonice~ : writing audio : %d samples, header : %d, body : %d", nbsamples, x->x_apage.header_len, x->x_apage.body_len);
+ if ( ( ret = send(x->x_socketfd, (void*)x->x_apage.header, x->x_apage.header_len, MSG_NOSIGNAL) ) < 0 )
+ {
+ post( "pdp_theonice~ : could not write audio packet (ret=%d).", ret );
+ perror( "send" );
+ pdp_theonice_disconnect(x);
+ return;
+ }
+ if ( ( ret = send(x->x_socketfd, (void*)x->x_apage.body, x->x_apage.body_len, MSG_NOSIGNAL) ) < 0 )
+ {
+ post( "pdp_theonice~ : could not write audio packet (ret=%d).", ret );
+ perror( "send" );
+ pdp_theonice_disconnect(x);
+ return;
+ }
+ if (ogg_page_eos(&x->x_apage)) x->x_eos=1;
+ }
+
+ memcpy( &x->x_audio_buf[0][0], &x->x_audio_buf[0][nbsamples],
+ ( x->x_audioin_position-nbsamples ) * sizeof( t_float ) );
+ memcpy( &x->x_audio_buf[1][0], &x->x_audio_buf[1][nbsamples],
+ ( x->x_audioin_position-nbsamples ) * sizeof( t_float ) );
+ x->x_audioin_position -= nbsamples;
+
+ }
+
+ return;
+}
+
+static void pdp_theonice_killpacket(t_pdp_theonice *x)
+{
+ /* release the packet */
+ pdp_packet_mark_unused(x->x_packet0);
+ x->x_packet0 = -1;
+}
+
+static void pdp_theonice_process(t_pdp_theonice *x)
+{
+ int encoding;
+ t_pdp *header = 0;
+
+ /* check if image data packets are compatible */
+ if ( (header = pdp_packet_header(x->x_packet0))
+ && (PDP_BITMAP == header->type)){
+
+ /* pdp_theonice_process inputs and write into active inlet */
+ switch(pdp_packet_header(x->x_packet0)->info.image.encoding)
+ {
+
+ case PDP_BITMAP_YV12:
+ pdp_queue_add(x, pdp_theonice_process_yv12, pdp_theonice_killpacket, &x->x_queue_id);
+ break;
+
+ default:
+ /* don't know the type, so dont pdp_theonice_process */
+ break;
+
+ }
+ }
+}
+
+static void pdp_theonice_input_0(t_pdp_theonice *x, t_symbol *s, t_floatarg f)
+{
+ /* if this is a register_ro message or register_rw message, register with packet factory */
+
+ if (s== gensym("register_rw"))
+ {
+ x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("bitmap/yv12/*") );
+ }
+
+ if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped))
+ {
+ /* add the process method and callback to the process queue */
+ pdp_theonice_process(x);
+ }
+
+}
+
+static void pdp_theonice_free(t_pdp_theonice *x)
+{
+ int i;
+
+ pdp_queue_finish(x->x_queue_id);
+ pdp_packet_mark_unused(x->x_packet0);
+ // close video file if existing
+ pdp_theonice_disconnect(x);
+
+}
+
+t_class *pdp_theonice_class;
+
+void *pdp_theonice_new(void)
+{
+ t_int i;
+
+ t_pdp_theonice *x = (t_pdp_theonice *)pd_new(pdp_theonice_class);
+ inlet_new (&x->x_obj, &x->x_obj.ob_pd, gensym ("signal"), gensym ("signal"));
+ x->x_outlet_streaming = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet_nbframes = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet_nbframes_dropped = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet_framerate = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet_atime = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet_vtime = outlet_new(&x->x_obj, &s_float);
+
+ x->x_packet0 = -1;
+ x->x_packet1 = -1;
+ x->x_queue_id = -1;
+
+ x->x_yuvbuffer.y = NULL;
+ x->x_yuvbuffer.u = NULL;
+ x->x_yuvbuffer.v = NULL;
+
+ /* audio defaults */
+ x->x_samplerate = sys_getsr();
+ x->x_channels = DEFAULT_CHANNELS;
+ x->x_bits = DEFAULT_BITS;
+
+ x->x_framerate = DEFAULT_FRAME_RATE;
+ x->x_vkbps = DEFAULT_VIDEO_BITRATE;
+ x->x_vquality = DEFAULT_VIDEO_QUALITY;
+ x->x_akbps = DEFAULT_AUDIO_BITRATE;
+ x->x_aquality = DEFAULT_AUDIO_QUALITY;
+ x->x_maxdrift = DEFAULT_DRIFT/1000;
+
+ x->x_socketfd = -1;
+ x->x_passwd = "letmein";
+ strcpy( x->x_title, "The Aesthetics Of Our Anger" );
+ strcpy(x->x_url, "http://www.indymedia.org");
+ strcpy( x->x_genre, "angrrry");
+ strcpy( x->x_description, "Images From Infowar");
+ strcpy( x->x_artist, "Recuerdos De Luchas");
+ strcpy( x->x_copyright, "Creative Commons");
+ x->x_public = 1;
+ strcpy( x->x_mountpoint, "theora.ogg");
+ strcpy( x->x_hostname, "localhost");
+ x->x_port = 8000;
+
+ x->x_frames = 0;
+ x->x_eos = 0;
+ x->x_frameswritten = 0;
+ x->x_pframeswritten = 0;
+ x->x_frameslate = 0;
+ x->x_mframerate = 0;
+ x->x_pmframerate = 0;
+ x->x_nbframes_dropped = 0;
+ x->x_pnbframes_dropped = 0;
+
+ x->x_tzero.tv_sec = 0;
+ x->x_tzero.tv_usec = 0;
+
+ x->x_audiotime = -1.;
+ x->x_paudiotime = -1.;
+ x->x_videotime = -1.;
+ x->x_pvideotime = -1.;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_theonice_tilde_setup(void)
+{
+ // post( pdp_theonice_version );
+ pdp_theonice_class = class_new(gensym("pdp_theonice~"), (t_newmethod)pdp_theonice_new,
+ (t_method)pdp_theonice_free, sizeof(t_pdp_theonice), 0, A_NULL);
+
+ CLASS_MAINSIGNALIN(pdp_theonice_class, t_pdp_theonice, x_f );
+ class_addmethod(pdp_theonice_class, (t_method)pdp_theonice_dsp, gensym("dsp"), 0);
+ class_addmethod(pdp_theonice_class, (t_method)pdp_theonice_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_theonice_class, (t_method)pdp_theonice_connect, gensym("connect"), A_SYMBOL, A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_theonice_class, (t_method)pdp_theonice_disconnect, gensym("disconnect"), A_NULL);
+ class_addmethod(pdp_theonice_class, (t_method)pdp_theonice_abitrate, gensym("audiobitrate"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_theonice_class, (t_method)pdp_theonice_vbitrate, gensym("videobitrate"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_theonice_class, (t_method)pdp_theonice_aquality, gensym("audioquality"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_theonice_class, (t_method)pdp_theonice_vquality, gensym("videoquality"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_theonice_class, (t_method)pdp_theonice_framerate, gensym("framerate"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_theonice_class, (t_method)pdp_theonice_passwd, gensym("passwd"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_theonice_class, (t_method)pdp_theonice_title, gensym("title"), A_GIMME, A_NULL);
+ class_addmethod(pdp_theonice_class, (t_method)pdp_theonice_artist, gensym("artist"), A_GIMME, A_NULL);
+ class_addmethod(pdp_theonice_class, (t_method)pdp_theonice_url, gensym("url"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_theonice_class, (t_method)pdp_theonice_description, gensym("description"), A_GIMME, A_NULL);
+ class_addmethod(pdp_theonice_class, (t_method)pdp_theonice_genre, gensym("genre"), A_GIMME, A_NULL);
+ class_sethelpsymbol( pdp_theonice_class, gensym("pdp_theonice~.pd") );
+
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/pdp_theorin~.c b/modules/pdp_theorin~.c
index 2a7c72b..b52aa33 100644
--- a/modules/pdp_theorin~.c
+++ b/modules/pdp_theorin~.c
@@ -42,7 +42,7 @@
#define VIDEO_BUFFER_SIZE (1024*1024)
#define MAX_AUDIO_PACKET_SIZE (64 * 1024)
-#define MIN_AUDIO_SIZE (64*1024)
+#define MIN_AUDIO_SIZE (128*1024)
#define DEFAULT_CHANNELS 1
#define DEFAULT_WIDTH 320
@@ -52,6 +52,7 @@
#define MIN_PRIORITY 0
#define DEFAULT_PRIORITY 1
#define MAX_PRIORITY 20
+#define NB_NOFRAMES_HIT 10
#define THEORA_NUM_HEADER_PACKETS 3
@@ -80,6 +81,8 @@ typedef struct pdp_theorin_struct
t_outlet *x_outlet_filesize; // for informing of the file size
pthread_t x_decodechild; // file decoding thread
+ pthread_mutex_t x_audiolock; // audio mutex
+ pthread_mutex_t x_videolock; // video mutex
t_int x_usethread; // flag to activate decoding in a thread
t_int x_autoplay; // flag to autoplay the file ( default = true )
t_int x_nextimage; // flag to play next image in manual mode
@@ -90,9 +93,9 @@ typedef struct pdp_theorin_struct
t_int x_decoding; // decoding flag
t_int x_theorainit; // flag for indicating that theora is initialized
t_int x_videoready; // video ready flag
+ t_int x_noframeshits; // number of tries without getting a frame
t_int x_newpicture; // new picture flag
t_int x_newpictureready;// new picture ready flag
- t_int x_loop; // looping flag ( default = on )
t_int x_notpackets; // number of theora packets decoded
t_int x_novpackets; // number of vorbis packets decoded
t_int x_endoffile; // end of the file reached
@@ -124,9 +127,10 @@ typedef struct pdp_theorin_struct
/* audio structures */
t_int x_audio; // flag to activate the decoding of audio
- t_float x_audio_inl[4*MAX_AUDIO_PACKET_SIZE]; /* buffer for float audio decoded from ogg */
- t_float x_audio_inr[4*MAX_AUDIO_PACKET_SIZE]; /* buffer for float audio decoded from ogg */
- t_int x_audioin_position; // writing position for incoming audio
+ t_float x_audio_inl[4*MAX_AUDIO_PACKET_SIZE]; // left buffer for pd
+ t_float x_audio_inr[4*MAX_AUDIO_PACKET_SIZE]; // right buffer for pd
+ t_int x_audioin_position;// writing position for incoming audio
+ t_float **x_pcm; // buffer for vorbis decoding
} t_pdp_theorin;
@@ -162,14 +166,6 @@ static void pdp_theorin_autoplay(t_pdp_theorin *x, t_floatarg fautoplay )
}
}
-static void pdp_theorin_loop(t_pdp_theorin *x, t_floatarg floop )
-{
- if ( ( floop == 0. ) || ( floop == 1. ) )
- {
- x->x_loop = (int)floop;
- }
-}
-
static void pdp_theorin_bang(t_pdp_theorin *x)
{
if ( x->x_nextimage == 1 )
@@ -201,40 +197,39 @@ static t_int pdp_theorin_queue_page(t_pdp_theorin *x)
static t_int pdp_theorin_decode_packet(t_pdp_theorin *x)
{
int ret, count, maxsamples, samples, si=0, sj=0;
- float **pcm;
struct timespec mwait;
struct timeval ctime;
long long tplaying;
long long ttheoretical;
unsigned char *pY, *pU, *pV;
unsigned char *psY, *psU, *psV;
+ t_float **lpcm;
t_int px, py;
// post( "pdp_theorin~ : decode packet" );
if ( !x->x_reading ) return -1;
- while ( x->x_novpackets && !x->x_audioon )
+ while ( x->x_novpackets )
{
/* if there's pending, decoded audio, grab it */
- if((ret=vorbis_synthesis_pcmout(&x->x_dsp_state, &pcm))>0)
+ x->x_pcm = NULL;
+ if((ret=vorbis_synthesis_pcmout(&x->x_dsp_state, &x->x_pcm))>0)
{
if (x->x_audio)
{
+ if ( pthread_mutex_lock( &x->x_audiolock ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to lock audio mutex" );
+ perror( "pthread_mutex_lock" );
+ }
maxsamples=(3*MAX_AUDIO_PACKET_SIZE-x->x_audioin_position);
samples=(ret<maxsamples)?ret:maxsamples;
- if ( x->x_audioin_position + samples*x->x_audiochannels < 3*MAX_AUDIO_PACKET_SIZE )
- {
- memcpy( (void*)&x->x_audio_inl[x->x_audioin_position], pcm[0], samples*sizeof(t_float) );
- memcpy( (void*)&x->x_audio_inr[x->x_audioin_position], pcm[1], samples*sizeof(t_float) );
- x->x_audioin_position = ( x->x_audioin_position + samples ) % (4*MAX_AUDIO_PACKET_SIZE);
- }
- else
- {
- post( "pdp_theorin~ : audio overflow : packet ignored...");
- x->x_audioin_position = 0;
- }
+ memcpy( (void*)&x->x_audio_inl[x->x_audioin_position], x->x_pcm[0], samples*sizeof(t_float) );
+ memcpy( (void*)&x->x_audio_inr[x->x_audioin_position], x->x_pcm[1], samples*sizeof(t_float) );
+ x->x_audioin_position = ( x->x_audioin_position + samples ) % (3*MAX_AUDIO_PACKET_SIZE);
+
if ( ( x->x_audioin_position > MIN_AUDIO_SIZE ) && (!x->x_audioon) )
{
x->x_audioon = 1;
@@ -243,6 +238,15 @@ static t_int pdp_theorin_decode_packet(t_pdp_theorin *x)
// tell vorbis how many samples were read
// post( "pdp_theorin~ : got %d audio samples (audioin=%d)", samples, x->x_audioin_position );
vorbis_synthesis_read(&x->x_dsp_state, samples);
+ if((ret=vorbis_synthesis_lapout(&x->x_dsp_state, &x->x_pcm))>0)
+ {
+ // post( "pdp_theorin~ : supplemental samples (nb=%d)", ret );
+ }
+ if ( pthread_mutex_unlock( &x->x_audiolock ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to audio unlock mutex" );
+ perror( "pthread_mutex_unlock" );
+ }
}
else
{
@@ -276,27 +280,15 @@ static t_int pdp_theorin_decode_packet(t_pdp_theorin *x)
theora_decode_packetin(&x->x_theora_state, &x->x_ogg_packet);
// post( "pdp_theorin~ : got one video frame" );
x->x_videoready=1;
+ x->x_noframeshits=0;
}
else
{
// post( "pdp_theorin~ : no more video frame (frames=%d)", x->x_nbframes );
- if ( x->x_nbframes > 0 )
+ x->x_noframeshits++;
+ if ( x->x_nbframes > 0 && ( x->x_noframeshits > NB_NOFRAMES_HIT ) )
{
- if ( !x->x_loop )
- {
x->x_endoffile = 1;
- }
- else
- {
- // restart a new loop
- if ( gettimeofday(&x->x_starttime, NULL) == -1)
- {
- post("pdp_theorin~ : could not set start time" );
- }
- }
- x->x_nbframes = 0;
- x->x_audioin_position = 0; // reset audio
- x->x_audioon = 0;
}
break;
}
@@ -304,6 +296,11 @@ static t_int pdp_theorin_decode_packet(t_pdp_theorin *x)
if ( x->x_videoready )
{
+ if ( pthread_mutex_lock( &x->x_videolock ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to lock video mutex" );
+ perror( "pthread_mutex_lock" );
+ }
theora_decode_YUVout(&x->x_theora_state, &x->x_yuvbuffer);
// create a new pdp packet from PIX_FMT_YUV420P image format
@@ -350,6 +347,11 @@ static t_int pdp_theorin_decode_packet(t_pdp_theorin *x)
{
x->x_newpictureready = 1;
}
+ if ( pthread_mutex_unlock( &x->x_videolock ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to unlock video mutex" );
+ perror( "pthread_mutex_unlock" );
+ }
}
}
@@ -363,7 +365,7 @@ static t_int pdp_theorin_decode_packet(t_pdp_theorin *x)
tplaying = ( ctime.tv_sec-x->x_starttime.tv_sec )*1000 +
( ctime.tv_usec-x->x_starttime.tv_usec )/1000;
ttheoretical = ((x->x_nbframes)*1000 )/x->x_framerate;
- // post( "pdp-theorin~ : %d playing since : %lldms ( theory : %lldms )",
+ // post( "pdp_theorin~ : %d playing since : %lldms ( theory : %lldms )",
// x->x_nbframes, tplaying, ttheoretical );
if ( ttheoretical <= tplaying )
@@ -374,19 +376,6 @@ static t_int pdp_theorin_decode_packet(t_pdp_theorin *x)
}
- // check end of file
- if(!x->x_videoready && feof(x->x_infile))
- {
- if ( x->x_loop )
- {
- if ( fseek( x->x_infile, 0x0, SEEK_SET ) < 0 )
- {
- post( "pdp_theorin~ : could not reset file." );
- perror( "fseek" );
- }
- }
- }
-
// read more data in
if( ( x->x_audioin_position < MIN_AUDIO_SIZE ) || ( !x->x_newpicture && !x->x_newpictureready ) )
{
@@ -412,7 +401,7 @@ static void *pdp_decode_file(void *tdata)
struct timespec twait;
twait.tv_sec = 0;
- twait.tv_nsec = 5000000; // 5 ms
+ twait.tv_nsec = 10000000; // 10 ms
schedprio.sched_priority = sched_get_priority_min(SCHED_FIFO) + x->x_priority;
if ( sched_setscheduler(0, SCHED_FIFO, &schedprio) == -1)
@@ -449,7 +438,7 @@ static void pdp_theorin_close(t_pdp_theorin *x)
struct timespec twait;
twait.tv_sec = 0;
- twait.tv_nsec = 10000000; // 10 ms
+ twait.tv_nsec = 100000000; // 100 ms
if ( x->x_infile == NULL )
{
@@ -460,8 +449,9 @@ static void pdp_theorin_close(t_pdp_theorin *x)
if ( x->x_reading )
{
x->x_newpicture = 0;
+ x->x_newpictureready = 0;
x->x_reading = 0;
- post("pdp_theorin~ : waiting end of decoding..." );
+ // post("pdp_theorin~ : waiting end of decoding..." );
while ( x->x_decoding ) nanosleep( &twait, NULL );
if ( fclose( x->x_infile ) < 0 )
@@ -492,7 +482,6 @@ static void pdp_theorin_close(t_pdp_theorin *x)
x->x_notpackets = 0;
x->x_novpackets = 0;
- x->x_endoffile = 0;
x->x_nbframes = 0;
x->x_decoding = 0;
x->x_theorainit = 0;
@@ -515,14 +504,15 @@ static void pdp_theorin_open(t_pdp_theorin *x, t_symbol *s)
if ( x->x_infile != NULL )
{
- post("pdp_theorin~ : open request but a file is open ... closing" );
+ // post("pdp_theorin~ : open request but a file is open ... closing" );
pdp_theorin_close(x);
}
if ( x->x_filename ) free( x->x_filename );
x->x_filename = (char*) malloc( strlen( s->s_name ) + 1 );
strcpy( x->x_filename, s->s_name );
- post( "pdp_theorin~ : opening file : %s", x->x_filename );
+ // post( "pdp_theorin~ : opening file : %s", x->x_filename );
+ x->x_audio = 1;
if ( ( x->x_infile = fopen(x->x_filename,"r") ) == NULL )
{
@@ -635,17 +625,17 @@ static void pdp_theorin_open(t_pdp_theorin *x, t_symbol *s)
}
}
}
- post( "pdp_theorin~ : parsed headers ok." );
+ // post( "pdp_theorin~ : parsed headers ok." );
// initialize decoders
if( x->x_notpackets )
{
theora_decode_init(&x->x_theora_state, &x->x_theora_info);
x->x_framerate = (t_int)x->x_theora_info.fps_numerator/x->x_theora_info.fps_denominator;
- post("pdp_theorin~ : stream %x is theora %dx%d %d fps video.",
- x->x_statet.serialno,
- x->x_theora_info.width,x->x_theora_info.height,
- x->x_framerate);
+ // post("pdp_theorin~ : stream %x is theora %dx%d %d fps video.",
+ // x->x_statet.serialno,
+ // x->x_theora_info.width,x->x_theora_info.height,
+ // x->x_framerate);
if(x->x_theora_info.width!=x->x_theora_info.frame_width ||
x->x_theora_info.height!=x->x_theora_info.frame_height)
{
@@ -663,10 +653,10 @@ static void pdp_theorin_open(t_pdp_theorin *x, t_symbol *s)
/* nothing to report */
break;;
case OC_CS_ITU_REC_470M:
- post("pdp_theorin~ : encoder specified ITU Rec 470M (NTSC) color.");
+ // post("pdp_theorin~ : encoder specified ITU Rec 470M (NTSC) color.");
break;;
case OC_CS_ITU_REC_470BG:
- post("pdp_theorin~ : encoder specified ITU Rec 470BG (PAL) color.");
+ // post("pdp_theorin~ : encoder specified ITU Rec 470BG (PAL) color.");
break;;
default:
post("pdp_theorin~ : warning: encoder specified unknown colorspace (%d).",
@@ -690,9 +680,9 @@ static void pdp_theorin_open(t_pdp_theorin *x, t_symbol *s)
vorbis_block_init(&x->x_dsp_state, &x->x_vorbis_block);
x->x_audiochannels = x->x_vorbis_info.channels;
x->x_samplerate = x->x_vorbis_info.rate;
- post("pdp_theorin~ : ogg logical stream %x is vorbis %d channel %d Hz audio.",
- x->x_statev.serialno,
- x->x_audiochannels, x->x_samplerate);
+ // post("pdp_theorin~ : ogg logical stream %x is vorbis %d channel %d Hz audio.",
+ // x->x_statev.serialno,
+ // x->x_audiochannels, x->x_samplerate);
}
else
{
@@ -788,8 +778,13 @@ static t_int *pdp_theorin_perform(t_int *w)
x->x_blocksize = n;
// just read the buffer
- if ( x->x_audioon )
+ if ( x->x_audioon && x->x_reading )
{
+ if ( pthread_mutex_lock( &x->x_audiolock ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to lock audio mutex" );
+ perror( "pthread_mutex_lock" );
+ }
sn=0;
while (n--)
{
@@ -816,6 +811,11 @@ static t_int *pdp_theorin_perform(t_int *w)
// post( "pdp_theorin~ : audio off ( audioin : %d, channels=%d )",
// x->x_audioin_position, x->x_audiochannels );
}
+ if ( pthread_mutex_unlock( &x->x_audiolock ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to unlock audio mutex" );
+ perror( "pthread_mutex_unlock" );
+ }
}
else
{
@@ -827,6 +827,8 @@ static t_int *pdp_theorin_perform(t_int *w)
}
}
+ if ( !x->x_reading ) return (w+5);
+
// check if the framerate has been exceeded
if ( gettimeofday(&etime, NULL) == -1)
{
@@ -842,19 +844,28 @@ static t_int *pdp_theorin_perform(t_int *w)
// output image if there's a new one decoded
if ( x->x_newpicture )
{
+ if ( pthread_mutex_lock( &x->x_videolock ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to lock video mutex" );
+ perror( "pthread_mutex_lock" );
+ }
pdp_packet_pass_if_valid(x->x_pdp_out, &x->x_packet0);
x->x_newpicture = 0;
// update streaming status
x->x_nbframes++;
x->x_secondcount++;
+ // post( "pdp_theorin~ : frame #%d", x->x_nbframes );
outlet_float( x->x_outlet_nbframes, x->x_nbframes );
-
+ if ( pthread_mutex_unlock( &x->x_videolock ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to unlock video mutex" );
+ perror( "pthread_mutex_unlock" );
+ }
}
if ( x->x_endoffile == 1 ) // only once
{
outlet_float( x->x_outlet_endoffile, x->x_endoffile );
- x->x_endoffile = 0;
}
if ( x->x_endoffile == -1 ) // reset
{
@@ -883,8 +894,19 @@ static void pdp_theorin_free(t_pdp_theorin *x)
{
pdp_theorin_close(x);
}
+
+ if ( pthread_mutex_destroy( &x->x_audiolock ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to destroy audio mutex" );
+ perror( "pthread_mutex_destroy" );
+ }
+ if ( pthread_mutex_destroy( &x->x_videolock ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to destroy video mutex" );
+ perror( "pthread_mutex_destroy" );
+ }
- post( "pdp_theorin~ : freeing object" );
+ // post( "pdp_theorin~ : freeing object" );
}
t_class *pdp_theorin_class;
@@ -909,6 +931,18 @@ void *pdp_theorin_new(void)
x->x_packet0 = -1;
x->x_decodechild = 0;
+ if ( pthread_mutex_init( &x->x_audiolock, NULL ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to initialize audio mutex" );
+ perror( "pthread_mutex_init" );
+ return NULL;
+ }
+ if ( pthread_mutex_init( &x->x_videolock, NULL ) < 0 )
+ {
+ post( "pdp_theorin~ : unable to initialize video mutex" );
+ perror( "pthread_mutex_init" );
+ return NULL;
+ }
x->x_decoding = 0;
x->x_theorainit = 0;
x->x_usethread = 1;
@@ -927,7 +961,6 @@ void *pdp_theorin_new(void)
x->x_novpackets = 0;
x->x_blocksize = MIN_AUDIO_SIZE;
x->x_autoplay = 1;
- x->x_loop = 1;
x->x_nextimage = 0;
x->x_infile = NULL;
x->x_reading = 0;
@@ -957,7 +990,6 @@ void pdp_theorin_tilde_setup(void)
class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_priority, gensym("priority"), A_FLOAT, A_NULL);
class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_audio, gensym("audio"), A_FLOAT, A_NULL);
class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_autoplay, gensym("autoplay"), A_FLOAT, A_NULL);
- class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_loop, gensym("loop"), A_FLOAT, A_NULL);
class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_threadify, gensym("thread"), A_FLOAT, A_NULL);
class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_bang, gensym("bang"), A_NULL);
class_addmethod(pdp_theorin_class, (t_method)pdp_theorin_frame_cold, gensym("frame_cold"), A_FLOAT, A_NULL);
diff --git a/modules/pdp_theorout~.c b/modules/pdp_theorout~.c
index 96d610a..f5c776b 100644
--- a/modules/pdp_theorout~.c
+++ b/modules/pdp_theorout~.c
@@ -166,8 +166,8 @@ static void pdp_theorout_init_encoder(t_pdp_theorout *x)
x->x_theora_info.offset_y=(x->x_tvheight-x->x_vheight)>>1;
x->x_theora_info.fps_numerator=x->x_framerate;
x->x_theora_info.fps_denominator=1;
- x->x_theora_info.aspect_numerator=x->x_vwidth;
- x->x_theora_info.aspect_denominator=x->x_vheight;
+ x->x_theora_info.aspect_numerator=1;
+ x->x_theora_info.aspect_denominator=1;
x->x_theora_info.colorspace=OC_CS_UNSPECIFIED;
x->x_theora_info.target_bitrate=x->x_vkbps;
x->x_theora_info.quality=x->x_vquality;
@@ -181,8 +181,10 @@ static void pdp_theorout_init_encoder(t_pdp_theorout *x)
x->x_theora_info.keyframe_auto_threshold=80;
x->x_theora_info.keyframe_mindistance=8;
x->x_theora_info.noise_sensitivity=1;
+ x->x_theora_info.sharpness=2;
theora_encode_init(&x->x_theora_state,&x->x_theora_info);
+ theora_info_clear (&x->x_theora_info);
vorbis_info_init(&x->x_vorbis_info);
@@ -203,6 +205,7 @@ static void pdp_theorout_init_encoder(t_pdp_theorout *x)
}
vorbis_comment_init(&x->x_vorbis_comment);
+ vorbis_comment_add_tag (&x->x_vorbis_comment, "ENCODER", "pdp_theorout~");
vorbis_analysis_init(&x->x_dsp_state,&x->x_vorbis_info);
vorbis_block_init(&x->x_dsp_state,&x->x_vorbis_block);
@@ -249,6 +252,7 @@ static void pdp_theorout_write_headers(t_pdp_theorout *x)
}
theora_comment_init(&x->x_theora_comment);
+ theora_comment_add_tag (&x->x_theora_comment, "ENCODER", "pdp_theorout~");
theora_encode_comment(&x->x_theora_comment, &x->x_ogg_packet);
ogg_stream_packetin(&x->x_statet, &x->x_ogg_packet);
theora_encode_tables(&x->x_theora_state, &x->x_ogg_packet);
@@ -532,6 +536,10 @@ static void pdp_theorout_process_yv12(t_pdp_theorout *x)
ogg_page vpage;
t_float **vbuffer;
double videotime, audiotime;
+ theora_info lti;
+ theora_comment ltc;
+ ogg_packet logp, logp2;
+
if ( ( (int)(header->info.image.width) != x->x_vwidth ) ||
( (int)(header->info.image.height) != x->x_vheight ) ||
@@ -607,17 +615,28 @@ static void pdp_theorout_process_yv12(t_pdp_theorout *x)
else
{
// stream one packet
- theora_encode_packetout(&x->x_theora_state, 0, &x->x_ogg_packet);
- ogg_stream_packetin(&x->x_statet, &x->x_ogg_packet);
+ theora_encode_packetout(&x->x_theora_state, 0, &logp);
+ ogg_stream_packetin(&x->x_statet, &logp);
// post( "pdp_theorout~ : new (theora) ogg packet : bytes:%ld, bos:%ld, eos:%ld, no:%lld",
- // x->x_ogg_packet.bytes, x->x_ogg_packet.b_o_s,
- // x->x_ogg_packet.e_o_s, x->x_ogg_packet.packetno );
+ // logp.bytes, logp.b_o_s,
+ // logp.e_o_s, logp.packetno );
+
while( ( ret = ogg_stream_pageout(&x->x_statet, &vpage) ) >0 )
{
videotime = theora_granule_time(&x->x_theora_state, ogg_page_granulepos(&vpage));
- x->x_vbytesout+=fwrite(vpage.header, 1, vpage.header_len, x->x_tfile );
- x->x_vbytesout+=fwrite(vpage.body, 1, vpage.body_len, x->x_tfile );
+ if ( ( ret = fwrite(vpage.header, 1, vpage.header_len, x->x_tfile) ) <= 0 )
+ {
+ post( "pdp_theorout~ : could not write headers (ret=%d).", ret );
+ perror( "fwrite" );
+ }
+ x->x_vbytesout+=ret;
+ if ( ( ret = fwrite(vpage.body, 1, vpage.body_len, x->x_tfile) ) <= 0 )
+ {
+ post( "pdp_theorout~ : could not write headers (ret=%d).", ret );
+ perror( "fwrite" );
+ }
+ x->x_vbytesout+=ret;
}
}
@@ -655,9 +674,9 @@ static void pdp_theorout_process_yv12(t_pdp_theorout *x)
vorbis_bitrate_addblock( &x->x_vorbis_block );
// weld packets into the bitstream
- while(vorbis_bitrate_flushpacket( &x->x_dsp_state, &x->x_ogg_packet))
+ while(vorbis_bitrate_flushpacket( &x->x_dsp_state, &logp2))
{
- ogg_stream_packetin( &x->x_statev, &x->x_ogg_packet);
+ ogg_stream_packetin( &x->x_statev, &logp2);
}
}
@@ -665,8 +684,18 @@ static void pdp_theorout_process_yv12(t_pdp_theorout *x)
while( ogg_stream_pageout( &x->x_statev, &apage) >0 )
{
audiotime = vorbis_granule_time(&x->x_dsp_state, ogg_page_granulepos(&apage));
- x->x_abytesout+=fwrite(apage.header, 1, apage.header_len, x->x_tfile );
- x->x_abytesout+=fwrite(apage.body, 1, apage.body_len, x->x_tfile );
+ if ( ( ret = fwrite(apage.header, 1, apage.header_len, x->x_tfile) ) <= 0 )
+ {
+ post( "pdp_theorout~ : could not write headers (ret=%d).", ret );
+ perror( "fwrite" );
+ }
+ x->x_abytesout+=ret;
+ if ( ( ret = fwrite(apage.body, 1, apage.body_len, x->x_tfile) ) <= 0 )
+ {
+ post( "pdp_theorout~ : could not write headers (ret=%d).", ret );
+ perror( "fwrite" );
+ }
+ x->x_abytesout+=ret;
}
memcpy( &x->x_audio_buf[0][0], &x->x_audio_buf[0][nbrecorded],
@@ -693,14 +722,24 @@ static void pdp_theorout_process_yv12(t_pdp_theorout *x)
else
{
// stream one packet
- theora_encode_packetout(&x->x_theora_state, 1, &x->x_ogg_packet);
- ogg_stream_packetin( &x->x_statet, &x->x_ogg_packet);
+ theora_encode_packetout(&x->x_theora_state, 1, &logp);
+ ogg_stream_packetin( &x->x_statet, &logp);
while( ( ret = ogg_stream_pageout( &x->x_statet, &vpage) ) > 0 )
{
videotime = theora_granule_time(&x->x_theora_state, ogg_page_granulepos(&vpage));
- x->x_vbytesout+=fwrite(vpage.header, 1, vpage.header_len, x->x_tfile );
- x->x_vbytesout+=fwrite(vpage.body, 1, vpage.body_len, x->x_tfile );
+ if ( ( ret = fwrite(vpage.header, 1, vpage.header_len, x->x_tfile) ) <= 0 )
+ {
+ post( "pdp_theorout~ : could not write headers (ret=%d).", ret );
+ perror( "fwrite" );
+ }
+ x->x_vbytesout+=ret;
+ if ( ( ret = fwrite(vpage.body, 1, vpage.body_len, x->x_tfile) ) <= 0 )
+ {
+ post( "pdp_theorout~ : could not write headers (ret=%d).", ret );
+ perror( "fwrite" );
+ }
+ x->x_vbytesout+=ret;
}
}
@@ -714,17 +753,27 @@ static void pdp_theorout_process_yv12(t_pdp_theorout *x)
vorbis_bitrate_addblock( &x->x_vorbis_block);
// weld packets into the bitstream
- while(vorbis_bitrate_flushpacket( &x->x_dsp_state, &x->x_ogg_packet))
+ while(vorbis_bitrate_flushpacket( &x->x_dsp_state, &logp2))
{
- ogg_stream_packetin( &x->x_statev, &x->x_ogg_packet);
+ ogg_stream_packetin( &x->x_statev, &logp2);
}
}
while( ogg_stream_pageout( &x->x_statev, &apage) >0 )
{
audiotime = vorbis_granule_time(&x->x_dsp_state, ogg_page_granulepos(&apage));
- x->x_abytesout+=fwrite(apage.header, 1, apage.header_len, x->x_tfile );
- x->x_abytesout+=fwrite(apage.body, 1, apage.body_len, x->x_tfile );
+ if ( ( ret = fwrite(apage.header, 1, apage.header_len, x->x_tfile) ) <= 0 )
+ {
+ post( "pdp_theorout~ : could not write headers (ret=%d).", ret );
+ perror( "fwrite" );
+ }
+ x->x_abytesout+=ret;
+ if ( ( ret = fwrite(apage.body, 1, apage.body_len, x->x_tfile) ) <= 0 )
+ {
+ post( "pdp_theorout~ : could not write headers (ret=%d).", ret );
+ perror( "fwrite" );
+ }
+ x->x_abytesout+=ret;
}
post("pdp_theorout~ : stop recording");
diff --git a/patches/collage.pd b/patches/collage.pd
index 0bfbcff..75425ae 100644
--- a/patches/collage.pd
+++ b/patches/collage.pd
@@ -43,7 +43,7 @@
#X obj 196 20 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
-1;
#X msg 55 85 loop \$1;
-#X obj 56 63 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 1
+#X obj 56 63 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 1
;
#X msg 100 54 open \$1;
#X obj 99 30 openpanel;
@@ -70,7 +70,7 @@
#X obj 157 255 hradio 15 1 0 8 empty empty empty 0 -6 0 8 -262144 -1
-1 0;
#X msg 156 274 unhide \$1;
-#X obj 506 434 hradio 15 1 0 5 hide-layer empty empty 0 -6 128 8 -262144
+#X obj 506 434 hradio 15 1 0 5 hide-layer empty empty 0 -6 0 8 -262144
-1 -1 4;
#X text 506 416 Select layer;
#X obj 486 292 r layer-4;
@@ -108,6 +108,7 @@
#X floatatom 122 360 5 0 0 0 - - -;
#X obj 75 483 pdp_affine;
#X floatatom 105 442 5 0 0 0 - - -;
+#X msg 178 427 cursor 1;
#X connect 0 0 6 1;
#X connect 1 0 6 2;
#X connect 2 0 7 0;
@@ -196,3 +197,4 @@
#X connect 88 0 84 1;
#X connect 89 0 32 0;
#X connect 90 0 89 1;
+#X connect 91 0 83 0;
diff --git a/patches/morphology/help-closing.pd b/patches/morphology/help-closing.pd
index de4f8a8..a54090d 100644
--- a/patches/morphology/help-closing.pd
+++ b/patches/morphology/help-closing.pd
@@ -2,7 +2,7 @@
#X obj 341 20 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
-1;
#X msg 196 92 loop \$1;
-#X obj 197 70 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 1
+#X obj 197 70 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 1
;
#X msg 453 93 open \$1;
#X obj 452 69 openpanel;
@@ -11,7 +11,7 @@
#X floatatom 389 55 5 0 0 0 - - -;
#X msg 298 21 stop;
#X obj 396 24 hsl 300 15 0 1000 0 0 empty empty empty -2 -6 0 8 -262144
--1 -1 6900 1;
+-1 -1 0 1;
#X obj 330 91 metro 70;
#X obj 325 123 pdp_yqt;
#X obj 25 193 pdp_v4l;
@@ -52,6 +52,7 @@
#X obj 61 547 pdp_glx;
#X obj 148 437 pdp_dilate ----;
#X obj 148 509 pdp_erode ----;
+#X obj 42 283 pdp_glx;
#X connect 0 0 9 0;
#X connect 1 0 10 0;
#X connect 2 0 1 0;
@@ -63,6 +64,7 @@
#X connect 8 0 6 0;
#X connect 9 0 10 0;
#X connect 10 0 29 0;
+#X connect 10 0 47 0;
#X connect 11 0 29 0;
#X connect 12 0 11 0;
#X connect 13 0 12 0;
@@ -85,6 +87,7 @@
#X connect 29 3 27 0;
#X connect 30 0 24 0;
#X connect 31 0 34 0;
+#X connect 31 0 47 0;
#X connect 32 0 45 1;
#X connect 34 0 30 0;
#X connect 35 0 45 2;
@@ -96,3 +99,4 @@
#X connect 45 0 46 0;
#X connect 46 0 42 0;
#X connect 46 0 43 1;
+#X connect 47 0 30 0;
diff --git a/patches/morphology/help-opening.pd b/patches/morphology/help-opening.pd
index 660a59e..af73cec 100644
--- a/patches/morphology/help-opening.pd
+++ b/patches/morphology/help-opening.pd
@@ -2,7 +2,7 @@
#X obj 341 20 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
-1;
#X msg 196 92 loop \$1;
-#X obj 197 70 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 1
+#X obj 197 70 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 1
;
#X msg 453 93 open \$1;
#X obj 452 69 openpanel;
@@ -52,6 +52,7 @@
#X obj 148 550 pdp_glx;
#X obj 61 508 pdp_xor;
#X obj 61 547 pdp_glx;
+#X obj 41 285 pdp_glx;
#X connect 0 0 9 0;
#X connect 1 0 10 0;
#X connect 2 0 1 0;
@@ -63,6 +64,7 @@
#X connect 8 0 6 0;
#X connect 9 0 10 0;
#X connect 10 0 29 0;
+#X connect 10 0 47 0;
#X connect 11 0 29 0;
#X connect 12 0 11 0;
#X connect 13 0 12 0;
@@ -85,6 +87,7 @@
#X connect 29 3 27 0;
#X connect 30 0 24 0;
#X connect 31 0 34 0;
+#X connect 31 0 47 0;
#X connect 32 0 39 1;
#X connect 34 0 30 0;
#X connect 35 0 39 2;
@@ -96,3 +99,4 @@
#X connect 43 0 44 0;
#X connect 43 0 45 1;
#X connect 45 0 46 0;
+#X connect 47 0 30 0;
diff --git a/patches/morphology/help-thickening.pd b/patches/morphology/help-thickening.pd
index 4bb41ca..c428f74 100644
--- a/patches/morphology/help-thickening.pd
+++ b/patches/morphology/help-thickening.pd
@@ -2,7 +2,7 @@
#X obj 341 20 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
-1;
#X msg 196 92 loop \$1;
-#X obj 197 70 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 1
+#X obj 197 70 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 1
;
#X msg 453 93 open \$1;
#X obj 452 69 openpanel;
@@ -53,6 +53,7 @@
#X obj 64 550 pdp_or;
#X obj 152 560 pdp_xor;
#X obj 152 589 pdp_glx;
+#X obj 42 284 pdp_glx;
#X connect 0 0 9 0;
#X connect 1 0 10 0;
#X connect 2 0 1 0;
@@ -64,6 +65,7 @@
#X connect 8 0 6 0;
#X connect 9 0 10 0;
#X connect 10 0 39 0;
+#X connect 10 0 48 0;
#X connect 11 0 39 0;
#X connect 12 0 11 0;
#X connect 13 0 12 0;
@@ -79,6 +81,7 @@
#X connect 24 0 39 0;
#X connect 29 0 24 0;
#X connect 30 0 37 0;
+#X connect 30 0 48 0;
#X connect 32 0 36 2;
#X connect 33 0 36 3;
#X connect 36 0 45 1;
@@ -98,3 +101,4 @@
#X connect 45 0 38 0;
#X connect 45 0 46 0;
#X connect 46 0 47 0;
+#X connect 48 0 29 0;
diff --git a/patches/morphology/help-thinning.pd b/patches/morphology/help-thinning.pd
index 5b49da0..32df725 100644
--- a/patches/morphology/help-thinning.pd
+++ b/patches/morphology/help-thinning.pd
@@ -2,7 +2,7 @@
#X obj 341 20 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
-1;
#X msg 196 92 loop \$1;
-#X obj 197 70 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 1
+#X obj 197 70 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 1
;
#X msg 453 93 open \$1;
#X obj 452 69 openpanel;
@@ -51,6 +51,7 @@
#X obj 64 551 pdp_xor;
#X msg 327 471 kernel -1 -1 -1 -1 1 -1 1 1 1;
#X obj 326 444 loadbang;
+#X obj 43 282 pdp_glx;
#X connect 0 0 9 0;
#X connect 1 0 10 0;
#X connect 2 0 1 0;
@@ -62,6 +63,7 @@
#X connect 8 0 6 0;
#X connect 9 0 10 0;
#X connect 10 0 39 0;
+#X connect 10 0 46 0;
#X connect 11 0 39 0;
#X connect 12 0 11 0;
#X connect 13 0 12 0;
@@ -77,6 +79,7 @@
#X connect 24 0 39 0;
#X connect 29 0 24 0;
#X connect 30 0 37 0;
+#X connect 30 0 46 0;
#X connect 32 0 36 2;
#X connect 33 0 36 3;
#X connect 36 0 43 1;
@@ -93,3 +96,4 @@
#X connect 43 0 38 0;
#X connect 44 0 36 0;
#X connect 45 0 44 0;
+#X connect 46 0 29 0;
diff --git a/system/pidip.c b/system/pidip.c
index 21c8d2d..31c7c55 100644
--- a/system/pidip.c
+++ b/system/pidip.c
@@ -74,6 +74,9 @@ extern "C"
void pdp_theorout_tilde_setup(void);
void pdp_cropper_setup(void);
void pdp_background_setup(void);
+ void pdp_mapper_setup(void);
+ void pdp_theonice_tilde_setup(void);
+ void pdp_icedthe_tilde_setup(void);
#ifdef HAVE_PIDIP_FFMPEG
void pdp_ffmpeg_tilde_setup(void);
@@ -155,6 +158,9 @@ void pidip_setup(void){
pdp_theorout_tilde_setup();
pdp_cropper_setup();
pdp_background_setup();
+ pdp_mapper_setup();
+ pdp_theonice_tilde_setup();
+ pdp_icedthe_tilde_setup();
#ifdef HAVE_PIDIP_FFMPEG
pdp_ffmpeg_tilde_setup();