Subversion Repositories Games.Rick Dangerous

Rev

Rev 5 | 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
 
11 pmbaty 14
#include <SDL2/SDL.h>
1 pmbaty 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;
5 pmbaty 27
static channel_t channels[SYSSND_MIXCHANNELS];
1 pmbaty 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
 
34
/*
35
 * prototypes
36
 */
5 pmbaty 37
static void end_channel (channel_t *);
1 pmbaty 38
 
39
 
40
/*
41
 * Callback -- this is also where all sound mixing is done
42
 *
43
 * Note: it may not be that much a good idea to do all the mixing here ; it
44
 * may be more efficient to mix samples every frame, or maybe everytime a
45
 * new sound is sent to be played. I don't know.
46
 */
47
void syssnd_callback (void *userdata, U8 *stream, int len)
48
{
5 pmbaty 49
   channel_t *channel;
50
   U8 channel_index;
51
   S16 final_sample;
1 pmbaty 52
   U32 i;
53
 
5 pmbaty 54
   // 
55
   for (i = 0; i < (U32)len; i += 2)
56
   {
57
      final_sample = 0;
1 pmbaty 58
 
5 pmbaty 59
      for (channel_index = 0; channel_index < SYSSND_MIXCHANNELS; channel_index++)
1 pmbaty 60
      {
5 pmbaty 61
         channel = &channels[channel_index]; // quick access to channel
62
 
63
         if (channel->loop == 0)
64
            continue;
65
 
66
         // channel is active
67
         if (channel->len > 0)
1 pmbaty 68
         {
5 pmbaty 69
            // not ending
70
            final_sample += ADJVOL (*((U16 *) channel->buf));
71
            channel->buf += 2;
72
            channel->len -= 2;
73
         }
74
         else
75
         {
76
            // ending
77
            if (channel->loop > 0)
78
               channel->loop--;
79
 
80
            if (channel->loop)
1 pmbaty 81
            {
5 pmbaty 82
               // just loop
83
               channel->buf = channel->snd->buf;
84
               channel->len = channel->snd->len;
85
 
86
               final_sample += ADJVOL (*((U16 *) channel->buf));
87
               channel->buf += 2;
88
               channel->len -= 2;
1 pmbaty 89
            }
90
            else
5 pmbaty 91
               end_channel (channel); // end for real
1 pmbaty 92
         }
93
      }
94
 
5 pmbaty 95
      *((S16 *) &stream[i]) = (sndMute ? 0 : final_sample);
1 pmbaty 96
   }
97
}
98
 
99
 
5 pmbaty 100
static void end_channel (channel_t *channel)
1 pmbaty 101
{
5 pmbaty 102
   channel->loop = 0;
103
   if (channel->snd->dispose)
104
      syssnd_free (channel->snd);
105
   channel->snd = NULL;
1 pmbaty 106
}
107
 
108
 
109
void syssnd_init (void)
110
{
5 pmbaty 111
   SDL_AudioSpec desired;
1 pmbaty 112
   U16 c;
113
 
114
   if (SDL_InitSubSystem (SDL_INIT_AUDIO) < 0)
115
      return;
116
 
117
   desired.freq = SYSSND_FREQ;
5 pmbaty 118
   desired.format = AUDIO_S16;
1 pmbaty 119
   desired.channels = SYSSND_CHANNELS;
120
   desired.samples = SYSSND_MIXSAMPLES;
121
   desired.callback = syssnd_callback;
122
   desired.userdata = NULL;
123
 
5 pmbaty 124
   if (SDL_OpenAudio (&desired, NULL) < 0)
1 pmbaty 125
      return;
126
 
127
   if (sysarg_args_vol != 0)
128
   {
129
      sndUVol = sysarg_args_vol;
130
      sndVol = SDL_MIX_MAXVOLUME * sndUVol / SYSSND_MAXVOL;
131
   }
132
 
133
   for (c = 0; c < SYSSND_MIXCHANNELS; c++)
5 pmbaty 134
      channels[c].loop = 0;   /* deactivate */
1 pmbaty 135
 
136
   isAudioActive = TRUE;
137
   SDL_PauseAudio (0);
138
}
139
 
140
 
141
/*
142
 * Shutdown
143
 */
144
void syssnd_shutdown (void)
145
{
146
   if (!isAudioActive)
147
      return;
148
 
149
   SDL_CloseAudio ();
150
   isAudioActive = FALSE;
151
}
152
 
153
 
154
/*
155
 * Toggle mute
156
 *
157
 * When muted, sounds are still managed but not sent to the dsp, hence
158
 * it is possible to un-mute at any time.
159
 */
160
void syssnd_toggleMute (void)
161
{
162
   sndMute = !sndMute;
163
}
164
 
165
 
166
void syssnd_vol (S8 d)
167
{
168
   if ((d < 0 && sndUVol > 0) || (d > 0 && sndUVol < SYSSND_MAXVOL))
169
   {
170
      sndUVol += d;
171
      sndVol = SDL_MIX_MAXVOLUME * sndUVol / SYSSND_MAXVOL;
172
   }
173
}
174
 
175
 
