1 /*
2  * xgal.sndsrv.c -
3  *                 Modified for SunOS/Solaris.
4  *                 Reportedly this really sucks, use NAS_SOUND instead
5  *                 if you have NAS installed.
6  *                     -Joe
7  *
8  * Copyright 1994-1995 Sujal M. Patel (smpatel@wam.umd.edu)
9  * Conditions in "copyright.h"
10  */
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include <sys/ioctl.h>
17 #include <sys/time.h>
18 #include <signal.h>
19 #include <string.h>
20 
21 
22 #ifdef SOLARIS
23 #define bzero(s,l) memset(s, 0, l)
24 #define bcopy(s,d,l) memcpy(d,s,l)
25 #endif
26 
27 char *FILENAME[] = {
28                      "/explode.raw",
29                      "/firetorp.raw",
30                      "/shield.raw",
31                      "/torphit.raw",
32                      "/explode_big.raw",
33 		     "/ddloo.raw",
34 		     "/warp.raw",
35 		     "/smart.raw",
36                    };
37 
38 #define NUM_SOUNDS	(sizeof(FILENAME)/sizeof(char*))
39 
40 signed char *sound_buffer[NUM_SOUNDS];
41 int sound_size[NUM_SOUNDS];
42 int fragsize;
43 
44 
45 /* Terminate: Signal Handler */
quit()46 void quit ()
47 {
48   exit (0);
49 }
50 
51 
52 
init(int argc,char ** argv)53 void init (int argc, char **argv)
54 {
55   int i;
56   char s[1024];
57 
58   if (argc != 3)
59   {
60     printf ("This program is only executed by xgal\n");
61     exit (1);
62   }
63 
64   for (i=0; i < NUM_SOUNDS; i++)
65   {
66     s[0] = 0;
67     strcat (s, argv[1]);
68     if (s[(int)strlen(s) - 1] == '/') FILENAME[i]++;
69     strcat (s, FILENAME[i]);
70     FILENAME[i] = malloc ((int)strlen (s));
71     strcpy (FILENAME[i],s);
72     sound_buffer[i]=NULL;
73     sound_size[i]=0;
74   }
75 
76   signal(SIGTERM, quit);   /* Setup Terminate Signal Handler */
77 }
78 
79 
80 /*
81    Setup DSP: Opens /dev/audio
82               Sets fragment size to 512
83               Error checking
84 */
setup_dsp(char * dspdev)85 int setup_dsp (char *dspdev)
86 {
87   int dsp, frag, value;
88   int mixer;
89 
90   dsp = open(dspdev, O_RDWR);
91   if (dsp < 1)
92   {
93     fprintf (stderr, "xgal.sndsrv: Couldn't open DSP %s\n",dspdev);
94     return -1;
95   }
96 
97   fragsize = 512;
98 
99   return dsp;
100 }
101 
102 /*
103    This just keeps the pipe from breaking...
104    Eventually I'll look at the xgal signal handlers and
105    just trap this.
106 */
do_nothing(void)107 int do_nothing(void)
108 {
109     fprintf(stderr,"xgal.sndsrv: doing nothing, something is broken\n");
110     while(1)  sleep (5);
111 }
112 
read_sound(int k)113 int read_sound(int k)
114 {
115   int i,fd,size;
116 
117   /*fprintf(stderr,"loading sound %d, %s\n",k,FILENAME[k]);*/
118 
119   fd = open(FILENAME[k], O_RDONLY);
120   if(fd<=0)
121   {
122     fprintf (stderr, "xgal.sndsrv: The sound %s could not be opened\n", FILENAME[k]);
123     sound_size[k]=-1;
124     return(0);
125   };
126   size=lseek(fd,0,SEEK_END);
127   sound_size[k]=(size/fragsize)+1;   /*size in fragments*/
128   sound_buffer[k]=malloc(sound_size[k]*fragsize);
129   if(sound_buffer[k]==NULL)
130   {
131     fprintf(stderr,"xgal.sndsrv: couldn't malloc memory for sound\n");
132     sound_size[k]=-1;
133     close(fd);
134     return(0);
135   };
136   lseek(fd,0,SEEK_SET);
137   read(fd,sound_buffer[k],size);
138   close(fd);
139   for(i=0;i<size;i++)  sound_buffer[k][i]^=0x80;
140   bzero(sound_buffer[k]+size,sound_size[k]*fragsize-size);
141 
142   /*fprintf(stderr,"sound has been loaded, %d bytes\n",size);*/ /*DEBUG*/
143   return(1);
144 }
145 
146 
do_everything(int dsp)147 void do_everything (int dsp)
148 {
149   char k;
150   int i, j ;
151   int terminate = -1;             /* Which Sound to Terminate                              */
152   int playing[16];                /* Sound numbers that we are playing                     */
153   int position[16];		  /* Current position in each sound file */
154   int playnum = 0;                /* Number of sounds currently being played               */
155   unsigned char final[512];       /* Final Mixing Buffer                                   */
156   int premix[512];
157   char *sample;
158 
159   for(;;)  {
160     terminate = -1;
161     /* Try to open a new sound if we get an integer on the 'in' pipe */
162     i=read(STDIN_FILENO,&k,sizeof(k));
163     if(i==0)  {   /* EOF on pipe means parent has closed its end */
164         /*fprintf(stderr,"xgal.sndsrv: shutting down\n"); */
165         kill(getpid(), SIGTERM);
166     };
167     if(i!=-1)  {  /* there was something in the pipe */
168         /*fprintf(stderr,"Just read a %d from pipe\n",(int)k);*/ /*DEBUG*/
169         /* Negative means terminate the FIRST sound in the buffer */
170         if(k<0)  {
171             /*fprintf(stderr,"terminating sound\n");*/ /*DEBUG*/
172             terminate = 0;
173         } else {
174             if(sound_size[(int)k]==0) read_sound(k);
175             if(sound_size[(int)k]>0 && playnum<16)  {
176 	        position[playnum]=0;
177                 playing[playnum++]=k;
178                 /*fprintf(stderr,"sound %d added to play queue\n",playnum-1);*/ /*DEBUG*/
179             };
180         };
181     };
182 
183     /* terminate a sound if necessary */
184     for(i=0;i<playnum;i++)
185     {
186       if((position[i]==sound_size[playing[i]]) || (terminate==i))
187       {
188         /*fprintf(stderr,"finished playing sound %d\n",i);*/ /*DEBUG*/
189 	/*fprintf(stderr,"is was at position %d\n",position[i]);*/ /*DEBUG*/
190         bcopy(playing+i+1,playing+i,(playnum-i)*sizeof(int));
191         bcopy(position+i+1,position+i,(playnum-i)*sizeof(int));
192         playnum--;i--;
193       };
194     };
195 
196     if(playnum)  {
197         /* Mix each sound into the final buffer */
198         bzero(premix,sizeof(premix));
199         for(i=0;i<playnum;i++)  {
200             sample=sound_buffer[playing[i]]+position[i]*fragsize;
201             for(j=0;j<fragsize;j++)  {
202                 premix[j]+=*(sample+j);
203             };
204             position[i]++;
205         };
206         for(i=0;i<fragsize;i++)
207             final[i]=(premix[i]>255)?255:(premix[i]<-256?0:(premix[i]>>1)+128);
208     } else {
209         /*
210            We have no sounds to play
211            Just fill the buffer with silence and maybe play it
212         */
213         memset(final,128,sizeof(final));
214     };
215     write (dsp, final, fragsize);
216     /*
217        The sound server is in a tight loop, EXCEPT for this
218        write which blocks.  Any optimizations in the above
219        code would really be helpful.  Right now the server
220        takes up to 7% cpu on a 486DX/50.
221     */
222   }
223 }
224 
225 
226 
main(argc,argv)227 void main (argc, argv)
228 int argc;
229 char **argv;
230 {
231   int dsp;
232 
233   fcntl(STDIN_FILENO,F_SETFL,O_NONBLOCK);
234   init (argc, argv);
235   dsp = setup_dsp (argv[2]);
236 
237   if (!dsp) do_nothing();
238 
239   do_everything (dsp);
240 }
241