1 /* Synaesthesia - program to display sound graphically
2 Copyright (C) 1997 Paul Francis Harrison
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 675 Mass Ave, Cambridge, MA 02139, USA.
18 The author may be contacted at:
19 pfh@yoyo.cc.monash.edu.au
21 27 Bond St., Mt. Waverley, 3149, Melbourne, Australia
31 double cosTable
[NumSamples
], negSinTable
[NumSamples
];
32 int bitReverse
[NumSamples
];
36 int bitReverser(int i
) {
38 for(j
=0;j
<LogSize
;j
++) {
45 void fft(double *x
,double *y
) {
46 int n2
= NumSamples
, n1
;
48 for(twoToTheK
=1;twoToTheK
<NumSamples
;twoToTheK
*=2) {
51 for(int j
=0;j
<n2
;j
++) {
52 double c
= cosTable
[j
*twoToTheK
&(NumSamples
-1)],
53 s
= negSinTable
[j
*twoToTheK
&(NumSamples
-1)];
54 for(int i
=j
;i
<NumSamples
;i
+=n1
) {
56 double xt
= x
[i
] - x
[l
];
58 double yt
= y
[i
] - y
[l
];
70 for(i
=0;i
<NumSamples
;i
++) {
71 negSinTable
[i
] = -sin(3.141592*2.0/NumSamples
*i
);
72 cosTable
[i
] = cos(3.141592*2.0/NumSamples
*i
);
73 bitReverse
[i
] = bitReverser(i
);
77 void setStarSize(double size
) {
78 //int factor = (fadeMode == Flame ? 100 :
79 // (fadeMode == Wave ? 150 : 200));
81 double fadeModeFudge
= (fadeMode
== Wave
? 0.4 :
82 (fadeMode
== Flame
? 0.6 : 0.78));
86 factor
= int(exp(log(fadeModeFudge
) / (size
*8.0))*255);
90 if (factor
> 255) factor
= 255;
92 for(int i
=0;i
<256;i
++)
93 scaleDown
[i
] = i
*factor
>>8;
96 for(int i
=255;i
;i
= scaleDown
[i
])
100 inline void addPixel(int x
,int y
,int br1
,int br2
) {
101 if (x
< 0 || x
>= outWidth
|| y
< 0 || y
>= outHeight
) return;
103 unsigned char *p
= output
+x
*2+y
*outWidth
*2;
104 if (p
[0] < 255-br1
) p
[0] += br1
; else p
[0] = 255;
105 if (p
[1] < 255-br2
) p
[1] += br2
; else p
[1] = 255;
106 //p += lastOutput-output;
107 //if (p[0] < 255-br1) p[0] += br1; else p[0] = 255;
108 //if (p[1] < 255-br2) p[1] += br2; else p[1] = 255;
111 inline void addPixelFast(unsigned char *p
,int br1
,int br2
) {
112 if (p
[0] < 255-br1
) p
[0] += br1
; else p
[0] = 255;
113 if (p
[1] < 255-br2
) p
[1] += br2
; else p
[1] = 255;
114 //p += lastOutput-output;
115 //if (p[0] < 255-br1) p[0] += br1; else p[0] = 255;
116 //if (p[1] < 255-br2) p[1] += br2; else p[1] = 255;
120 register uint32_t *ptr
= (uint32_t*)output
;
121 int i
= outWidth
*outHeight
*2/sizeof(uint32_t);
123 //Bytewize version was: *(ptr++) -= *ptr+(*ptr>>1)>>4;
126 *(ptr
++) = x
- ((x
& 0xf0f0f0f0ul
) >> 4) - ((x
& 0xe0e0e0e0ul
) >> 5);
132 inline unsigned char getPixel(int x
,int y
,int where
) {
133 if (x
< 0 || y
< 0 || x
>= outWidth
|| y
>= outHeight
) return 0;
134 return lastOutput
[where
];
137 inline void fadePixelWave(int x
,int y
,int where
,int step
) {
139 ( short(getPixel(x
-1,y
,where
-2))+
140 getPixel(x
+1,y
,where
+2)+
141 getPixel(x
,y
-1,where
-step
)+
142 getPixel(x
,y
+1,where
+step
)
145 if (!j
) { output
[where
] = 0; return; }
147 -lastLastOutput
[where
]
149 if (j
< 0) output
[where
] = 0;
150 else if (j
& (255*256)) output
[where
] = 255;
151 else output
[where
] = j
;
155 unsigned short *t
= lastLastOutputBmp
.data
;
156 lastLastOutputBmp
.data
= lastOutputBmp
.data
;
157 lastOutputBmp
.data
= outputBmp
.data
;
160 int x
,y
,i
,j
,start
,end
;
161 int step
= outWidth
*2;
162 for(x
=0,i
=0,j
=outWidth
*(outHeight
-1)*2;x
<outWidth
;x
++,i
+=2,j
+=2) {
163 fadePixelWave(x
,0,i
,step
);
164 fadePixelWave(x
,0,i
+1,step
);
165 fadePixelWave(x
,outHeight
-1,j
,step
);
166 fadePixelWave(x
,outHeight
-1,j
+1,step
);
169 for(y
=1,i
=outWidth
*2,j
=outWidth
*4-2;y
<outHeight
;y
++,i
+=step
,j
+=step
) {
170 fadePixelWave(0,y
,i
,step
);
171 fadePixelWave(0,y
,i
+1,step
);
172 fadePixelWave(outWidth
-1,y
,j
,step
);
173 fadePixelWave(outWidth
-1,y
,j
+1,step
);
178 end
=outWidth
*4-2; y
<outHeight
-1; y
++,start
+=step
,end
+=step
) {
182 ( short(lastOutput
[i
-2])+
194 if (j
< 0) output
[i
] = 0;
195 else if (j
& (255*256)) output
[i
] = 255;
202 inline void fadePixelHeat(int x
,int y
,int where
,int step
) {
204 ( short(getPixel(x
-1,y
,where
-2))+
205 getPixel(x
+1,y
,where
+2)+
206 getPixel(x
,y
-1,where
-step
)+
207 getPixel(x
,y
+1,where
+step
)
210 if (!j
) { output
[where
] = 0; return; }
212 -lastLastOutput
[where
]
214 if (j
< 0) output
[where
] = 0;
215 else if (j
& (255*256)) output
[where
] = 255;
216 else output
[where
] = j
;
220 unsigned short *t
= lastLastOutputBmp
.data
;
221 lastLastOutputBmp
.data
= lastOutputBmp
.data
;
222 lastOutputBmp
.data
= outputBmp
.data
;
225 int x
,y
,i
,j
,start
,end
;
226 int step
= outWidth
*2;
227 for(x
=0,i
=0,j
=outWidth
*(outHeight
-1)*2;x
<outWidth
;x
++,i
+=2,j
+=2) {
228 fadePixelHeat(x
,0,i
,step
);
229 fadePixelHeat(x
,0,i
+1,step
);
230 fadePixelHeat(x
,outHeight
-1,j
,step
);
231 fadePixelHeat(x
,outHeight
-1,j
+1,step
);
234 for(y
=1,i
=outWidth
*2,j
=outWidth
*4-2;y
<outHeight
;y
++,i
+=step
,j
+=step
) {
235 fadePixelHeat(0,y
,i
,step
);
236 fadePixelHeat(0,y
,i
+1,step
);
237 fadePixelHeat(outWidth
-1,y
,j
,step
);
238 fadePixelHeat(outWidth
-1,y
,j
+1,step
);
243 end
=outWidth
*4-2; y
<outHeight
-1; y
++,start
+=step
,end
+=step
) {
247 ( short(lastOutput
[i
-2])+
261 if (j
< 0) output
[i
] = 0;
262 else if (j
& (255*256)) output
[i
] = 255;
286 double x
[NumSamples
], y
[NumSamples
];
287 double a
[NumSamples
], b
[NumSamples
];
289 int clarity
[NumSamples
]; //Surround sound
292 int brightFactor
= int(Brightness
* brightnessTwiddler
/(starSize
+0.01));
294 if (-1 == getNextFragment())
297 for(i
=0;i
<NumSamples
;i
++) {
306 for(i
=0 +1;i
<NumSamples
/2;i
++) {
307 double x1
= x
[bitReverse
[i
]],
308 y1
= y
[bitReverse
[i
]],
309 x2
= x
[bitReverse
[NumSamples
-i
]],
310 y2
= y
[bitReverse
[NumSamples
-i
]],
312 a
[i
] = sqrt(aa
= (x1
+x2
)*(x1
+x2
) + (y1
-y2
)*(y1
-y2
) );
313 b
[i
] = sqrt(bb
= (x1
-x2
)*(x1
-x2
) + (y1
+y2
)*(y1
+y2
) );
316 ( (x1
+x2
) * (x1
-x2
) + (y1
+y2
) * (y1
-y2
) )/(aa
+bb
) * 256 );
320 energy
+= (aa
+bb
)*i
*i
;
323 energy
= sqrt(energy
/NumSamples
)/65536.0;
325 //int heightFactor = NumSamples/2 / outHeight + 1;
326 //int actualHeight = NumSamples/2/heightFactor;
327 //int heightAdd = outHeight + actualHeight >> 1;
329 /* Correct for window size */
330 //double brightFactor2 = (brightFactor/65536.0/NumSamples)*
331 // sqrt(actualHeight*outWidth/(320.0*200.0));
332 double brightFactor2
= (brightFactor
/65536.0/NumSamples
)*
333 sqrt(outHeight
*outWidth
/(320.0*200.0));
335 // Some more arbitrary constants,
336 // this time for dynamic range compression of the display
337 // (breath slowly, relax, please don't hunt me down and kill me)
338 static double energy_avg
= 80.0;
339 energy_avg
= energy_avg
*0.95 + energy
*0.05;
340 if (energy_avg
> 0.0)
341 brightFactor2
*= 80.0/(energy_avg
+ 5.0);
343 for(i
=1;i
<NumSamples
/2;i
++) {
344 //int h = (int)( b[i]*280 / (a[i]+b[i]+0.0001)+20 );
345 if (a
[i
] > 0 || b
[i
] > 0) {
346 int h
= (int)( b
[i
]*outWidth
/ (a
[i
]+b
[i
]) );
347 int br1
, br2
, br
= (int)(
348 (a
[i
]+b
[i
])*i
*brightFactor2
);
349 br1
= br
*(clarity
[i
]+128)>>8;
350 br2
= br
*(128-clarity
[i
])>>8;
352 if (br1
< 0) br1
= 0; else if (br1
> 255) br1
= 255;
353 if (br2
< 0) br2
= 0; else if (br2
> 255) br2
= 255;
356 py
= outHeight
-i
*outHeight
/(NumSamples
/2);
357 //was heightAdd - i / heightFactor;
359 if (pointsAreDiamonds
) {
360 addPixel(px
,py
,br1
,br2
);
361 br1
=scaleDown
[br1
];br2
=scaleDown
[br2
];
363 //TODO: Use addpixelfast
364 for(j
=1;br1
>0||br2
>0;j
++,br1
=scaleDown
[br1
],br2
=scaleDown
[br2
]) {
366 addPixel(px
-j
+k
,py
-k
,br1
,br2
);
367 addPixel(px
+k
,py
-j
+k
,br1
,br2
);
368 addPixel(px
+j
-k
,py
+k
,br1
,br2
);
369 addPixel(px
-k
,py
+j
-k
,br1
,br2
);
373 if (px
< maxStarRadius
|| py
< maxStarRadius
||
374 px
> outWidth
-maxStarRadius
|| py
> outHeight
-maxStarRadius
) {
375 addPixel(px
,py
,br1
,br2
);
376 for(j
=1;br1
>0||br2
>0;j
++,br1
=scaleDown
[br1
],br2
=scaleDown
[br2
]) {
377 addPixel(px
+j
,py
,br1
,br2
);
378 addPixel(px
,py
+j
,br1
,br2
);
379 addPixel(px
-j
,py
,br1
,br2
);
380 addPixel(px
,py
-j
,br1
,br2
);
383 unsigned char *p
= output
+px
*2+py
*outWidth
*2, *p1
=p
, *p2
=p
, *p3
=p
, *p4
=p
;
384 addPixelFast(p
,br1
,br2
);
385 for(;br1
>0||br2
>0;br1
=scaleDown
[br1
],br2
=scaleDown
[br2
]) {
387 addPixelFast(p1
,br1
,br2
);
389 addPixelFast(p2
,br1
,br2
);
391 addPixelFast(p3
,br1
,br2
);
393 addPixelFast(p4
,br1
,br2
);