home *** CD-ROM | disk | FTP | other *** search
- /* Emacs style mode select -*- C++ -*- */
- /* ----------------------------------------------------------------------------- */
- /* */
- /* $Id:$ */
- /* */
- /* Copyright (C) 1993-1996 by id Software, Inc. */
- /* */
- /* This source is available for distribution and/or modification */
- /* only under the terms of the DOOM Source Code License as */
- /* published by id Software. All rights reserved. */
- /* */
- /* The source is distributed in the hope that it will be useful, */
- /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
- /* FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License */
- /* for more details. */
- /* */
- /* $Log:$ */
- /* */
- /* DESCRIPTION: */
- /* System interface for sound. */
- /* */
- /* ----------------------------------------------------------------------------- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
-
- #include <math.h>
-
- #include <sys/time.h>
- #include <sys/types.h>
-
- #ifndef LINUX
- #ifndef ATARI
- #include <sys/filio.h>
- #endif
- #endif
-
- #include <fcntl.h>
- #include <unistd.h>
- #include <sys/ioctl.h>
-
- /* Linux voxware output. */
- #ifdef LINUX
- #include <linux/soundcard.h>
- #endif
-
- /* Timer stuff. Experimental. */
- #include <time.h>
- #include <signal.h>
-
- #include "z_zone.h"
-
- #include "i_system.h"
- #include "i_sound.h"
- #include "m_argv.h"
- #include "m_misc.h"
- #include "w_wad.h"
-
- #include "doomdef.h"
-
- /* The number of internal mixing channels, */
- /* the samples calculated for each mixing step, */
- /* the size of the 16bit, 2 hardware channel (stereo) */
- /* mixing buffer, and the samplerate of the raw data. */
-
-
- /* Needed for calling the actual sound output. */
- #define SAMPLECOUNT 512
- #define NUM_CHANNELS 8
- /* It is 2 for 16bit, and 2 for two channels. */
- #define BUFMUL 4
- #define MIXBUFFERSIZE (SAMPLECOUNT*BUFMUL)
-
- #define SAMPLERATE 11025 /* Hz */
- #define SAMPLESIZE 2 /* 16bit */
-
- /* The actual lengths of all sound effects. */
- int lengths[NUMSFX];
-
- /* The actual output device. */
- int audio_fd;
-
- /* The global mixing buffer. */
- /* Basically, samples from all active internal channels */
- /* are modifed and added, and stored in the buffer */
- /* that is submitted to the audio device. */
- signed short mixbuffer[MIXBUFFERSIZE];
-
-
- /* The channel step amount... */
- unsigned int channelstep[NUM_CHANNELS];
- /* ... and a 0.16 bit remainder of last step. */
- unsigned int channelstepremainder[NUM_CHANNELS];
-
-
- /* The channel data pointers, start and end. */
- unsigned char* channels[NUM_CHANNELS];
- unsigned char* channelsend[NUM_CHANNELS];
-
-
- /* Time/gametic that the channel started playing, */
- /* used to determine oldest, which automatically */
- /* has lowest priority. */
- /* In case number of active sounds exceeds */
- /* available channels. */
- int channelstart[NUM_CHANNELS];
-
- /* The sound in channel handles, */
- /* determined on registration, */
- /* might be used to unregister/stop/modify, */
- /* currently unused. */
- int channelhandles[NUM_CHANNELS];
-
- /* SFX id of the playing sound effect. */
- /* Used to catch duplicates (like chainsaw). */
- int channelids[NUM_CHANNELS];
-
- /* Pitch to stepping lookup, unused. */
- int steptable[256];
-
- /* Volume lookups. */
- int vol_lookup[128*256];
-
- /* Hardware left and right channel volume lookup. */
- int* channelleftvol_lookup[NUM_CHANNELS];
- int* channelrightvol_lookup[NUM_CHANNELS];
-
-
- /* */
- /* This function loads the sound data from the WAD lump, */
- /* for single sound. */
- /* */
- void*
- getsfx
- ( char* sfxname,
- int* len )
- {
- unsigned char* sfx;
- int size;
- int paddedsize;
- char name[20];
- int sfxlump;
-
-
- /* Get the sound data from the WAD, allocate lump */
- /* in zone memory. */
- sprintf(name, "ds%s", sfxname);
-
- /* Now, there is a severe problem with the */
- /* sound handling, in it is not (yet/anymore) */
- /* gamemode aware. That means, sounds from */
- /* DOOM II will be requested even with DOOM */
- /* shareware. */
- /* The sound list is wired into sounds.c, */
- /* which sets the external variable. */
- /* I do not do runtime patches to that */
- /* variable. Instead, we will use a */
- /* default sound for replacement. */
- if ( W_CheckNumForName(name) == -1 )
- sfxlump = W_GetNumForName("dspistol");
- else
- sfxlump = W_GetNumForName(name);
-
- size = W_LumpLength( sfxlump );
-
- /* Pads the sound effect out to the mixing buffer size. */
- /* The original realloc would interfere with zone memory. */
- #ifdef ATARI
- paddedsize = size-8 + SAMPLECOUNT;
- #else
- paddedsize = ((size-8 + (SAMPLECOUNT-1)) / SAMPLECOUNT) * SAMPLECOUNT;
- #endif
- /* Allocate from zone memory. */
- sfx = (unsigned char*)W_CacheLumpNumPadded( sfxlump, PU_STATIC,paddedsize+8 );
- memset(&sfx[size],128,paddedsize+8-size);
-
- /* Preserve padded length. */
- #ifdef ATARI
- *len = size-8;
- #else
- *len = paddedsize;
- #endif
- /* Return allocated padded data. */
- return (void *) (sfx + 8);
- }
-
-
-
-
-
- /* */
- /* This function adds a sound to the */
- /* list of currently active sounds, */
- /* which is maintained as a given number */
- /* (eight, usually) of internal channels. */
- /* Returns a handle. */
- /* */
- int
- addsfx
- ( int sfxid,
- int volume,
- int step,
- int seperation )
- {
- static unsigned short handlenums = 0;
-
- int i;
- int rc = -1;
-
- int oldest = gametic;
- int oldestnum = 0;
- int slot;
-
- int rightvol;
- int leftvol;
-
- /* Chainsaw troubles. */
- /* Play these sound effects only one at a time. */
- if ( sfxid == sfx_sawup
- || sfxid == sfx_sawidl
- || sfxid == sfx_sawful
- || sfxid == sfx_sawhit
- || sfxid == sfx_stnmov
- || sfxid == sfx_pistol )
- {
- /* Loop all channels, check. */
- for (i=0 ; i<NUM_CHANNELS ; i++)
- {
- /* Active, and using the same SFX? */
- if ( (channels[i])
- && (channelids[i] == sfxid) )
- {
- /* Reset. */
- channels[i] = 0;
- /* We are sure that iff, */
- /* there will only be one. */
- break;
- }
- }
- }
-
- /* Loop all channels to find oldest SFX. */
- for (i=0; (i<NUM_CHANNELS) && (channels[i]); i++)
- {
- if (channelstart[i] < oldest)
- {
- oldestnum = i;
- oldest = channelstart[i];
- }
- }
-
- /* Tales from the cryptic. */
- /* If we found a channel, fine. */
- /* If not, we simply overwrite the first one, 0. */
- /* Probably only happens at startup. */
- if (i == NUM_CHANNELS)
- slot = oldestnum;
- else
- slot = i;
-
- /* Uncache previous sample */
- if (channelids[slot]>=0)
- {
- sfxinfo_t *oldsfx;
-
- oldsfx=&S_sfx[channelids[slot]];
- (oldsfx->nbusing)--;
- if ((oldsfx->nbusing)==0)
- {
- Z_ChangeTag( (oldsfx->data)-8, PU_CACHE);
- }
- }
-
- /* Okay, in the less recent channel, */
- /* we will handle the new SFX. */
- /* Set pointer to raw data. */
- channels[slot] = (unsigned char *) S_sfx[sfxid].data;
- /* Set pointer to end of raw data. */
- channelsend[slot] = channels[slot] + lengths[sfxid];
-
- /* Reset current handle number, limited to 0..100. */
- if (!handlenums)
- handlenums = 100;
-
- /* Assign current handle number. */
- /* Preserved so sounds could be stopped (unused). */
- channelhandles[slot] = rc = handlenums++;
-
- /* Set stepping??? */
- /* Kinda getting the impression this is never used. */
- #ifdef ATARI
- channelstep[slot]=0;
- #else
- channelstep[slot] = step;
- #endif
- /* ??? */
- channelstepremainder[slot] = 0;
- /* Should be gametic, I presume. */
- channelstart[slot] = gametic;
-
- /* Separation, that is, orientation/stereo. */
- /* range is: 1 - 256 */
- seperation += 1;
-
- /* Per left/right channel. */
- /* x^2 seperation, */
- /* adjust volume properly. */
- leftvol =
- volume - ((volume*seperation*seperation) >> 16); /* /(256*256); */
- seperation = seperation - 257;
- rightvol =
- volume - ((volume*seperation*seperation) >> 16);
-
- /* Sanity check, clamp volume. */
- if (rightvol<0) rightvol=0;
- if (rightvol>127) rightvol=127;
- if (leftvol<0) leftvol=0;
- if (leftvol>127) leftvol=127;
-
- /* Get the proper lookup table piece */
- /* for this volume level??? */
- channelleftvol_lookup[slot] = &vol_lookup[leftvol*256];
- channelrightvol_lookup[slot] = &vol_lookup[rightvol*256];
-
- /* Preserve sound SFX id, */
- /* e.g. for avoiding duplicates of chainsaw. */
- channelids[slot] = sfxid;
-
- /* You tell me. */
- return rc;
- }
-
-
-
-
-
- /* */
- /* SFX API */
- /* Note: this was called by S_Init. */
- /* However, whatever they did in the */
- /* old DPMS based DOS version, this */
- /* were simply dummies in the Linux */
- /* version. */
- /* See soundserver initdata(). */
- /* */
- void I_SetChannels()
- {
- /* Init internal lookups (raw data, mixing buffer, channels). */
- /* This function sets up internal lookups used during */
- /* the mixing process. */
- int i;
- int j;
-
- int* steptablemid = steptable + 128;
-
- /* Okay, reset internal mixing channels to zero. */
- /*for (i=0; i<NUM_CHANNELS; i++)
- {
- channels[i] = 0;
- }*/
-
- /* This table provides step widths for pitch parameters. */
- /* I fail to see that this is currently used. */
- for (i=-128 ; i<128 ; i++)
- steptablemid[i] = (int)(pow(2.0, (i/64.0))*65536.0);
-
- /* Generates volume lookup tables */
- /* which also turn the unsigned samples */
- /* into signed samples. */
- for (i=0 ; i<128 ; i++)
- for (j=0 ; j<256 ; j++)
- vol_lookup[i*256+j] = (i*(j-128)*256)/127;
- }
-
-
- void I_SetSfxVolume(int volume)
- {
- /* Identical to DOS. */
- /* Basically, this should propagate */
- /* the menu/config file setting */
- /* to the state variable used in */
- /* the mixing. */
- snd_SfxVolume = volume;
- }
-
- /* MUSIC API - dummy. Some code from DOS version. */
- void I_SetMusicVolume(int volume)
- {
- /* Internal state variable. */
- snd_MusicVolume = volume;
- /* Now set volume on output device. */
- /* Whatever( snd_MusciVolume ); */
- }
-
-
- /* */
- /* Retrieve the raw data lump index */
- /* for a given SFX name. */
- /* */
- int I_GetSfxLumpNum(sfxinfo_t* sfx)
- {
- char namebuf[9];
- sprintf(namebuf, "ds%s", sfx->name);
- return W_GetNumForName(namebuf);
- }
-
- int
- (*I_StartSound)
- ( int id,
- int vol,
- int sep,
- int pitch,
- int priority );
-
- void I_StopSound (int handle)
- {
- /* You need the handle returned by StartSound. */
- /* Would be looping all channels, */
- /* tracking down the handle, */
- /* an setting the channel to zero. */
-
- /* UNUSED. */
- handle = 0;
- }
-
-
- int I_SoundIsPlaying(int handle)
- {
- /* Ouch. */
- return gametic < handle;
- }
-
- void
- I_UpdateSoundParams
- ( int handle,
- int vol,
- int sep,
- int pitch)
- {
- /* I fail too see that this is used. */
- /* Would be using the handle to identify */
- /* on which channel the sound might be active, */
- /* and resetting the channel parameters. */
-
- /* UNUSED. */
- handle = vol = sep = pitch = 0;
- }
-
-
- /* */
- /* MUSIC API. */
- /* Still no music done. */
- /* Remains. Dummies. */
- /* */
- void I_InitMusic(void) { }
- void I_ShutdownMusic(void) { }
-
- static int looping=0;
- static int musicdies=-1;
-
- void I_PlaySong(int handle, int looping)
- {
- /* UNUSED. */
- handle = looping = 0;
- musicdies = gametic + TICRATE*30;
- }
-
- void I_PauseSong (int handle)
- {
- /* UNUSED. */
- handle = 0;
- }
-
- void I_ResumeSong (int handle)
- {
- /* UNUSED. */
- handle = 0;
- }
-
- void I_StopSong(int handle)
- {
- /* UNUSED. */
- handle = 0;
-
- looping = 0;
- musicdies = 0;
- }
-
- void I_UnRegisterSong(int handle)
- {
- /* UNUSED. */
- handle = 0;
- }
-
- int I_RegisterSong(void* data)
- {
- /* UNUSED. */
- data = NULL;
-
- return 1;
- }
-
- /* Is the song playing? */
- int I_QrySongPlaying(int handle)
- {
- /* UNUSED. */
- handle = 0;
- return looping || musicdies > gametic;
- }
-