📄 i_sound.c
字号:
}#endif}int I_SoundIsPlaying(int handle){ // Ouch. // return gametic < handle;#ifndef SNDSERV int i; for (i=0; i<cv_numChannels.value; i++) { if (channelhandles[i] == handle) return 1; }#endif return 0;}//// 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).//void I_UpdateSound( void ){ // Debug. Count buffer misses with interrupt. static int misses = 0; // Flag. Will be set if the mixing buffer really gets updated. int updated = 0; // Mix current sound data. // Data, from raw sound, for right and left. register unsigned int sample; register int dl; register int dr; unsigned short sdl; unsigned short sdr; // Pointers in global mixbuffer, left, right, end. signed short* leftout; signed short* rightout; signed short* leftend; unsigned char* bothout; // 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; bothout = (unsigned char *)mixbuffer; step = 2; // Determine end, for left channel only // (right channel is implicit). leftend = mixbuffer + SAMPLECOUNT*step; // Mix sounds into the mixing buffer. // Loop over step*SAMPLECOUNT. 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 < cv_numChannels.value; chan++ ) { // Check channel, if active. if (channels[ chan ]) { // we are updating the mixer buffer, set flag updated++; // 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 (!audio_8bit_flag) { 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; } else { if (dl > 0x7fff) dl = 0x7fff; else if (dl < -0x8000) dl = -0x8000; sdl = dl ^ 0xfff8000; if (dr > 0x7fff) dr = 0x7fff; else if (dr < -0x8000) dr = -0x8000; sdr = dr ^ 0xfff8000; *bothout++ = (((sdr + sdl) / 2) >> 8); } // Increment current pointers in mixbuffer. leftout += step; rightout += step; } if (updated) { // 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++; }}// // This is used to write out the mixbuffer// during each game loop update.//voidI_SubmitSound(void){ // Write it to DSP device. if (flag) { if (!audio_8bit_flag) write(audio_fd, mixbuffer, SAMPLECOUNT*BUFMUL); else write(audio_fd, mixbuffer, SAMPLECOUNT); flag = 0; }}voidI_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. fputc('q',sndserver); fflush(sndserver); }#else // Wait till all pending sounds are finished. int done = 0; int i; if (nosound) return;#ifdef SNDINTR I_SoundDelTimer();#endif while ( !done ) { for( i=0 ; i<cv_numChannels.value && !channels[i] ; i++) ; if (i==cv_numChannels.value) done++; else { I_UpdateSound(); I_SubmitSound(); } } // Cleaning up -releasing the DSP device. close ( audio_fd );#endif // Done. return;}voidI_StartupSound(){ #ifdef SNDSERV char buffer[2048]; char *fn_snd; if (nosound) return; fn_snd = searchpath(sndserver_cmd.string); // start sound process if ( !access(fn_snd, X_OK) ) { sprintf(buffer, "%s %s", fn_snd, sndserver_arg.string); sndserver = popen(buffer, "w"); } else fprintf(stderr, "Could not start sound server [%s]\n", fn_snd);#else int i, j; if (nosound) return; // Secure and configure sound device first. fprintf( stderr, "I_InitSound: "); audio_fd = open("/dev/dsp", O_WRONLY); if (audio_fd<0) { fprintf(stderr, "Could not open /dev/dsp\n"); nosound++; return; } #ifndef OLD_SOUND_DRIVER myioctl(audio_fd, SNDCTL_DSP_RESET, 0);#endif if (getenv("DOOM_SOUND_SAMPLEBITS") == NULL) { myioctl(audio_fd, SNDCTL_DSP_GETFMTS, &i); if (i&=AFMT_S16_LE) { j = 11 | (2<<16); myioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &j); myioctl(audio_fd, SNDCTL_DSP_SETFMT, &i); i=1; myioctl(audio_fd, SNDCTL_DSP_STEREO, &i); } else { i = 10 | (2<<16); myioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &i); i=AFMT_U8; myioctl(audio_fd, SNDCTL_DSP_SETFMT, &i); audio_8bit_flag++; } } else { i = 10 | (2<<16); myioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &i); i=AFMT_U8; myioctl(audio_fd, SNDCTL_DSP_SETFMT, &i); audio_8bit_flag++; } i=SAMPLERATE; myioctl(audio_fd, SNDCTL_DSP_SPEED, &i); fprintf(stderr, " configured %dbit audio device\n", (audio_8bit_flag) ? 8 : 16 );#ifdef SNDINTR fprintf( stderr, "I_SoundSetTimer: %d microsecs\n", SOUND_INTERVAL ); I_SoundSetTimer( SOUND_INTERVAL );#endif // Initialize external data (all sounds) at start, keep static. fprintf( stderr, "I_InitSound: "); // Do we have a sound lump for the chaingun? if (W_CheckNumForName("dschgun") == -1) { // No, so link it to the pistol sound //S_sfx[sfx_chgun].link = &S_sfx[sfx_pistol]; //S_sfx[sfx_chgun].pitch = 150; //S_sfx[sfx_chgun].volume = 0; //S_sfx[sfx_chgun].data = 0; fprintf(stderr, "linking chaingun sound to pistol sound,"); } else { fprintf(stderr, "found chaingun sound,"); } //for (i=1 ; i<NUMSFX ; i++) //{ // lengths[i] = 0; //} fprintf( stderr, " pre-cached all sound data\n"); // Now initialize mixbuffer with zero. for ( i = 0; i< MIXBUFFERSIZE; i++ ) mixbuffer[i] = 0; // Finished initialization. fprintf(stderr, "I_InitSound: sound module ready\n"); #endif}//// MUSIC API.// Music done now, we'll use Michael Heasley's musserver.//void I_InitMusic(void){#ifdef MUSSERV char buffer[2048]; char *fn_mus;#endif if (nomusic) return;#ifdef MUSSERV fn_mus = searchpath(musserver_cmd.string); // now try to start the music server process if (!access(fn_mus, X_OK)) { int p; sprintf(buffer, "%s %s", fn_mus, musserver_arg.string); // check for a specific iwad file if ( (p = M_CheckParm ("-iwad")) && p < myargc-1 ) { sprintf(buffer, "%s -i %s", buffer, myargv[p+1]); } fprintf(stderr, "Starting music server [%s]\n", buffer); musserver = popen(buffer, "w"); msg_id = msgget(53075, IPC_CREAT | 0777); } else fprintf(stderr, "Could not start music server [%s]\n", fn_mus);#endif}void I_ShutdownMusic(void){ if (nomusic) return;#ifdef MUSSERV if (musserver) { // send a "quit" command. if (msg_id != -1) msgctl(msg_id, IPC_RMID, (struct msqid_ds *) NULL); }#endif}static int looping=0;static int musicdies=-1;void I_PlaySong(int handle, int looping){ // UNUSED. handle = looping = 0; musicdies = gametic + TICRATE*30; if (nomusic) return;}void I_PauseSong (int handle){ // UNUSED. handle = 0; if (nomusic) return;}void I_ResumeSong (int handle){ // UNUSED. handle = 0; if (nomusic) return;}void I_StopSong(int handle){ // UNUSED. handle = 0; looping = 0; musicdies = 0; if (nomusic) return;}void I_UnRegisterSong(int handle){ // UNUSED. handle = 0;}// BP: len is unused but is just to have compatible apiint I_RegisterSong(void* data,int len){#ifdef MUSSERV struct { long msg_type; char msg_text[12]; } msg_buffer;#endif if (nomusic) { data = NULL; return 1; }#ifdef MUSSERV if (msg_id != -1) { msg_buffer.msg_type = 6; memset(msg_buffer.msg_text, 0, 12); sprintf(msg_buffer.msg_text, "d_%s", (char *) data); msgsnd(msg_id, (struct msgbuf *) &msg_buffer, 12, IPC_NOWAIT); }#else data = NULL;#endif return 1;}// Is the song playing?int I_QrySongPlaying(int handle){ // UNUSED. handle = 0; return looping || musicdies > gametic;}//// Experimental stuff.// A Linux timer interrupt, for asynchronous// sound output.// I ripped this out of the Timer class in// our Difference Engine, including a few// SUN remains...// #ifdef sun typedef sigset_t tSigSet;#else typedef int tSigSet;#endif// We might use SIGVTALRM and ITIMER_VIRTUAL, if the process// time independend timer happens to get lost due to heavy load.// SIGALRM and ITIMER_REAL doesn't really work well.// There are issues with profiling as well.//static int /*__itimer_which*/ itimer = ITIMER_REAL;static int /*__itimer_which*/ itimer = ITIMER_VIRTUAL;//static int sig = SIGALRM;static int sig = SIGVTALRM;// Interrupt handler.void I_HandleSoundTimer( int ignore ){ // Debug. //fprintf( stderr, "%c", '+' ); fflush( stderr ); // Feed sound device if necesary. if ( flag ) { // See I_SubmitSound(). // Write it to DSP device. if (!audio_8bit_flag) write(audio_fd, mixbuffer, SAMPLECOUNT*BUFMUL); else write(audio_fd, mixbuffer, SAMPLECOUNT); // Reset flag counter. flag = 0; } else return; // UNUSED, but required. ignore = 0; return;}// Get the interrupt. Set duration in millisecs.int I_SoundSetTimer( int duration_of_tick ){ // Needed for gametick clockwork. struct itimerval value; struct itimerval ovalue; struct sigaction act; struct sigaction oact; int res; // This sets to SA_ONESHOT and SA_NOMASK, thus we can not use it. // signal( _sig, handle_SIG_TICK ); // Now we have to change this attribute for repeated calls. act.sa_handler = I_HandleSoundTimer;#ifndef sun //ac t.sa_mask = _sig;#endif act.sa_flags = SA_RESTART; sigaction( sig, &act, &oact ); value.it_interval.tv_sec = 0; value.it_interval.tv_usec = duration_of_tick; value.it_value.tv_sec = 0; value.it_value.tv_usec = duration_of_tick; // Error is -1. res = setitimer( itimer, &value, &ovalue ); // Debug. if ( res == -1 ) fprintf( stderr, "I_SoundSetTimer: interrupt n.a.\n"); return res;}// Remove the interrupt. Set duration to zero.void I_SoundDelTimer(){ // Debug. if ( I_SoundSetTimer( 0 ) == -1) fprintf( stderr, "I_SoundDelTimer: failed to remove interrupt. Doh!\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -