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

📄 win_snd.c

📁 The source code of Doom legacy for windows
💻 C
📖 第 1 页 / 共 5 页
字号:
// Emacs style mode select   -*- C++ -*- 
//-----------------------------------------------------------------------------
//
// $Id: win_snd.c,v 1.13 2001/04/08 10:15:54 bpereira Exp $
//
// 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: win_snd.c,v $
// Revision 1.13  2001/04/08 10:15:54  bpereira
// no message
//
// Revision 1.12  2001/04/04 20:19:07  judgecutor
// Added support for the 3D Sound
//
// Revision 1.11  2001/01/25 22:15:45  bpereira
// added heretic support
//
// Revision 1.10  2001/01/21 04:33:35  judgecutor
// *** empty log message ***
//
// Revision 1.9  2000/10/27 20:38:21  judgecutor
// - Added the SurroundSound support
//
// Revision 1.8  2000/10/23 17:05:00  judgecutor
// Fixed old bug of midi stream
//
// Revision 1.7  2000/10/08 13:30:03  bpereira
// no message
//
// Revision 1.6  2000/09/28 20:57:22  bpereira
// no message
//
// Revision 1.5  2000/09/01 19:34:38  bpereira
// no message
//
// Revision 1.4  2000/08/10 19:58:05  bpereira
// no message
//
// Revision 1.3  2000/04/16 18:38:07  bpereira
// no message
//
// Revision 1.2  2000/02/27 00:42:12  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:
//      interface level code for sound
//      uses the midiStream* Win32 functions to play MIDI data with low latency and low 
//      processor overhead.
//
//-----------------------------------------------------------------------------

#include "../doomdef.h"

#include "win_main.h"
#include <mmsystem.h>
#define DXVERSION
#include <dsound.h>

#include "../command.h"
#include "../i_sound.h"
#include "../s_sound.h"
#include "../i_system.h"
#include "../m_argv.h"
#include "../w_wad.h"
#include "../z_zone.h"
#include "../doomstat.h"

#include "dx_error.h"

#include "../qmus2mid.h"
#include "mid2strm.h"

#ifdef HW3SOUND
#include "../hardware/hw3sound.h"
#endif

#include "win_dll.h"


//#define TESTCODE            // remove this for release version

#ifndef SURROUND
#define SURROUND              // comment out this to disable the SurroundSound code
#endif

// DirectSound3D mode
#define HWS_DS3D    1

/* briefly described here for convenience:
typedef struct { 
    WORD  wFormatTag;       // WAVE_FORMAT_PCM is the only format accepted for DirectSound: 
                            // this tag indicates Pulse Code Modulation (PCM), an uncompressed format
                            // in which each samples represents the amplitude of the signal at the time
                            // of sampling. 
    WORD  nChannels;        // either one (mono) or two (stereo)
    DWORD nSamplesPerSec;   // the sampling rate, or frequency, in hertz.
                            //  Typical values are 11,025, 22,050, and 44,100
    DWORD nAvgBytesPerSec;  // nAvgBytesPerSec is the product of nBlockAlign and nSamplesPerSec
    WORD  nBlockAlign;      // the number of bytes required for each complete sample, for PCM formats
                            // is equal to (wBitsPerSample * nChannels / 8). 
    WORD  wBitsPerSample;   // gives the size of each sample, generally 8 or 16 bits
    WORD  cbSize;           // cbSize gives the size of any extra fields required to describe a
                            // specialized wave format. This member is always zero for PCM formats.
} WAVEFORMATEX; 
*/


// --------------------------------------------------------------------------
// DirectSound stuff
// --------------------------------------------------------------------------
LPDIRECTSOUND           DSnd = NULL;
LPDIRECTSOUNDBUFFER     DSndPrimary;

// Stack sounds means sounds put on top of each other, since DirectSound can't play
// the same sound buffer at different locations at the same time, we need to dupli-
// cate existing buffers to play multiple instances of the same sound in the same
// time frame. A duplicate sound is freed when it is no more used. The priority that
// comes from the s_sound engine, is kept so that the lowest priority sounds are
// stopped to make place for the new sound, unless the new sound has a lower priority
// than all playing sounds, in which case the sound is not started.
#define MAXSTACKSOUNDS      32          // this is the absolute number of sounds that
                                        // can play simultaneously, whatever the value
                                        // of cv_numChannels
typedef struct {
    LPDIRECTSOUNDBUFFER lpSndBuf;
#ifdef SURROUND
        // judgecutor:
        // Need for produce surround sound
    LPDIRECTSOUNDBUFFER lpSurround;
#endif
    int                 priority;
    boolean             duplicate;
} StackSound_t;
StackSound_t    StackSounds[MAXSTACKSOUNDS];


