// 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. // //----------------------------------------------------------------------------- static const char rcsid[] = "$Id: i_unix.c,v 1.5 1997/02/03 22:45:10 b1 Exp $"; #include #include "SDL_audio.h" #include "SDL_mixer.h" // cosmito #include "SDL_mutex.h" #include "SDL_byteorder.h" #include "SDL_version.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" // cosmito static boolean sound_inited = false; static boolean first_sound_init = true; int snd_pcspeaker; // 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. static int SAMPLECOUNT= 512; #define NUM_CHANNELS 8 #define SAMPLERATE 11025 // Hz // TBD : cosmito : confirm if good to use on PS2 // The actual lengths of all sound effects. int lengths[NUMSFX]; // The actual output device. int audio_fd; typedef struct { // SFX id of the playing sound effect. // Used to catch duplicates (like chainsaw). int id; // The channel step amount... unsigned int step; // ... and a 0.16 bit remainder of last step. unsigned int stepremainder; unsigned int samplerate; // The channel data pointers, start and end. const unsigned char* data; const unsigned char* enddata; // 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 starttime; // Hardware left and right channel volume lookup. int *leftvol_lookup; int *rightvol_lookup; } channel_info_t; channel_info_t channelinfo[/*MAX_CHANNELS*/NUM_CHANNELS]; // cosmito replaced prboom MAX_CHANNELS here by NUM_CHANNELS // 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]; // cosmito : no used anymore ... comment in the furure // // This function loads the sound data from the WAD lump, // 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 ); //for(i=0; i<100; i++) // printf("sfx[%d] = %d\n ", i, sfx[i]); //printf("(---)\n"); //for(i=size-100; i> 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; } */ static int addsfx(int sfxid, int channel, const unsigned char* data, size_t len) { int i=0; stopchan(channel); // debug //printf("channel = %d\n ", channel); //printf("data[2] = %d\n ", data[2]); //printf("data[3] = %d\n ", data[3]); //printf("data[3] = %d\n ", (data[3]<<8)+data[2]); //printf("i_sound.c : addsfx()\n\n"); //printf("sfxid = %d, channel = %d, len = %d\n\n", sfxid, channel, len); //for(i=0; i<100; i++) // printf("data[%d] = %d\n ", i, data[i]); //printf("(---)\n"); //for(i=len-100; i= /*MAX_CHANNELS*/NUM_CHANNELS)) I_Error("I_UpdateSoundParams: handle out of range"); #endif /* // cosmito if (snd_pcspeaker) return; */ // Set stepping // MWM 2000-12-24: Calculates proportion of channel samplerate // to global samplerate for mixing purposes. // Patched to shift left *then* divide, to minimize roundoff errors // as well as to use SAMPLERATE as defined above, not to assume 11025 Hz if (pitched_sounds) channelinfo[slot].step = step + (((channelinfo[slot].samplerate<<16)/SAMPLERATE/*snd_samplerate*/)-65536); else channelinfo[slot].step = ((channelinfo[slot].samplerate<<16)/SAMPLERATE/*snd_samplerate*/); // 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); // cosmito : TBD : check if >> 16 works under PS2 seperation = seperation - 257; rightvol= volume - ((volume*seperation*seperation) >> 16); // cosmito : TBD : check if >> 16 works under PS2 // 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??? channelinfo[slot].leftvol_lookup = &vol_lookup[leftvol*256]; channelinfo[slot].rightvol_lookup = &vol_lookup[rightvol*256]; } // // 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; iname); return W_GetNumForName(namebuf); } */ int I_GetSfxLumpNum(sfxinfo_t* sfx) { char namebuf[9]; char *prefix; // Different prefix for PC speaker sound effects. prefix = (snd_pcspeaker ? "dp" : "ds"); sprintf(namebuf, "%s%s", prefix, 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 id, int channel, int vol, int sep, int pitch, int priority) { const unsigned char* data; int lump; size_t len; if ((channel < 0) || (channel >= NUM_CHANNELS)) #ifdef RANGECHECK I_Error("I_StartSound: handle out of range"); #else return -1; #endif /* #ifdef HAVE_MIXER if (snd_pcspeaker) return I_PCS_StartSound(id, channel, vol, sep, pitch, priority); #endif */ lump = S_sfx[id].lumpnum; // We will handle the new SFX. // Set pointer to raw data. len = W_LumpLength(lump); // e6y: Crash with zero-length sounds. // Example wad: dakills (http://www.doomworld.com/idgames/index.php?id=2803) // The entries DSBSPWLK, DSBSPACT, DSSWTCHN and DSSWTCHX are all zero-length sounds if (len<=8) return -1; /* Find padded length */ len -= 8; // do the lump caching outside the SDL_LockAudio/SDL_UnlockAudio pair // use locking which makes sure the sound data is in a malloced area and // not in a memory mapped one //data = W_LockLumpNum(lump); // solucao : nao chamar isto mas garantir q se obtem o data. nota : o addsfx mais abaixo é agora bastante diferente... obter o raw data como se faz no tag 1.0.0.0 e passar como argumento ao addsfx SDL_LockAudio(); /// //printf("lenght %d\n", lengths[id]); data = (unsigned char *) S_sfx[id].data; // cosmito : just this? //printf("data address %p\n\n", data); /// // Returns a handle (not used). addsfx(id, channel, data, len); updateSoundParams(channel, vol, sep, pitch); SDL_UnlockAudio(); //printf("I_StartSound returning\n"); // cosmito : if uncommented results in some noise return channel; } /* { // UNUSED priority = 0; // Debug. //fprintf( stderr, "starting sound %d", id ); // 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; } */ void I_StopSound (int handle) { #ifdef RANGECHECK if ((handle < 0) || (handle >= /*MAX_CHANNELS*/NUM_CHANNELS)) I_Error("I_StopSound: handle out of range"); #endif #ifdef HAVE_MIXER if (snd_pcspeaker) { //I_PCS_StopSound(handle); // cosmito : not implemented for PS2 return; } #endif SDL_LockAudio(); stopchan(handle); SDL_UnlockAudio(); } /* int I_SoundIsPlaying(int handle) { // Ouch. return gametic < handle; } */ boolean I_SoundIsPlaying(int handle) { #ifdef RANGECHECK if ((handle < 0) || (handle >= /*MAX_CHANNELS*/NUM_CHANNELS)) I_Error("I_SoundIsPlaying: handle out of range"); #endif //#ifdef HAVE_MIXER // if (snd_pcspeaker) // return I_PCS_SoundIsPlaying(handle); // cosmito : not implemented for PS2 //#endif return channelinfo[handle].data != NULL; } boolean I_AnySoundStillPlaying(void) { boolean result = false; int i; if (snd_pcspeaker) return false; for (i=0; i> 16; // Add left and right part // for this channel (sound) // to the current data. // Adjust volume accordingly. dl += channelinfo[chan].leftvol_lookup[sample]; // TBD : crash here dr += channelinfo[chan].rightvol_lookup[sample]; // Increment index ??? channelinfo[chan].stepremainder += channelinfo[chan].step; // MSB is next sample??? // TBD : Atenção channelinfo[chan].data += channelinfo[chan].stepremainder >> 16; // Limit to LSB??? channelinfo[chan].stepremainder &= 0xffff; // Check whether we are done. if (channelinfo[chan].data >= channelinfo[chan].enddata) stopchan(chan); } } /**/ // 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 stream leftout += step; rightout += step; } } /* 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_UpdateSoundParams(int handle, int volume, int seperation, int pitch) { SDL_LockAudio(); updateSoundParams(handle, volume, seperation, pitch); SDL_UnlockAudio(); } void I_ShutdownSound(void) { //SDL_CloseAudio(); // cosmito commented // cosmito from prboom+ if (sound_inited) { #ifdef HAVE_MIXER Mix_CloseAudio(); fprintf( stderr, "HAVE_MIXER defined : using Mix_CloseAudio()"); #else fprintf( stderr, "HAVE_MIXER not defined : using SDL_CloseAudio()"); SDL_CloseAudio(); #endif sound_inited = false; } } void I_InitSound() { // cosmito : commented. Previous code /* SDL_AudioSpec wanted; int i; // Secure and configure sound device first. fprintf( stderr, "I_InitSound: "); // Open the audio device wanted.freq = SAMPLERATE; if ( SDL_BYTEORDER == SDL_BIG_ENDIAN ) { wanted.format = AUDIO_S16MSB; } else { wanted.format = AUDIO_S16LSB; } wanted.channels = 2; wanted.samples = SAMPLECOUNT; wanted.callback = I_UpdateSound; if ( SDL_OpenAudio(&wanted, NULL) < 0 ) { fprintf(stderr, "couldn't open audio with desired format\n"); return; } SAMPLECOUNT = wanted.samples; fprintf(stderr, " configured audio device with %d samples/slice\n", SAMPLECOUNT); // Initialize external data (all sounds) at start, keep static. fprintf( stderr, "I_InitSound: "); for (i=1 ; idata; lengths[i] = lengths[(S_sfx[i].link - S_sfx)/sizeof(sfxinfo_t)]; } } fprintf( stderr, " pre-cached all sound data\n"); // Finished initialization. fprintf(stderr, "I_InitSound: sound module ready\n"); SDL_PauseAudio(0); */ // cosmito : still needed int i, debug; unsigned char* pto; unsigned char bu; for (i=1 ; idata; lengths[i] = lengths[(S_sfx[i].link - S_sfx)/sizeof(sfxinfo_t)]; } // debug 06102008 if (i==38) { printf("lengths[%d] = %d\n\n", i, lengths[i]); for (debug=0; debug<100; debug++) { pto = ((unsigned char*)S_sfx[i].data + debug); bu = *pto; printf("S_sfx[%d].data[%d] = %d\n", i, debug, (unsigned char)bu); //printf("pto = %p\n", pto); } } } fprintf( stderr, " pre-cached all sound data\n"); // ///// //while(1) //{}; ///// // // cosmito : prboom+ code boolean sound_inited_once = false; // cosmito : from e6y.c #ifdef HAVE_MIXER int audio_rate; Uint16 audio_format; int audio_channels; int audio_buffers; fprintf(stderr,"I_InitSound: HAVE_MIXER\n\n"); // cosmito if (sound_inited) I_ShutdownSound(); // Secure and configure sound device first. //lprintf(LO_INFO,"I_InitSound: "); fprintf(stderr, "I_InitSound: "); /* Initialize variables */ audio_rate = SAMPLERATE; #if ( SDL_BYTEORDER == SDL_BIG_ENDIAN ) // cosmito : TBD : check if little endian is really used. PS2 is little endian. audio_format = AUDIO_S16MSB; fprintf(stderr," SDL_BIG_ENDIAN - AUDIO_S16MSB\n\n"); #else audio_format = AUDIO_S16LSB; fprintf(stderr," SDL_LITTLE_ENDIAN - AUDIO_S16LSB\n\n"); #endif audio_channels = 2; //SAMPLECOUNT = 512; audio_buffers = SAMPLECOUNT*SAMPLERATE/SAMPLERATE;//44100; //if (Mix_OpenAudio(SAMPLERATE, AUDIO_S16, 2, SAMPLECOUNT) < 0) // cosmito : from lsdldoom if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) < 0) { fprintf(stderr,"couldn't open audio with desired format\n"); return; } sound_inited_once = true;//e6y // TBD : cosmito : variable defined at e6y.c ... what is this for? sound_inited = true; SAMPLECOUNT = audio_buffers; printf(" SAMPLECOUNT = audio_buffers = %d\n",SAMPLECOUNT); Mix_SetPostMix(I_UpdateSound, NULL); fprintf(stderr," configured audio device with %d samples/slice\n", SAMPLECOUNT); #else printf("never reach here ...\n\n"); // cosmito SDL_AudioSpec audio; // Secure and configure sound device first. fprintf(stderr,"I_InitSound: "); // Open the audio device audio.freq = SAMPLERATE; #if ( SDL_BYTEORDER == SDL_BIG_ENDIAN ) audio.format = AUDIO_S16MSB; fprintf(stderr," SDL_BIG_ENDIAN - AUDIO_S16MSB\n\n"); #else audio.format = AUDIO_S16LSB; fprintf(stderr," SDL_LITTLE_ENDIAN - AUDIO_S16LSB\n\n"); #endif audio.channels = 2; audio.samples = SAMPLECOUNT*SAMPLERATE/SAMPLERATE;//11025; audio.callback = I_UpdateSound; if ( SDL_OpenAudio(&audio, NULL) < 0 ) { fprintf(stderr,"just called SDL_OpenAudio\n"); // cosmito fprintf(stderr,"couldn't open audio with desired format\n"); return; } SAMPLECOUNT = audio.samples; fprintf(stderr," configured audio device with %d samples/slice\n", SAMPLECOUNT); #endif if (first_sound_init) { //atexit(I_ShutdownSound); // TBD first_sound_init = false; } // cosmito /* // If we are using the PC speaker, we now need to initialise it. #ifdef HAVE_MIXER if (snd_pcspeaker) I_PCS_InitSound(); #endif */ // TBD /* if (!nomusicparm) I_InitMusic(); */ // Finished initialization. fprintf(stderr,"I_InitSound: sound module ready\n"); #ifndef HAVE_MIXER SDL_PauseAudio(0); #endif } // // 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; }