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