// --------------------------------------------------------------------------
// Fill the DirectSoundBuffer with data from a sample, made separate so that
// sound data cna be reloaded if a sound buffer was lost.
// --------------------------------------------------------------------------
// win9x version olny
static boolean CopySoundData_win95 (LPDIRECTSOUNDBUFFER dsbuffer, byte* data)
{
    LPVOID  lpvAudio1;              // receives address of lock start
    DWORD   dwBytes1;               // receives number of bytes locked
    LPVOID  lpvAudio2;              // receives address of lock start
    DWORD   dwBytes2;               // receives number of bytes locked
    HRESULT hr;

    // Obtain memory address of write block.
    hr = dsbuffer->lpVtbl->Lock (dsbuffer, 0, 0, &lpvAudio1, &dwBytes1, &lpvAudio2, &dwBytes2, DSBLOCK_ENTIREBUFFER);
    
    // If DSERR_BUFFERLOST is returned, restore and retry lock. 
    if (hr == DSERR_BUFFERLOST) 
    { 
        hr = dsbuffer->lpVtbl->Restore (dsbuffer);
        if( FAILED (hr) )
            I_Error("Restor fail on %x, %s\n",dsbuffer,DXErrorToString(hr));
        hr = dsbuffer->lpVtbl->Lock (dsbuffer, 0, 0, &lpvAudio1, &dwBytes1, NULL, NULL, DSBLOCK_ENTIREBUFFER);
        if( FAILED (hr) )
            I_Error("Lock fail(2) on %x, %s\n",dsbuffer,DXErrorToString(hr));
    }
    else
        if( FAILED (hr) )
            I_Error("Lock fail(1) on %x, %s\n",dsbuffer,DXErrorToString(hr));



        // copy wave data into the buffer (note: dwBytes1 should equal to dsbdesc->dwBufferBytes ...)
        CopyMemory (lpvAudio1, data, dwBytes1);
    
        // finally, unlock the buffer
    hr = dsbuffer->lpVtbl->Unlock (dsbuffer, lpvAudio1, dwBytes1, lpvAudio2, dwBytes2);

    if( FAILED (hr) )
        I_Error("Unlock fail on %x, %s\n",dsbuffer,DXErrorToString(hr));

    return true;
}

// NT compatible version
static boolean CopySoundData (LPDIRECTSOUNDBUFFER dsbuffer, byte* data, int length)
{
    LPVOID  lpvAudio1;              // receives address of lock start
    DWORD   dwBytes1;               // receives number of bytes locked
    LPVOID  lpvAudio2;              // receives address of lock start
    DWORD   dwBytes2;               // receives number of bytes locked
    HRESULT hr;

    // Obtain memory address of write block.
    hr = dsbuffer->lpVtbl->Lock (dsbuffer, 0, length, &lpvAudio1, &dwBytes1, &lpvAudio2, &dwBytes2, 0);

    // If DSERR_BUFFERLOST is returned, restore and retry lock. 
    if (hr == DSERR_BUFFERLOST) 
    { 
        hr = dsbuffer->lpVtbl->Restore (dsbuffer);
        if( FAILED (hr) )
            I_Error("Restor fail on %x, %s\n",dsbuffer,DXErrorToString(hr));
        hr = dsbuffer->lpVtbl->Lock (dsbuffer, 0, length, &lpvAudio1, &dwBytes1, NULL, NULL, 0);
        if( FAILED (hr) )
            I_Error("Lock fail(2) on %x, %s\n",dsbuffer,DXErrorToString(hr));
    }
    else
        if( FAILED (hr) )
            I_Error("Lock fail(1) on %x, %s\n",dsbuffer,DXErrorToString(hr));

    // copy wave data into the buffer (note: dwBytes1 should equal to dsbdesc->dwBufferBytes ...)
    CopyMemory (lpvAudio1, data, dwBytes1);

    if ( dwBytes2 && lpvAudio2)  
         CopyMemory(lpvAudio2, data+dwBytes1, dwBytes2); 

    
    // finally, unlock the buffer
    hr = dsbuffer->lpVtbl->Unlock (dsbuffer, lpvAudio1, dwBytes1, lpvAudio2, dwBytes2);

    if( FAILED (hr) )
        I_Error("Unlock fail on %x, %s\n",dsbuffer,DXErrorToString(hr));

    return true;
}

#ifdef SURROUND
// judgecutor:
// Hmmm... May be this function is not too good...
static void CopyAndInvertMemory(void *dest, void *src, int bytes)
{
    _asm
    {
        push esi
        push edi
        push ecx
        mov  ecx,bytes
        mov  esi,src
        mov  edi,dest
a:
        lodsb
        neg  al
        stosb
        loop a
        pop  ecx
        pop  edi
        pop  esi
    }
}

// judgecutor:
// Like normal CopySoundData but sound data will be inverted
static boolean CopyAndInvertSoundData(LPDIRECTSOUNDBUFFER dsbuffer, byte* data, int length)
{
        LPVOID  lpvAudio1;              // receives address of lock start
    DWORD   dwBytes1;               // receives number of bytes locked
    LPVOID  lpvAudio2;
    DWORD   dwBytes2;
    HRESULT hr;

    // Obtain memory address of write block.
    hr = dsbuffer->lpVtbl->Lock (dsbuffer, 0, length, &lpvAudio1, &dwBytes1, &lpvAudio2, &dwBytes2, 0);
    
    // If DSERR_BUFFERLOST is returned, restore and retry lock. 
    if (hr == DSERR_BUFFERLOST) 
    { 
        hr = dsbuffer->lpVtbl->Restore (dsbuffer);
        if( FAILED (hr) )
            I_Error("CopyAndInvert: Restore fail on %x, %s\n",dsbuffer,DXErrorToString(hr));
        hr = dsbuffer->lpVtbl->Lock (dsbuffer, 0, length, &lpvAudio1, &dwBytes1, NULL, NULL, 0);
        if( FAILED (hr) )
            I_Error("CopyAndInvert: Lock fail(2) on %x, %s\n",dsbuffer,DXErrorToString(hr));
    } else if( FAILED (hr) )
              I_Error("CopyAndInvetrt: Lock fail(1) on %x, %s\n",dsbuffer,DXErrorToString(hr));
    
    
    // copy wave data into the buffer (note: dwBytes1 should equal to dsbdesc->dwBufferBytes ...)
    CopyAndInvertMemory (lpvAudio1, data, dwBytes1);

    if ( dwBytes2 && lpvAudio2)  
        CopyAndInvertMemory(lpvAudio2, data+dwBytes1, dwBytes2);
    
   
    hr = dsbuffer->lpVtbl->Unlock (dsbuffer, lpvAudio1, dwBytes1, lpvAudio2, dwBytes2);
    if( FAILED (hr) )
        I_Error("CopyAndInvert: Unlock fail on %x, %s\n",dsbuffer,DXErrorToString(hr));

    return false;
}
#endif

// --------------------------------------------------------------------------
// raw2DS : convert a raw sound data, returns a LPDIRECTSOUNDBUFFER
// --------------------------------------------------------------------------
//   dsdata points a 4 unsigned short header:
//    +0 : value 3 what does it mean?
//    +2 : sample rate, either 11025 or 22050.
//    +4 : number of samples, each sample is a single byte since it's 8bit
//    +6 : value 0
//
#ifdef SURROUND
// judgecutor:
// We need an another function definition for supporting the surround sound
// Invert just cause to copy an inverted sound data
static LPDIRECTSOUNDBUFFER raw2DS(unsigned char *dsdata, int len, boolean invert)

#else
static LPDIRECTSOUNDBUFFER raw2DS(unsigned char *dsdata, int len)

#endif
{
    HRESULT             hr;
    WAVEFORMATEX        wfm;
    DSBUFFERDESC        dsbdesc;
    LPDIRECTSOUNDBUFFER dsbuffer;

    // initialise WAVEFORMATEX structure describing the wave format
    ZeroMemory (&wfm, sizeof(WAVEFORMATEX));
    wfm.wFormatTag = WAVE_FORMAT_PCM;
    wfm.nChannels = 1;
    wfm.nSamplesPerSec = *((unsigned short*)dsdata+1);      //mostly 11025, but some at 22050.
    wfm.wBitsPerSample = 8;
    wfm.nBlockAlign = wfm.wBitsPerSample / 8 * wfm.nChannels;
    wfm.nAvgBytesPerSec = wfm.nSamplesPerSec * wfm.nBlockAlign;

    // Set up DSBUFFERDESC structure.
    ZeroMemory (&dsbdesc, sizeof(DSBUFFERDESC) );
    dsbdesc.dwSize = sizeof (DSBUFFERDESC);
    dsbdesc.dwFlags = DSBCAPS_CTRLPAN |
                      DSBCAPS_CTRLVOLUME |
                      DSBCAPS_STICKYFOCUS |
                      //DSBCAPS_LOCSOFTWARE |
                      DSBCAPS_STATIC;
    dsbdesc.dwBufferBytes = len-8;
    dsbdesc.lpwfxFormat = &wfm;             // pointer to WAVEFORMATEX structure

    // Create the sound buffer
    hr = DSnd->lpVtbl->CreateSoundBuffer (DSnd, &dsbdesc, &dsbuffer, NULL);
    if ( FAILED( hr ) )
        I_Error ("CreateSoundBuffer() FAILED: %s\n", DXErrorToString(hr));

#ifdef SURROUND
        
    if (invert)
        // just invert a sound data for producing the surround sound
        CopyAndInvertSoundData(dsbuffer, (byte*)dsdata + 8, dsbdesc.dwBufferBytes);
    else
        // Do a normal operation
#endif 
    // fill the DirectSoundBuffer waveform data
    CopySoundData (dsbuffer, (byte*)dsdata + 8, dsbdesc.dwBufferBytes);

    return dsbuffer;
}


// --------------------------------------------------------------------------
// This function loads the sound data from the WAD lump, for single sound.
// --------------------------------------------------------------------------
void* I_GetSfx (sfxinfo_t*  sfx)
{
    byte*               dssfx;
    int                 size;

    if (sfx->lumpnum<0)
        sfx->lumpnum = S_GetSfxLumpNum (sfx);

#ifdef HW3SOUND
    if (hws_mode != HWS_DEFAULT_MODE)
        return W_CacheLumpNum(sfx->lumpnum, PU_STATIC);
#endif

    size = W_LumpLength (sfx->lumpnum);

⌨️ 快捷键说明

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