From a7bc7485b1a4d7e1b1a12ff593ca4ccb1d59e466 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Sat, 23 Feb 2008 01:51:37 +0000 Subject: configure.ac: Add checks for Flex/Yacc/Bison and other furry animals, for the new goom 2k4 based plugin Original commit message from CVS: 2008-02-23 Bastien Nocera * configure.ac: Add checks for Flex/Yacc/Bison and other furry animals, for the new goom 2k4 based plugin * gst/goom/*: Update to use goom 2k4, uses liboil to detect CPU optimisations (not working yet), move the old plugin to... * gst/goom2k1/*: ... here, in case somebody is sick enough Fixes #515073 --- gst/goom2k1/Makefile.am | 14 ++ gst/goom2k1/README | 5 + gst/goom2k1/filters.c | 606 ++++++++++++++++++++++++++++++++++++++++++++++ gst/goom2k1/filters.h | 83 +++++++ gst/goom2k1/filters_mmx.s | 130 ++++++++++ gst/goom2k1/goom.vcproj | 172 +++++++++++++ gst/goom2k1/goom_core.c | 412 +++++++++++++++++++++++++++++++ gst/goom2k1/goom_core.h | 43 ++++ gst/goom2k1/goom_tools.h | 24 ++ gst/goom2k1/graphic.c | 14 ++ gst/goom2k1/graphic.h | 23 ++ gst/goom2k1/gstgoom.c | 602 +++++++++++++++++++++++++++++++++++++++++++++ gst/goom2k1/gstgoom.h | 91 +++++++ gst/goom2k1/lines.c | 107 ++++++++ gst/goom2k1/lines.h | 16 ++ 15 files changed, 2342 insertions(+) create mode 100644 gst/goom2k1/Makefile.am create mode 100644 gst/goom2k1/README create mode 100644 gst/goom2k1/filters.c create mode 100644 gst/goom2k1/filters.h create mode 100644 gst/goom2k1/filters_mmx.s create mode 100644 gst/goom2k1/goom.vcproj create mode 100644 gst/goom2k1/goom_core.c create mode 100644 gst/goom2k1/goom_core.h create mode 100644 gst/goom2k1/goom_tools.h create mode 100644 gst/goom2k1/graphic.c create mode 100644 gst/goom2k1/graphic.h create mode 100644 gst/goom2k1/gstgoom.c create mode 100644 gst/goom2k1/gstgoom.h create mode 100644 gst/goom2k1/lines.c create mode 100644 gst/goom2k1/lines.h (limited to 'gst/goom2k1') diff --git a/gst/goom2k1/Makefile.am b/gst/goom2k1/Makefile.am new file mode 100644 index 00000000..4f4abb76 --- /dev/null +++ b/gst/goom2k1/Makefile.am @@ -0,0 +1,14 @@ +plugin_LTLIBRARIES = libgstgoom.la + +GOOM_FILTER_FILES = filters.c +GOOM_FILTER_CFLAGS = -UMMX -UUSE_ASM + +noinst_HEADERS = gstgoom.h filters.h goom_core.h goom_tools.h graphic.h lines.h + +libgstgoom_la_SOURCES = gstgoom.c goom_core.c $(GOOM_FILTER_FILES) graphic.c lines.c + +libgstgoom_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GOOM_FILTER_CFLAGS) +libgstgoom_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) $(LIBM) +libgstgoom_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +EXTRA_DIST = filters.c diff --git a/gst/goom2k1/README b/gst/goom2k1/README new file mode 100644 index 00000000..f12cf1b5 --- /dev/null +++ b/gst/goom2k1/README @@ -0,0 +1,5 @@ +The Goom plugin is based on the Goom visualization code from +the Goom homepage found at: +http://ios.free.fr/?page=projet&quoi=1 + +Like the original library so is the Goom plugin available under the LGPL license diff --git a/gst/goom2k1/filters.c b/gst/goom2k1/filters.c new file mode 100644 index 00000000..b898e89c --- /dev/null +++ b/gst/goom2k1/filters.c @@ -0,0 +1,606 @@ +/* filter.c version 0.7 + * contient les filtres applicable a un buffer + * creation : 01/10/2000 + * -ajout de sinFilter() + * -ajout de zoomFilter() + * -copie de zoomFilter() en zoomFilterRGB(), gérant les 3 couleurs + * -optimisation de sinFilter (utilisant une table de sin) + * -asm + * -optimisation de la procedure de génération du buffer de transformation + * la vitesse est maintenant comprise dans [0..128] au lieu de [0..100] +*/ + +/*#define _DEBUG_PIXEL; */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "filters.h" +#include "graphic.h" +#include "goom_tools.h" +#include "goom_core.h" +#include +#include +#include + +#ifdef MMX +#define USE_ASM +#endif +#ifdef POWERPC +#define USE_ASM +#endif + +#ifdef USE_ASM +#define EFFECT_DISTORS 4 +#else +#define EFFECT_DISTORS 10 +#endif + + +#ifdef USE_ASM + +#ifdef MMX +int mmx_zoom (); +guint32 mmx_zoom_size; +#endif /* MMX */ + +#ifdef POWERPC +extern unsigned int useAltivec; +extern void ppc_zoom (void); +extern void ppc_zoom_altivec (void); +unsigned int ppcsize4; +#endif /* PowerPC */ + + +unsigned int *coeffs = 0, *freecoeffs = 0; +guint32 *expix1 = 0; /* pointeur exporte vers p1 */ +guint32 *expix2 = 0; /* pointeur exporte vers p2 */ +guint32 zoom_width; +#endif /* ASM */ + + +static int firstTime = 1; +static int sintable[0xffff]; + +ZoomFilterData * +zoomFilterNew () +{ + ZoomFilterData *zf = malloc (sizeof (ZoomFilterData)); + + zf->vitesse = 128; + zf->pertedec = 8; + zf->sqrtperte = 16; + zf->middleX = 1; + zf->middleY = 1; + zf->reverse = 0; + zf->mode = WAVE_MODE; + zf->hPlaneEffect = 0; + zf->vPlaneEffect = 0; + zf->noisify = 0; + zf->buffsize = 0; + zf->res_x = 0; + zf->res_y = 0; + + zf->buffer = NULL; + zf->firedec = NULL; + + zf->wave = 0; + zf->wavesp = 0; + + return zf; +} + +/* retourne x>>s , en testant le signe de x */ +static inline int +ShiftRight (int x, const unsigned char s) +{ + if (x < 0) + return -(-x >> s); + else + return x >> s; +} + +/* + calculer px et py en fonction de x,y,middleX,middleY et theMode + px et py indique la nouvelle position (en sqrtperte ieme de pixel) + (valeur * 16) +*/ +void +calculatePXandPY (GoomData * gd, int x, int y, int *px, int *py) +{ + ZoomFilterData *zf = gd->zfd; + int middleX, middleY; + guint32 resoly = zf->res_y; + int vPlaneEffect = zf->vPlaneEffect; + int hPlaneEffect = zf->hPlaneEffect; + int vitesse = zf->vitesse; + char theMode = zf->mode; + + if (theMode == WATER_MODE) { + int wavesp = zf->wavesp; + int wave = zf->wave; + int yy = y + RAND (gd) % 4 + wave / 10; + + yy -= RAND (gd) % 4; + if (yy < 0) + yy = 0; + if (yy >= resoly) + yy = resoly - 1; + + *px = (x << 4) + zf->firedec[yy] + (wave / 10); + *py = (y << 4) + 132 - ((vitesse < 132) ? vitesse : 131); + + wavesp += RAND (gd) % 3; + wavesp -= RAND (gd) % 3; + if (wave < -10) + wavesp += 2; + if (wave > 10) + wavesp -= 2; + wave += (wavesp / 10) + RAND (gd) % 3; + wave -= RAND (gd) % 3; + if (wavesp > 100) + wavesp = (wavesp * 9) / 10; + + zf->wavesp = wavesp; + zf->wave = wave; + } else { + int dist; + register int vx, vy; + int fvitesse = vitesse << 4; + + middleX = zf->middleX; + middleY = zf->middleY; + + if (zf->noisify) { + x += RAND (gd) % zf->noisify; + x -= RAND (gd) % zf->noisify; + y += RAND (gd) % zf->noisify; + y -= RAND (gd) % zf->noisify; + } + + if (hPlaneEffect) + vx = ((x - middleX) << 9) + hPlaneEffect * (y - middleY); + else + vx = (x - middleX) << 9; + + if (vPlaneEffect) + vy = ((y - middleY) << 9) + vPlaneEffect * (x - middleX); + else + vy = (y - middleY) << 9; + + switch (theMode) { + case WAVE_MODE: + dist = + ShiftRight (vx, 9) * ShiftRight (vx, 9) + ShiftRight (vy, + 9) * ShiftRight (vy, 9); + fvitesse *= + 1024 + + ShiftRight (sintable[(unsigned short) (0xffff * dist * + EFFECT_DISTORS)], 6); + fvitesse /= 1024; + break; + case CRYSTAL_BALL_MODE: + dist = + ShiftRight (vx, 9) * ShiftRight (vx, 9) + ShiftRight (vy, + 9) * ShiftRight (vy, 9); + fvitesse += (dist * EFFECT_DISTORS >> 10); + break; + case AMULETTE_MODE: + dist = + ShiftRight (vx, 9) * ShiftRight (vx, 9) + ShiftRight (vy, + 9) * ShiftRight (vy, 9); + fvitesse -= (dist * EFFECT_DISTORS >> 4); + break; + case SCRUNCH_MODE: + dist = + ShiftRight (vx, 9) * ShiftRight (vx, 9) + ShiftRight (vy, + 9) * ShiftRight (vy, 9); + fvitesse -= (dist * EFFECT_DISTORS >> 9); + break; + } + if (vx < 0) + *px = (middleX << 4) - (-(vx * fvitesse) >> 16); + else + *px = (middleX << 4) + ((vx * fvitesse) >> 16); + if (vy < 0) + *py = (middleY << 4) - (-(vy * fvitesse) >> 16); + else + *py = (middleY << 4) + ((vy * fvitesse) >> 16); + } +} + +/*#define _DEBUG */ + +static inline void +setPixelRGB (Uint * buffer, Uint x, Uint y, Color c, + guint32 resolx, guint32 resoly) +{ +/* buffer[ y*WIDTH + x ] = (c.r<<16)|(c.v<<8)|c.b */ +#ifdef _DEBUG_PIXEL + if (x + y * resolx >= resolx * resoly) { + fprintf (stderr, "setPixel ERROR : hors du tableau... %i, %i\n", x, y); + /*exit (1) ; */ + } +#endif + +#ifdef USE_DGA + buffer[y * resolx + x] = (c.b << 16) | (c.v << 8) | c.r; +#else + buffer[y * resolx + x] = (c.r << 16) | (c.v << 8) | c.b; +#endif +} + + +static inline void +setPixelRGB_ (Uint * buffer, Uint x, Color c, guint32 resolx, guint32 resoly) +{ +#ifdef _DEBUG + if (x >= resolx * resoly) { + printf ("setPixel ERROR : hors du tableau... %i >= %i*%i (%i)\n", x, resolx, + resoly, resolx * resoly); + exit (1); + } +#endif + +#ifdef USE_DGA + buffer[x] = (c.b << 16) | (c.v << 8) | c.r; +#else + buffer[x] = (c.r << 16) | (c.v << 8) | c.b; +#endif +} + + + +static inline void +getPixelRGB (Uint * buffer, Uint x, Uint y, Color * c, + guint32 resolx, guint32 resoly) +{ + register unsigned char *tmp8; + +#ifdef _DEBUG + if (x + y * resolx >= resolx * resoly) { + printf ("getPixel ERROR : hors du tableau... %i, %i\n", x, y); + exit (1); + } +#endif + +#ifdef __BIG_ENDIAN__ + c->b = *(unsigned char *) (tmp8 = + (unsigned char *) (buffer + (x + y * resolx))); + c->r = *(unsigned char *) (++tmp8); + c->v = *(unsigned char *) (++tmp8); + c->b = *(unsigned char *) (++tmp8); + +#else + /* ATTENTION AU PETIT INDIEN */ + c->b = *(unsigned char *) (tmp8 = + (unsigned char *) (buffer + (x + y * resolx))); + c->v = *(unsigned char *) (++tmp8); + c->r = *(unsigned char *) (++tmp8); +/* *c = (Color) buffer[x+y*WIDTH] ; */ +#endif +} + + +static inline void +getPixelRGB_ (Uint * buffer, Uint x, Color * c, guint32 resolx, guint32 resoly) +{ + register unsigned char *tmp8; + +#ifdef _DEBUG + if (x >= resolx * resoly) { + printf ("getPixel ERROR : hors du tableau... %i\n", x); + exit (1); + } +#endif + +#ifdef __BIG_ENDIAN__ + c->b = *(unsigned char *) (tmp8 = (unsigned char *) (buffer + x)); + c->r = *(unsigned char *) (++tmp8); + c->v = *(unsigned char *) (++tmp8); + c->b = *(unsigned char *) (++tmp8); + +#else + /* ATTENTION AU PETIT INDIEN */ + tmp8 = (unsigned char *) (buffer + x); + c->b = *(unsigned char *) (tmp8++); + c->v = *(unsigned char *) (tmp8++); + c->r = *(unsigned char *) (tmp8); +/* *c = (Color) buffer[x+y*WIDTH] ; */ +#endif +} + +static void +zoomFilterSetResolution (GoomData * gd, ZoomFilterData * zf) +{ + unsigned short us; + + if (zf->buffsize >= gd->buffsize) { + zf->res_x = gd->resolx; + zf->res_y = gd->resoly; + zf->middleX = gd->resolx / 2; + zf->middleY = gd->resoly - 1; + + return; + } +#ifndef USE_ASM + if (zf->buffer) + free (zf->buffer); + zf->buffer = 0; +#else + if (coeffs) + free (freecoeffs); + coeffs = 0; +#endif + zf->middleX = gd->resolx / 2; + zf->middleY = gd->resoly - 1; + zf->res_x = gd->resolx; + zf->res_y = gd->resoly; + + if (zf->firedec) + free (zf->firedec); + zf->firedec = 0; + + zf->buffsize = gd->resolx * gd->resoly * sizeof (unsigned int); + +#ifdef USE_ASM + freecoeffs = (unsigned int *) + malloc (resx * resy * 2 * sizeof (unsigned int) + 128); + coeffs = (guint32 *) ((1 + ((unsigned int) (freecoeffs)) / 128) * 128); + +#else + zf->buffer = calloc (sizeof (guint32), zf->buffsize * 5); + zf->pos10 = zf->buffer; + zf->c[0] = zf->pos10 + zf->buffsize; + zf->c[1] = zf->c[0] + zf->buffsize; + zf->c[2] = zf->c[1] + zf->buffsize; + zf->c[3] = zf->c[2] + zf->buffsize; +#endif + zf->firedec = (int *) malloc (zf->res_y * sizeof (int)); + + if (firstTime) { + firstTime = 0; + + /* generation d'une table de sinus */ + for (us = 0; us < 0xffff; us++) { + sintable[us] = (int) (1024.0f * sin (us * 2 * 3.31415f / 0xffff)); + } + } + + { + int loopv; + + for (loopv = zf->res_y; loopv != 0;) { + int decc = 0; + int spdc = 0; + int accel = 0; + + loopv--; + zf->firedec[loopv] = decc; + decc += spdc / 10; + spdc += RAND (gd) % 3; + spdc -= RAND (gd) % 3; + + if (decc > 4) + spdc -= 1; + if (decc < -4) + spdc += 1; + + if (spdc > 30) + spdc = spdc - RAND (gd) % 3 + accel / 10; + if (spdc < -30) + spdc = spdc + RAND (gd) % 3 + accel / 10; + + if (decc > 8 && spdc > 1) + spdc -= RAND (gd) % 3 - 2; + + if (decc < -8 && spdc < -1) + spdc += RAND (gd) % 3 + 2; + + if (decc > 8 || decc < -8) + decc = decc * 8 / 9; + + accel += RAND (gd) % 2; + accel -= RAND (gd) % 2; + if (accel > 20) + accel -= 2; + if (accel < -20) + accel += 2; + } + } +} + +void +zoomFilterDestroy (ZoomFilterData * zf) +{ + if (zf) { + if (zf->firedec) + free (zf->firedec); + if (zf->buffer) + free (zf->buffer); + free (zf); + } +} + +/*===============================================================*/ +void +zoomFilterFastRGB (GoomData * goomdata, ZoomFilterData * zf, int zfd_update) +{ + guint32 prevX = goomdata->resolx; + guint32 prevY = goomdata->resoly; + + guint32 *pix1 = goomdata->p1; + guint32 *pix2 = goomdata->p2; + unsigned int *pos10; + unsigned int **c; + + Uint x, y; + +/* static unsigned int prevX = 0, prevY = 0; */ + +#ifdef USE_ASM + expix1 = pix1; + expix2 = pix2; +#else + Color couleur; + Color col1, col2, col3, col4; + Uint position; +#endif + + if ((goomdata->resolx != zf->res_x) || (goomdata->resoly != zf->res_y)) { + zoomFilterSetResolution (goomdata, zf); + } + + pos10 = zf->pos10; + c = zf->c; + + if (zfd_update) { + guchar sqrtperte = zf->sqrtperte; + gint start_y = 0; + + if (zf->reverse) + zf->vitesse = 256 - zf->vitesse; + + /* generation du buffer */ + for (y = 0; y < zf->res_y; y++) { + gint y_16 = y << 4; + gint max_px = (prevX - 1) * sqrtperte; + gint max_py = (prevY - 1) * sqrtperte; + + for (x = 0; x < zf->res_x; x++) { + gint px, py; + guchar coefv, coefh; + + /* calculer px et py en fonction de */ + /* x,y,middleX,middleY et theMode */ + calculatePXandPY (goomdata, x, y, &px, &py); + + if ((px == x << 4) && (py == y_16)) + py += 8; + + if ((py < 0) || (px < 0) || (py >= max_py) || (px >= max_px)) { +#ifdef USE_ASM + coeffs[(y * prevX + x) * 2] = 0; + coeffs[(y * prevX + x) * 2 + 1] = 0; +#else + pos10[start_y + x] = 0; + c[0][start_y + x] = 0; + c[1][start_y + x] = 0; + c[2][start_y + x] = 0; + c[3][start_y + x] = 0; +#endif + } else { + int npx10; + int npy10; + int pos; + + npx10 = (px / sqrtperte); + npy10 = (py / sqrtperte); + +/* if (npx10 >= prevX) fprintf(stderr,"error npx:%d",npx10); + if (npy10 >= prevY) fprintf(stderr,"error npy:%d",npy10); +*/ + coefh = px % sqrtperte; + coefv = py % sqrtperte; +#ifdef USE_ASM + pos = (y * prevX + x) * 2; + coeffs[pos] = (npx10 + prevX * npy10) * 4; + + if (!(coefh || coefv)) + coeffs[pos + 1] = (sqrtperte * sqrtperte - 1); + else + coeffs[pos + 1] = ((sqrtperte - coefh) * (sqrtperte - coefv)); + + coeffs[pos + 1] |= (coefh * (sqrtperte - coefv)) << 8; + coeffs[pos + 1] |= ((sqrtperte - coefh) * coefv) << 16; + coeffs[pos + 1] |= (coefh * coefv) << 24; +#else + pos = start_y + x; + pos10[pos] = npx10 + prevX * npy10; + + if (!(coefh || coefv)) + c[0][pos] = sqrtperte * sqrtperte - 1; + else + c[0][pos] = (sqrtperte - coefh) * (sqrtperte - coefv); + + c[1][pos] = coefh * (sqrtperte - coefv); + c[2][pos] = (sqrtperte - coefh) * coefv; + c[3][pos] = coefh * coefv; +#endif + } + } + /* Advance start of line index */ + start_y += prevX; + } + } +#ifdef USE_ASM +#ifdef MMX + zoom_width = prevX; + mmx_zoom_size = prevX * prevY; + mmx_zoom (); +#endif + +#ifdef POWERPC + zoom_width = prevX; + if (useAltivec) { + ppcsize4 = ((unsigned int) (prevX * prevY)) / 4; + ppc_zoom_altivec (); + } else { + ppcsize4 = ((unsigned int) (prevX * prevY)); + ppc_zoom (); + } +#endif +#else + for (position = 0; position < prevX * prevY; position++) { + getPixelRGB_ (pix1, pos10[position], &col1, goomdata->resolx, + goomdata->resoly); + getPixelRGB_ (pix1, pos10[position] + 1, &col2, goomdata->resolx, + goomdata->resoly); + getPixelRGB_ (pix1, pos10[position] + prevX, &col3, goomdata->resolx, + goomdata->resoly); + getPixelRGB_ (pix1, pos10[position] + prevX + 1, &col4, goomdata->resolx, + goomdata->resoly); + + couleur.r = col1.r * c[0][position] + + col2.r * c[1][position] + + col3.r * c[2][position] + + col4.r * c[3][position]; + couleur.r >>= zf->pertedec; + + couleur.v = col1.v * c[0][position] + + col2.v * c[1][position] + + col3.v * c[2][position] + + col4.v * c[3][position]; + couleur.v >>= zf->pertedec; + + couleur.b = col1.b * c[0][position] + + col2.b * c[1][position] + + col3.b * c[2][position] + + col4.b * c[3][position]; + couleur.b >>= zf->pertedec; + + setPixelRGB_ (pix2, position, couleur, goomdata->resolx, goomdata->resoly); + } +#endif +} + + +void +pointFilter (GoomData * goomdata, Color c, + float t1, float t2, float t3, float t4, Uint cycle) +{ + Uint *pix1 = goomdata->p1; + ZoomFilterData *zf = goomdata->zfd; + Uint x = (Uint) (zf->middleX + (int) (t1 * cos ((float) cycle / t3))); + Uint y = (Uint) (zf->middleY + (int) (t2 * sin ((float) cycle / t4))); + + if ((x > 1) && (y > 1) && (x < goomdata->resolx - 2) + && (y < goomdata->resoly - 2)) { + setPixelRGB (pix1, x + 1, y, c, goomdata->resolx, goomdata->resoly); + setPixelRGB (pix1, x, y + 1, c, goomdata->resolx, goomdata->resoly); + setPixelRGB (pix1, x + 1, y + 1, WHITE, goomdata->resolx, goomdata->resoly); + setPixelRGB (pix1, x + 2, y + 1, c, goomdata->resolx, goomdata->resoly); + setPixelRGB (pix1, x + 1, y + 2, c, goomdata->resolx, goomdata->resoly); + } +} diff --git a/gst/goom2k1/filters.h b/gst/goom2k1/filters.h new file mode 100644 index 00000000..65eb3e25 --- /dev/null +++ b/gst/goom2k1/filters.h @@ -0,0 +1,83 @@ +#ifndef FILTERS_H +#define FILTERS_H + +#include + +#include "graphic.h" +#include "goom_core.h" + +#define NORMAL_MODE 0 +#define WAVE_MODE 1 +#define CRYSTAL_BALL_MODE 2 +#define SCRUNCH_MODE 3 +#define AMULETTE_MODE 4 +#define WATER_MODE 5 + +struct ZoomFilterData +{ + int vitesse; + unsigned char pertedec; + unsigned char sqrtperte; + int middleX; + int middleY; + char reverse; + char mode; + /** @since June 2001 */ + int hPlaneEffect; + int vPlaneEffect; + char noisify; + + guint32 res_x; + guint32 res_y; + guint32 buffsize; + + guint32 *buffer; + guint32 *pos10; + guint32 *c[4]; + int *firedec; + + int wave; + int wavesp; +}; + +void pointFilter(GoomData *goomdata, Color c, + float t1, float t2, float t3, float t4, + guint32 cycle); + +/* filtre de zoom : + le contenu de pix1 est copie dans pix2, avec l'effet appliqué + midx et midy represente le centre du zoom + +void zoomFilter(Uint *pix1, Uint *pix2, Uint middleX, Uint middleY); +void zoomFilterRGB(Uint *pix1, +Uint *pix2, +Uint middleX, +Uint middleY); +*/ + +ZoomFilterData *zoomFilterNew (); +void zoomFilterDestroy (ZoomFilterData *zf); +void zoomFilterFastRGB (GoomData *goomdata, ZoomFilterData *zf, + int zfd_update); + +/* filtre sin : + le contenu de pix1 est copie dans pix2, avec l'effet appliqué + cycle est la variable de temps. + mode vaut SIN_MUL ou SIN_ADD + rate est le pourcentage de l'effet appliqué + lenght : la longueur d'onde (1..10) [5] + speed : la vitesse (1..100) [10] +*/ +/* +void sinFilter(Uint *pix1,Uint *pix2, + Uint cycle, + Uint mode, + Uint rate, + char lenght, + Uint speed); +*/ + +#define SIN_MUL 1 +#define SIN_ADD 2 + +#endif diff --git a/gst/goom2k1/filters_mmx.s b/gst/goom2k1/filters_mmx.s new file mode 100644 index 00000000..337de56c --- /dev/null +++ b/gst/goom2k1/filters_mmx.s @@ -0,0 +1,130 @@ +;// file : mmx_zoom.s +;// author : JC Hoelt +;// +;// history +;// 07/01/2001 : Changing FEMMS to EMMS : slower... but run on intel machines +;// 03/01/2001 : WIDTH and HEIGHT are now variable +;// 28/12/2000 : adding comments to the code, suppress some useless lines +;// 27/12/2000 : reducing memory access... improving performance by 20% +;// coefficients are now on 1 byte +;// 22/12/2000 : Changing data structure +;// 16/12/2000 : AT&T version +;// 14/12/2000 : unrolling loop +;// 12/12/2000 : 64 bits memory access + + +.data + +thezero: + .long 0x00000000 + .long 0x00000000 + + +.text + +.globl mmx_zoom ;// name of the function to call by C program +.extern coeffs ;// the transformation buffer +.extern expix1,expix2 ;// the source and destination buffer +.extern mmx_zoom_size, zoom_width ;// size of the buffers + +.align 16 +mmx_zoom: + +push %ebp +push %esp + +;// initialisation du mm7 à zero +movq (thezero), %mm7 + +movl zoom_width, %eax +movl $4, %ebx +mull %ebx +movl %eax, %ebp + +movl (coeffs), %eax +movl (expix1), %edx +movl (expix2), %ebx +movl $10, %edi +movl mmx_zoom_size, %ecx + +.while: + ;// esi <- nouvelle position + movl (%eax), %esi + leal (%edx, %esi), %esi + + ;// recuperation des deux premiers pixels dans mm0 et mm1 + movq (%esi), %mm0 /* b1-v1-r1-a1-b2-v2-r2-a2 */ + movq %mm0, %mm1 /* b1-v1-r1-a1-b2-v2-r2-a2 */ + + ;// recuperation des 4 coefficients + movd 4(%eax), %mm6 /* ??-??-??-??-c4-c3-c2-c1 */ + ;// depackage du premier pixel + punpcklbw %mm7, %mm0 /* 00-b2-00-v2-00-r2-00-a2 */ + + movq %mm6, %mm5 /* ??-??-??-??-c4-c3-c2-c1 */ + ;// depackage du 2ieme pixel + punpckhbw %mm7, %mm1 /* 00-b1-00-v1-00-r1-00-a1 */ + + ;// extraction des coefficients... + punpcklbw %mm5, %mm6 /* c4-c4-c3-c3-c2-c2-c1-c1 */ + movq %mm6, %mm4 /* c4-c4-c3-c3-c2-c2-c1-c1 */ + movq %mm6, %mm5 /* c4-c4-c3-c3-c2-c2-c1-c1 */ + + punpcklbw %mm5, %mm6 /* c2-c2-c2-c2-c1-c1-c1-c1 */ + punpckhbw %mm5, %mm4 /* c4-c4-c4-c4-c3-c3-c3-c3 */ + + movq %mm6, %mm3 /* c2-c2-c2-c2-c1-c1-c1-c1 */ + punpcklbw %mm7, %mm6 /* 00-c1-00-c1-00-c1-00-c1 */ + punpckhbw %mm7, %mm3 /* 00-c2-00-c2-00-c2-00-c2 */ + + ;// multiplication des pixels par les coefficients + pmullw %mm6, %mm0 /* c1*b2-c1*v2-c1*r2-c1*a2 */ + pmullw %mm3, %mm1 /* c2*b1-c2*v1-c2*r1-c2*a1 */ + paddw %mm1, %mm0 + + ;// ...extraction des 2 derniers coefficients + movq %mm4, %mm5 /* c4-c4-c4-c4-c3-c3-c3-c3 */ + punpcklbw %mm7, %mm4 /* 00-c3-00-c3-00-c3-00-c3 */ + punpckhbw %mm7, %mm5 /* 00-c4-00-c4-00-c4-00-c4 */ + + ;// recuperation des 2 derniers pixels + movq (%esi,%ebp), %mm1 + movq %mm1, %mm2 + + ;// depackage des pixels + punpcklbw %mm7, %mm1 + punpckhbw %mm7, %mm2 + + ;// multiplication pas les coeffs + pmullw %mm4, %mm1 + pmullw %mm5, %mm2 + + ;// ajout des valeurs obtenues à la valeur finale + paddw %mm1, %mm0 + paddw %mm2, %mm0 + + ;// division par 256 = 16+16+16+16, puis repackage du pixel final + psrlw $8, %mm0 + packuswb %mm7, %mm0 + + ;// passage au suivant + leal 8(%eax), %eax + + decl %ecx + ;// enregistrement du resultat + movd %mm0, (%ebx) + leal 4(%ebx), %ebx + + ;// test de fin du tantque + cmpl $0, %ecx ;// 400x300 + +jz .fin_while +jmp .while + +.fin_while: +emms + +pop %esp +pop %ebp + +ret ;//The End diff --git a/gst/goom2k1/goom.vcproj b/gst/goom2k1/goom.vcproj new file mode 100644 index 00000000..7d4c1efa --- /dev/null +++ b/gst/goom2k1/goom.vcproj @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gst/goom2k1/goom_core.c b/gst/goom2k1/goom_core.c new file mode 100644 index 00000000..d66ffe25 --- /dev/null +++ b/gst/goom2k1/goom_core.c @@ -0,0 +1,412 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include + +#include +#include +#include "goom_core.h" +#include "goom_tools.h" +#include "filters.h" +#include "lines.h" + +/*#define VERBOSE */ + +#ifdef VERBOSE +#include +#endif + +#define STOP_SPEED 128 + +void +goom_init (GoomData * goomdata, guint32 resx, guint32 resy) +{ +#ifdef VERBOSE + printf ("GOOM: init (%d, %d);\n", resx, resy); +#endif + goomdata->resolx = 0; + goomdata->resoly = 0; + goomdata->buffsize = 0; + + goomdata->pixel = NULL; + goomdata->back = NULL; + goomdata->p1 = NULL; + goomdata->p2 = NULL; + + goom_set_resolution (goomdata, resx, resy); + RAND_INIT (goomdata, GPOINTER_TO_INT (goomdata->pixel)); + goomdata->cycle = 0; + + + goomdata->goomlimit = 2; /* sensibilité du goom */ + goomdata->zfd = zoomFilterNew (); + goomdata->lockvar = 0; /* pour empecher de nouveaux changements */ + goomdata->goomvar = 0; /* boucle des gooms */ + goomdata->totalgoom = 0; /* nombre de gooms par seconds */ + goomdata->agoom = 0; /* un goom a eu lieu.. */ + goomdata->loopvar = 0; /* mouvement des points */ + goomdata->speedvar = 0; /* vitesse des particules */ + goomdata->lineMode = 0; /* l'effet lineaire a dessiner */ +} + +void +goom_set_resolution (GoomData * goomdata, guint32 resx, guint32 resy) +{ + guint32 buffsize = resx * resy; + + if ((goomdata->resolx == resx) && (goomdata->resoly == resy)) + return; + + if (goomdata->buffsize < buffsize) { + if (goomdata->pixel) + free (goomdata->pixel); + if (goomdata->back) + free (goomdata->back); + goomdata->pixel = (guint32 *) malloc (buffsize * sizeof (guint32) + 128); + goomdata->back = (guint32 *) malloc (buffsize * sizeof (guint32) + 128); + goomdata->buffsize = buffsize; + + goomdata->p1 = + (void *) (((unsigned long) goomdata->pixel + 0x7f) & (~0x7f)); + goomdata->p2 = (void *) (((unsigned long) goomdata->back + 0x7f) & (~0x7f)); + } + + goomdata->resolx = resx; + goomdata->resoly = resy; + + memset (goomdata->pixel, 0, buffsize * sizeof (guint32) + 128); + memset (goomdata->back, 0, buffsize * sizeof (guint32) + 128); +} + +guint32 * +goom_update (GoomData * goomdata, gint16 data[2][512]) +{ + guint32 *return_val; + guint32 pointWidth; + guint32 pointHeight; + int incvar; /* volume du son */ + int accelvar; /* acceleration des particules */ + int i; + float largfactor; /* elargissement de l'intervalle d'évolution des points */ + int zfd_update = 0; + int resolx = goomdata->resolx; + int resoly = goomdata->resoly; + ZoomFilterData *pzfd = goomdata->zfd; + guint32 *tmp; + + /* test if the config has changed, update it if so */ + + pointWidth = (resolx * 2) / 5; + pointHeight = (resoly * 2) / 5; + + /* ! etude du signal ... */ + incvar = 0; + for (i = 0; i < 512; i++) { + if (incvar < data[0][i]) + incvar = data[0][i]; + } + + accelvar = incvar / 5000; + if (goomdata->speedvar > 5) { + accelvar--; + if (goomdata->speedvar > 20) + accelvar--; + if (goomdata->speedvar > 40) + goomdata->speedvar = 40; + } + accelvar--; + goomdata->speedvar += accelvar; + + if (goomdata->speedvar < 0) + goomdata->speedvar = 0; + if (goomdata->speedvar > 40) + goomdata->speedvar = 40; + + + /* ! calcul du deplacement des petits points ... */ + + largfactor = + ((float) goomdata->speedvar / 40.0f + (float) incvar / 50000.0f) / 1.5f; + if (largfactor > 1.5f) + largfactor = 1.5f; + + for (i = 1; i * 15 <= goomdata->speedvar + 15; i++) { + goomdata->loopvar += goomdata->speedvar + 1; + + pointFilter (goomdata, + YELLOW, + ((pointWidth - 6.0f) * largfactor + 5.0f), + ((pointHeight - 6.0f) * largfactor + 5.0f), + i * 152.0f, 128.0f, goomdata->loopvar + i * 2032); + pointFilter (goomdata, ORANGE, + ((pointWidth / 2) * largfactor) / i + 10.0f * i, + ((pointHeight / 2) * largfactor) / i + 10.0f * i, + 96.0f, i * 80.0f, goomdata->loopvar / i); + pointFilter (goomdata, VIOLET, + ((pointHeight / 3 + 5.0f) * largfactor) / i + 10.0f * i, + ((pointHeight / 3 + 5.0f) * largfactor) / i + 10.0f * i, + i + 122.0f, 134.0f, goomdata->loopvar / i); + pointFilter (goomdata, BLACK, + ((pointHeight / 3) * largfactor + 20.0f), + ((pointHeight / 3) * largfactor + 20.0f), + 58.0f, i * 66.0f, goomdata->loopvar / i); + pointFilter (goomdata, WHITE, + (pointHeight * largfactor + 10.0f * i) / i, + (pointHeight * largfactor + 10.0f * i) / i, + 66.0f, 74.0f, goomdata->loopvar + i * 500); + } + + /* diminuer de 1 le temps de lockage */ + /* note pour ceux qui n'ont pas suivis : le lockvar permet d'empecher un */ + /* changement d'etat du plugins juste apres un autre changement d'etat. oki ? */ + if (--goomdata->lockvar < 0) + goomdata->lockvar = 0; + + /* temps du goom */ + if (--goomdata->agoom < 0) + goomdata->agoom = 0; + + /* on verifie qu'il ne se pas un truc interressant avec le son. */ + if ((accelvar > goomdata->goomlimit) || (accelvar < -goomdata->goomlimit)) { + /* UN GOOM !!! YAHOO ! */ + goomdata->totalgoom++; + goomdata->agoom = 20; /* mais pdt 20 cycles, il n'y en aura plus. */ + goomdata->lineMode = (goomdata->lineMode + 1) % 20; /* Tous les 10 gooms on change de mode lineaire */ + + /* changement eventuel de mode */ + switch (iRAND (goomdata, 10)) { + case 0: + case 1: + case 2: + pzfd->mode = WAVE_MODE; + pzfd->vitesse = STOP_SPEED - 1; + pzfd->reverse = 0; + break; + case 3: + case 4: + pzfd->mode = CRYSTAL_BALL_MODE; + break; + case 5: + pzfd->mode = AMULETTE_MODE; + break; + case 6: + pzfd->mode = WATER_MODE; + break; + case 7: + pzfd->mode = SCRUNCH_MODE; + break; + default: + pzfd->mode = NORMAL_MODE; + } + } + + /* tout ceci ne sera fait qu'en cas de non-blocage */ + if (goomdata->lockvar == 0) { + /* reperage de goom (acceleration forte de l'acceleration du volume) */ + /* -> coup de boost de la vitesse si besoin.. */ + if ((accelvar > goomdata->goomlimit) || (accelvar < -goomdata->goomlimit)) { + goomdata->goomvar++; + /*if (goomvar % 1 == 0) */ + { + guint32 vtmp; + guint32 newvit; + + newvit = STOP_SPEED - goomdata->speedvar / 2; + /* retablir le zoom avant.. */ + if ((pzfd->reverse) && (!(goomdata->cycle % 12)) && (rand () % 3 == 0)) { + pzfd->reverse = 0; + pzfd->vitesse = STOP_SPEED - 2; + goomdata->lockvar = 50; + } + if (iRAND (goomdata, 10) == 0) { + pzfd->reverse = 1; + goomdata->lockvar = 100; + } + + /* changement de milieu.. */ + switch (iRAND (goomdata, 20)) { + case 0: + pzfd->middleY = resoly - 1; + pzfd->middleX = resolx / 2; + break; + case 1: + pzfd->middleX = resolx - 1; + break; + case 2: + pzfd->middleX = 1; + break; + default: + pzfd->middleY = resoly / 2; + pzfd->middleX = resolx / 2; + } + + if (pzfd->mode == WATER_MODE) { + pzfd->middleX = resolx / 2; + pzfd->middleY = resoly / 2; + } + + switch (vtmp = (iRAND (goomdata, 27))) { + case 0: + pzfd->vPlaneEffect = iRAND (goomdata, 3); + pzfd->vPlaneEffect -= iRAND (goomdata, 3); + pzfd->hPlaneEffect = iRAND (goomdata, 3); + pzfd->hPlaneEffect -= iRAND (goomdata, 3); + break; + case 3: + pzfd->vPlaneEffect = 0; + pzfd->hPlaneEffect = iRAND (goomdata, 8); + pzfd->hPlaneEffect -= iRAND (goomdata, 8); + break; + case 4: + case 5: + case 6: + case 7: + pzfd->vPlaneEffect = iRAND (goomdata, 5); + pzfd->vPlaneEffect -= iRAND (goomdata, 5); + pzfd->hPlaneEffect = -pzfd->vPlaneEffect; + break; + case 8: + pzfd->hPlaneEffect = 5 + iRAND (goomdata, 8); + pzfd->vPlaneEffect = -pzfd->hPlaneEffect; + break; + case 9: + pzfd->vPlaneEffect = 5 + iRAND (goomdata, 8); + pzfd->hPlaneEffect = -pzfd->hPlaneEffect; + break; + case 13: + pzfd->hPlaneEffect = 0; + pzfd->vPlaneEffect = iRAND (goomdata, 10); + pzfd->vPlaneEffect -= iRAND (goomdata, 10); + break; + default: + if (vtmp < 10) { + pzfd->vPlaneEffect = 0; + pzfd->hPlaneEffect = 0; + } + } + + if (iRAND (goomdata, 3) != 0) + pzfd->noisify = 0; + else { + pzfd->noisify = iRAND (goomdata, 3) + 2; + goomdata->lockvar *= 3; + } + + if (pzfd->mode == AMULETTE_MODE) { + pzfd->vPlaneEffect = 0; + pzfd->hPlaneEffect = 0; + pzfd->noisify = 0; + } + + if ((pzfd->middleX == 1) || (pzfd->middleX == resolx - 1)) { + pzfd->vPlaneEffect = 0; + pzfd->hPlaneEffect = iRAND (goomdata, 2) ? 0 : pzfd->hPlaneEffect; + } + + if (newvit < pzfd->vitesse) { /* on accelere */ + zfd_update = 1; + if (((newvit < STOP_SPEED - 7) && + (pzfd->vitesse < STOP_SPEED - 6) && + (goomdata->cycle % 3 == 0)) || (iRAND (goomdata, 40) == 0)) { + pzfd->vitesse = STOP_SPEED - 1; + pzfd->reverse = !pzfd->reverse; + } else { + pzfd->vitesse = (newvit + pzfd->vitesse * 4) / 5; + } + goomdata->lockvar += 50; + } + } + } + /* mode mega-lent */ + if (iRAND (goomdata, 1000) == 0) { + /* + printf ("coup du sort...\n") ; + */ + zfd_update = 1; + pzfd->vitesse = STOP_SPEED - 1; + pzfd->pertedec = 8; + pzfd->sqrtperte = 16; + goomdata->goomvar = 1; + goomdata->lockvar += 70; + } + } + + /* gros frein si la musique est calme */ + if ((goomdata->speedvar < 1) && (pzfd->vitesse < STOP_SPEED - 4) + && (goomdata->cycle % 16 == 0)) { + /* + printf ("++slow part... %i\n", zfd.vitesse) ; + */ + zfd_update = 1; + pzfd->vitesse += 3; + pzfd->pertedec = 8; + pzfd->sqrtperte = 16; + goomdata->goomvar = 0; + /* + printf ("--slow part... %i\n", zfd.vitesse) ; + */ + } + + /* baisser regulierement la vitesse... */ + if ((goomdata->cycle % 73 == 0) && (pzfd->vitesse < STOP_SPEED - 5)) { + /* + printf ("slow down...\n") ; + */ + zfd_update = 1; + pzfd->vitesse++; + } + + /* arreter de decrémenter au bout d'un certain temps */ + if ((goomdata->cycle % 101 == 0) && (pzfd->pertedec == 7)) { + zfd_update = 1; + pzfd->pertedec = 8; + pzfd->sqrtperte = 16; + } + + /* Zoom here ! */ + zoomFilterFastRGB (goomdata, pzfd, zfd_update); + + /* si on est dans un goom : afficher les lignes... */ + if (goomdata->agoom > 15) + goom_lines (goomdata, data, ((pzfd->middleX == resolx / 2) + && (pzfd->middleY == resoly / 2) + && (pzfd->mode != WATER_MODE)) + ? (goomdata->lineMode / 10) : 0, goomdata->p2, goomdata->agoom - 15); + + return_val = goomdata->p2; + tmp = goomdata->p1; + goomdata->p1 = goomdata->p2; + goomdata->p2 = tmp; + + /* affichage et swappage des buffers.. */ + goomdata->cycle++; + + /* tous les 100 cycles : vérifier si le taux de goom est correct */ + /* et le modifier sinon.. */ + if (!(goomdata->cycle % 100)) { + if (goomdata->totalgoom > 15) { + /* printf ("less gooms\n") ; */ + goomdata->goomlimit++; + } else { + if ((goomdata->totalgoom == 0) && (goomdata->goomlimit > 1)) + goomdata->goomlimit--; + } + goomdata->totalgoom = 0; + } + return return_val; +} + +void +goom_close (GoomData * goomdata) +{ + if (goomdata->pixel != NULL) + free (goomdata->pixel); + if (goomdata->back != NULL) + free (goomdata->back); + if (goomdata->zfd != NULL) { + zoomFilterDestroy (goomdata->zfd); + goomdata->zfd = NULL; + } + goomdata->pixel = goomdata->back = NULL; + RAND_CLOSE (goomdata); +} diff --git a/gst/goom2k1/goom_core.h b/gst/goom2k1/goom_core.h new file mode 100644 index 00000000..1fbc0ee8 --- /dev/null +++ b/gst/goom2k1/goom_core.h @@ -0,0 +1,43 @@ +#ifndef _GOOMCORE_H +#define _GOOMCORE_H + +#include + +typedef struct ZoomFilterData ZoomFilterData; + +typedef struct +{ +/**-----------------------------------------------------** + ** SHARED DATA ** + **-----------------------------------------------------**/ + guint32 *pixel; + guint32 *back; + guint32 *p1, *p2; + guint32 cycle; + + guint32 resolx, resoly, buffsize; + + int lockvar; /* pour empecher de nouveaux changements */ + int goomvar; /* boucle des gooms */ + int totalgoom; /* nombre de gooms par seconds */ + int agoom; /* un goom a eu lieu.. */ + int loopvar; /* mouvement des points */ + int speedvar; /* vitesse des particules */ + int lineMode; /* l'effet lineaire a dessiner */ + char goomlimit; /* sensibilité du goom */ + + ZoomFilterData *zfd; + + /* Random table */ + gint *rand_tab; + guint rand_pos; +} GoomData; + +void goom_init (GoomData *goomdata, guint32 resx, guint32 resy); +void goom_set_resolution (GoomData *goomdata, guint32 resx, guint32 resy); + +guint32 *goom_update (GoomData *goomdata, gint16 data [2][512]); + +void goom_close (GoomData *goomdata); + +#endif diff --git a/gst/goom2k1/goom_tools.h b/gst/goom2k1/goom_tools.h new file mode 100644 index 00000000..6178dbaf --- /dev/null +++ b/gst/goom2k1/goom_tools.h @@ -0,0 +1,24 @@ +#ifndef _GOOMTOOLS_H +#define _GOOMTOOLS_H + +#define NB_RAND 0x10000 + +#define RAND_INIT(gd,i) \ + srand (i); \ + if (gd->rand_tab == NULL) \ + gd->rand_tab = g_malloc (NB_RAND * sizeof(gint)) ;\ + gd->rand_pos = 0; \ + while (gd->rand_pos < NB_RAND) \ + gd->rand_tab [gd->rand_pos++] = rand (); + +#define RAND(gd) \ + (gd->rand_tab[gd->rand_pos = ((gd->rand_pos + 1) % NB_RAND)]) + +#define RAND_CLOSE(gd) \ + g_free (gd->rand_tab); \ + gd->rand_tab = NULL; + +/*#define iRAND(i) ((guint32)((float)i * RAND()/RAND_MAX)) */ +#define iRAND(gd,i) (RAND(gd) % i) + +#endif diff --git a/gst/goom2k1/graphic.c b/gst/goom2k1/graphic.c new file mode 100644 index 00000000..c20f987d --- /dev/null +++ b/gst/goom2k1/graphic.c @@ -0,0 +1,14 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "graphic.h" + +const Color BLACK = { 0, 0, 0 }; +const Color WHITE = { 0xff, 0xff, 0xff }; +const Color RED = { 0xff, 0, 0 }; +const Color GREEN = { 0, 0xff, 0 }; +const Color BLUE = { 0, 0, 0xff }; +const Color YELLOW = { 0xff, 0xff, 0x33 }; +const Color ORANGE = { 0xff, 0xcc, 0x00 }; +const Color VIOLET = { 0x55, 0x00, 0xff }; diff --git a/gst/goom2k1/graphic.h b/gst/goom2k1/graphic.h new file mode 100644 index 00000000..4154d7fd --- /dev/null +++ b/gst/goom2k1/graphic.h @@ -0,0 +1,23 @@ +#ifndef GRAPHIC_H +#define GRAPHIC_H + +#include /* defines inline for better portability */ + +typedef unsigned int Uint; + +typedef struct +{ + unsigned short r,v,b; +} +Color; + +extern const Color BLACK; +extern const Color WHITE; +extern const Color RED; +extern const Color BLUE; +extern const Color GREEN; +extern const Color YELLOW; +extern const Color ORANGE; +extern const Color VIOLET; + +#endif /*GRAPHIC_H*/ diff --git a/gst/goom2k1/gstgoom.c b/gst/goom2k1/gstgoom.c new file mode 100644 index 00000000..812d4239 --- /dev/null +++ b/gst/goom2k1/gstgoom.c @@ -0,0 +1,602 @@ +/* gstgoom.c: implementation of goom drawing element + * Copyright (C) <2001> Richard Boulton + * (C) <2006> Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * SECTION:element-goom + * @see_also: synaesthesia + * + * + * + * Goom is an audio visualisation element. It creates warping structures + * based on the incomming audio signal. + * + * Example launch line + * + * + * gst-launch -v audiotestsrc ! goom2k1 ! ffmpegcolorspace ! xvimagesink + * + * + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "gstgoom.h" +#include +#include "goom_core.h" + +GST_DEBUG_CATEGORY_STATIC (goom_debug); +#define GST_CAT_DEFAULT goom_debug + +/* elementfactory information */ +static const GstElementDetails gst_goom_details = +GST_ELEMENT_DETAILS ("GOOM: what a GOOM! 2k1", + "Visualization", + "Takes frames of data and outputs video frames using the GOOM 2k1 filter", + "Wim Taymans "); + +/* signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + ARG_0 + /* FILL ME */ +}; + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN) + ); + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", /* the name of the pads */ + GST_PAD_SINK, /* type of the pad */ + GST_PAD_ALWAYS, /* ALWAYS/SOMETIMES */ + GST_STATIC_CAPS ("audio/x-raw-int, " + "endianness = (int) BYTE_ORDER, " + "signed = (boolean) TRUE, " + "width = (int) 16, " + "depth = (int) 16, " + "rate = (int) [ 8000, 96000 ], " "channels = (int) { 1, 2 }") + ); + + +static void gst_goom_class_init (GstGoomClass * klass); +static void gst_goom_base_init (GstGoomClass * klass); +static void gst_goom_init (GstGoom * goom); +static void gst_goom_finalize (GObject * object); + +static GstStateChangeReturn gst_goom_change_state (GstElement * element, + GstStateChange transition); + +static GstFlowReturn gst_goom_chain (GstPad * pad, GstBuffer * buffer); +static gboolean gst_goom_src_event (GstPad * pad, GstEvent * event); +static gboolean gst_goom_sink_event (GstPad * pad, GstEvent * event); + +static gboolean gst_goom_sink_setcaps (GstPad * pad, GstCaps * caps); +static gboolean gst_goom_src_setcaps (GstPad * pad, GstCaps * caps); + +static GstElementClass *parent_class = NULL; + +GType +gst_goom_get_type (void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (GstGoomClass), + (GBaseInitFunc) gst_goom_base_init, + NULL, + (GClassInitFunc) gst_goom_class_init, + NULL, + NULL, + sizeof (GstGoom), + 0, + (GInstanceInitFunc) gst_goom_init, + }; + + type = g_type_register_static (GST_TYPE_ELEMENT, "GstGoom", &info, 0); + } + return type; +} + +static void +gst_goom_base_init (GstGoomClass * klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_set_details (element_class, &gst_goom_details); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_template)); +} + +static void +gst_goom_class_init (GstGoomClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->finalize = gst_goom_finalize; + + gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_goom_change_state); + + GST_DEBUG_CATEGORY_INIT (goom_debug, "goom", 0, "goom visualisation element"); +} + +static void +gst_goom_init (GstGoom * goom) +{ + /* create the sink and src pads */ + goom->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink"); + gst_pad_set_chain_function (goom->sinkpad, + GST_DEBUG_FUNCPTR (gst_goom_chain)); + gst_pad_set_event_function (goom->sinkpad, + GST_DEBUG_FUNCPTR (gst_goom_sink_event)); + gst_pad_set_setcaps_function (goom->sinkpad, + GST_DEBUG_FUNCPTR (gst_goom_sink_setcaps)); + gst_element_add_pad (GST_ELEMENT (goom), goom->sinkpad); + + goom->srcpad = gst_pad_new_from_static_template (&src_template, "src"); + gst_pad_set_setcaps_function (goom->srcpad, + GST_DEBUG_FUNCPTR (gst_goom_src_setcaps)); + gst_pad_set_event_function (goom->srcpad, + GST_DEBUG_FUNCPTR (gst_goom_src_event)); + gst_element_add_pad (GST_ELEMENT (goom), goom->srcpad); + + goom->adapter = gst_adapter_new (); + + goom->width = 320; + goom->height = 200; + goom->fps_n = 25; /* desired frame rate */ + goom->fps_d = 1; /* desired frame rate */ + goom->channels = 0; + goom->rate = 0; + goom->duration = 0; + + goom_init (&(goom->goomdata), goom->width, goom->height); +} + +static void +gst_goom_finalize (GObject * object) +{ + GstGoom *goom = GST_GOOM (object); + + goom_close (&(goom->goomdata)); + + g_object_unref (goom->adapter); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_goom_reset (GstGoom * goom) +{ + goom->next_ts = -1; + gst_adapter_clear (goom->adapter); + gst_segment_init (&goom->segment, GST_FORMAT_UNDEFINED); + + GST_OBJECT_LOCK (goom); + goom->proportion = 1.0; + goom->earliest_time = -1; + GST_OBJECT_UNLOCK (goom); +} + +static gboolean +gst_goom_sink_setcaps (GstPad * pad, GstCaps * caps) +{ + GstGoom *goom; + GstStructure *structure; + gboolean res; + + goom = GST_GOOM (GST_PAD_PARENT (pad)); + + structure = gst_caps_get_structure (caps, 0); + + res = gst_structure_get_int (structure, "channels", &goom->channels); + res &= gst_structure_get_int (structure, "rate", &goom->rate); + + goom->bps = goom->channels * sizeof (gint16); + + return res; +} + +static gboolean +gst_goom_src_setcaps (GstPad * pad, GstCaps * caps) +{ + GstGoom *goom; + GstStructure *structure; + + goom = GST_GOOM (GST_PAD_PARENT (pad)); + + structure = gst_caps_get_structure (caps, 0); + + if (!gst_structure_get_int (structure, "width", &goom->width) || + !gst_structure_get_int (structure, "height", &goom->height) || + !gst_structure_get_fraction (structure, "framerate", &goom->fps_n, + &goom->fps_d)) + return FALSE; + + goom_set_resolution (&(goom->goomdata), goom->width, goom->height); + + /* size of the output buffer in bytes, depth is always 4 bytes */ + goom->outsize = goom->width * goom->height * 4; + goom->duration = + gst_util_uint64_scale_int (GST_SECOND, goom->fps_d, goom->fps_n); + goom->spf = gst_util_uint64_scale_int (goom->rate, goom->fps_d, goom->fps_n); + goom->bpf = goom->spf * goom->bps; + + GST_DEBUG_OBJECT (goom, "dimension %dx%d, framerate %d/%d, spf %d", + goom->width, goom->height, goom->fps_n, goom->fps_d, goom->spf); + + return TRUE; +} + +static gboolean +gst_goom_src_negotiate (GstGoom * goom) +{ + GstCaps *othercaps, *target, *intersect; + GstStructure *structure; + const GstCaps *templ; + + templ = gst_pad_get_pad_template_caps (goom->srcpad); + + GST_DEBUG_OBJECT (goom, "performing negotiation"); + + /* see what the peer can do */ + othercaps = gst_pad_peer_get_caps (goom->srcpad); + if (othercaps) { + intersect = gst_caps_intersect (othercaps, templ); + gst_caps_unref (othercaps); + + if (gst_caps_is_empty (intersect)) + goto no_format; + + target = gst_caps_copy_nth (intersect, 0); + gst_caps_unref (intersect); + } else { + target = gst_caps_ref ((GstCaps *) templ); + } + + structure = gst_caps_get_structure (target, 0); + gst_structure_fixate_field_nearest_int (structure, "width", 320); + gst_structure_fixate_field_nearest_int (structure, "height", 240); + gst_structure_fixate_field_nearest_fraction (structure, "framerate", 30, 1); + + gst_pad_set_caps (goom->srcpad, target); + gst_caps_unref (target); + + return TRUE; + +no_format: + { + gst_caps_unref (intersect); + return FALSE; + } +} + +static gboolean +gst_goom_src_event (GstPad * pad, GstEvent * event) +{ + gboolean res; + GstGoom *goom; + + goom = GST_GOOM (gst_pad_get_parent (pad)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_QOS: + { + gdouble proportion; + GstClockTimeDiff diff; + GstClockTime timestamp; + + gst_event_parse_qos (event, &proportion, &diff, ×tamp); + + /* save stuff for the _chain() function */ + GST_OBJECT_LOCK (goom); + goom->proportion = proportion; + if (diff >= 0) + /* we're late, this is a good estimate for next displayable + * frame (see part-qos.txt) */ + goom->earliest_time = timestamp + 2 * diff + goom->duration; + else + goom->earliest_time = timestamp + diff; + GST_OBJECT_UNLOCK (goom); + + res = gst_pad_push_event (goom->sinkpad, event); + break; + } + default: + res = gst_pad_push_event (goom->sinkpad, event); + break; + } + gst_object_unref (goom); + + return res; +} + +static gboolean +gst_goom_sink_event (GstPad * pad, GstEvent * event) +{ + gboolean res; + GstGoom *goom; + + goom = GST_GOOM (gst_pad_get_parent (pad)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_START: + res = gst_pad_push_event (goom->srcpad, event); + break; + case GST_EVENT_FLUSH_STOP: + gst_goom_reset (goom); + res = gst_pad_push_event (goom->srcpad, event); + break; + case GST_EVENT_NEWSEGMENT: + { + GstFormat format; + gdouble rate, arate; + gint64 start, stop, time; + gboolean update; + + /* the newsegment values are used to clip the input samples + * and to convert the incomming timestamps to running time so + * we can do QoS */ + gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, + &start, &stop, &time); + + /* now configure the values */ + gst_segment_set_newsegment_full (&goom->segment, update, + rate, arate, format, start, stop, time); + + res = gst_pad_push_event (goom->srcpad, event); + break; + } + default: + res = gst_pad_push_event (goom->srcpad, event); + break; + } + gst_object_unref (goom); + + return res; +} + +static GstFlowReturn +get_buffer (GstGoom * goom, GstBuffer ** outbuf) +{ + GstFlowReturn ret; + + if (GST_PAD_CAPS (goom->srcpad) == NULL) { + if (!gst_goom_src_negotiate (goom)) + return GST_FLOW_NOT_NEGOTIATED; + } + + GST_DEBUG_OBJECT (goom, "allocating output buffer with caps %" + GST_PTR_FORMAT, GST_PAD_CAPS (goom->srcpad)); + + ret = + gst_pad_alloc_buffer_and_set_caps (goom->srcpad, + GST_BUFFER_OFFSET_NONE, goom->outsize, + GST_PAD_CAPS (goom->srcpad), outbuf); + if (ret != GST_FLOW_OK) + return ret; + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_goom_chain (GstPad * pad, GstBuffer * buffer) +{ + GstGoom *goom; + GstFlowReturn ret; + GstBuffer *outbuf = NULL; + + goom = GST_GOOM (gst_pad_get_parent (pad)); + + /* If we don't have an output format yet, preallocate a buffer to try and + * set one */ + if (GST_PAD_CAPS (goom->srcpad) == NULL) { + ret = get_buffer (goom, &outbuf); + if (ret != GST_FLOW_OK) { + gst_buffer_unref (buffer); + goto beach; + } + } + + /* don't try to combine samples from discont buffer */ + if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) { + gst_adapter_clear (goom->adapter); + goom->next_ts = -1; + } + + /* Match timestamps from the incoming audio */ + if (GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE) + goom->next_ts = GST_BUFFER_TIMESTAMP (buffer); + + GST_DEBUG_OBJECT (goom, + "Input buffer has %d samples, time=%" G_GUINT64_FORMAT, + GST_BUFFER_SIZE (buffer) / goom->bps, GST_BUFFER_TIMESTAMP (buffer)); + + /* Collect samples until we have enough for an output frame */ + gst_adapter_push (goom->adapter, buffer); + + ret = GST_FLOW_OK; + + while (TRUE) { + const guint16 *data; + gboolean need_skip; + guchar *out_frame; + gint i; + guint avail, to_flush; + + avail = gst_adapter_available (goom->adapter); + GST_DEBUG_OBJECT (goom, "avail now %u", avail); + + /* we need GOOM_SAMPLES to get a meaningful result from goom. */ + if (avail < (GOOM_SAMPLES * goom->bps)) + break; + + /* we also need enough samples to produce one frame at least */ + if (avail < goom->bpf) + break; + + GST_DEBUG_OBJECT (goom, "processing buffer"); + + if (goom->next_ts != -1) { + gint64 qostime; + + qostime = gst_segment_to_running_time (&goom->segment, GST_FORMAT_TIME, + goom->next_ts); + + GST_OBJECT_LOCK (goom); + /* check for QoS, don't compute buffers that are known to be late */ + need_skip = goom->earliest_time != -1 && qostime <= goom->earliest_time; + GST_OBJECT_UNLOCK (goom); + + if (need_skip) { + GST_WARNING_OBJECT (goom, + "QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT, + GST_TIME_ARGS (qostime), GST_TIME_ARGS (goom->earliest_time)); + goto skip; + } + } + + /* get next GOOM_SAMPLES, we have at least this amount of samples */ + data = + (const guint16 *) gst_adapter_peek (goom->adapter, + GOOM_SAMPLES * goom->bps); + + if (goom->channels == 2) { + for (i = 0; i < GOOM_SAMPLES; i++) { + goom->datain[0][i] = *data++; + goom->datain[1][i] = *data++; + } + } else { + for (i = 0; i < GOOM_SAMPLES; i++) { + goom->datain[0][i] = *data; + goom->datain[1][i] = *data++; + } + } + + /* alloc a buffer if we don't have one yet, this happens + * when we pushed a buffer in this while loop before */ + if (outbuf == NULL) { + ret = get_buffer (goom, &outbuf); + if (ret != GST_FLOW_OK) { + goto beach; + } + } + + GST_BUFFER_TIMESTAMP (outbuf) = goom->next_ts; + GST_BUFFER_DURATION (outbuf) = goom->duration; + GST_BUFFER_SIZE (outbuf) = goom->outsize; + + out_frame = (guchar *) goom_update (&(goom->goomdata), goom->datain); + memcpy (GST_BUFFER_DATA (outbuf), out_frame, goom->outsize); + + GST_DEBUG ("Pushing frame with time=%" GST_TIME_FORMAT ", duration=%" + GST_TIME_FORMAT, GST_TIME_ARGS (goom->next_ts), + GST_TIME_ARGS (goom->duration)); + + ret = gst_pad_push (goom->srcpad, outbuf); + outbuf = NULL; + + skip: + /* interpollate next timestamp */ + if (goom->next_ts != -1) + goom->next_ts += goom->duration; + + /* Now flush the samples we needed for this frame, which might be more than + * the samples we used (GOOM_SAMPLES). */ + to_flush = goom->bpf; + + GST_DEBUG_OBJECT (goom, "finished frame, flushing %u bytes from input", + to_flush); + gst_adapter_flush (goom->adapter, to_flush); + + if (ret != GST_FLOW_OK) + break; + } + + if (outbuf != NULL) + gst_buffer_unref (outbuf); + +beach: + gst_object_unref (goom); + + return ret; +} + +static GstStateChangeReturn +gst_goom_change_state (GstElement * element, GstStateChange transition) +{ + GstGoom *goom = GST_GOOM (element); + GstStateChangeReturn ret; + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + gst_goom_reset (goom); + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_PAUSED_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + + return ret; +} + +static gboolean +plugin_init (GstPlugin * plugin) +{ + return gst_element_register (plugin, "goom2k1", GST_RANK_NONE, GST_TYPE_GOOM); +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "goom2k1", + "GOOM 2k1 visualization filter", + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/gst/goom2k1/gstgoom.h b/gst/goom2k1/gstgoom.h new file mode 100644 index 00000000..9c25f453 --- /dev/null +++ b/gst/goom2k1/gstgoom.h @@ -0,0 +1,91 @@ +/* gstgoom.c: implementation of goom drawing element + * Copyright (C) <2001> Richard Boulton + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_GOOM_H__ +#define __GST_GOOM_H__ + +G_BEGIN_DECLS + +#include +#include +#include "goom_core.h" + +#define GOOM_SAMPLES 512 + +#define GST_TYPE_GOOM (gst_goom_get_type()) +#define GST_GOOM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GOOM,GstGoom)) +#define GST_GOOM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GOOM,GstGoomClass)) +#define GST_IS_GOOM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GOOM)) +#define GST_IS_GOOM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GOOM)) + +typedef struct _GstGoom GstGoom; +typedef struct _GstGoomClass GstGoomClass; + +struct _GstGoom +{ + GstElement element; + + /* pads */ + GstPad *sinkpad, *srcpad; + GstAdapter *adapter; + + /* input tracking */ + gint rate; + gint channels; + guint bps; + + /* video state */ + gint fps_n; + gint fps_d; + gint width; + gint height; + GstClockTime duration; + guint outsize; + + /* samples per frame */ + guint spf; + /* bytes per frame */ + guint bpf; + + /* goom stuff */ + gint16 datain[2][GOOM_SAMPLES]; + GoomData goomdata; + + /* segment state */ + GstSegment segment; + + /* the timestamp of the next frame */ + GstClockTime next_ts; + + /* QoS stuff *//* with LOCK */ + gdouble proportion; + GstClockTime earliest_time; +}; + +struct _GstGoomClass +{ + GstElementClass parent_class; +}; + +GType gst_goom_get_type (void); + +G_END_DECLS + +#endif /* __GST_GOOM_H__ */ + diff --git a/gst/goom2k1/lines.c b/gst/goom2k1/lines.c new file mode 100644 index 00000000..3214e1db --- /dev/null +++ b/gst/goom2k1/lines.c @@ -0,0 +1,107 @@ +/* + * lines.c + * iTunesXPlugIn + * + * Created by guillaum on Tue Aug 14 2001. + * Copyright (c) 2001 __CompanyName__. All rights reserved. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "lines.h" +#include + +static inline unsigned char +lighten (unsigned char value, unsigned char power) +{ + unsigned char i; + + for (i = 0; i < power; i++) + value += (255 - value) / 5; + return value; +} + +void +goom_lines (GoomData * goomdata, gint16 data[2][512], unsigned int ID, + unsigned int *p, guint32 power) +{ + guint32 color1; + guint32 color2; + guint32 resolx = goomdata->resolx; + guint32 resoly = goomdata->resoly; + unsigned char *color = 1 + (unsigned char *) &color1; + + switch (ID) { + case 0: /* Horizontal stereo lines */ + { + color1 = 0x0000AA00; + color2 = 0x00AA0000; + break; + } + + case 1: /* Stereo circles */ + { + color1 = 0x00AA33DD; + color2 = 0x00AA33DD; + break; + } + } + *color = lighten (*color, power); + color++; + *color = lighten (*color, power); + color++; + *color = lighten (*color, power); + color = 1 + (unsigned char *) &color2; + *color = lighten (*color, power); + color++; + *color = lighten (*color, power); + color++; + *color = lighten (*color, power); + + switch (ID) { + case 0: /* Horizontal stereo lines */ + { + unsigned int i; + + for (i = 0; i < 512; i++) { + guint32 plot; + + plot = i * resolx / 512 + (resoly / 4 + data[0][i] / 1600) * resolx; + p[plot] = color1; + p[plot + 1] = color1; + plot = i * resolx / 512 + (resoly * 3 / 4 - data[1][i] / 1600) * resolx; + p[plot] = color2; + p[plot + 1] = color2; + } + break; + } + + case 1: /* Stereo circles */ + { + float z; + unsigned int monX = resolx / 2; + float monY = resoly / 4; + float monY2 = resoly / 2; + + for (z = 0; z < 6.2832f; z += 1.0f / monY) { + /* float offset1 = 128+data[1][(unsigned int)(z*81.33f)])/200000; */ + p[monX + (unsigned int) ((monY + ((float) resoly) * (128 + + data[1][(unsigned int) (z * 81.33f)]) / 200000) * + cos (z) + resolx * (unsigned int) (monY2 + (monY + + ((float) resoly) * (128 + + data[1][(unsigned int) (z * 81.33f)]) / 400000) * + sin (z)))] = color1; + p[monX + (unsigned int) ((monY - ((float) resoly) * (128 + + data[0][(unsigned int) (z * 81.33f)]) / 200000) * + cos (z) + resolx * (unsigned int) (monY2 + (monY - + ((float) resoly) * (128 + + data[0][(unsigned int) (z * 81.33f)]) / 400000) * + sin (z)))] = color2; + } + break; + } + } +} diff --git a/gst/goom2k1/lines.h b/gst/goom2k1/lines.h new file mode 100644 index 00000000..548f339a --- /dev/null +++ b/gst/goom2k1/lines.h @@ -0,0 +1,16 @@ +/* + * lines.h + * iGoom + * + * Created by guillaum on Tue Aug 14 2001. + * Copyright (c) 2001 ios. All rights reserved. + * + */ +#include + +#include "graphic.h" +#include "goom_core.h" + +void goom_lines(GoomData *goomdata, gint16 data [2][512], unsigned int ID,unsigned int* p, guint32 power); + + -- cgit