From 8f93753160c914d40e292bc3757fac168b1cb17a Mon Sep 17 00:00:00 2001 From: Richard Boulton Date: Fri, 1 Mar 2002 14:31:12 +0000 Subject: [PATCH] Initial rough version of new synaesthesia plugin. Original commit message from CVS: Initial rough version of new synaesthesia plugin. Works like goom: reads audio in, and outputs raw video. It currently works for a short time, and then freezes: I've no idea why. But at least it works a little. ;-) --- gst/synaesthesia/Makefile.am | 12 +- gst/synaesthesia/README | 13 +- gst/synaesthesia/core.c | 408 ------------------------ gst/synaesthesia/core.h | 38 --- gst/synaesthesia/gstsynaesthesia.c | 414 ++++++++++++++---------- gst/synaesthesia/gstsynaesthesia.h | 72 ----- gst/synaesthesia/synaescope.c | 486 +++++++++++++++++++++++++++++ gst/synaesthesia/synaescope.h | 10 + 8 files changed, 752 insertions(+), 701 deletions(-) delete mode 100644 gst/synaesthesia/core.c delete mode 100644 gst/synaesthesia/core.h delete mode 100644 gst/synaesthesia/gstsynaesthesia.h create mode 100644 gst/synaesthesia/synaescope.c create mode 100644 gst/synaesthesia/synaescope.h diff --git a/gst/synaesthesia/Makefile.am b/gst/synaesthesia/Makefile.am index a4af34e6df..9e86bdf8e8 100644 --- a/gst/synaesthesia/Makefile.am +++ b/gst/synaesthesia/Makefile.am @@ -2,11 +2,11 @@ plugindir = $(libdir)/gst plugin_LTLIBRARIES = libgstsynaesthesia.la -libgstsynaesthesia_la_SOURCES = core.c gstsynaesthesia.c -libgstsynaesthesia_la_CFLAGS = $(GST_CFLAGS) $(GTK_CFLAGS) -libgstsynaesthesia_la_LIBADD = $(GST_LIBS) $(GTK_LIBS) +libgstsynaesthesia_la_SOURCES = gstsynaesthesia.c synaescope.c + +noinst_HEADERS = synaescope.h + +libgstsynaesthesia_la_CFLAGS = -O2 -ffast-math $(GST_CFLAGS) +libgstsynaesthesia_la_LIBADD = $(GST_LIBS) libgstsynaesthesia_la_LDFLAGS = @GST_PLUGIN_LDFLAGS@ -noinst_HEADERS = core.h gstsynaesthesia.h - -EXTRA_DIST = README README-syna diff --git a/gst/synaesthesia/README b/gst/synaesthesia/README index a83b615abb..1983672c2b 100644 --- a/gst/synaesthesia/README +++ b/gst/synaesthesia/README @@ -1,6 +1,7 @@ -This is a nifty visualization based on synaesthesia-2.0 (see README-syna). -I've librarified the program to a fair degree, but don't have all the -output stuff working yet. I'll be looking at ALSAPlayer's modifications -to synaesthesia to see what they did to merge it into another -architecture. It shouldn't be too hard to get this working, I just -haven't had a need yet. +This is a visualization based on on synaesthesia. (see README-syna). + +This implementation is taken from alsaplayer: http://www.alsaplayer.org/ It +is based on synaesthesia version 1.3 (or maybe 1.4, I'm not entirely +certain), with some modifications by Richard Boulton to try and ensure that +something interesting is displayed for both very quiet and very loud music. + diff --git a/gst/synaesthesia/core.c b/gst/synaesthesia/core.c deleted file mode 100644 index c266e4be69..0000000000 --- a/gst/synaesthesia/core.c +++ /dev/null @@ -1,408 +0,0 @@ -/* Synaesthesia - program to display sound graphically - Copyright (C) 1997 Paul Francis Harrison - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 675 Mass Ave, Cambridge, MA 02139, USA. - - The author may be contacted at: - pfh@yoyo.cc.monash.edu.au - or - 27 Bond St., Mt. Waverley, 3149, Melbourne, Australia -*/ - -#include -#include -#include -#include - -#include - -inline int bitReverser(int i) { - int sum=0,j; - for(j=0;j>= 1; - } - return sum; -} - -static void fft(struct syna_priv *sp,double *x,double *y) { - int n2 = SYNA_SIZE, n1; - int twoToTheK; - int i,j; - for(twoToTheK=1;twoToTheKcosTable[j*twoToTheK&(SYNA_SIZE-1)], - s = sp->negSinTable[j*twoToTheK&(SYNA_SIZE-1)]; - for(i=j;inegSinTable[i] = -sin(3.141592*2.0/SYNA_SIZE*i); - sp->cosTable[i] = cos(3.141592*2.0/SYNA_SIZE*i); - sp->bitReverse[i] = bitReverser(i); - } - - sp->outWidth = w; - sp->outHeight = h; - - sp->output = g_malloc(w*h); - sp->lastOutput = g_malloc(w*h); - sp->lastLastOutput = g_malloc(w*h); - memset(sp->output,0,w*h); - memset(sp->lastOutput,0,w*h); - memset(sp->lastLastOutput,0,w*h); - - sp->fadeMode = FADE_STARS; - sp->pointsAreDiamonds = TRUE; - sp->brightnessTwiddler = 0.33; - sp->starSize = 0.125; - sp->fgRedSlider = 0.0; - sp->fgGreenSlider = 0.5; - sp->bgRedSlider = 1.0; - sp->bgGreenSlider = 0.2; -} - -void setStarSize(struct syna_priv *sp,gdouble size) { - gdouble fadeModeFudge = (sp->fadeMode == FADE_WAVE ? 0.4 : - (sp->fadeMode == FADE_FLAME ? 0.6 : 0.78)); - - gint factor; - gint i; - if (size > 0.0) - factor = (int)(exp(log(fadeModeFudge) / (size*8.0))*255); - else - factor = 0; - - if (factor > 255) factor = 255; - - for(i=0;i<256;i++) - sp->scaleDown[i] = i*factor>>8; - - sp->maxStarRadius = 1; - for(i=255;i;i = sp->scaleDown[i]) - sp->maxStarRadius++; -} - -inline void addPixel(struct syna_priv *sp,int x,int y,int br1,int br2) -{ - unsigned char *p; - - if (x < 0 || x >= sp->outWidth || y < 0 || y >= sp->outHeight) return; - - p = sp->output+x*2+y*sp->outWidth*2; - if (p[0] < 255-br1) p[0] += br1; else p[0] = 255; - if (p[1] < 255-br2) p[1] += br2; else p[1] = 255; -} - -inline void addPixelFast(unsigned char *p,int br1,int br2) { - if (p[0] < 255-br1) p[0] += br1; else p[0] = 255; - if (p[1] < 255-br2) p[1] += br2; else p[1] = 255; -} - -void fadeFade(struct syna_priv *sp) { - register unsigned long *ptr = (unsigned long*)sp->output; - int i = sp->outWidth*sp->outHeight*2/4; - do { - if (*ptr) - *(ptr++) -= ((*ptr & 0xf0f0f0f0ul) >> 4) + ((*ptr & 0xe0e0e0e0ul) >> 5); - else - ptr++; - } while(--i > 0); -} - -inline unsigned char getPixel(struct syna_priv *sp,int x,int y,int where) { - if (x < 0 || y < 0 || x >= sp->outWidth || y >= sp->outHeight) return 0; - return sp->lastOutput[where]; -} - -inline void fadePixelWave(struct syna_priv *sp,int x,int y,int where,int step) { - short j = - (short)((getPixel(sp,x-1,y,where-2)+ - getPixel(sp,x+1,y,where+2)+ - getPixel(sp,x,y-1,where-step)+ - getPixel(sp,x,y+1,where+step)) >> 2) - + sp->lastOutput[where]; - if (!j) { sp->output[where] = 0; return; } - j = j - sp->lastLastOutput[where] - 1; - if (j < 0) sp->output[where] = 0; - else if (j & (255*256)) sp->output[where] = 255; - else sp->output[where] = j; -} - -void fadeWave(struct syna_priv *sp) { - int x,y,i,j,start,end; - int step = sp->outWidth*2; - unsigned char *t = sp->lastLastOutput; - sp->lastLastOutput = sp->lastOutput; - sp->lastOutput = sp->output; - sp->output = t; - - for(x=0,i=0,j=sp->outWidth*(sp->outHeight-1)*2;xoutWidth;x++,i+=2,j+=2) { - fadePixelWave(sp,x,0,i,step); - fadePixelWave(sp,x,0,i+1,step); - fadePixelWave(sp,x,sp->outHeight-1,j,step); - fadePixelWave(sp,x,sp->outHeight-1,j+1,step); - } - - for(y=1,i=sp->outWidth*2,j=sp->outWidth*4-2;youtHeight;y++,i+=step,j+=step) { - fadePixelWave(sp,0,y,i,step); - fadePixelWave(sp,0,y,i+1,step); - fadePixelWave(sp,sp->outWidth-1,y,j,step); - fadePixelWave(sp,sp->outWidth-1,y,j+1,step); - } - - for(y=1, - start=sp->outWidth*2+2, - end=sp->outWidth*4-2; youtHeight-1; y++,start+=step,end+=step) { - int i = start; - do { - short j = - (short)((sp->lastOutput[i-2]+ - sp->lastOutput[i+2]+ - sp->lastOutput[i-step]+ - sp->lastOutput[i+step]) >> 2) - + sp->lastOutput[i]; - if (!j) { - sp->output[i] = 0; - } else { - j = j - sp->lastLastOutput[i] - 1; - if (j < 0) sp->output[i] = 0; - else if (j & (255*256)) sp->output[i] = 255; - else sp->output[i] = j; - } - } while(++i < end); - } -} - -inline void fadePixelHeat(struct syna_priv *sp,int x,int y,int where,int step) { - short j = - (short)((getPixel(sp,x-1,y,where-2)+ - getPixel(sp,x+1,y,where+2)+ - getPixel(sp,x,y-1,where-step)+ - getPixel(sp,x,y+1,where+step)) >> 2) - + sp->lastOutput[where]; - if (!j) { sp->output[where] = 0; return; } - j = j - sp->lastLastOutput[where] - 1; - if (j < 0) sp->output[where] = 0; - else if (j & (255*256)) sp->output[where] = 255; - else sp->output[where] = j; -} - -void fadeHeat(struct syna_priv *sp) { - int x,y,i,j,start,end; - int step = sp->outWidth*2; - unsigned char *t = sp->lastLastOutput; - sp->lastLastOutput = sp->lastOutput; - sp->lastOutput = sp->output; - sp->output = t; - - for(x=0,i=0,j=sp->outWidth*(sp->outHeight-1)*2;xoutWidth;x++,i+=2,j+=2) { - fadePixelHeat(sp,x,0,i,step); - fadePixelHeat(sp,x,0,i+1,step); - fadePixelHeat(sp,x,sp->outHeight-1,j,step); - fadePixelHeat(sp,x,sp->outHeight-1,j+1,step); - } - - for(y=1,i=sp->outWidth*2,j=sp->outWidth*4-2;youtHeight;y++,i+=step,j+=step) { - fadePixelHeat(sp,0,y,i,step); - fadePixelHeat(sp,0,y,i+1,step); - fadePixelHeat(sp,sp->outWidth-1,y,j,step); - fadePixelHeat(sp,sp->outWidth-1,y,j+1,step); - } - - for (y=1,start=sp->outWidth*2+2, - end=sp->outWidth*4-2; youtHeight-1; y++,start+=step,end+=step) { - int i = start; - do { - short j = - (short)((sp->lastOutput[i-2]+ - sp->lastOutput[i+2]+ - sp->lastOutput[i-step]+ - sp->lastOutput[i+step]) >> 2) - + sp->lastOutput[i]; - if (!j) { - sp->output[i] = 0; - } else { - j = j - sp->lastLastOutput[i] + - (sp->lastLastOutput[i] - ((sp->lastOutput[i])>>2)) - 1; - if (j < 0) sp->output[i] = 0; - else if (j & (255*256)) sp->output[i] = 255; - else sp->output[i] = j; - } - } while(++i < end); - } -} - -void fade(struct syna_priv *sp) { - switch(sp->fadeMode) { - case FADE_STARS : - fadeFade(sp); - break; - case FADE_FLAME : - fadeHeat(sp); - break; - case FADE_WAVE : - fadeWave(sp); - break; - default: - break; - } -} - -int coreGo(struct syna_priv *sp,guchar *data,gint len) { - double x[SYNA_SIZE], y[SYNA_SIZE]; - double a[SYNA_SIZE], b[SYNA_SIZE]; - int clarity[SYNA_SIZE]; //Surround sound - int i,j,k; - int heightFactor = SYNA_SIZE / 2 / sp->outHeight + 1; - int actualHeight = SYNA_SIZE / 2 / heightFactor; - int heightAdd = sp->outHeight + (actualHeight >> 1); - - int brightFactor = (int)(150 * sp->brightnessTwiddler / (sp->starSize+0.01)); - double brightFactor2; - - for(i=0;ibitReverse[i]], - y1 = y[sp->bitReverse[i]], - x2 = x[sp->bitReverse[SYNA_SIZE-i]], - y2 = y[sp->bitReverse[SYNA_SIZE-i]], - aa,bb; - a[i] = sqrt(aa= (x1+x2)*(x1+x2) + (y1-y2)*(y1-y2) ); - b[i] = sqrt(bb= (x1-x2)*(x1-x2) + (y1+y2)*(y1+y2) ); - if (aa+bb != 0.0) - clarity[i] = (int)( - ( (x1+x2) * (x1-x2) + (y1+y2) * (y1-y2) )/(aa+bb) * 256 ); - else - clarity[i] = 0; - } - - /* Correct for window size */ - brightFactor2 = (brightFactor/65536.0/SYNA_SIZE)* - sqrt(actualHeight*sp->outWidth/(320.0*200.0)); - - for(i=1;i 0 || b[i] > 0) { - int h = (int)( b[i]*sp->outWidth / (a[i]+b[i]) ); - int br1, br2, br = (int)( - (a[i]+b[i])*i*brightFactor2 ); - int px = h, - py = heightAdd - i / heightFactor; - br1 = br*(clarity[i]+128)>>8; - br2 = br*(128-clarity[i])>>8; - if (br1 < 0) br1 = 0; else if (br1 > 255) br1 = 255; - if (br2 < 0) br2 = 0; else if (br2 > 255) br2 = 255; - - if (sp->pointsAreDiamonds) { - addPixel(sp,px,py,br1,br2); - br1=sp->scaleDown[br1];br2=sp->scaleDown[br2]; - - //TODO: Use addpixelfast - for(j=1;br1>0||br2>0;j++,br1=sp->scaleDown[br1], - br2=sp->scaleDown[br2]) { - for(k=0;kmaxStarRadius || py < sp->maxStarRadius || - px > sp->outWidth-sp->maxStarRadius || - py > sp->outHeight-sp->maxStarRadius) { - addPixel(sp,px,py,br1,br2); - for (j=1;(br1>0) || (br2>0);j++,br1=sp->scaleDown[br1], - br2=sp->scaleDown[br2]) { - addPixel(sp,px+j,py,br1,br2); - addPixel(sp,px,py+j,br1,br2); - addPixel(sp,px-j,py,br1,br2); - addPixel(sp,px,py-j,br1,br2); - } - } else { - unsigned char *p = sp->output+px*2+py*sp->outWidth*2; - unsigned char *p1=p, *p2=p, *p3=p, *p4=p; - addPixelFast(p,br1,br2); - for(;br1>0||br2>0;br1=sp->scaleDown[br1],br2=sp->scaleDown[br2]) { - p1 += 2; - addPixelFast(p1,br1,br2); - p2 -= 2; - addPixelFast(p2,br1,br2); - p3 += sp->outWidth*2; - addPixelFast(p3,br1,br2); - p4 -= sp->outWidth*2; - addPixelFast(p4,br1,br2); - } - } - } - } - } - return 0; -} - -void setupPalette(struct syna_priv *sp,guchar *palette) { - #define BOUND(x) ((x) > 255 ? 255 : (x)) - #define PEAKIFY(x) (int)(BOUND((x) - (x)*(255-(x))/255/2)) -#ifndef MAX - #define MAX(x,y) ((x) > (y) ? (x) : (y)) -#endif /* MAX */ - int i,f,b; - - double scale, fgRed, fgGreen, fgBlue, bgRed, bgGreen, bgBlue; - fgRed = sp->fgRedSlider; - fgGreen = sp->fgGreenSlider; - fgBlue = 1.0 - MAX(fgRed,fgGreen); - scale = MAX(MAX(fgRed,fgGreen),fgBlue); - fgRed /= scale; - fgGreen /= scale; - fgBlue /= scale; - - bgRed = sp->bgRedSlider; - bgGreen = sp->bgGreenSlider; - bgBlue = 1.0 - MAX(sp->bgRedSlider,sp->bgGreenSlider); - scale = MAX(MAX(bgRed,bgGreen),bgBlue); - bgRed /= scale; - bgGreen /= scale; - bgBlue /= scale; - - for(i=0;i<256;i++) { - f = i&15; - b = i/16; - palette[i*4+0] = PEAKIFY(b*bgRed*16+f*fgRed*16); - palette[i*4+1] = PEAKIFY(b*bgGreen*16+f*fgGreen*16); - palette[i*4+2] = PEAKIFY(b*bgBlue*16+f*fgBlue*16); - } -} diff --git a/gst/synaesthesia/core.h b/gst/synaesthesia/core.h deleted file mode 100644 index 4e18357d43..0000000000 --- a/gst/synaesthesia/core.h +++ /dev/null @@ -1,38 +0,0 @@ - -#ifndef HGUARD_SYNAESTHESIA_CORE_H -#define HGUARD_SYNAESTHESIA_CORE_H - -#include - -#define SYNA_BITS 8 -#define SYNA_SIZE (1 << SYNA_BITS) - -struct syna_priv { - gdouble cosTable[SYNA_SIZE],negSinTable[SYNA_SIZE]; - gint bitReverse[SYNA_SIZE]; - gint scaleDown[256]; - gint maxStarRadius; - gint outWidth,outHeight; - gint fadeMode; - gint brightnessTwiddler; - gint starSize; - gint pointsAreDiamonds; - - gdouble fgRedSlider, fgGreenSlider, bgRedSlider, bgGreenSlider; - - guchar *output,*lastOutput,*lastLastOutput; -}; - -#define FADE_WAVE 1 -#define FADE_HEAT 2 -#define FADE_STARS 3 -#define FADE_FLAME 4 - -void setStarSize(struct syna_priv *sp, gdouble size); -void coreInit(struct syna_priv *sp, int w, int h); -int coreGo(struct syna_priv *sp, guchar *data, gint len); -void fade(struct syna_priv *sp); -void setupPalette(struct syna_priv *sp, guchar *palette); - - -#endif /* HGUARD_SYNAESTHESIA_CORE_H */ diff --git a/gst/synaesthesia/gstsynaesthesia.c b/gst/synaesthesia/gstsynaesthesia.c index 1c2198dcef..3ed8002e77 100644 --- a/gst/synaesthesia/gstsynaesthesia.c +++ b/gst/synaesthesia/gstsynaesthesia.c @@ -1,5 +1,5 @@ -/* Gnome-Streamer - * Copyright (C) <1999> Erik Walthinsen +/* gstsynaesthesia.c: implementation of synaesthesia 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 @@ -17,28 +17,56 @@ * Boston, MA 02111-1307, USA. */ -#include "config.h" +#include +#include -#include "gstsynaesthesia.h" -#include "core.h" +#include "synaescope.h" -#warning hi, i'm synaesthesia. i'm severely broken. somebody please fix me. +#define GST_TYPE_SYNAESTHESIA (gst_synaesthesia_get_type()) +#define GST_SYNAESTHESIA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SYNAESTHESIA,GstSynaesthesia)) +#define GST_SYNAESTHESIA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SYNAESTHESIA,GstSynaesthesia)) +#define GST_IS_SYNAESTHESIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SYNAESTHESIA)) +#define GST_IS_SYNAESTHESIA_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SYNAESTHESIA)) -static gboolean gst_synaesthesia_start(GstElement *element); +typedef struct _GstSynaesthesia GstSynaesthesia; +typedef struct _GstSynaesthesiaClass GstSynaesthesiaClass; -GstElementDetails gst_synaesthesia_details = { - "Synaesthesia display", - "Sink/Visualization", - "Cool color display based on stereo info", - VERSION, - "Erik Walthinsen ", - "(C) 1999", +struct _GstSynaesthesia { + GstElement element; + + /* pads */ + GstPad *sinkpad,*srcpad; + GstBufferPool *peerpool; + + // the timestamp of the next frame + guint64 next_time; + gint16 datain[2][512]; + + // video state + gint fps; + gint width; + gint height; + gboolean first_buffer; }; -static GstElementClass *parent_class = NULL; -//static guint gst_synaesthesia_signals[LAST_SIGNAL] = { 0 }; +struct _GstSynaesthesiaClass { + GstElementClass parent_class; +}; -/* Synaesthesia signals and args */ +GType gst_synaesthesia_get_type(void); + + +/* elementfactory information */ +static GstElementDetails gst_synaesthesia_details = { + "Synaesthesia", + "Filter/Visualization", + "Creates video visualizations of audio input, using stereo and pitch information", + VERSION, + "Richard Boulton ", + "(C) 2002", +}; + +/* signals and args */ enum { /* FILL ME */ LAST_SIGNAL @@ -48,61 +76,84 @@ enum { ARG_0, ARG_WIDTH, ARG_HEIGHT, - ARG_WIDGET, + ARG_FPS, + /* FILL ME */ }; -static GstPadTemplate* -sink_factory (void) -{ - return - gst_padtemplate_new ( - "sink", /* the name of the pads */ - GST_PAD_SINK, /* type of the pad */ - GST_PAD_ALWAYS, /* ALWAYS/SOMETIMES */ - gst_caps_new ( - "synaesthesia_sink16", /* the name of the caps */ - "audio/raw", /* the mime type of the caps */ - gst_props_new ( - /* Properties follow: */ - "format", GST_PROPS_INT (16), - "depth", GST_PROPS_INT (16), - NULL)), - NULL); - // These properties commented out so that autoplugging works for now: - // the autoplugging needs to be fixed (caps negotiation needed) - //,"rate", GST_PROPS_INT (44100) - //,"channels", GST_PROPS_INT (2) -} +GST_PADTEMPLATE_FACTORY (src_template, + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "synaesthesiasrc", + "video/raw", + "format", GST_PROPS_FOURCC (GST_STR_FOURCC ("RGB ")), + "bpp", GST_PROPS_INT (32), + "depth", GST_PROPS_INT (32), + "endianness", GST_PROPS_INT (G_BYTE_ORDER), + "red_mask", GST_PROPS_INT (0xff0000), + "green_mask", GST_PROPS_INT (0xff00), + "blue_mask", GST_PROPS_INT (0xff), + "width", GST_PROPS_INT_RANGE (16, 4096), + "height", GST_PROPS_INT_RANGE (16, 4096) + ) +) -static void gst_synaesthesia_class_init(GstSynaesthesiaClass *klass); -static void gst_synaesthesia_init(GstSynaesthesia *synaesthesia); - -static void gst_synaesthesia_chain(GstPad *pad,GstBuffer *buf); - -static void gst_synaesthesia_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static void gst_synaesthesia_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); +GST_PADTEMPLATE_FACTORY (sink_template, + "sink", /* the name of the pads */ + GST_PAD_SINK, /* type of the pad */ + GST_PAD_ALWAYS, /* ALWAYS/SOMETIMES */ + GST_CAPS_NEW ( + "synaesthesiasink", /* the name of the caps */ + "audio/raw", /* the mime type of the caps */ + /* Properties follow: */ + "format", GST_PROPS_STRING ("int"), + "law", GST_PROPS_INT (0), + "endianness", GST_PROPS_INT (G_BYTE_ORDER), + "signed", GST_PROPS_BOOLEAN (TRUE), + "width", GST_PROPS_INT (16), + "depth", GST_PROPS_INT (16), + "rate", GST_PROPS_INT_RANGE (8000, 96000), + "channels", GST_PROPS_INT (1) + ) +) -static GstPadTemplate *sink_template; +static void gst_synaesthesia_class_init (GstSynaesthesiaClass *klass); +static void gst_synaesthesia_init (GstSynaesthesia *synaesthesia); + +static void gst_synaesthesia_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec); +static void gst_synaesthesia_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec); + +static void gst_synaesthesia_chain (GstPad *pad, GstBuffer *buf); + +static GstPadConnectReturn + gst_synaesthesia_sinkconnect (GstPad *pad, GstCaps *caps); + +static GstElementClass *parent_class = NULL; GType -gst_synaesthesia_get_type(void) { - static GType synaesthesia_type = 0; +gst_synaesthesia_get_type (void) +{ + static GType type = 0; - if (!synaesthesia_type) { - static const GTypeInfo synaesthesia_info = { - sizeof(GstSynaesthesiaClass), NULL, - NULL, - (GClassInitFunc)gst_synaesthesia_class_init, + if (!type) { + static const GTypeInfo info = { + sizeof (GstSynaesthesiaClass), + NULL, + NULL, + (GClassInitFunc) gst_synaesthesia_class_init, NULL, NULL, - sizeof(GstSynaesthesia), + sizeof (GstSynaesthesia), 0, - (GInstanceInitFunc)gst_synaesthesia_init, + (GInstanceInitFunc) gst_synaesthesia_init, }; - synaesthesia_type = g_type_register_static(GST_TYPE_ELEMENT, "GstSynaesthesia", &synaesthesia_info, 0); + type = g_type_register_static (GST_TYPE_ELEMENT, "GstSynaesthesia", &info, 0); } - return synaesthesia_type; + return type; } static void @@ -111,83 +162,143 @@ gst_synaesthesia_class_init(GstSynaesthesiaClass *klass) GObjectClass *gobject_class; GstElementClass *gstelement_class; - gobject_class = (GObjectClass*)klass; - gstelement_class = (GstElementClass*)klass; + gobject_class = (GObjectClass*) klass; + gstelement_class = (GstElementClass*) klass; - parent_class = g_type_class_ref(GST_TYPE_ELEMENT); + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_WIDTH, - g_param_spec_int("width","width","width", - G_MININT,G_MAXINT,0,G_PARAM_READABLE)); // CHECKME - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HEIGHT, - g_param_spec_int("height","height","height", - G_MININT,G_MAXINT,0,G_PARAM_READABLE)); // CHECKME + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_WIDTH, + g_param_spec_int ("width","Width","The Width", + 1, 2048, 320, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HEIGHT, + g_param_spec_int ("height","Height","The height", + 1, 2048, 320, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FPS, + g_param_spec_int ("fps","FPS","Frames per second", + 1, 100, 25, G_PARAM_READWRITE)); gobject_class->set_property = gst_synaesthesia_set_property; gobject_class->get_property = gst_synaesthesia_get_property; } static void -gst_synaesthesia_init(GstSynaesthesia *synaesthesia) +gst_synaesthesia_init (GstSynaesthesia *synaesthesia) { - synaesthesia->sinkpad = gst_pad_new_from_template (sink_template, "sink"); - gst_element_add_pad(GST_ELEMENT(synaesthesia), synaesthesia->sinkpad); - gst_pad_set_chain_function(synaesthesia->sinkpad, gst_synaesthesia_chain); + /* create the sink and src pads */ + synaesthesia->sinkpad = gst_pad_new_from_template ( + GST_PADTEMPLATE_GET (sink_template ), "sink"); + synaesthesia->srcpad = gst_pad_new_from_template ( + GST_PADTEMPLATE_GET (src_template ), "src"); + gst_element_add_pad (GST_ELEMENT (synaesthesia), synaesthesia->sinkpad); + gst_element_add_pad (GST_ELEMENT (synaesthesia), synaesthesia->srcpad); + + gst_pad_set_chain_function (synaesthesia->sinkpad, gst_synaesthesia_chain); + gst_pad_set_connect_function (synaesthesia->sinkpad, gst_synaesthesia_sinkconnect); + + synaesthesia->next_time = 0; + synaesthesia->peerpool = NULL; + + // reset the initial video state + synaesthesia->first_buffer = TRUE; + synaesthesia->width = 320; + synaesthesia->height = 200; + synaesthesia->fps = 25; // desired frame rate - gst_synaesthesia_start(GST_ELEMENT(synaesthesia)); } -static void gst_synaesthesia_chain(GstPad *pad,GstBuffer *buf) { - GstSynaesthesia *syna; - gint samplecount; +static GstPadConnectReturn +gst_synaesthesia_sinkconnect (GstPad *pad, GstCaps *caps) +{ + GstSynaesthesia *synaesthesia; + synaesthesia = GST_SYNAESTHESIA (gst_pad_get_parent (pad)); - g_return_if_fail(pad != NULL); - g_return_if_fail(GST_IS_PAD(pad)); - g_return_if_fail(buf != NULL); + if (!GST_CAPS_IS_FIXED (caps)) { + return GST_PAD_CONNECT_DELAYED; + } - syna = GST_SYNAESTHESIA(GST_OBJECT_PARENT (pad)); - g_return_if_fail(syna != NULL); - g_return_if_fail(GST_IS_SYNAESTHESIA(syna)); - - samplecount = GST_BUFFER_SIZE(buf) / - (2 * sizeof(gint16)); - -// GST_DEBUG (0,"fading\n"); -// fade(&syna->sp); - GST_DEBUG (0,"doing effect\n"); - coreGo(&syna->sp,GST_BUFFER_DATA(buf),samplecount); - -// GST_DEBUG (0,"drawing\n"); -/* GST_DEBUG (0,"gdk_draw_indexed_image(%p,%p,%d,%d,%d,%d,%s,%p,%d,%p);\n", - syna->image->window, - syna->image->style->fg_gc[GTK_STATE_NORMAL], - 0,0,syna->width,syna->height, - "GDK_RGB_DITHER_NORMAL", - syna->sp.output,syna->width, - &syna->cmap);*/ -/* gdk_draw_indexed_image(syna->image->window, - syna->image->style->fg_gc[GTK_STATE_NORMAL], - 0,0,syna->width,syna->height, - GDK_RGB_DITHER_NORMAL, - syna->sp.output,syna->width, - &syna->cmap);*/ -/* gdk_draw_gray_image(syna->image->window, - syna->image->style->fg_gc[GTK_STATE_NORMAL], - 0,0,syna->width,syna->height, - GDK_RGB_DITHER_NORMAL, - syna->sp.output,syna->width); */ - - gst_trace_add_entry(NULL,0,buf,"synaesthesia: calculated syna"); - - gst_buffer_unref(buf); + return GST_PAD_CONNECT_OK; } -static void gst_synaesthesia_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { +static void +gst_synaesthesia_chain (GstPad *pad, GstBuffer *bufin) +{ + GstSynaesthesia *synaesthesia; + GstBuffer *bufout; + guint32 samples_in; + gint16 *data; + gint i; + + synaesthesia = GST_SYNAESTHESIA (gst_pad_get_parent (pad)); + + GST_DEBUG (0, "Synaesthesia: chainfunc called\n"); + + samples_in = GST_BUFFER_SIZE (bufin) / sizeof (gint16); + + GST_DEBUG (0, "input buffer has %d samples\n", samples_in); + + if (GST_BUFFER_TIMESTAMP (bufin) < synaesthesia->next_time || samples_in < 1024) { + gst_buffer_unref (bufin); + return; + } + + data = (gint16 *) GST_BUFFER_DATA (bufin); + for (i=0; i < 512; i++) { + synaesthesia->datain[0][i] = *data++; + synaesthesia->datain[1][i] = *data++; + } + + if (synaesthesia->first_buffer) { + GstCaps *caps; + + synaesthesia_init (synaesthesia->width, synaesthesia->height); + + GST_DEBUG (0, "making new pad\n"); + + caps = GST_CAPS_NEW ( + "synaesthesiasrc", + "video/raw", + "format", GST_PROPS_FOURCC (GST_STR_FOURCC ("RGB ")), + "bpp", GST_PROPS_INT (32), + "depth", GST_PROPS_INT (32), + "endianness", GST_PROPS_INT (G_BYTE_ORDER), + "red_mask", GST_PROPS_INT (0xff0000), + "green_mask", GST_PROPS_INT (0x00ff00), + "blue_mask", GST_PROPS_INT (0x0000ff), + "width", GST_PROPS_INT (synaesthesia->width), + "height", GST_PROPS_INT (synaesthesia->height) + ); + + if (!gst_pad_try_set_caps (synaesthesia->srcpad, caps)) { + gst_element_error (GST_ELEMENT (synaesthesia), "could not set caps"); + return; + } + synaesthesia->first_buffer = FALSE; + } + + bufout = gst_buffer_new (); + GST_BUFFER_SIZE (bufout) = synaesthesia->width * synaesthesia->height * 4; + GST_BUFFER_DATA (bufout) = (guchar *) synaesthesia_update (synaesthesia->datain); + GST_BUFFER_TIMESTAMP (bufout) = synaesthesia->next_time; + GST_BUFFER_FLAG_SET (bufout, GST_BUFFER_DONTFREE); + + synaesthesia->next_time += 1000000LL / synaesthesia->fps; + + gst_pad_push (synaesthesia->srcpad, bufout); + + gst_buffer_unref (bufin); + + GST_DEBUG (0, "Synaesthesia: exiting chainfunc\n"); + +} + +static void +gst_synaesthesia_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ GstSynaesthesia *synaesthesia; /* it's not null if we got it, but it might not be ours */ - g_return_if_fail(GST_IS_SYNAESTHESIA(object)); - synaesthesia = GST_SYNAESTHESIA(object); + g_return_if_fail (GST_IS_SYNAESTHESIA (object)); + synaesthesia = GST_SYNAESTHESIA (object); switch (prop_id) { case ARG_WIDTH: @@ -196,59 +307,50 @@ static void gst_synaesthesia_set_property(GObject *object, guint prop_id, const case ARG_HEIGHT: synaesthesia->height = g_value_get_int (value); break; + case ARG_FPS: + synaesthesia->fps = g_value_get_int (value); + break; default: break; } } static void -gst_synaesthesia_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +gst_synaesthesia_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GstSynaesthesia *synaesthesia; /* it's not null if we got it, but it might not be ours */ - g_return_if_fail(GST_IS_SYNAESTHESIA(object)); - synaesthesia = GST_SYNAESTHESIA(object); - - GST_DEBUG (0,"have synaesthesia get_property(%d), wanting %d\n",prop_id,ARG_WIDGET); + g_return_if_fail (GST_IS_SYNAESTHESIA (object)); + synaesthesia = GST_SYNAESTHESIA (object); switch (prop_id) { - case ARG_WIDTH: { + case ARG_WIDTH: g_value_set_int (value, synaesthesia->width); - GST_DEBUG (0,"returning width value %d\n",g_value_get_int (value)); break; - } - case ARG_HEIGHT: { + case ARG_HEIGHT: g_value_set_int (value, synaesthesia->height); - GST_DEBUG (0,"returning height value %d\n",g_value_get_int (value)); break; - } -/* case ARG_WIDGET: { - g_value_set_object (value, G_OBJECT(synaesthesia->image)); - GST_DEBUG (0,"returning widget value %p\n",g_value_get_object (value)); + case ARG_FPS: + g_value_set_int (value, synaesthesia->fps); break; - }*/ - default: { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - GST_DEBUG (0,"returning invalid type\n"); + default: break; - } } } - - static gboolean plugin_init (GModule *module, GstPlugin *plugin) { GstElementFactory *factory; - factory = gst_elementfactory_new("synaesthesia", GST_TYPE_SYNAESTHESIA, + /* create an elementfactory for the synaesthesia element */ + factory = gst_elementfactory_new("synaesthesia",GST_TYPE_SYNAESTHESIA, &gst_synaesthesia_details); g_return_val_if_fail(factory != NULL, FALSE); - sink_template = sink_factory (); - gst_elementfactory_add_padtemplate(factory, sink_template); + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_template)); + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (sink_template)); gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); @@ -261,33 +363,3 @@ GstPluginDesc plugin_desc = { "synaesthesia", plugin_init }; - -static gboolean -gst_synaesthesia_start(GstElement *element) -{ - GstSynaesthesia *syna; - - g_return_val_if_fail(GST_IS_SYNAESTHESIA(element), FALSE); - syna = GST_SYNAESTHESIA(element); - - syna->width = 255; - syna->height = 255; - syna->starsize = 2; - - coreInit(&syna->sp, syna->width, syna->height); - setStarSize(&syna->sp, syna->starsize); - -/* setupPalette(&syna->sp, syna->cmap.colors); */ - - gdk_rgb_init(); -/* syna->image = gtk_drawing_area_new(); - GST_DEBUG (0,"image is %p\n",syna->image); - gtk_drawing_area_size(GTK_DRAWING_AREA(syna->image), - syna->width, - syna->height); - gtk_widget_show(syna->image);*/ - - GST_DEBUG (0,"started synaesthesia\n"); - return TRUE; -} - diff --git a/gst/synaesthesia/gstsynaesthesia.h b/gst/synaesthesia/gstsynaesthesia.h deleted file mode 100644 index 2550fef645..0000000000 --- a/gst/synaesthesia/gstsynaesthesia.h +++ /dev/null @@ -1,72 +0,0 @@ -/* Gnome-Streamer - * Copyright (C) <1999> Erik Walthinsen - * - * 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_SYNAESTHESIA_H__ -#define __GST_SYNAESTHESIA_H__ - - -#include - -#include - - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -#define GST_TYPE_SYNAESTHESIA \ - (gst_synaesthesia_get_type()) -#define GST_SYNAESTHESIA(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SYNAESTHESIA,GstSynaesthesia)) -#define GST_SYNAESTHESIA_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SYNAESTHESIA,GstSynaesthesia)) -#define GST_IS_SYNAESTHESIA(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SYNAESTHESIA)) -#define GST_IS_SYNAESTHESIA_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SYNAESTHESIA)) - -typedef struct _GstSynaesthesia GstSynaesthesia; -typedef struct _GstSynaesthesiaClass GstSynaesthesiaClass; - -struct _GstSynaesthesia { - GstElement element; - - GstPad *sinkpad; - - gint width,height; - gdouble starsize; - - struct syna_priv sp; -}; - -struct _GstSynaesthesiaClass { - GstElementClass parent_class; -}; - -GType gst_synaesthesia_get_type(void); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - - -#endif /* __GST_SYNAESTHESIA_H__ */ diff --git a/gst/synaesthesia/synaescope.c b/gst/synaesthesia/synaescope.c new file mode 100644 index 0000000000..827fcc0a06 --- /dev/null +++ b/gst/synaesthesia/synaescope.c @@ -0,0 +1,486 @@ +/* synaescope.cpp + * Copyright (C) 1999,2002 Richard Boulton + * + * Much code copied from Synaesthesia - a program to display sound + * graphically, by Paul Francis Harrison + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include "synaescope.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SCOPE_BG_RED 0 +#define SCOPE_BG_GREEN 0 +#define SCOPE_BG_BLUE 0 + +#define FFT_BUFFER_SIZE_LOG 9 +#define FFT_BUFFER_SIZE (1 << FFT_BUFFER_SIZE_LOG) + +#define syn_width 320 +#define syn_height 200 +#define brightMin 200 +#define brightMax 2000 +#define brightDec 10 +#define brightInc 6 +#define brTotTargetLow 5000 +#define brTotTargetHigh 15000 + +static int autobrightness = 1; /* Whether to use automatic brightness adjust */ +static unsigned int brightFactor = 400; +static unsigned char output[syn_width * syn_height * 2]; +static guint32 display[syn_width * syn_height]; +static gint16 pcmt_l[FFT_BUFFER_SIZE]; +static gint16 pcmt_r[FFT_BUFFER_SIZE]; +static gint16 pcm_l[FFT_BUFFER_SIZE]; +static gint16 pcm_r[FFT_BUFFER_SIZE]; +static double fftout_l[FFT_BUFFER_SIZE]; +static double fftout_r[FFT_BUFFER_SIZE]; +static double fftmult[FFT_BUFFER_SIZE / 2 + 1]; +static double corr_l[FFT_BUFFER_SIZE]; +static double corr_r[FFT_BUFFER_SIZE]; +static int clarity[FFT_BUFFER_SIZE]; /* Surround sound */ +static double cosTable[FFT_BUFFER_SIZE]; +static double negSinTable[FFT_BUFFER_SIZE]; +static int bitReverse[FFT_BUFFER_SIZE]; +static int scaleDown[256]; + +static void synaes_fft(double *x, double *y); +static void synaescope_coreGo(void); + +#define SYNAESCOPE_DOLOOP() \ +while (running) { \ + gint bar; \ + guint val; \ + gint val2; \ + unsigned char *outptr = output; \ + int w; \ +\ + synaescope_coreGo(); \ +\ + outptr = output; \ + for (w=0; w < syn_width * syn_height; w++) { \ + bits[w] = colEq[(outptr[0] >> 4) + (outptr[1] & 0xf0)]; \ + outptr += 2; \ + } \ +\ + GDK_THREADS_ENTER(); \ + gdk_draw_image(win,gc,image,0,0,0,0,-1,-1); \ + gdk_flush(); \ + GDK_THREADS_LEAVE(); \ + dosleep(SCOPE_SLEEP); \ +} + +static inline void addPixel(unsigned char *output, int x,int y,int br1,int br2) { + unsigned char *p; + if (x < 0 || x >= syn_width || y < 0 || y >= syn_height) return; + + p = output + x * 2 + y * syn_width * 2; + if (p[0] < 255 - br1) p[0] += br1; else p[0] = 255; + if (p[1] < 255 - br2) p[1] += br2; else p[1] = 255; +} + +static inline void addPixelFast(unsigned char *p,int br1,int br2) { + if (p[0] < 255 - br1) p[0] += br1; else p[0] = 255; + if (p[1] < 255 - br2) p[1] += br2; else p[1] = 255; +} + +static void synaescope_coreGo(void) { + int i,j; + register unsigned long *ptr; + register unsigned long *end; + int heightFactor; + int actualHeight; + int heightAdd; + double brightFactor2; + long int brtot; + + memcpy(pcm_l, pcmt_l, sizeof(pcm_l)); + memcpy(pcm_r, pcmt_r, sizeof(pcm_r)); + + for(i = 0; i < FFT_BUFFER_SIZE; i++) { + fftout_l[i] = pcm_l[i]; + fftout_r[i] = pcm_r[i]; + } + + synaes_fft(fftout_l,fftout_r); + + for(i=0 +1;i>1)>>4; + if (*ptr) + + if (*ptr & 0xf0f0f0f0) + *ptr = *ptr - ((*ptr & 0xf0f0f0f0) >> 4) - ((*ptr & 0xe0e0e0e0) >> 5); + else { + *ptr = (*ptr * 14 >> 4) & 0x0f0f0f0f; + //Should be 29/32 to be consistent. Who cares. This is totally + // hacked anyway. + //unsigned char *subptr = (unsigned char*)(ptr++); + //subptr[0] = (int)subptr[0] * 29 / 32; + //subptr[1] = (int)subptr[0] * 29 / 32; + //subptr[2] = (int)subptr[0] * 29 / 32; + //subptr[3] = (int)subptr[0] * 29 / 32; + } + ptr++; + } while(ptr < end); + + heightFactor = FFT_BUFFER_SIZE/2 / syn_height + 1; + actualHeight = FFT_BUFFER_SIZE/2 / heightFactor; + heightAdd = syn_height + actualHeight >> 1; + + /* Correct for window size */ + brightFactor2 = (brightFactor/65536.0/FFT_BUFFER_SIZE)* + sqrt(actualHeight * syn_width / (320.0*200.0)); + + brtot = 0; + for(i=1;i 0 || corr_r[i] > 0) { + int h = (int)( corr_r[i] * syn_width / (corr_l[i]+corr_r[i]) ); +// int h = (int)( syn_width - 1 ); + int br1, br2, br = (int)( + (corr_l[i]+corr_r[i])*i*brightFactor2 ); + int px = h, + py = heightAdd - i / heightFactor; + brtot += br; + br1 = br*(clarity[i]+128)>>8; + br2 = br*(128-clarity[i])>>8; + if (br1 < 0) br1 = 0; else if (br1 > 255) br1 = 255; + if (br2 < 0) br2 = 0; else if (br2 > 255) br2 = 255; + //unsigned char *p = output+ h*2+(164-((i<<8)>>FFT_BUFFER_SIZE_LOG))*(syn_width*2); + + if (px < 30 || py < 30 || px > syn_width-30 || py > syn_height-30) { + addPixel(output, px,py,br1,br2); + for(j=1;br1>0||br2>0;j++,br1=scaleDown[br1],br2=scaleDown[br2]) { + addPixel(output, px+j,py,br1,br2); + addPixel(output, px,py+j,br1,br2); + addPixel(output, px-j,py,br1,br2); + addPixel(output, px,py-j,br1,br2); + } + } else { + unsigned char *p = output+px*2+py*syn_width*2, *p1=p, *p2=p, *p3=p, *p4=p; + addPixelFast(p,br1,br2); + for(;br1>0||br2>0;br1=scaleDown[br1],br2=scaleDown[br2]) { + p1 += 2; + addPixelFast(p1,br1,br2); + p2 -= 2; + addPixelFast(p2,br1,br2); + p3 += syn_width * 2; + addPixelFast(p3,br1,br2); + p4 -= syn_width * 2; + addPixelFast(p4,br1,br2); + } + } + } + } + + /* Apply autoscaling: makes quiet bits brighter, and loud bits + * darker, but still keeps loud bits brighter than quiet bits. */ + if(brtot != 0 && autobrightness) { + long int brTotTarget = brTotTargetHigh; + if(brightMax != brightMin) { + brTotTarget -= ((brTotTargetHigh - brTotTargetLow) * + (brightFactor - brightMin)) / + (brightMax - brightMin); + } + if(brtot < brTotTarget) { + brightFactor += brightInc; + if(brightFactor > brightMax) brightFactor = brightMax; + } else { + brightFactor -= brightDec; + if(brightFactor < brightMin) brightFactor = brightMin; + } + /* printf("brtot: %ld\tbrightFactor: %d\tbrTotTarget: %d\n", + brtot, brightFactor, brTotTarget); */ + } +} + +#define BOUND(x) ((x) > 255 ? 255 : (x)) +#define PEAKIFY(x) BOUND((x) - (x)*(255-(x))/255/2) + +static void synaescope32() +{ + unsigned char *outptr; + guint32 colEq[256]; + int i; + guint32 bg_color; + + for (i = 0; i < 256; i++) { + int red = PEAKIFY((i&15*16)); + int green = PEAKIFY((i&15)*16+(i&15*16)/4); + int blue = PEAKIFY((i&15)*16); + colEq[i] = (red << 16) + (green << 8) + blue; + } + bg_color = (SCOPE_BG_RED << 16) + (SCOPE_BG_GREEN << 8) + SCOPE_BG_BLUE; + + synaescope_coreGo(); + + outptr = output; + for (i=0; i < syn_width * syn_height; i++) { + display[i] = colEq[(outptr[0] >> 4) + (outptr[1] & 0xf0)]; + outptr += 2; + } +} + + +#if 0 +static void synaescope16(void *data) +{ + guint16 *bits; + guint16 colEq[256]; + int i; + GdkWindow *win; + GdkColormap *c; + GdkVisual *v; + GdkGC *gc; + GdkColor bg_color; + + win = (GdkWindow *)data; + GDK_THREADS_ENTER(); + c = gdk_colormap_get_system(); + gc = gdk_gc_new(win); + v = gdk_window_get_visual(win); + + for (i = 0; i < 256; i++) { + GdkColor color; + color.red = PEAKIFY((i&15*16)) << 8; + color.green = PEAKIFY((i&15)*16+(i&15*16)/4) << 8; + color.blue = PEAKIFY((i&15)*16) << 8; + gdk_color_alloc(c, &color); + colEq[i] = color.pixel; + } + + // Create render image + if (image) { + gdk_image_destroy(image); + image = NULL; + } + image = gdk_image_new(GDK_IMAGE_FASTEST, v, syn_width, syn_height); + bg_color.red = SCOPE_BG_RED << 8; + bg_color.green = SCOPE_BG_GREEN << 8; + bg_color.blue = SCOPE_BG_BLUE << 8; + gdk_color_alloc(c, &bg_color); + GDK_THREADS_LEAVE(); + + assert(image); + assert(image->bpp == 2); + + bits = (guint16 *)image->mem; + + running = 1; + + SYNAESCOPE_DOLOOP(); +} + + +static void synaescope8(void *data) +{ + unsigned char *outptr; + guint8 *bits; + guint8 colEq[256]; + int i; + GdkWindow *win; + GdkColormap *c; + GdkVisual *v; + GdkGC *gc; + GdkColor bg_color; + + win = (GdkWindow *)data; + GDK_THREADS_ENTER(); + c = gdk_colormap_get_system(); + gc = gdk_gc_new(win); + v = gdk_window_get_visual(win); + + for (i = 0; i < 64; i++) { + GdkColor color; + color.red = PEAKIFY((i&7*8)*4) << 8; + color.green = PEAKIFY((i&7)*32+(i&7*8)*2) << 8; + color.blue = PEAKIFY((i&7)*32) << 8; + gdk_color_alloc(c, &color); + colEq[i * 4] = color.pixel; + colEq[i * 4 + 1] = color.pixel; + colEq[i * 4 + 2] = color.pixel; + colEq[i * 4 + 3] = color.pixel; + } + + // Create render image + if (image) { + gdk_image_destroy(image); + image = NULL; + } + image = gdk_image_new(GDK_IMAGE_FASTEST, v, syn_width, syn_height); + bg_color.red = SCOPE_BG_RED << 8; + bg_color.green = SCOPE_BG_GREEN << 8; + bg_color.blue = SCOPE_BG_BLUE << 8; + gdk_color_alloc(c, &bg_color); + GDK_THREADS_LEAVE(); + + assert(image); + assert(image->bpp == 1); + + bits = (guint8 *)image->mem; + + running = 1; + + SYNAESCOPE_DOLOOP(); +} +#endif + +#if 0 +static void run_synaescope(void *data) +{ + switch (depth) { + case 8: + synaescope8(win); + break; + case 16: + synaescope16(win); + break; + case 24: + case 32: + synaescope32(win); + break; + + } +} + +static void start_synaescope(void *data) +{ + init_synaescope_window(); +} + +#endif + + +static int bitReverser(int i) { + int sum = 0; + int j; + + for(j = 0; j < FFT_BUFFER_SIZE_LOG; j++) { + sum = (i & 1) + sum * 2; + i >>= 1; + } + + return sum; +} + +static void init_synaescope() +{ + int i; + + for(i = 0; i <= FFT_BUFFER_SIZE / 2 + 1; i++) { + double mult = (double)128 / ((FFT_BUFFER_SIZE * 16384) ^ 2); + // Result now guaranteed (well, almost) to be in range 0..128 + + // Low values represent more frequencies, and thus get more + // intensity - this helps correct for that. + mult *= log(i + 1) / log(2); + + mult *= 3; // Adhoc parameter, looks about right for me. + + fftmult[i] = mult; + } + + for(i = 0; i < FFT_BUFFER_SIZE; i++) { + negSinTable[i] = -sin(M_PI * 2 / FFT_BUFFER_SIZE*i); + cosTable[i] = cos(M_PI * 2 / FFT_BUFFER_SIZE*i); + bitReverse[i] = bitReverser(i); + } + + for(i=0;i<256;i++) + scaleDown[i] = i*200>>8; + + memset(output, 0, syn_width * syn_height * 2); +} + +static void synaes_fft(double *x, double *y) { + int n2 = FFT_BUFFER_SIZE; + int n1; + int twoToTheK; + int j; + for(twoToTheK = 1; twoToTheK < FFT_BUFFER_SIZE; twoToTheK *= 2) { + n1 = n2; + n2 /= 2; + for(j = 0; j < n2; j++) { + double c = cosTable[j * twoToTheK & (FFT_BUFFER_SIZE - 1)]; + double s = negSinTable[j * twoToTheK & (FFT_BUFFER_SIZE - 1)]; + int i; + for(i = j; i < FFT_BUFFER_SIZE; i += n1) { + int l = i + n2; + double xt = x[i] - x[l]; + double yt = y[i] - y[l]; + x[i] = (x[i] + x[l]); + y[i] = (y[i] + y[l]); + x[l] = xt * c - yt * s; + y[l] = xt * s + yt * c; + } + } + } +} + +static void synaescope_set_data(gint16 data [2][512]) +{ + int i; + gint16 *newset_l = pcmt_l; + gint16 *newset_r = pcmt_r; + for (i=0; i < FFT_BUFFER_SIZE; i++) { + newset_l[i] = data[0][i]; + newset_r[i] = data[1][i]; + } +} + +void synaesthesia_init (guint32 resx, guint32 resy) +{ + init_synaescope(); +} + +guint32 * synaesthesia_update (gint16 data [2][512]) +{ + synaescope_set_data(data); + synaescope32(); + return display; +} + +void synaesthesia_close () +{ +} + diff --git a/gst/synaesthesia/synaescope.h b/gst/synaesthesia/synaescope.h new file mode 100644 index 0000000000..1392131c15 --- /dev/null +++ b/gst/synaesthesia/synaescope.h @@ -0,0 +1,10 @@ +#ifndef _SYNAESCOPE_H +#define _SYNAESCOPE_H + +#include + +void synaesthesia_init (guint32 resx, guint32 resy); +guint32 * synaesthesia_update (gint16 data [2][512]); +void synaesthesia_close (); + +#endif