1 /*
2   tempest for eliza code
3   Copyright (C) 2001  Erik Thiele
4 
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 #include <math.h>
21 #include <stdlib.h>
22 #include <sys/time.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <SDL.h>
26 #include <string.h>
27 
28 double carrier;
29 int resx;
30 int resy;
31 int horizontalspan;
32 double pixelclock;
33 
34 SDL_Surface *screen;
35 Uint32 white, black;
36 
37 class zeit : public timeval {
38 public:
zeit()39   zeit() { setzero(); };
getcurrenttime()40   void getcurrenttime() { gettimeofday (this,0); };
subtract(const zeit & subme)41   void subtract (const zeit &subme)
42     {
43       tv_sec-=subme.tv_sec;
44       tv_usec-=subme.tv_usec;
45       normalize();
46     };
add(const zeit & addme)47   void add (const zeit &addme)
48     {
49       tv_sec+=addme.tv_sec;
50       tv_usec+=addme.tv_usec;
51       normalize();
52     };
normalize()53   void normalize()
54     {
55       while (tv_usec<0) {
56 	tv_usec+=1000000;
57 	tv_sec--;
58       };
59       while (tv_usec>=1000000) {
60 	tv_usec-=1000000;
61 	tv_sec++;
62       };
63     };
zero()64   bool zero()
65     {
66       return (tv_sec==0)&&(tv_usec==0);
67     };
setzero()68   void setzero()
69     {
70       tv_sec=tv_usec=0;
71     };
print()72   void print()
73     {
74       printf("%8d:%8d\n",int(tv_sec),int(tv_usec));
75     };
setdouble(const double val)76   void setdouble(const double val)
77     {
78       long long i=(long long)(val*1000000);
79       tv_usec=i%1000000;
80       tv_sec=i/1000000;
81       normalize();
82     };
83 };
84 
pixelchen(const int x,const int y,const Uint32 pixel)85 inline void pixelchen (const int x, const int y, const Uint32 pixel)
86 {
87   Uint8 *bits=((Uint8*)screen->pixels)+y*screen->pitch+x*screen->format->BytesPerPixel;
88   switch(screen->format->BytesPerPixel) {
89   case 1:
90     *((Uint8 *)(bits)) = (Uint8)pixel;
91     break;
92   case 2:
93     *((Uint16 *)(bits)) = (Uint16)pixel;
94     break;
95   case 3:
96     { /* Format/endian independent */
97       Uint8 r, g, b;
98 
99       r = (pixel>>screen->format->Rshift)&0xFF;
100       g = (pixel>>screen->format->Gshift)&0xFF;
101       b = (pixel>>screen->format->Bshift)&0xFF;
102       *((bits)+screen->format->Rshift/8) = r;
103       *((bits)+screen->format->Gshift/8) = g;
104       *((bits)+screen->format->Bshift/8) = b;
105     }
106     break;
107   case 4:
108     *((Uint32 *)(bits)) = (Uint32)pixel;
109     break;
110   };
111 };
112 
waituntil(const zeit & desttime)113 void waituntil (const zeit &desttime)
114 {
115   zeit tm(desttime);
116   zeit cur;
117   cur.getcurrenttime();
118   tm.subtract(cur);
119 
120   select(1,0,0,0,&tm);
121 };
122 
mkrealsound(double freq)123 void mkrealsound(double freq)
124 {
125   SDL_Rect myrect;
126   myrect.x=myrect.y=0;
127   myrect.w=resx;
128   myrect.h=resy;
129   SDL_FillRect(screen,&myrect,black);
130 
131   int x, y;
132   double t;
133 
134   double ftfp2 = freq / pixelclock * 2.0;
135   double fcfp2 = carrier / pixelclock * 2.0;
136 
137   t = 0;
138   for (y = 0; y < resy; y++) {
139     if (int(t*ftfp2)%2) {
140       // 1
141       t+=resx;
142     }else{
143       // 0
144       for (x = 0; x < resx; x++) {
145 	if (int(t*fcfp2)%2)
146 	  pixelchen(x,y,white);
147 	t++;
148       };
149     };
150 
151     t += horizontalspan - resx;
152   }
153 }
154 
note(int nr)155 double note (int nr)
156 {
157   return pow(2.0,nr/12.0)*440.0*2;
158 };
159 
160 
161 int curoct, curnot;
162 double curlen;
163 bool loaded;
164 zeit timefornextsound;
165 
resetplay()166 void resetplay()
167 {
168   curoct=0;
169   curnot=0;
170   curlen=128;
171   loaded=false;
172   timefornextsound.setzero();
173 };
174 
finishplay()175 void finishplay ()
176 {
177   SDL_Rect myrect;
178   myrect.x=myrect.y=0;
179   myrect.w=resx;
180   myrect.h=resy;
181   SDL_FillRect(screen,&myrect,black);
182 
183   waituntil(timefornextsound);
184   SDL_UpdateRect(screen,0,0,resx,resy);
185 };
186 
flushplay()187 void flushplay ()
188 {
189   if (loaded) {
190     if (curnot==-1000) {
191       SDL_Rect myrect;
192       myrect.x=myrect.y=0;
193       myrect.w=resx;
194       myrect.h=resy;
195       SDL_FillRect(screen,&myrect,black);
196 
197       waituntil(timefornextsound);
198     }else{
199       mkrealsound(note(curnot+12*curoct));
200     };
201     if (timefornextsound.zero()) {
202       timefornextsound.getcurrenttime();
203     }else{
204       waituntil(timefornextsound);
205     };
206     SDL_UpdateRect(screen,0,0,resx,resy);
207 
208     zeit length;
209     length.setdouble(curlen/40.0);
210     timefornextsound.add(length);
211     loaded=false;
212   };
213 };
214 
play(const char * const song)215 void play (const char *const song)
216 {
217   int pos=0;
218   while (pos<int(strlen(song))) {
219     SDL_Event event;
220     while(SDL_PollEvent(&event)) if (event.type == SDL_MOUSEBUTTONDOWN) exit(0);
221     switch(song[pos]) {
222     case 'c': flushplay(); curnot=0; loaded=true; break;
223     case 'd': flushplay(); curnot=2; loaded=true; break;
224     case 'e': flushplay(); curnot=4; loaded=true; break;
225     case 'f': flushplay(); curnot=5; loaded=true; break;
226     case 'g': flushplay(); curnot=7; loaded=true; break;
227     case 'a': flushplay(); curnot=9; loaded=true; break;
228     case 'b': flushplay(); curnot=11; loaded=true; break;
229     case 'p': flushplay(); curnot=-1000; loaded=true; break;
230     case '#': curnot++; break;
231     case '1': flushplay(); curlen=128; break;
232     case '2': flushplay(); curlen=64; break;
233     case '4': flushplay(); curlen=32; break;
234     case '5': flushplay(); curlen=48; break;
235     case '8': flushplay(); curlen=16; break;
236     case '6': flushplay(); curlen=8; break;
237     case 'u': flushplay(); curoct=-2; break;
238     case 'l': flushplay(); curoct=-1; break;
239     case 'h': flushplay(); curoct=0; break;
240     case 'x': flushplay(); curoct=1; break;
241     default:break;
242     };
243     pos++;
244   };
245   flushplay();
246 };
247 
usage()248 void usage()
249 {
250   printf("\nwrong parameters ! read readme file!\n\n");
251   exit(1);
252 };
253 
main(int argc,char * argv[])254 int main(int argc, char *argv[])
255 {
256   carrier=10000000.0;
257   resx=1024;
258   resy=768;
259   horizontalspan=1400;
260   pixelclock=105.0 * 1e6;
261   char *filename;
262 
263   atexit(SDL_Quit);
264 
265   printf(
266 	 "\n"
267 	 "Tempest for Eliza - by erikyyy !\n"
268 	 "--------------------------------\n"
269 	 "\n"
270 	 "Read the README file to understand what's happening\n"
271 	 "if you do not read it, you will NOT know what to do\n"
272 	 );
273 
274   if (argc!=7) usage();
275   pixelclock=atof(argv[1]);
276   resx=atol(argv[2]);
277   resy=atol(argv[3]);
278   horizontalspan=atol(argv[4]);
279   carrier=atof(argv[5]);
280   filename=argv[6];
281 
282   printf("\n"
283 	 "Pixel Clock %.0f Hz\n"
284 	 "X Resolution %d Pixels\n"
285 	 "Y Resolution %d Pixels\n"
286 	 "Horizontal Total %d Pixels\n"
287 	 "AM Carrier Frequency %.0f Hz\n"
288 	 "\n\n",
289 	 pixelclock,resx,resy,horizontalspan,carrier);
290 
291   if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
292     fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
293     exit(1);
294   };
295 
296   /* Have a preference for 8-bit, but accept any depth */
297   screen = SDL_SetVideoMode(resx, resy, 8, SDL_SWSURFACE|SDL_ANYFORMAT|SDL_FULLSCREEN);
298   if ( screen == NULL ) {
299     fprintf(stderr, "Couldn't set video mode: %s\n", SDL_GetError());
300     exit(1);
301   }
302   printf("Have Set %d bits-per-pixel mode\n",
303 	 screen->format->BitsPerPixel);
304 
305   SDL_Color col[2];
306   col[0].r=col[0].g=col[0].b=0xff; // white
307   col[1].r=col[1].g=col[1].b=0x00; // black
308 
309   SDL_SetColors(screen,col,0,2);
310   white = SDL_MapRGB(screen->format,0xff,0xff,0xff);
311   black = SDL_MapRGB(screen->format,0x00,0x00,0x00);
312 
313   char song[100000];
314   FILE *input=fopen(filename,"r");
315   if (!input) { printf("cannot open file\n"); return 1; };
316   resetplay();
317   char *ret;
318   do {
319     ret=fgets(song,100000,input);
320     if (ret) {
321       for (unsigned i=0;i<strlen(song);i++)
322 	if (song[i]=='*') song[i]=0;
323       play (song);
324     }
325   } while(ret);
326   finishplay();
327   fclose(input);
328 
329   return 0;
330 };
331