- /* 
-  * src/syssnd.c 
-  * 
-  * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net). All rights reserved. 
-  * 
-  * The use and distribution terms for this software are contained in the file 
-  * named README, which can be found in the root of this distribution. By 
-  * using this software in any fashion, you are agreeing to be bound by the 
-  * terms of this license. 
-  * 
-  * You must not remove this notice, or any other, from this software. 
-  */ 
-   
- #include <SDL.h> 
- #include <stdlib.h> 
- #include <memory.h> 
-   
- #include "system.h" 
- #include "game.h" 
- #include "syssnd.h" 
-   
-   
- #define ADJVOL(S) (((S) *sndVol) / SDL_MIX_MAXVOLUME) 
-   
-   
- static U8 isAudioActive = FALSE; 
- static channel_t channel[SYSSND_MIXCHANNELS]; 
-   
- static U8 sndVol = SDL_MIX_MAXVOLUME;   /* internal volume */ 
- static U8 sndUVol = SYSSND_MAXVOL;   /* user-selected volume */ 
- static U8 sndMute = FALSE;   /* mute flag */ 
-   
- static SDL_mutex *sndlock; 
-   
-   
- /* 
-  * prototypes 
-  */ 
- static int sdlRWops_open (SDL_RWops *context, char *name); 
- static int sdlRWops_seek (SDL_RWops *context, int offset, int whence); 
- static int sdlRWops_read (SDL_RWops *context, void *ptr, int size, int maxnum); 
- static int sdlRWops_write (SDL_RWops *context, const void *ptr, int size, int num); 
- static int sdlRWops_close (SDL_RWops *context); 
- static void end_channel (U8); 
-   
-   
- /* 
-  * Callback -- this is also where all sound mixing is done 
-  * 
-  * Note: it may not be that much a good idea to do all the mixing here ; it 
-  * may be more efficient to mix samples every frame, or maybe everytime a 
-  * new sound is sent to be played. I don't know. 
-  */ 
- void syssnd_callback (void *userdata, U8 *stream, int len) 
- { 
-    U8 c; 
-    S16 s; 
-    U32 i; 
-   
-    SDL_mutexP(sndlock); 
-   
-    for (i = 0; i < (U32)len; i++) 
-    { 
-       s = 0; 
-       for (c = 0; c < SYSSND_MIXCHANNELS; c++) 
-       { 
-          if (channel[c].loop != 0) 
-          { 
-             /* channel is active */ 
-             if (channel[c].len > 0) 
-             { 
-                /* not ending */ 
-                s += ADJVOL (*channel[c].buf - 0x80); 
-                channel[c].buf++; 
-                channel[c].len--; 
-             } 
-             else 
-             { 
-                /* ending */ 
-                if (channel[c].loop > 0) 
-                   channel[c].loop--; 
-   
-                if (channel[c].loop) 
-                { 
-                   /* just loop */ 
-                   channel[c].buf = channel[c].snd->buf; 
-                   channel[c].len = channel[c].snd->len; 
-                   s += ADJVOL (*channel[c].buf - 0x80); 
-                   channel[c].buf++; 
-                   channel[c].len--; 
-                } 
-                else 
-                   end_channel(c); /* end for real */ 
-             } 
-          } 
-       } 
-   
-       if (sndMute) 
-          stream[i] = 0x80; 
-       else 
-       { 
-          s += 0x80; 
-          if (s > 0xff) s = 0xff; 
-          if (s < 0x00) s = 0x00; 
-          stream[i] = (U8) s; 
-       } 
-    } 
-   
-   
-    SDL_mutexV (sndlock); 
- } 
-   
-   
- static void end_channel (U8 c) 
- { 
-    channel[c].loop = 0; 
-    if (channel[c].snd->dispose) 
-       syssnd_free (channel[c].snd); 
-    channel[c].snd = NULL; 
- } 
-   
-   
- void syssnd_init (void) 
- { 
-    SDL_AudioSpec desired, obtained; 
-    U16 c; 
-   
-    if (SDL_InitSubSystem (SDL_INIT_AUDIO) < 0) 
-       return; 
-   
-    desired.freq = SYSSND_FREQ; 
-    desired.format = AUDIO_U8; 
-    desired.channels = SYSSND_CHANNELS; 
-    desired.samples = SYSSND_MIXSAMPLES; 
-    desired.callback = syssnd_callback; 
-    desired.userdata = NULL; 
-   
-    if (SDL_OpenAudio (&desired, &obtained) < 0) 
-       return; 
-   
-    sndlock = SDL_CreateMutex (); 
-    if (sndlock == NULL) 
-    { 
-       SDL_CloseAudio (); 
-       return; 
-    } 
-   
-    if (sysarg_args_vol != 0) 
-    { 
-       sndUVol = sysarg_args_vol; 
-       sndVol = SDL_MIX_MAXVOLUME * sndUVol / SYSSND_MAXVOL; 
-    } 
-   
-    for (c = 0; c < SYSSND_MIXCHANNELS; c++) 
-       channel[c].loop = 0;   /* deactivate */ 
-   
-    isAudioActive = TRUE; 
-    SDL_PauseAudio (0); 
- } 
-   
-   
- /* 
-  * Shutdown 
-  */ 
- void syssnd_shutdown (void) 
- { 
-    if (!isAudioActive) 
-       return; 
-   
-    SDL_CloseAudio (); 
-    SDL_DestroyMutex (sndlock); 
-    isAudioActive = FALSE; 
- } 
-   
-   
- /* 
-  * Toggle mute 
-  * 
-  * When muted, sounds are still managed but not sent to the dsp, hence 
-  * it is possible to un-mute at any time. 
-  */ 
- void syssnd_toggleMute (void) 
- { 
-    SDL_mutexP (sndlock); 
-    sndMute = !sndMute; 
-    SDL_mutexV (sndlock); 
- } 
-   
-   
- void syssnd_vol (S8 d) 
- { 
-    if ((d < 0 && sndUVol > 0) || (d > 0 && sndUVol < SYSSND_MAXVOL)) 
-    { 
-       sndUVol += d; 
-       SDL_mutexP (sndlock); 
-       sndVol = SDL_MIX_MAXVOLUME * sndUVol / SYSSND_MAXVOL; 
-       SDL_mutexV (sndlock); 
-    } 
- } 
-   
-   
- /* 
-  * Play a sound 
-  * 
-  * loop: number of times the sound should be played, -1 to loop forever 
-  * returns: channel number, or -1 if none was available 
-  * 
-  * NOTE if sound is already playing, simply reset it (i.e. can not have 
-  * twice the same sound playing -- tends to become noisy when too many 
-  * bad guys die at the same time). 
-  */ 
- S8 syssnd_play (sound_t *sound, S8 loop) 
- { 
-    S8 c; 
-   
-    if (!isAudioActive) 
-       return -1; 
-    if (sound == NULL) 
-       return -1; 
-   
-    c = 0; 
-    SDL_mutexP (sndlock); 
-    while ((channel[c].snd != sound || channel[c].loop == 0) && channel[c].loop != 0 && c < SYSSND_MIXCHANNELS) 
-       c++; 
-    if (c == SYSSND_MIXCHANNELS) 
-       c = -1; 
-   
-    if (c >= 0) 
-    { 
-       channel[c].loop = loop; 
-       channel[c].snd = sound; 
-       channel[c].buf = sound->buf; 
-       channel[c].len = sound->len; 
-    } 
-   
-    SDL_mutexV (sndlock); 
-   
-    return c; 
- } 
-   
-   
- /* 
-  * Pause 
-  * 
-  * pause: TRUE or FALSE 
-  * clear: TRUE to cleanup all sounds and make sure we start from scratch 
-  */ 
- void syssnd_pause (U8 pause, U8 clear) 
- { 
-    U8 c; 
-   
-    if (!isAudioActive) 
-       return; 
-   
-    if (clear == TRUE) 
-    { 
-       SDL_mutexP (sndlock); 
-       for (c = 0; c < SYSSND_MIXCHANNELS; c++) 
-          channel[c].loop = 0; 
-       SDL_mutexV (sndlock); 
-    } 
-   
-    if (pause == TRUE) 
-       SDL_PauseAudio (1); 
-    else 
-       SDL_PauseAudio (0); 
- } 
-   
-   
- /* 
-  * Stop a channel 
-  */ 
- void syssnd_stopchan (S8 chan) 
- { 
-    if (chan < 0 || chan > SYSSND_MIXCHANNELS) 
-       return; 
-   
-    SDL_mutexP (sndlock); 
-   
-    if (channel[chan].snd) 
-       end_channel (chan); 
-   
-    SDL_mutexV (sndlock); 
- } 
-   
-   
- /* 
-  * Stop a sound 
-  */ 
- void syssnd_stopsound (sound_t *sound) 
- { 
-    U8 i; 
-   
-    if (!sound) 
-       return; 
-   
-    SDL_mutexP (sndlock); 
-   
-    for (i = 0; i < SYSSND_MIXCHANNELS; i++) 
-       if (channel[i].snd == sound) 
-          end_channel (i); 
-   
-    SDL_mutexV (sndlock); 
- } 
-   
-   
- /* 
-  * See if a sound is playing 
-  */ 
- int syssnd_isplaying (sound_t *sound) 
- { 
-    U8 i, playing; 
-   
-    playing = 0; 
-    SDL_mutexP (sndlock); 
-   
-    for (i = 0; i < SYSSND_MIXCHANNELS; i++) 
-       if (channel[i].snd == sound) 
-          playing = 1; 
-   
-    SDL_mutexV (sndlock); 
-    return playing; 
- } 
-   
-   
- /* 
-  * Stops all channels. 
-  */ 
- void syssnd_stopall (void) 
- { 
-    U8 i; 
-   
-    SDL_mutexP (sndlock); 
-   
-    for (i = 0; i < SYSSND_MIXCHANNELS; i++) 
-       if (channel[i].snd) 
-          end_channel (i); 
-   
-    SDL_mutexV (sndlock); 
- } 
-   
-   
- /* 
-  * Load a sound. 
-  */ 
- sound_t *syssnd_load (char *name) 
- { 
-    char *soundfile_fullpathname; 
-    sound_t *s; 
-    SDL_RWops *context; 
-    SDL_AudioSpec audiospec; 
-   
-    /* alloc space for sound file's full pathname and build it */ 
-    soundfile_fullpathname  = (char *) malloc (1024);
-    sprintf_s (soundfile_fullpathname, 1024, "%s/%s", sys_getbasepath (), name); 
-   
-    /* alloc context */ 
-    context  = malloc (sizeof (- SDL_RWops ));
-    context->seek = sdlRWops_seek; 
-    context->read = sdlRWops_read; 
-    context->write = sdlRWops_write; 
-    context->close = sdlRWops_close; 
-   
-    /* open */ 
-    if (sdlRWops_open (context, soundfile_fullpathname) == -1) 
-    { 
-       free (- soundfile_fullpathname );
 
-       return NULL; 
-    } 
-    free (- soundfile_fullpathname );
 
-   
-    /* alloc sound */ 
-    s  = malloc (sizeof (- sound_t ));
-   
-    /* read */ 
-    /* second param == 1 -> close source once read */ 
-    if (!SDL_LoadWAV_RW (context, 1, &audiospec, &(s->buf), &(s->len))) 
-    { 
-       return NULL; 
-    } 
-   
-    s->dispose = FALSE; 
-   
-    return s; 
- } 
-   
-   
- /* 
-  * 
-  */ 
- void syssnd_free (sound_t *s) 
- { 
-    if (!s) 
-       return; 
-   
-    if (s->buf) 
-       SDL_FreeWAV (s->buf); 
-   
-    s->buf = NULL; 
-    s->len = 0; 
- } 
-   
-   
- /* 
-  * 
-  */ 
- static int sdlRWops_open (SDL_RWops *context, char *name) 
- { 
-    FILE *fp; 
-   
-    fopen_s (&fp, name, "rb"); 
-   
-    if (!fp) 
-       return -1; 
-   
-    context->hidden.unknown.data1 = (void *) fp; 
-   
-    return 0; 
- } 
-   
-   
- static int sdlRWops_seek (SDL_RWops *context, int offset, int whence) 
- { 
-    return (fseek ((- FILE  *)-  context ->- hidden. unknown- . data1,-  offset ,-  whence ));
 
- } 
-   
-   
- static int sdlRWops_read (SDL_RWops *context, void *ptr, int size, int maxnum) 
- { 
-    return (fread (- ptr ,-  size ,-  maxnum , (- FILE  *)-  context ->- hidden. unknown- . data1));
 
- } 
-   
-   
- static int sdlRWops_write (SDL_RWops *context, const void *ptr, int size, int num) 
- { 
-    return -1; /* not implemented */ 
- } 
-   
-   
- static int sdlRWops_close (SDL_RWops *context) 
- { 
-    if (context) 
-    { 
-       fclose ((- FILE  *)-  context ->- hidden. unknown- . data1);
 
-    } 
-   
-    return 0; 
- } 
-