176
/*
177
 * Play a sound
178
 *
179
 * loop: number of times the sound should be played, -1 to loop forever
180
 * returns: channel number, or -1 if none was available
181
 *
182
 * NOTE if sound is already playing, simply reset it (i.e. can not have
183
 * twice the same sound playing -- tends to become noisy when too many
184
 * bad guys die at the same time).
185
 */
186
S8 syssnd_play (sound_t *sound, S8 loop)
187
{
5 pmbaty 188
   S8 channel_index;
1 pmbaty 189
 
5 pmbaty 190
   if ((sound == NULL) || !isAudioActive)
191
      return (-1);
1 pmbaty 192
 
5 pmbaty 193
   for (channel_index = 0; channel_index < SYSSND_MIXCHANNELS; channel_index++)
194
      if ((channels[channel_index].snd == sound) || (channels[channel_index].loop == 0))
195
         break; // look for a free channel slot
196
   if (channel_index == SYSSND_MIXCHANNELS)
197
      return (-1);
1 pmbaty 198
 
5 pmbaty 199
   channels[channel_index].loop = loop;
200
   channels[channel_index].snd = sound;
201
   channels[channel_index].buf = sound->buf;
202
   channels[channel_index].len = sound->len;
1 pmbaty 203
 
5 pmbaty 204
   return (channel_index);
1 pmbaty 205
}
206
 
207
 
208
/*
209
 * Pause
210
 *
211
 * pause: TRUE or FALSE
212
 * clear: TRUE to cleanup all sounds and make sure we start from scratch
213
 */
5 pmbaty 214
void syssnd_pause (U8 want_pause, U8 want_clear)
1 pmbaty 215
{
5 pmbaty 216
   U8 channel_index;
1 pmbaty 217
 
218
   if (!isAudioActive)
219
      return;
220
 
5 pmbaty 221
   if (want_clear)
222
      for (channel_index = 0; channel_index < SYSSND_MIXCHANNELS; channel_index++)
223
         channels[channel_index].loop = 0;
1 pmbaty 224
 
5 pmbaty 225
   SDL_PauseAudio (want_pause ? 1 : 0);
1 pmbaty 226
}
227
 
228
 
229
/*
230
 * Stop a channel
231
 */
232
void syssnd_stopchan (S8 chan)
233
{
234
   if (chan < 0 || chan > SYSSND_MIXCHANNELS)
235
      return;
236
 
5 pmbaty 237
   if (channels[chan].snd)
238
      end_channel (&channels[chan]);
1 pmbaty 239
}
240
 
241
 
242
/*
243
 * Stop a sound
244
 */
245
void syssnd_stopsound (sound_t *sound)
246
{
247
   U8 i;
248
 
249
   if (!sound)
250
      return;
251
 
252
   for (i = 0; i < SYSSND_MIXCHANNELS; i++)
5 pmbaty 253
      if (channels[i].snd == sound)
254
         end_channel (&channels[i]);
1 pmbaty 255
}
256
 
257
 
258
/*
259
 * See if a sound is playing
260
 */
261
int syssnd_isplaying (sound_t *sound)
262
{
5 pmbaty 263
   U8 i;
1 pmbaty 264
 
265
   for (i = 0; i < SYSSND_MIXCHANNELS; i++)
5 pmbaty 266
      if (channels[i].snd == sound)
267
         return (1);
1 pmbaty 268
 
5 pmbaty 269
   return (0);
1 pmbaty 270
}
271
 
272
 
273
/*
274
 * Stops all channels.
275
 */
276
void syssnd_stopall (void)
277
{
278
   U8 i;
279
 
280
   for (i = 0; i < SYSSND_MIXCHANNELS; i++)
5 pmbaty 281
      if (channels[i].snd)
282
         end_channel (&channels[i]);
1 pmbaty 283
}
284
 
285
 
286
/*
287
 * Load a sound.
288
 */
289
sound_t *syssnd_load (char *name)
290
{
2 pmbaty 291
   char *soundfile_fullpathname;
1 pmbaty 292
   sound_t *s;
293
   SDL_AudioSpec audiospec;
294
 
2 pmbaty 295
   /* alloc space for sound file's full pathname and build it */
296
   soundfile_fullpathname = (char *) malloc (1024);
297
   sprintf_s (soundfile_fullpathname, 1024, "%s/%s", sys_getbasepath (), name);
298
 
1 pmbaty 299
   /* alloc sound */
300
   s = malloc (sizeof (sound_t));
301
 
302
   /* read */
303
   /* second param == 1 -> close source once read */
5 pmbaty 304
   if (!SDL_LoadWAV_RW (SDL_RWFromFile (soundfile_fullpathname, "rb"), 1, &audiospec, &(s->buf), &(s->len)))
1 pmbaty 305
   {
306
      free (s);
307
      return NULL;
308
   }
5 pmbaty 309
   free (soundfile_fullpathname);
1 pmbaty 310
 
311
   s->dispose = FALSE;
312
 
313
   return s;
314
}
315
 
316
 
317
/*
318
 *
319
 */
320
void syssnd_free (sound_t *s)
321
{
322
   if (!s)
323
      return;
324
 
325
   if (s->buf)
326
      SDL_FreeWAV (s->buf);
327
 
328
   s->buf = NULL;
329
   s->len = 0;
330
}