Subversion Repositories Games.Rick Dangerous

Rev

Rev 1 | Rev 5 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
/*
2
 * src/syssnd.c
3
 *
4
 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net). All rights reserved.
5
 *
6
 * The use and distribution terms for this software are contained in the file
7
 * named README, which can be found in the root of this distribution. By
8
 * using this software in any fashion, you are agreeing to be bound by the
9
 * terms of this license.
10
 *
11
 * You must not remove this notice, or any other, from this software.
12
 */
13
 
14
#include <SDL.h>
15
#include <stdlib.h>
16
#include <memory.h>
17
 
18
#include "system.h"
19
#include "game.h"
20
#include "syssnd.h"
21
 
22
 
23
#define ADJVOL(S) (((S) *sndVol) / SDL_MIX_MAXVOLUME)
24
 
25
 
26
static U8 isAudioActive = FALSE;
27
static channel_t channel[SYSSND_MIXCHANNELS];
28
 
29
static U8 sndVol = SDL_MIX_MAXVOLUME;   /* internal volume */
30
static U8 sndUVol = SYSSND_MAXVOL;   /* user-selected volume */
31
static U8 sndMute = FALSE;   /* mute flag */
32
 
33
static SDL_mutex *sndlock;
34
 
35
 
36
/*
37
 * prototypes
38
 */
39
static int sdlRWops_open (SDL_RWops *context, char *name);
40
static int sdlRWops_seek (SDL_RWops *context, int offset, int whence);
41
static int sdlRWops_read (SDL_RWops *context, void *ptr, int size, int maxnum);
42
static int sdlRWops_write (SDL_RWops *context, const void *ptr, int size, int num);
43
static int sdlRWops_close (SDL_RWops *context);
44
static void end_channel (U8);
45
 
46
 
47
/*
48
 * Callback -- this is also where all sound mixing is done
49
 *
50
 * Note: it may not be that much a good idea to do all the mixing here ; it
51
 * may be more efficient to mix samples every frame, or maybe everytime a
52
 * new sound is sent to be played. I don't know.
53
 */
54
void syssnd_callback (void *userdata, U8 *stream, int len)
55
{
56
   U8 c;
57
   S16 s;
58
   U32 i;
59
 
60
   SDL_mutexP(sndlock);
61
 
62
   for (i = 0; i < (U32)len; i++)
63
   {
64
      s = 0;
65
      for (c = 0; c < SYSSND_MIXCHANNELS; c++)
66
      {
67
         if (channel[c].loop != 0)
68
         {
69
            /* channel is active */
70
            if (channel[c].len > 0)
71
            {
72
               /* not ending */
73
               s += ADJVOL (*channel[c].buf - 0x80);
74
               channel[c].buf++;
75
               channel[c].len--;
76
            }
77
            else
78
            {
79
               /* ending */
80
               if (channel[c].loop > 0)
81
                  channel[c].loop--;
82
 
83
               if (channel[c].loop)
84
               {
85
                  /* just loop */
86
                  channel[c].buf = channel[c].snd->buf;
87
                  channel[c].len = channel[c].snd->len;
88
                  s += ADJVOL (*channel[c].buf - 0x80);
89
                  channel[c].buf++;
90
                  channel[c].len--;
91
               }
92
               else
93
                  end_channel(c); /* end for real */
94
            }
95
         }
96
      }
97
 
98
      if (sndMute)
99
         stream[i] = 0x80;
100
      else
101
      {
102
         s += 0x80;
103
         if (s > 0xff) s = 0xff;
104
         if (s < 0x00) s = 0x00;
105
         stream[i] = (U8) s;
106
      }
107
   }
108
 
109
   memcpy (stream, stream, len);
110
 
111
   SDL_mutexV (sndlock);
112
}
113
 
114
 
115
static void end_channel (U8 c)
116
{
117
   channel[c].loop = 0;
118
   if (channel[c].snd->dispose)
119
      syssnd_free (channel[c].snd);
120
   channel[c].snd = NULL;
121
}
122
 
123
 
124
void syssnd_init (void)
125
{
126
   SDL_AudioSpec desired, obtained;
127
   U16 c;
128
 
129
   if (SDL_InitSubSystem (SDL_INIT_AUDIO) < 0)
130
      return;
131
 
132
   desired.freq = SYSSND_FREQ;
133
   desired.format = AUDIO_U8;
134
   desired.channels = SYSSND_CHANNELS;
135
   desired.samples = SYSSND_MIXSAMPLES;
136
   desired.callback = syssnd_callback;
137
   desired.userdata = NULL;
138
 
139
   if (SDL_OpenAudio (&desired, &obtained) < 0)
140
      return;
141
 
142
   sndlock = SDL_CreateMutex ();
143
   if (sndlock == NULL)
144
   {
145
      SDL_CloseAudio ();
146
      return;
147
   }
148
 
149
   if (sysarg_args_vol != 0)
150
   {
151
      sndUVol = sysarg_args_vol;
152
      sndVol = SDL_MIX_MAXVOLUME * sndUVol / SYSSND_MAXVOL;
153
   }
154
 
155
   for (c = 0; c < SYSSND_MIXCHANNELS; c++)
156
      channel[c].loop = 0;   /* deactivate */
157
 
158
   isAudioActive = TRUE;
159
   SDL_PauseAudio (0);
160
}
161
 
162
 
163
/*
164
 * Shutdown
165
 */
166
void syssnd_shutdown (void)
167
{
168
   if (!isAudioActive)
169
      return;
170
 
171
   SDL_CloseAudio ();
172
   SDL_DestroyMutex (sndlock);
173
   isAudioActive = FALSE;
174
}
175
 
176
 
177
/*
178
 * Toggle mute
179
 *
180
 * When muted, sounds are still managed but not sent to the dsp, hence
181
 * it is possible to un-mute at any time.
182
 */
183
void syssnd_toggleMute (void)
184
{
185
   SDL_mutexP (sndlock);
186
   sndMute = !sndMute;
187
   SDL_mutexV (sndlock);
188
}
189
 
190
 
191
void syssnd_vol (S8 d)
192
{
193
   if ((d < 0 && sndUVol > 0) || (d > 0 && sndUVol < SYSSND_MAXVOL))
194
   {
195
      sndUVol += d;
196
      SDL_mutexP (sndlock);
197
      sndVol = SDL_MIX_MAXVOLUME * sndUVol / SYSSND_MAXVOL;
198
      SDL_mutexV (sndlock);
199
   }
200
}
201
 
202
 
203
/*
204
 * Play a sound
205
 *
206
 * loop: number of times the sound should be played, -1 to loop forever
207
 * returns: channel number, or -1 if none was available
208
 *
209
 * NOTE if sound is already playing, simply reset it (i.e. can not have
210
 * twice the same sound playing -- tends to become noisy when too many
211
 * bad guys die at the same time).
212
 */
213
S8 syssnd_play (sound_t *sound, S8 loop)
214
{
215
   S8 c;
216
 
217
   if (!isAudioActive)
218
      return -1;
219
   if (sound == NULL)
220
      return -1;
221
 
222
   c = 0;
223
   SDL_mutexP (sndlock);
224
   while ((channel[c].snd != sound || channel[c].loop == 0) && channel[c].loop != 0 && c < SYSSND_MIXCHANNELS)
225
      c++;
226
   if (c == SYSSND_MIXCHANNELS)
227
      c = -1;
228
 
229
   if (c >= 0)
230
   {
231
      channel[c].loop = loop;
232
      channel[c].snd = sound;
233
      channel[c].buf = sound->buf;
234
      channel[c].len = sound->len;
235
   }
236
 
237
   SDL_mutexV (sndlock);
238
 
239
   return c;
240
}
241
 
242
 
243
/*
244
 * Pause
245
 *
246
 * pause: TRUE or FALSE
247
 * clear: TRUE to cleanup all sounds and make sure we start from scratch
248
 */
249
void syssnd_pause (U8 pause, U8 clear)
250
{
251
   U8 c;
252
 
253
   if (!isAudioActive)
254
      return;
255
 
256
   if (clear == TRUE)
257
   {
258
      SDL_mutexP (sndlock);
259
      for (c = 0; c < SYSSND_MIXCHANNELS; c++)
260
         channel[c].loop = 0;
261
      SDL_mutexV (sndlock);
262
   }
263
 
264
   if (pause == TRUE)
265
      SDL_PauseAudio (1);
266
   else
267
      SDL_PauseAudio (0);
268
}
269
 
270
 
271
/*
272
 * Stop a channel
273
 */
274
void syssnd_stopchan (S8 chan)
275
{
276
   if (chan < 0 || chan > SYSSND_MIXCHANNELS)
277
      return;
278
 
279
   SDL_mutexP (sndlock);
280
 
281
   if (channel[chan].snd)
282
      end_channel (chan);
283
 
284
   SDL_mutexV (sndlock);
285
}
286
 
287
 
288
/*
289
 * Stop a sound
290
 */
291
void syssnd_stopsound (sound_t *sound)
292
{
293
   U8 i;
294
 
295
   if (!sound)
296
      return;
297
 
298
   SDL_mutexP (sndlock);
299
 
300
   for (i = 0; i < SYSSND_MIXCHANNELS; i++)
301
      if (channel[i].snd == sound)
302
         end_channel (i);
303
 
304
   SDL_mutexV (sndlock);
305
}
306
 
307
 
308
/*
309
 * See if a sound is playing
310
 */
311
int syssnd_isplaying (sound_t *sound)
312
{
313
   U8 i, playing;
314
 
315
   playing = 0;
316
   SDL_mutexP (sndlock);
317
 
318
   for (i = 0; i < SYSSND_MIXCHANNELS; i++)
319
      if (channel[i].snd == sound)
320
         playing = 1;
321
 
322
   SDL_mutexV (sndlock);
323
   return playing;
324
}
325
 
326
 
327
/*
328
 * Stops all channels.
329
 */
330
void syssnd_stopall (void)
331
{
332
   U8 i;
333
 
334
   SDL_mutexP (sndlock);
335
 
336
   for (i = 0; i < SYSSND_MIXCHANNELS; i++)
337
      if (channel[i].snd)
338
         end_channel (i);
339
 
340
   SDL_mutexV (sndlock);
341
}
342
 
343
 
344
/*
345
 * Load a sound.
346
 */
347
sound_t *syssnd_load (char *name)
348
{
2 pmbaty 349
   char *soundfile_fullpathname;
1 pmbaty 350
   sound_t *s;
351
   SDL_RWops *context;
352
   SDL_AudioSpec audiospec;
353
 
2 pmbaty 354
   /* alloc space for sound file's full pathname and build it */
355
   soundfile_fullpathname = (char *) malloc (1024);
356
   sprintf_s (soundfile_fullpathname, 1024, "%s/%s", sys_getbasepath (), name);
357
 
1 pmbaty 358
   /* alloc context */
359
   context = malloc (sizeof (SDL_RWops));
360
   context->seek = sdlRWops_seek;
361
   context->read = sdlRWops_read;
362
   context->write = sdlRWops_write;
363
   context->close = sdlRWops_close;
364
 
365
   /* open */
2 pmbaty 366
   if (sdlRWops_open (context, soundfile_fullpathname) == -1)
367
   {
368
      free (soundfile_fullpathname);
1 pmbaty 369
      return NULL;
2 pmbaty 370
   }
371
   free (soundfile_fullpathname);
1 pmbaty 372
 
373
   /* alloc sound */
374
   s = malloc (sizeof (sound_t));
375
 
376
   /* read */
377
   /* second param == 1 -> close source once read */
378
   if (!SDL_LoadWAV_RW (context, 1, &audiospec, &(s->buf), &(s->len)))
379
   {
380
      free (s);
381
      return NULL;
382
   }
383
 
384
   s->dispose = FALSE;
385
 
386
   return s;
387
}
388
 
389
 
390
/*
391
 *
392
 */
393
void syssnd_free (sound_t *s)
394
{
395
   if (!s)
396
      return;
397
 
398
   if (s->buf)
399
      SDL_FreeWAV (s->buf);
400
 
401
   s->buf = NULL;
402
   s->len = 0;
403
}
404
 
405
 
406
/*
407
 *
408
 */
409
static int sdlRWops_open (SDL_RWops *context, char *name)
410
{
411
   FILE *fp;
412
 
413
   fopen_s (&fp, name, "rb");
414
 
415
   if (!fp)
416
      return -1;
417
 
418
   context->hidden.unknown.data1 = (void *) fp;
419
 
420
   return 0;
421
}
422
 
423
 
424
static int sdlRWops_seek (SDL_RWops *context, int offset, int whence)
425
{
426
   return (fseek ((FILE *) context->hidden.unknown.data1, offset, whence));
427
}
428
 
429
 
430
static int sdlRWops_read (SDL_RWops *context, void *ptr, int size, int maxnum)
431
{
432
   return (fread (ptr, size, maxnum, (FILE *) context->hidden.unknown.data1));
433
}
434
 
435
 
436
static int sdlRWops_write (SDL_RWops *context, const void *ptr, int size, int num)
437
{
438
   return -1; /* not implemented */
439
}
440
 
441
 
442
static int sdlRWops_close (SDL_RWops *context)
443
{
444
   if (context)
445
   {
446
      fclose ((FILE *) context->hidden.unknown.data1);
447
      free (context);
448
   }
449
 
450
   return 0;
451
}