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. ;-)
This commit is contained in:
Richard Boulton 2002-03-01 14:31:12 +00:00
parent b9b2e358bf
commit 8f93753160
8 changed files with 752 additions and 701 deletions

View file

@ -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

View file

@ -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.

View file

@ -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 <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <core.h>
inline int bitReverser(int i) {
int sum=0,j;
for(j=0;j<SYNA_BITS;j++) {
sum = (i&1)+sum*2;
i >>= 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;twoToTheK<SYNA_SIZE;twoToTheK*=2) {
n1 = n2;
n2 /= 2;
for(j=0;j<n2;j++) {
double c = sp->cosTable[j*twoToTheK&(SYNA_SIZE-1)],
s = sp->negSinTable[j*twoToTheK&(SYNA_SIZE-1)];
for(i=j;i<SYNA_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;
}
}
}
}
void coreInit(struct syna_priv *sp,int w,int h) {
gint i;
for(i=0;i<SYNA_SIZE;i++) {
sp->negSinTable[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;x<sp->outWidth;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;y<sp->outHeight;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; y<sp->outHeight-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;x<sp->outWidth;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;y<sp->outHeight;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; y<sp->outHeight-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;i<SYNA_SIZE;i++) {
x[i] = data[i*2];
y[i] = data[i*2+1];
}
fft(sp,x,y);
for(i=0 +1;i<SYNA_SIZE;i++) {
double x1 = x[sp->bitReverse[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<SYNA_SIZE/2;i++) {
if (a[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;k<j;k++) {
addPixel(sp,px-j+k,py-k,br1,br2);
addPixel(sp,px+k,py-j+k,br1,br2);
addPixel(sp,px+j-k,py+k,br1,br2);
addPixel(sp,px-k,py+j-k,br1,br2);
}
}
} else {
if (px < sp->maxStarRadius || 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);
}
}

View file

@ -1,38 +0,0 @@
#ifndef HGUARD_SYNAESTHESIA_CORE_H
#define HGUARD_SYNAESTHESIA_CORE_H
#include <glib.h>
#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 */

View file

@ -1,5 +1,5 @@
/* Gnome-Streamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
/* gstsynaesthesia.c: implementation of synaesthesia drawing element
* Copyright (C) <2001> Richard Boulton <richard@tartarus.org>
*
* 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 <config.h>
#include <gst/gst.h>
#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 <omega@cse.ogi.edu>",
"(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 <richard@tartarus.org>",
"(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;
}

View file

@ -1,72 +0,0 @@
/* Gnome-Streamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* 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 <gst/gst.h>
#include <core.h>
#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__ */

View file

@ -0,0 +1,486 @@
/* synaescope.cpp
* Copyright (C) 1999,2002 Richard Boulton <richard@tartarus.org>
*
* Much code copied from Synaesthesia - a program to display sound
* graphically, by Paul Francis Harrison <pfh@yoyo.cc.monash.edu.au>
*
* 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 <pthread.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <assert.h>
#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<FFT_BUFFER_SIZE;i++) {
double x1 = fftout_l[bitReverse[i]];
double y1 = fftout_r[bitReverse[i]];
double x2 = fftout_l[bitReverse[FFT_BUFFER_SIZE-i]];
double y2 = fftout_r[bitReverse[FFT_BUFFER_SIZE-i]];
double aa,bb;
corr_l[i] = sqrt(aa= (x1+x2)*(x1+x2) + (y1-y2)*(y1-y2) );
corr_r[i] = sqrt(bb= (x1-x2)*(x1-x2) + (y1+y2)*(y1+y2) );
clarity[i] = (int)(
( (x1+x2) * (x1-x2) + (y1+y2) * (y1-y2) )/(aa+bb) * 256 );
}
// Asger Alstrupt's optimized 32 bit fade
// (alstrup@diku.dk)
ptr = (unsigned long*)output;
end = (unsigned long*)(output + syn_width * syn_height * 2);
do {
//Bytewize version was: *(ptr++) -= *ptr+(*ptr>>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<FFT_BUFFER_SIZE/2;i++) {
//int h = (int)( corr_r[i]*280 / (corr_l[i]+corr_r[i]+0.0001)+20 );
if (corr_l[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 ()
{
}

View file

@ -0,0 +1,10 @@
#ifndef _SYNAESCOPE_H
#define _SYNAESCOPE_H
#include <glib.h>
void synaesthesia_init (guint32 resx, guint32 resy);
guint32 * synaesthesia_update (gint16 data [2][512]);
void synaesthesia_close ();
#endif