[Git]Ignore work files.
[synaesthesia.git] / core.cc
blob50408a6af813d4e6901c41fe4ba919b71dcffb28
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
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdint.h>
27 #include <math.h>
28 #include <string.h>
29 #include "syna.h"
31 double cosTable[NumSamples], negSinTable[NumSamples];
32 int bitReverse[NumSamples];
33 int scaleDown[256];
34 int maxStarRadius;
36 int bitReverser(int i) {
37 int sum=0,j;
38 for(j=0;j<LogSize;j++) {
39 sum = (i&1)+sum*2;
40 i >>= 1;
42 return sum;
45 void fft(double *x,double *y) {
46 int n2 = NumSamples, n1;
47 int twoToTheK;
48 for(twoToTheK=1;twoToTheK<NumSamples;twoToTheK*=2) {
49 n1 = n2;
50 n2 /= 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) {
55 int l = i+n2;
56 double xt = x[i] - x[l];
57 x[i] = (x[i] + x[l]);
58 double yt = y[i] - y[l];
59 y[i] = (y[i] + y[l]);
60 x[l] = xt*c - yt*s;
61 y[l] = xt*s + yt*c;
67 void coreInit() {
68 int i;
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));
84 int factor;
85 if (size > 0.0)
86 factor = int(exp(log(fadeModeFudge) / (size*8.0))*255);
87 else
88 factor = 0;
90 if (factor > 255) factor = 255;
92 for(int i=0;i<256;i++)
93 scaleDown[i] = i*factor>>8;
95 maxStarRadius = 1;
96 for(int i=255;i;i = scaleDown[i])
97 maxStarRadius++;
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;
119 void fadeFade() {
120 register uint32_t *ptr = (uint32_t*)output;
121 int i = outWidth*outHeight*2/sizeof(uint32_t);
122 do {
123 //Bytewize version was: *(ptr++) -= *ptr+(*ptr>>1)>>4;
124 uint32_t x = *ptr;
125 if (x)
126 *(ptr++) = x - ((x & 0xf0f0f0f0ul) >> 4) - ((x & 0xe0e0e0e0ul) >> 5);
127 else
128 ptr++;
129 } while(--i > 0);
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) {
138 short j =
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)
143 >> 2)
144 +lastOutput[where];
145 if (!j) { output[where] = 0; return; }
146 j = j
147 -lastLastOutput[where]
149 if (j < 0) output[where] = 0;
150 else if (j & (255*256)) output[where] = 255;
151 else output[where] = j;
154 void fadeWave() {
155 unsigned short *t = lastLastOutputBmp.data;
156 lastLastOutputBmp.data = lastOutputBmp.data;
157 lastOutputBmp.data = outputBmp.data;
158 outputBmp.data = t;
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);
176 for(y=1,
177 start=outWidth*2+2,
178 end=outWidth*4-2; y<outHeight-1; y++,start+=step,end+=step) {
179 int i = start;
180 do {
181 short j =
182 ( short(lastOutput[i-2])+
183 lastOutput[i+2]+
184 lastOutput[i-step]+
185 lastOutput[i+step]
186 >> 2)
187 +lastOutput[i];
188 if (!j) {
189 output[i] = 0;
190 } else {
191 j = j
192 -lastLastOutput[i]
194 if (j < 0) output[i] = 0;
195 else if (j & (255*256)) output[i] = 255;
196 else output[i] = j;
198 } while(++i < end);
202 inline void fadePixelHeat(int x,int y,int where,int step) {
203 short j =
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)
208 >> 2)
209 +lastOutput[where];
210 if (!j) { output[where] = 0; return; }
211 j = j
212 -lastLastOutput[where]
214 if (j < 0) output[where] = 0;
215 else if (j & (255*256)) output[where] = 255;
216 else output[where] = j;
219 void fadeHeat() {
220 unsigned short *t = lastLastOutputBmp.data;
221 lastLastOutputBmp.data = lastOutputBmp.data;
222 lastOutputBmp.data = outputBmp.data;
223 outputBmp.data = t;
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);
241 for(y=1,
242 start=outWidth*2+2,
243 end=outWidth*4-2; y<outHeight-1; y++,start+=step,end+=step) {
244 int i = start;
245 do {
246 short j =
247 ( short(lastOutput[i-2])+
248 lastOutput[i+2]+
249 +lastOutput[i-step]
250 +lastOutput[i+step]
251 >> 2)
252 +lastOutput[i];
253 if (!j) {
254 output[i] = 0;
255 } else {
256 j = j
257 -lastLastOutput[i]
258 +(lastLastOutput[i]
259 -lastOutput[i]>>2)
261 if (j < 0) output[i] = 0;
262 else if (j & (255*256)) output[i] = 255;
263 else output[i] = j;
265 } while(++i < end);
269 void fade() {
270 switch(fadeMode) {
271 case Stars :
272 fadeFade();
273 break;
274 case Flame :
275 fadeHeat();
276 break;
277 case Wave :
278 fadeWave();
279 break;
280 default:
281 break;
285 int coreGo() {
286 double x[NumSamples], y[NumSamples];
287 double a[NumSamples], b[NumSamples];
288 double energy;
289 int clarity[NumSamples]; //Surround sound
290 int i,j,k;
292 int brightFactor = int(Brightness * brightnessTwiddler /(starSize+0.01));
294 if (-1 == getNextFragment())
295 return -1;
297 for(i=0;i<NumSamples;i++) {
298 x[i] = data[i*2];
299 y[i] = data[i*2+1];
302 fft(x,y);
304 energy = 0.0;
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]],
311 aa,bb;
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) );
314 if (aa+bb != 0.0)
315 clarity[i] = (int)(
316 ( (x1+x2) * (x1-x2) + (y1+y2) * (y1-y2) )/(aa+bb) * 256 );
317 else
318 clarity[i] = 0;
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;
355 int px = h,
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]) {
365 for(k=0;k<j;k++) {
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);
372 } else {
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);
382 } else {
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]) {
386 p1 += 2;
387 addPixelFast(p1,br1,br2);
388 p2 -= 2;
389 addPixelFast(p2,br1,br2);
390 p3 += outWidth*2;
391 addPixelFast(p3,br1,br2);
392 p4 -= outWidth*2;
393 addPixelFast(p4,br1,br2);
399 return 0;