📄 i_sound.c
字号:
// Emacs style mode select -*- C++ -*-//-----------------------------------------------------------------------------//// $Id: i_sound.c,v 1.7 2001/04/14 14:15:14 metzgermeister Exp $//// 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: i_sound.c,v $// Revision 1.7 2001/04/14 14:15:14 metzgermeister// fixed bug no sound device//// Revision 1.6 2001/04/09 20:21:56 metzgermeister// dummy for I_FreeSfx//// Revision 1.5 2001/03/25 18:11:24 metzgermeister// * SDL sound bug with swapped stereo channels fixed// * separate hw_trick.c now for HW_correctSWTrick(.)//// Revision 1.4 2001/03/09 21:53:56 metzgermeister// *** empty log message ***//// Revision 1.3 2000/11/02 19:49:40 bpereira// no message//// Revision 1.2 2000/09/10 10:56:00 metzgermeister// clean up & made it work again//// Revision 1.1 2000/08/21 21:17:32 metzgermeister// Initial import to CVS////// DESCRIPTION:// System interface for sound.////-----------------------------------------------------------------------------static const charrcsid[] = "$Id: i_sound.c,v 1.7 2001/04/14 14:15:14 metzgermeister Exp $";#include <math.h>#include <SDL/SDL.h>#include <SDL/SDL_audio.h>#include <SDL/SDL_mutex.h>#include <SDL/SDL_byteorder.h>#include <SDL/SDL_version.h>#include <unistd.h>#include "z_zone.h"#include "m_swap.h"#include "i_system.h"#include "i_sound.h"#include "m_argv.h"#include "m_misc.h"#include "w_wad.h"#include "doomdef.h"#include "doomstat.h"#include "s_sound.h"#include "doomtype.h"#include "d_main.h"#include <SDL/SDL_mixer.h>#include "qmus2mid.h"#define W_CacheLumpNum(num) (W_CacheLumpNum)((num),1)#define W_CacheLumpName(name) W_CacheLumpNum (W_GetNumForName(name))#define PIPE_CHECK(fh) if (broken_pipe) { fclose(fh); fh = NULL; broken_pipe = 0; }#define MIDBUFFERSIZE 128*1024// 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 NUM_CHANNELS 8#define SAMPLERATE 11025 // Hzstatic int samplecount = 512;static int lengths[NUMSFX]; // The actual lengths of all sound effects.static unsigned int channelstep[NUM_CHANNELS]; // The channel step amount...static unsigned int channelstepremainder[NUM_CHANNELS]; // ... and a 0.16 bit remainder of last step.// The channel data pointers, start and end.static unsigned char* channels[NUM_CHANNELS];static 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.static int channelstart[NUM_CHANNELS];// The sound in channel handles,// determined on registration,// might be used to unregister/stop/modify,// currently unused.static int channelhandles[NUM_CHANNELS];// SFX id of the playing sound effect.// Used to catch duplicates (like chainsaw).static int channelids[NUM_CHANNELS];// Pitch to stepping lookup, unused.static int steptable[256];// Volume lookups.static int vol_lookup[128*256];// Hardware left and right channel volume lookup.static int* channelleftvol_lookup[NUM_CHANNELS];static int* channelrightvol_lookup[NUM_CHANNELS];// Buffer for MIDIstatic char* musicbuffer;// Flags for the -nosound and -nomusic optionsextern boolean nosound;extern boolean nomusic;//// This function loads the sound data from the WAD lump,// for single sound.//static void* getsfx(const char* sfxname, int* len){ unsigned char* sfx; unsigned char* paddedsfx; int i; 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 ); // Debug. // fprintf( stderr, "." ); //fprintf( stderr, " -loading %s (lump %d, %d bytes)\n", // sfxname, sfxlump, size ); //fflush( stderr ); sfx = (unsigned char*)W_CacheLumpNum(sfxlump); // Pads the sound effect out to the mixing buffer size. // The original realloc would interfere with zone memory. paddedsize = ((size-8 + (samplecount-1)) / samplecount) * samplecount; // Allocate from zone memory. paddedsfx = (unsigned char*)Z_Malloc( paddedsize+8, PU_STATIC, 0 ); // ddt: (unsigned char *) realloc(sfx, paddedsize+8); // This should interfere with zone memory handling, // which does not kick in in the soundserver. // Now copy and pad. memcpy( paddedsfx, sfx, size ); for (i=size ; i<paddedsize+8 ; i++) paddedsfx[i] = 128; // Remove the cached lump. Z_Free( sfx ); // Preserve padded length. *len = paddedsize; // Return allocated padded data. return (void *) (paddedsfx + 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.//static 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; // 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. channelstep[slot] = step; // ??? 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. // volume *= 8; // Volume arrives in range 0..255 and it must be in 0..cv_soundvolume... volume = (volume * cv_soundvolume.value) >> 6; // Notice : sdldoom replaced all the calls to avoid this conversion // fprintf(stderr,"Volume dern : %d\n",volume); 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 > 127) I_Error("rightvol out of bounds"); if (leftvol < 0 || leftvol > 127) I_Error("leftvol out of bounds"); // 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().//// Well... To keep compatibility with legacy doom, I have to call this in// I_InitSound since it is not called in S_Init... (emanne@absysteme.fr)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; if(nosound) return; // 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; //fprintf(stderr, "vol_lookup[%d*256+%d] = %d\n", i, j, vol_lookup[i*256+j]); }}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. // printf("Setting volume to %d\n",volume); CV_SetValue(&cv_soundvolume, volume); //snd_SfxVolume = volume;}//// 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);}void* I_GetSfx (sfxinfo_t* sfx) { int len; return getsfx(sfx->name,&len);}// FIXME: dummy for now Apr.9 2001 by Robvoid I_FreeSfx(sfxinfo_t* sfx) {}//// Starting a sound means adding it// to the current list of active sounds// in the internal channels.// As the SFX info struct contains// e.g. a pointer to the raw data,// it is ignored.// As our sound handling does not handle// priority, it is ignored.// Pitching (that is, increased speed of playback)// is set, but currently not used by mixing.//int I_StartSound( int id, int vol, int sep, int pitch, int priority ){ // UNUSED priority = 0; if(nosound) return 0; // Debug. /* fprintf( stderr, "starting sound %d vol %d sep %d pitch %d priority %d", id,vol,sep,pitch,priority ); */ // Returns a handle (not used). SDL_LockAudio(); id = addsfx( id, vol, steptable[pitch], sep ); SDL_UnlockAudio(); // fprintf( stderr, "/handle is %d\n", id ); return id;}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;}//// This function loops all active (internal) sound// channels, retrieves a given number of samples// from the raw sound data, modifies it according// to the current (internal) channel parameters,// mixes the per channel samples into the given// mixing buffer, and clamping it to the allowed// range.//// This function currently supports only 16bit.//void I_UpdateSound () { /* Pour une raison que j'ignore, la version SDL n'appelle jamais ce truc directement. Fonction vide pour garder une compatibilit
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -