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

📄 win_snd.c

📁 The source code of Doom legacy for windows
💻 C
📖 第 1 页 / 共 5 页
字号:
    // PU_CACHE because the data is copied to the DIRECTSOUNDBUFFER, the one here will not be used
    dssfx = (byte*) W_CacheLumpNum (sfx->lumpnum, PU_CACHE);

#ifdef SURROUND
    // Make a normal (not inverted) sound buffer
    return (void*)raw2DS (dssfx, size, FALSE);
#else
    // return the LPDIRECTSOUNDBUFFER, which will be stored in S_sfx[].data
    return (void *)raw2DS (dssfx, size);
#endif
}


// --------------------------------------------------------------------------
// Free all allocated resources for a single sound
// --------------------------------------------------------------------------
void I_FreeSfx (sfxinfo_t* sfx)
{
    LPDIRECTSOUNDBUFFER dsbuffer;

    

    if (sfx->lumpnum<0)
        return;

#ifdef HW3SOUND
    if (hws_mode != HWS_DEFAULT_MODE)
    {
        if (sfx->data)
            Z_Free(sfx->data);
      
    }
    else
#endif
    {
        //CONS_Printf ("I_FreeSfx(%d)\n", sfx->lumpnum);

        // free DIRECTSOUNDBUFFER
        dsbuffer = (LPDIRECTSOUNDBUFFER) sfx->data;
        if( dsbuffer )
            dsbuffer->lpVtbl->Release (dsbuffer);
    }
    sfx->data = NULL;
    sfx->lumpnum = -1;
}


// --------------------------------------------------------------------------
// Set the global volume for sound effects
// --------------------------------------------------------------------------
void I_SetSfxVolume(int volume)
{
    int     vol;
    HRESULT hr;

    if (nosound || !sound_started)
        return;
        
    // use the last quarter of volume range
    if (cv_soundvolume.value)
        vol = (cv_soundvolume.value * ((DSBVOLUME_MAX-DSBVOLUME_MIN)/4)) / 31 +
              (DSBVOLUME_MAX - ((DSBVOLUME_MAX-DSBVOLUME_MIN)/4));
    else
        vol = DSBVOLUME_MIN;    // make sure 0 is silence
    //CONS_Printf ("setvolume to %d\n", vol);
    hr = DSndPrimary->lpVtbl->SetVolume (DSndPrimary, vol);
    //if (FAILED(hr))
    //    CONS_Printf ("setvolumne failed\n");
}


// --------------------------------------------------------------------------
// Update the volume for a secondary buffer, make sure it was created with
// DSBCAPS_CTRLVOLUME
// --------------------------------------------------------------------------
static void I_UpdateSoundVolume (LPDIRECTSOUNDBUFFER lpSnd, int volume)
{
    HRESULT hr;
    volume = (volume * ((DSBVOLUME_MAX-DSBVOLUME_MIN)/4)) / 256 +
                        (DSBVOLUME_MAX - ((DSBVOLUME_MAX-DSBVOLUME_MIN)/4));
    hr = lpSnd->lpVtbl->SetVolume (lpSnd, volume);
    //if (FAILED(hr))
    //    CONS_Printf ("\2SetVolume FAILED\n");
}


// --------------------------------------------------------------------------
// Update the panning for a secondary buffer, make sure it was created with
// DSBCAPS_CTRLPAN
// --------------------------------------------------------------------------
#define DSBPAN_RANGE    (DSBPAN_RIGHT-(DSBPAN_LEFT))
#define SEP_RANGE       256     //Doom sounds pan range 0-255 (128 is centre)
static void I_UpdateSoundPanning (LPDIRECTSOUNDBUFFER lpSnd, int sep)
{
    HRESULT hr;
    hr = lpSnd->lpVtbl->SetPan (lpSnd, (sep * DSBPAN_RANGE)/SEP_RANGE - DSBPAN_RIGHT);
    //if (FAILED(hr))
    //    CONS_Printf ("SetPan FAILED for sep %d pan %d\n", sep, (sep * DSBPAN_RANGE)/SEP_RANGE - DSBPAN_RIGHT);
}

// search a free slot in the stack, free it if needed
static int GetFreeStackNum(int  newpriority)
{
    int  lowestpri,lowestprihandle;
    int  i;
    // DirectSound can't play multiple instances of the same sound buffer
    // unless they are duplicated, so if the sound buffer is in use, make a duplicate
    lowestpri = 256;
    lowestprihandle = 0;
    for (i=0; i<MAXSTACKSOUNDS; i++)
    {
        // find a free 'playing sound slot' to use
        if (StackSounds[i].lpSndBuf==NULL) {
            //CONS_Printf ("\t\tfound free slot %d\n", i);
            return i;
        }
        else
            // check for sounds that finished playing, and can be freed
            if( !I_SoundIsPlaying(i) )
            {
                //CONS_Printf ("\t\tfinished sound in slot %d\n", i);
                //stop sound and free the 'slot'
                I_StopSound (i);
                // we can use this one since it's now freed
                return i;
            }
            else
            //remember lowest priority sound
            if (StackSounds[i].priority < lowestpri) {
                lowestpri = StackSounds[i].priority;
                lowestprihandle = i;
            }

    }
    
    // the maximum of sounds playing at the same time is reached, if we have at least
    // one sound playing with a lower priority, stop it and replace it with the new one

    //CONS_Printf ("\t\tall slots occupied..");
    if (newpriority >= lowestpri) {
        I_StopSound (lowestprihandle);
        return lowestprihandle;
            //CONS_Printf (" kicking out lowest priority slot: %d pri: %d, my priority: %d\n",
            //             handle, lowestpri, priority);
        }

    return -1;
}

#ifdef SURROUND
static LPDIRECTSOUNDBUFFER CreateInvertedSound(int id)
{
    int   lumpnum;
    byte  *dsdata;

    lumpnum = S_sfx[id].lumpnum;
    if (lumpnum<0)      
        lumpnum = S_GetSfxLumpNum (&S_sfx[id]);
    dsdata = W_CacheLumpNum (lumpnum, PU_CACHE);
    return raw2DS(dsdata, W_LumpLength (lumpnum), TRUE);

}
#endif

// --------------------------------------------------------------------------
// Start the given S_sfx[id] sound with given properties (panning, volume..)
// FIXME: if a specific sound Id is already being played, another instance
//        of that sound should be created with DuplicateSound()
// --------------------------------------------------------------------------
int I_StartSound (int            id,
                  int            vol,
                  int            sep,
                  int            pitch,
                  int            priority )
{
    HRESULT     hr;
    LPDIRECTSOUNDBUFFER     dsbuffer;
    DWORD       dwStatus;
    int         handle;
    int         i;
#ifdef SURROUND
    LPDIRECTSOUNDBUFFER     dssurround;
#endif

    if (nosound)
        return -1;

    //CONS_Printf ("I_StartSound:\n\t\tS_sfx[%d]\n", id);
    handle = GetFreeStackNum(priority);
    if( handle<0 )  
        return -1;

    //CONS_Printf ("\t\tusing handle %d\n", handle);

    // if the original buffer is playing, duplicate it (DirectSound specific)
    // else, use the original buffer
    dsbuffer = (LPDIRECTSOUNDBUFFER) S_sfx[id].data;
    dsbuffer->lpVtbl->GetStatus (dsbuffer, &dwStatus);
    if (dwStatus & (DSBSTATUS_PLAYING | DSBSTATUS_LOOPING))
    {
        //CONS_Printf ("\t\toriginal sound S_sfx[%d] is playing, duplicating.. ", id);
        hr = DSnd->lpVtbl->DuplicateSoundBuffer(DSnd,  (LPDIRECTSOUNDBUFFER) S_sfx[id].data, &dsbuffer);
        if (FAILED(hr))
        {
            //CONS_Printf ("Cound't duplicate sound buffer\n");
            // re-use the original then..
            dsbuffer = (LPDIRECTSOUNDBUFFER) S_sfx[id].data;
            // clean up stacksounds info
            for (i=0; i<MAXSTACKSOUNDS; i++)
                if (handle != i &&
                    StackSounds[i].lpSndBuf == dsbuffer)
                {
                    StackSounds[i].lpSndBuf = NULL;
                }
        }
        // stop the duplicate or the re-used original
        dsbuffer->lpVtbl->Stop (dsbuffer);
    }

    // store information on the playing sound
    StackSounds[handle].lpSndBuf = dsbuffer;
    StackSounds[handle].priority = priority;
    StackSounds[handle].duplicate = (dsbuffer != (LPDIRECTSOUNDBUFFER)S_sfx[id].data);

    //CONS_Printf ("StackSounds[%d].lpSndBuf is %s\n", handle, StackSounds[handle].lpSndBuf==NULL ? "Null":"valid");
    //CONS_Printf ("StackSounds[%d].priority is %d\n", handle, StackSounds[handle].priority);
    //CONS_Printf ("StackSounds[%d].duplicate is %s\n", handle, StackSounds[handle].duplicate ? "TRUE":"FALSE");

    I_UpdateSoundVolume (dsbuffer, vol);

#ifdef SURROUND
        // Prepare the surround sound buffer
    // Use a normal sound data for the left channel (with pan == 0)
    // and an inverted sound data for the right channel (with pan == 255)
    
    dssurround = CreateInvertedSound(id);
    if (sep == -128)
    {
        I_UpdateSoundPanning(dssurround, 255);
        I_UpdateSoundVolume(dssurround, vol);
        I_UpdateSoundPanning(dsbuffer, 0);
        dssurround->lpVtbl->SetCurrentPosition(dssurround, 0);
    }
        else
    // Perform normal operation
#endif

        I_UpdateSoundPanning (dsbuffer, sep);

    dsbuffer->lpVtbl->SetCurrentPosition (dsbuffer, 0);

    hr = dsbuffer->lpVtbl->Play (dsbuffer, 0, 0, 0);
    if (hr == DSERR_BUFFERLOST)
    {
        //CONS_Printf("buffer lost\n");
        // restores the buffer memory and all other settings for the buffer
        hr = dsbuffer->lpVtbl->Restore (dsbuffer);
        if ( SUCCEEDED ( hr ) )
        {
            byte*   dsdata;
            // reload sample data here
            int     lumpnum = S_sfx[id].lumpnum;
            if (lumpnum<0)
                lumpnum = S_GetSfxLumpNum (&S_sfx[id]);
            dsdata = W_CacheLumpNum (lumpnum, PU_CACHE);

            // Well... Data lenght must be -8!!!
            CopySoundData (dsbuffer, (byte*)dsdata + 8, W_LumpLength (S_sfx[id].lumpnum) - 8);
            
            // play
            hr = dsbuffer->lpVtbl->Play (dsbuffer, 0, 0, 0);
        }
        else
            I_Error ("I_StartSound : ->Restore FAILED, %s",DXErrorToString(hr));
    }

#ifdef SURROUND
        
    if (sep == -128)
    {
        hr = dssurround->lpVtbl->Play (dssurround, 0, 0, 0);
        //CONS_Printf("Surround playback\n");
        if (hr == DSERR_BUFFERLOST)
        {
            // restores the buffer memory and all other settings for the surround buffer
            hr = dssurround->lpVtbl->Restore (dssurround);
            if ( SUCCEEDED ( hr ) )
            {
                byte*   dsdata;
                int     lumpnum = S_sfx[id].lumpnum;

                if (lumpnum<0)
                    lumpnum = S_GetSfxLumpNum (&S_sfx[id]);
                dsdata = W_CacheLumpNum (lumpnum, PU_CACHE);
                CopyAndInvertSoundData (dssurround, (byte*)dsdata + 8, W_LumpLength (S_sfx[id].lumpnum) - 8);
            
                hr = dssurround->lpVtbl->Play (dssurround, 0, 0, 0);
            }
            else
                I_Error ("I_StartSound : ->Restore FAILED, %s",DXErrorToString(hr));
        }
    }
    StackSounds[handle].lpSurround = dssurround;
#endif

    // Returns a handle
    return handle;
}


