Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Iskhodnyy_kod_Doom

.pdf
Скачиваний:
7
Добавлен:
13.02.2015
Размер:
1.01 Mб
Скачать

#include "i_system.h" #include "i_sound.h" #include "m_argv.h"

#include "m_misc.h" #include "w_wad.h"

#include "doomdef.h"

//UNIX hack, to be removed. #ifdef SNDSERV

//Separate sound server process.

FILE*

sndserver=0;

char*

sndserver_filename = "./sndserver ";

#elif SNDINTR

 

//Update all 30 millisecs, approx. 30fps synchronized.

//Linux resolution is allegedly 10 millisecs,

//scale is microseconds.

#define SOUND_INTERVAL

500

//Get the interrupt. Set duration in millisecs. int I_SoundSetTimer( int duration_of_tick ); void I_SoundDelTimer( void );

#else

//None?

#endif

//A quick hack to establish a protocol between

//synchronous mix buffer updates and asynchronous

//audio writes. Probably redundant with gametic. static int flag = 0;

//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.

181

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];

//

// Safe ioctl, convenience.

//

 

 

void

 

 

myioctl

 

 

( int

fd,

 

int

command,

 

int*

arg )

 

{

 

 

int

 

rc;

extern int

errno;

rc = ioctl(fd, command, arg); if (rc < 0)

{

fprintf(stderr, "ioctl(dsp,%d,arg) failed\n", command); fprintf(stderr, "errno=%d\n", errno);

exit(-1);

}

}

//

// This function loads the sound data from the WAD lump,

182

// for single sound.

 

//

 

 

void*

 

 

getsfx

 

 

( 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, PU_STATIC );

//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;

183

sfxid,
volume,
step, seperation )

// 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.

//

int addsfx ( int

int int int

{

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)

{

184

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. 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;

185

// 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.

186

id,
vol,
sep,
pitch, priority )

// 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);

}

//

//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

int int int int

{

// UNUSED priority = 0;

#ifdef SNDSERV

if (sndserver)

{

fprintf(sndserver, "p%2.2x%2.2x%2.2x%2.2x\n", id, pitch, vol, sep); fflush(sndserver);

}

// warning: control reaches end of non-void function. return id;

#else

// Debug.

//fprintf( stderr, "starting sound %d", id );

// Returns a handle (not used).

id = addsfx( id, vol, steptable[pitch], sep );

// fprintf( stderr, "/handle is %d\n", id );

return id; #endif

}

void I_StopSound (int handle)

{

// You need the handle returned by StartSound.

187

//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 global

//mixbuffer, clamping it to the allowed range,

//and sets up everything for transferring the

//contents of the mixbuffer to the (two)

//hardware channels (left and right, that is).

//This function currently supports only 16bit.

//

void I_UpdateSound( void )

{

#ifdef SNDINTR

// Debug. Count buffer misses with interrupt. static int misses = 0;

#endif

//Mix current sound data.

//Data, from raw sound, for right and left.

register unsigned int

sample;

register

int

dl;

register

int

dr;

// Pointers in global mixbuffer, left, right, end.

signed short*

leftout;

signed

short*

rightout;

signed

short*

leftend;

//

Step in mixbuffer, left and right, thus two.

int

step;

//

Mixing channel index.

 

int

chan;

//Left and right channel

//are in global mixbuffer, alternating. leftout = mixbuffer;

rightout = mixbuffer+1; step = 2;

//Determine end, for left channel only

//(right channel is implicit).

leftend = mixbuffer + SAMPLECOUNT*step;

188

//Mix sounds into the mixing buffer.

//Loop over step*SAMPLECOUNT,

//that is 512 values for two channels. while (leftout != leftend)

{

//Reset left/right value.

dl = 0; dr = 0;

//Love thy L2 chache - made this a loop.

//Now more channels could be set at compile time

//as well. Thus loop those channels.

for ( chan = 0; chan < NUM_CHANNELS; chan++ )

{

// Check channel, if active. if (channels[ chan ])

{

//Get the raw data from the channel. sample = *channels[ chan ];

//Add left and right part

//for this channel (sound)

//to the current data.

//Adjust volume accordingly.

dl += channelleftvol_lookup[ chan ][sample]; dr += channelrightvol_lookup[ chan ][sample]; // Increment index ???

channelstepremainder[ chan ] += channelstep[ chan ]; // MSB is next sample???

channels[ chan ] += channelstepremainder[ chan ] >> 16; // Limit to LSB???

channelstepremainder[ chan ] &= 65536-1;

// Check whether we are done.

if (channels[ chan ] >= channelsend[ chan ]) channels[ chan ] = 0;

}

}

//Clamp to range. Left hardware channel.

//Has been char instead of short.

//if (dl > 127) *leftout = 127;

//else if (dl < -128) *leftout = -128;

//else *leftout = dl;

if (dl > 0x7fff) *leftout = 0x7fff;

else if (dl < -0x8000) *leftout = -0x8000;

else

*leftout = dl;

//Same for right hardware channel. if (dr > 0x7fff)

*rightout = 0x7fff; else if (dr < -0x8000)

*rightout = -0x8000;

else

*rightout = dr;

//Increment current pointers in mixbuffer. leftout += step;

rightout += step;

}

#ifdef SNDINTR

189

// Debug check. if ( flag )

{

misses += flag; flag = 0;

}

if ( misses > 10 )

{

fprintf( stderr, "I_SoundUpdate: missed 10 buffer writes\n"); misses = 0;

}

// Increment flag for update. flag++;

#endif

}

//

//This would be used to write out the mixbuffer

//during each game loop update.

//Updates sound buffer and audio device at runtime.

//It is called during Timer interrupt with SNDINTR.

//Mixing now done synchronous, and

//only output be done asynchronous?

//

void I_SubmitSound(void)

{

// Write it to DSP device.

write(audio_fd, mixbuffer, SAMPLECOUNT*BUFMUL);

}

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;

}

void I_ShutdownSound(void)

{

#ifdef SNDSERV if (sndserver)

{

// Send a "quit" command. fprintf(sndserver, "q\n"); fflush(sndserver);

}

#else

190

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]