1 /*
2  * SDLRoids - An Astroids clone.
3  *
4  * Copyright (c) 2000 David Hedbor <david@hedbor.org>
5  * 	based on xhyperoid by Russel Marks.
6  * 	xhyperoid is based on a Win16 game, Hyperoid by Edward Hutchins
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16  *
17  */
18 
19 /*
20  * sdlsound.c - Sound playing routines using raw SDL or SDL_mixer.
21  */
22 
23 #include "config.h"
24 RCSID("$Id: sdlsound.c,v 1.10 2001/03/24 04:04:06 neotron Exp $");
25 
26 #include "SDL_audio.h"
27 #include "sdlsound.h"
28 #include "misc.h"
29 #include "roidsupp.h"
30 
31 #ifdef HAVE_LIBSDL_MIXER
32 # ifdef HAVE_SDL_MIXER_H
33 #  include "SDL_mixer.h"
34 #  define USE_SDL_MIXER
35 # else
36 #  ifdef HAVE_SDL_SDL_MIXER_H
37 #   include "SDL/SDL_mixer.h"
38 #   define USE_SDL_MIXER
39 #  endif
40 # endif
41 #endif
42 
43 #include <stdlib.h>
44 
45 static int use_audio;
46 
47 /* sample filenames */
48 static char *samplename[]=
49 {
50   "sounds/pshot.wav",
51   "sounds/thrust.wav",
52   "sounds/explode.wav",
53   "sounds/explode2.wav",
54   "sounds/bshot.wav",
55   "sounds/phit.wav",
56   "sounds/title.wav",
57   "sounds/newbonus.wav",
58   "sounds/newbad.wav",
59   "sounds/bonusgot.wav",
60   "sounds/bwound.wav",
61   "sounds/swarmsplit.wav"
62 };
63 
64 #ifndef USE_SDL_MIXER
65 
66 struct channel_tag
67 {
68   struct sample_tag *sample;	/* pointer to sample struct, NULL if none */
69   int offset;			/* position in sample */
70   int loop;                     /* loop the sound */
71 } channel[NUM_CHANNELS];
72 
73 
74 /* for in-memory samples */
75 struct sample_tag
76 {
77   SDL_AudioSpec spec; /* Sample format spec */
78   Uint8 *data; /* Data buffer */
79   Uint32 len;  /* buffer length */
80 } samples[NUM_SAMPLES];
81 
82 #define BYTEFIX(x)	(((x)<0)?0:(((x)>255)?255:(x)))
83 
84 /* mix and play a chunk of sound to /dev/dsp. */
85 
play_audio(void * udata,Uint8 * stream,int len)86 void play_audio(void *udata, Uint8 *stream, int len)
87 {
88   int f,g,v;
89   struct channel_tag *cptr;
90   Uint8 soundbuf[1024];
91   if(udata == NULL) return;
92   for(f = 0; f < len; f++)
93   {
94     v=0;
95     for(g = 0, cptr = &(channel[0]); g < NUM_CHANNELS; g++, cptr++)
96       if(cptr->sample != NULL)
97       {
98 	v += (int)cptr->sample->data[ cptr->offset++ ];
99 	if(cptr->offset >= cptr->sample->len) {
100 	  if(cptr->loop == 1) {
101 	    cptr->offset = 0;
102 	  } else
103 	    cptr->sample = NULL;
104 	}
105       }
106       else
107 	v+=128;	/* make sure it doesn't click! */
108 
109     /* kludge to up the volume of sound effects - mmm, lovely distortion :-) */
110     v -= 128*NUM_CHANNELS;
111     v = 128 + (v * 3) / (2 * NUM_CHANNELS);
112     v = BYTEFIX(v);
113 
114     soundbuf[f] = (unsigned char)v;
115   }
116   SDL_MixAudio(stream, soundbuf, len, SDL_MIX_MAXVOLUME);
117 
118 }
119 
120 /* Load the specified sample */
load_sample(int num)121 int load_sample(int num) {
122 
123   if(SDL_LoadWAV(samplename[num], &samples[num].spec,
124 		 &samples[num].data, &samples[num].len) ||
125      SDL_LoadWAV(datafilename(NULL, samplename[num]), &samples[num].spec,
126 		   &samples[num].data, &samples[num].len) ||
127      SDL_LoadWAV(datafilename(DATADIR, samplename[num]), &samples[num].spec,
128 		   &samples[num].data, &samples[num].len) ||
129      SDL_LoadWAV(datafilename(bindir, samplename[num]), &samples[num].spec,
130 		   &samples[num].data, &samples[num].len))
131     return 1;
132   return 0;
133 }
134 
init_sound(void)135 void init_sound(void)
136 {
137   int f;
138   SDL_AudioSpec wanted;
139   /* Set the audio format */
140   wanted.freq = 8000;
141   wanted.format = AUDIO_U8;
142   wanted.channels = 1;    /* 1 = mono, 2 = stereo */
143   wanted.samples = 1024;  /* Good low-latency value for callback */
144   wanted.callback = play_audio;
145   wanted.userdata = NULL;
146 
147   if( SDL_OpenAudio(&wanted, NULL) < 0) {
148     fprintf(stderr, "Warning: %s\n", SDL_GetError());
149     use_audio=0;
150     return;
151   } else
152     use_audio=1;
153   memset(channel, 0, sizeof(channel));
154   for(f = 0; f < NUM_SAMPLES; f++)
155   {
156     if(!load_sample(f)) {
157       fprintf(stderr, "Fatal: Couldn't load sample %s.\n", samplename[f]);
158       exit(1);
159     }
160   }
161 }
162 
163 /* setup a new sample to be played on a given channel. */
queuesam(int chan,int sam)164 void queuesam(int chan,int sam)
165 {
166   if(!use_audio) return;
167   SDL_PauseAudio(1);
168   channel[chan].sample = &samples[sam];
169   channel[chan].offset = 0;
170   channel[chan].loop   = 0;
171   SDL_PauseAudio(0);
172 }
173 
loopsam(int chan,int sam)174 void loopsam(int chan,int sam)
175 {
176   if(!use_audio) return;
177   SDL_PauseAudio(1);
178   if(sam >=0 ) {
179     channel[chan].sample = &samples[sam];
180     channel[chan].offset = 0;
181     channel[chan].loop   = 1;
182   } else {
183     channel[chan].sample = NULL;
184     channel[chan].offset = 0;
185     channel[chan].loop   = 0;
186   }
187   SDL_PauseAudio(0);
188 }
189 
exit_sound()190 void exit_sound()
191 {
192   int f;
193   if(!use_audio) return;
194 
195   for(f = 0; f < NUM_SAMPLES; f++)
196     SDL_FreeWAV(samples[f].data);
197 }
198 
199 #else /*USE_SDL_MIXER */
200 
201 /* for in-memory samples */
202 static Mix_Chunk *samples[NUM_SAMPLES];
203 
204 /* Load the specified sample */
load_sample(int num)205 int load_sample(int num) {
206 
207   if((samples[num] = Mix_LoadWAV(samplename[num])) ||
208      Mix_LoadWAV(datafilename(NULL, samplename[num])) ||
209      Mix_LoadWAV(datafilename(DATADIR, samplename[num])) ||
210      Mix_LoadWAV(datafilename(bindir, samplename[num])))
211     return 1;
212   return 0;
213 }
214 
init_sound(void)215 void init_sound(void)
216 {
217   int f;
218   int audio_rate, audio_channels;
219   Uint16 audio_format;
220 
221   /* Set the audio format */
222   audio_rate = 8000;
223   audio_format = AUDIO_S16;
224   audio_channels = 2;    /* 1 = mono, 2 = stereo */
225 
226   if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, 256) < 0) {
227     fprintf(stderr, "Warning: %s\n", SDL_GetError());
228     use_audio = 0;
229     return;
230   }  else {
231     Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels);
232     use_audio = 1;
233   }
234   for(f = 0; f < NUM_CHANNELS; f++) Mix_Volume(f, 100);
235 
236   for(f = 0; f < NUM_SAMPLES; f++)
237   {
238     if(!load_sample(f))
239     {
240       fprintf(stderr, "Fatal: Couldn't load sample %s.\n", samplename[f]);
241       exit(1);
242     }
243   }
244 }
245 
exit_sound()246 void exit_sound()
247 {
248   int f;
249   if(!use_audio) return;
250 
251   for(f = 0; f < NUM_SAMPLES; f++)
252     Mix_FreeChunk(samples[f]);
253 }
254 
255 /* setup a new sample to be played on a given channel. */
queuesam(int chan,int sam)256 void queuesam(int chan,int sam)
257 {
258   if(!use_audio) return;
259   Mix_PlayChannel(chan, samples[sam], 0);
260 }
261 
262 
263 /* setup a new sample to be played on a given channel. */
loopsam(int chan,int sam)264 void loopsam(int chan,int sam)
265 {
266   if(!use_audio) return;
267   if(sam >=0 )
268     Mix_PlayChannel(chan, samples[sam], -1);
269   else
270     Mix_HaltChannel(chan);
271 }
272 
273 #endif
274 
275