// --------------------------------------------------------------------------
// Stop a sound if it is playing,
// free the corresponding 'playing sound slot' in StackSounds[]
// --------------------------------------------------------------------------
void I_StopSound (int handle)
{
    LPDIRECTSOUNDBUFFER dsbuffer;
    HRESULT hr;

    if (nosound || handle<0)
        return;

    //CONS_Printf ("I_StopSound (%d)\n", handle);
    
    dsbuffer = StackSounds[handle].lpSndBuf;
    hr = dsbuffer->lpVtbl->Stop (dsbuffer);

    // free duplicates of original sound buffer (DirectSound hassles)
    if (StackSounds[handle].duplicate) {
        //CONS_Printf ("\t\trelease a duplicate..\n");
        dsbuffer->lpVtbl->Release (dsbuffer);
    }

#ifdef SURROUND
    // Stop and release the surround sound buffer
    dsbuffer = StackSounds[handle].lpSurround;
    if (dsbuffer != NULL)
    {
        dsbuffer->lpVtbl->Stop(dsbuffer);
        dsbuffer->lpVtbl->Release(dsbuffer);
    }
    StackSounds[handle].lpSurround = NULL;
#endif

    StackSounds[handle].lpSndBuf = NULL;
}


// --------------------------------------------------------------------------
// Returns whether the sound is currently playing or not
// --------------------------------------------------------------------------
int I_SoundIsPlaying(int handle)
{
    LPDIRECTSOUNDBUFFER dsbuffer;
    DWORD   dwStatus;
    
    if (nosound || handle == -1)
        return FALSE;

    dsbuffer = StackSounds[handle].lpSndBuf;
    if (dsbuffer) {
        dsbuffer->lpVtbl->GetStatus (dsbuffer, &dwStatus);
        if (dwStatus & (DSBSTATUS_PLAYING | DSBSTATUS_LOOPING))
            return TRUE;
    }
    
    return FALSE;
}


// --------------------------------------------------------------------------
// Update properties of a sound currently playing
// --------------------------------------------------------------------------
void I_UpdateSoundParams(int    handle,
                                     int        vol,
                                     int        sep,
                                     int        pitch)
{
    LPDIRECTSOUNDBUFFER     dsbuffer;
#ifdef SURROUND
    LPDIRECTSOUNDBUFFER     dssurround;
    DWORD                   dwStatus;
    DWORD                   pos;
    boolean                 surround_inuse = FALSE;
#endif

⌨️ 快捷键说明

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