⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i_sound.c

📁 The source code of Doom legacy for windows
💻 C
📖 第 1 页 / 共 2 页
字号:
// Emacs style mode select   -*- C++ -*- //-----------------------------------------------------------------------------//// $Id: i_sound.c,v 1.6 2000/08/11 19:11:07 metzgermeister Exp $//// Copyright (C) 1993-1996 by id Software, Inc.// Portions Copyright (C) 1998-2000 by DooM Legacy Team.//// This program is free software; you can redistribute it and/or// modify it under the terms of the GNU General Public License// as published by the Free Software Foundation; either version 2// of the License, or (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the// GNU General Public License for more details.////// $Log: i_sound.c,v $// Revision 1.6  2000/08/11 19:11:07  metzgermeister// *** empty log message ***//// Revision 1.5  2000/04/30 19:47:38  metzgermeister// iwad support//// Revision 1.4  2000/03/28 16:18:42  linuxcub// Added a command to the Linux sound-server which sets a master volume.// Someone needs to check that this isn't too much of a performance drop// on slow machines. (Works for me).//// Added code to the main parts of doomlegacy which uses this command to// implement volume control for sound effects.//// Added code so the (really cool) cd music works for me. The volume didn't// work for me (with a Teac 532E drive): It always started at max (31) no-// matter what the setting in the config-file was. The added code "jiggles"// the volume-control, and now it works for me :-)// If this code is unacceptable, perhaps another solution is to periodically// compare the cd_volume.value with an actual value _read_ from the drive.// Ie. not trusting that calling the ioctl with the correct value actually// sets the hardware-volume to the requested value. Right now, the ioctl// is assumed to work perfectly, and the value in cd_volume.value is// compared periodically with cdvolume.//// Updated the spec file, so an updated RPM can easily be built, with// a minimum of editing. Where can I upload my pre-built (S)RPMS to ?//// Erling Jacobsen, linuxcub@email.dk//// Revision 1.3  2000/03/12 23:21:10  linuxcub// Added consvars which hold the filenames and arguments which will be used// when running the soundserver and musicserver (under Linux). I hope I// didn't break anything ... Erling Jacobsen, linuxcub@email.dk//// Revision 1.2  2000/02/27 00:42:11  hurdler// fix CR+LF problem//// Revision 1.1.1.1  2000/02/22 20:32:33  hurdler// Initial import into CVS (v1.29 pr3)////// 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>#if !defined(LINUX) && !defined(SCOOS5) && !defined(_AIX)#include <sys/filio.h>#endif#include <fcntl.h>#include <unistd.h>#include <sys/ioctl.h>#include <sys/msg.h>// Linux voxware output.#ifdef LINUX#include <linux/soundcard.h>#endif// SCO OS5 and Unixware OSS sound output#if defined(SCOOS5) || defined(SCOUW2) || defined(SCOUW7)#include <sys/soundcard.h>#endif// Timer stuff. Experimental.#include <time.h>#include <signal.h>// for IPC between xdoom and musserver#include <sys/ipc.h>#include "z_zone.h"#include "i_system.h"#include "i_sound.h"//#include "s_sound.h"int S_GetSfxLumpNum (sfxinfo_t* sfx);                                           #include "m_argv.h"#include "m_misc.h"#include "w_wad.h"#include "doomdef.h"// added for 1.27 19990203 by Kin#include "doomstat.h"#include "searchp.h"//#include "cd_audio.h"// Number of sound channels used as set in the config fileextern  consvar_t cv_numChannels;#ifdef SNDSERVextern consvar_t sndserver_cmd;extern consvar_t sndserver_arg;#endif#ifdef MUSSERVextern consvar_t musserver_cmd;extern consvar_t musserver_arg;#endif// UNIX hack, to be removed.#ifdef SNDSERVFILE*   sndserver=0;int     sndcnt = 0; // sfx serial no. 19990201 by Kin#elif SNDINTR// Update all 30 millisecs, approx. 30fps synchronized.// Linux resolution is allegedly 10 millisecs,//  scale is microseconds.#define SOUND_INTERVAL     10000// Get the interrupt. Set duration in millisecs.int I_SoundSetTimer( int duration_of_tick );void I_SoundDelTimer( void );#else// None?#endif// UNIX hack too, unlikely to be removed.#ifdef MUSSERVFILE*   musserver=0;int     msg_id = -1;#endif// Flags for the -nosound and -nomusic optionsextern boolean nosound;extern boolean nomusic;// Flag to signal CD audio support to not play a title//int playing_title;// A quick hack to establish a protocol between// synchronous mix buffer updates and asynchronous// audio writes. Probably redundant with gametic.volatile 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             1024#define NUM_CHANNELS            16// 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 and a flag for using 8bit samples.int     audio_fd;int     audio_8bit_flag;// 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,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];// master hardware sound volumeint		hw_sndvolume=31;//// Safe ioctl, convenience.//voidmyioctl( 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);    }}// dummy for now 19990220 by Kinvoid I_FreeSfx(sfxinfo_t* sfx) {}//// This function loads the sound data from the WAD lump,//  for single sound.//void* I_GetSfx (sfxinfo_t*  sfx){    byte*               dssfx;    int                 size,i;    unsigned char*      paddedsfx;    int                 paddedsize;    if (sfx->lumpnum<0)    {        sfx->lumpnum = S_GetSfxLumpNum (sfx);    }    size = W_LumpLength (sfx->lumpnum);    dssfx = (byte*) W_CacheLumpNum (sfx->lumpnum, PU_STATIC);    paddedsize = ((size-8 + (SAMPLECOUNT-1)) / SAMPLECOUNT) * SAMPLECOUNT;    paddedsfx = (unsigned char*)Z_Malloc( paddedsize+8, PU_STATIC, 0 );    memcpy(  paddedsfx, dssfx, size );    for (i=size ; i<paddedsize+8 ; i++)        paddedsfx[i] = 128;    // Remove the cached lump.    Z_Free( dssfx );    *((int*)paddedsfx) = paddedsize;    // convert raw data and header from Doom sfx to a SAMPLE for Allegro    // write data to llsndserv 19990201 by Kin#ifdef SNDSERV    if(sndserver) {        fputc('v',sndserver);        fputc((char)hw_sndvolume,sndserver);        fputc('l',sndserver);        fwrite(paddedsfx, sizeof(int), 1,sndserver);        fwrite(paddedsfx+8, 1, paddedsize, sndserver);        fflush(sndserver);    }    Z_Free(paddedsfx);    paddedsfx = (unsigned char*)Z_Malloc(sizeof(int),PU_STATIC,0);    *((int*)paddedsfx) = sndcnt;    sndcnt++;#endif    return (void*)(paddedsfx);}//// 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.//intaddsfx( 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<cv_numChannels.value ; 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<cv_numChannels.value) && (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 == cv_numChannels.value)        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+8;    // Set pointer to end of raw data.    channelsend[slot] = channels[slot] + *((int*)S_sfx[sfxid].data);    // 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*hw_sndvolume/31)*256];    channelrightvol_lookup[slot] = &vol_lookup[(rightvol*hw_sndvolume/31)*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<cv_numChannels.value; 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++)    {      if (!audio_8bit_flag)        vol_lookup[i*256+j] = (i*(j-128)*256)/127;      else        vol_lookup[i*256+j] = (i*(j-128)*256)/127*4;    }  }}        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.   // dummy for Linux 19990117 by Kin//  snd_SfxVolume = volume;  hw_sndvolume = volume;#ifdef SNDSERV    if(sndserver) {        fputc('v',sndserver);        fputc((char)hw_sndvolume,sndserver);        fflush(sndserver);    }#endif}// MUSIC APIvoid I_SetMusicVolume(int volume){  // Internal state variable.//  snd_MusicVolume = volume;  // Now set volume on output device.  // Whatever( snd_MusciVolume );  if (nomusic)    return;#ifdef MUSSERV  if (msg_id != -1) {    struct {      long msg_type;      char msg_text[12];    } msg_buffer;    msg_buffer.msg_type = 6;    memset(msg_buffer.msg_text, 0, 12);    msg_buffer.msg_text[0] = 'v';    msg_buffer.msg_text[1] = volume;    msgsnd(msg_id, (struct msgbuf *) &msg_buffer, 12, IPC_NOWAIT);  }#endif}//// 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.//intI_StartSound( int           id,  int           vol,  int           sep,  int           pitch,  int           priority ){  // UNUSED  priority = 0;  vol = vol >> 4; // xdoom only accept 0-15 19990124 by Kin    if (nosound)    return 0;#ifdef SNDSERV     if (sndserver)    {        unsigned char scmd[4];        scmd[0] = (unsigned char)*((int*)S_sfx[id].data);        scmd[1] = (unsigned char)pitch;        scmd[2] = (unsigned char)vol;        scmd[3] = (unsigned char)sep;        fputc('p',sndserver);        fwrite(scmd,1,4,sndserver);        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.  // Would be looping all channels,  //  tracking down the handle,  //  an setting the channel to zero.  #ifndef SNDSERV  int i;  for (i=0; i<cv_numChannels.value; i++)  {    if (channelhandles[i] == handle)    {      channels[i] = 0;      break;    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -