dxsound.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 490 行
CPP
490 行
#include "StdAfx.h"
#ifndef _WINSOCKAPI_
#define _WINSOCKAPI_
#include <windows.h>
#undef _WINSOCKAPI_
#else
#include <windows.h>
#endif
#include "LogOutput.h"
#include "Platform/ConfigHandler.h"
#include "Game/Camera.h"
#include "Sim/Objects/WorldObject.h"
#include "DxSound.h"
#include "Platform/byteorder.h"
#include "Platform/errorhandler.h"
#include "Platform/NullSound.h"
#include "FileSystem/FileHandler.h"
#include <SDL_syswm.h>
#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
// Ogg-Vorbis audio stream object
COggStream oggStream;
CDxSound::CDxSound()
{
maxSounds=ConfigHandler::GetInstance().GetInt("MaxSounds",16);
if (maxSounds <= 0) {
throw content_error("Internal error, (maxSounds <= 0) in CDxSound");
}
curThreshhold=0.1f;
wantedSounds=maxSounds*0.75f;
globalVolume=1.0f;
m_pDS = NULL;
m_hWnd = NULL;
HRESULT hr;
LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
// Get window from SDL
SDL_SysWMinfo wmInfo;
SDL_VERSION(&wmInfo.version);
if (SDL_GetWMInfo (&wmInfo) != 1) {
throw "DxSound: Could not get window from SDL";
}
m_hWnd = wmInfo.window;
// Initialize COM
hr = CoInitialize( NULL );
if (hr != S_OK && hr != S_FALSE && hr != RPC_E_CHANGED_MODE) {
throw "DxSound: Could not initialize com";
}
// Create IDirectSound using the primary sound device
if( FAILED( hr = DirectSoundCreate( NULL, &m_pDS, NULL ) ) ){
throw "DxSound: Could not create direct sound object";
}
// Set coop level to DSSCL_PRIORITY
if( FAILED( hr = m_pDS->SetCooperativeLevel( m_hWnd, DSSCL_PRIORITY ) ) ){
throw "DxSound: Could not set cooperative level";
}
// Get the primary buffer
DSBUFFERDESC dsbd;
ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
dsbd.dwBufferBytes = 0;
dsbd.lpwfxFormat = NULL;
if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) ){
throw "DxSound: Could not create primary sound buffer";
}
// Set primary buffer format to 22kHz and 16-bit output.
WAVEFORMATEX wfx;
ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2;
wfx.nSamplesPerSec = 22050;
wfx.wBitsPerSample = 16;
wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) ){
throw "DxSound: Could not initialize primary sound format";
}
SAFE_RELEASE( pDSBPrimary );
waveid[""]=0;
SoundInfo* si=SAFE_NEW SoundInfo;
loadedSounds.push_back(si);
}
CDxSound::~CDxSound()
{
// Release DirectSound interfaces
while(!buffers.empty()){
SAFE_RELEASE(buffers.back());
buffers.pop_back();
}
SAFE_RELEASE(m_pDS);
for(vector<SoundInfo*>::iterator si=loadedSounds.begin();si!=loadedSounds.end();++si)
delete *si;
// Release COM
CoUninitialize();
}
void CDxSound::PlayStream(const std::string& path, float volume,
const float3& pos, bool loop)
{
oggStream.setDSoundObject(m_pDS);
oggStream.play(path, volume, pos);
}
void CDxSound::StopStream()
{
oggStream.stop();
}
int CDxSound::InitFile(const string& name)
{
if(m_pDS==0) {
return -1;
}
// Create the sound buffer object from the wave file data
if(!CreateStaticBuffer(name.c_str()) )
{
logOutput << "no such sound: " << name.c_str() << "\n";
return -1;
}
waveid[name]=loadedSounds.size();
buf2id.push_back(loadedSounds.size());
SoundInfo* si=SAFE_NEW SoundInfo;
si->firstBuf=buffers.size()-1;
si->freebufs.push_back(buffers.size()-1);
loadedSounds.push_back(si);
return buffers.size()-1;
}
unsigned int CDxSound::GetWaveId(const string &name, bool _hardFail)
{
PUSH_CODE_MODE;
ENTER_MIXED;
map<string,int>::iterator si = waveid.find(name);
if (si == waveid.end()) {
hardFail = _hardFail;
InitFile(name);
si = waveid.find(name);
}
int ret = (si != waveid.end()) ? si->second : 0;
POP_CODE_MODE;
return ret;
}
int CDxSound::GetBuf(int id,float volume)
{
if(id<=0 || id>=loadedSounds.size())
return -1;
SoundInfo* s=loadedSounds[id];
int num;
if(s->freebufs.empty()){
LPDIRECTSOUNDBUFFER b=NULL;
buffers.push_back(b);
HRESULT r=m_pDS->DuplicateSoundBuffer(buffers[s->firstBuf],&(buffers.back()));
if(r!=DS_OK){
MessageBox(0,"Couldnt duplicate sound buffer","Sound error",0);
sound = SAFE_NEW CNullSound;
delete this;
return -2;
}
buf2id.push_back(id);
s->freebufs.push_back(buffers.size()-1);
}
num=s->freebufs.back();
s->freebufs.pop_back();
PlayingSound ps;
ps.num=num;
ps.volume=volume;
playingSounds.push_back(ps);
return num;
}
void CDxSound::SetVolume (float v)
{
// place the volume within the 0.5 to 1.0 range
if (v < 0.01f) {
globalVolume = 0.0f;
} else {
globalVolume = 0.5f + (0.5f * max(0.0f, min(1.0f, v)));
}
}
void CDxSound::PlaySample(int id,float volume)
{
PUSH_CODE_MODE;
ENTER_MIXED;
if(id<=0 || id>=loadedSounds.size() || playingSounds.size()>=maxSounds){
POP_CODE_MODE;
return;
}
const float v = 1.0f - (globalVolume * max(0.0f, min(1.0f, volume)));
int num = GetBuf(id,v);
if (num == -2) {
return; // shutting down
}
// Restore the buffers if they are lost
HRESULT hr;
if( FAILED( hr = RestoreBuffers(num) ) ){
POP_CODE_MODE;
return;
}
buffers[num]->SetVolume(int(DSBVOLUME_MIN*v));
buffers[num]->SetPan(0);
// if(reset)
// buffers[num]->SetCurrentPosition( 0L );
// Play buffer
// DWORD dwLooped = loop ? DSBPLAY_LOOPING : 0L;
if( FAILED( hr = buffers[num]->Play( 0, 0, 0/*dwLooped*/ ) ) ){
}
POP_CODE_MODE;
}
void CDxSound::PlaySample(int id,const float3& p,float volume)
{
PUSH_CODE_MODE;
ENTER_MIXED;
if(id<=0 || id>=loadedSounds.size()){
POP_CODE_MODE;
return;
}
float3 dif=p - camera->pos;
float dl=dif.Length();
float pan=dif.dot(camera->right)*DSBPAN_RIGHT/dl;
float v=0;
if (volume != 0.0f) {
v = dl / ((globalVolume + 0.01f) * volume * 2000.0f);
}
if (v > 0.6f) {
POP_CODE_MODE;
return; // too quiet
} else {
v = max(v, (1.0f - globalVolume)); // clamp so that it isn't too loud
}
// logOutput.Print("%i %i %f",maxSounds,playingSounds.size(),v);
if(v>curThreshhold+(wantedSounds-playingSounds.size())/wantedSounds){
POP_CODE_MODE;
return;
}
int num = GetBuf(id,v);
if (num == -2) {
return; // shutting down
}
// Restore the buffers if they are lost
HRESULT hr;
if( FAILED( hr = RestoreBuffers(num) ) )
return;
buffers[num]->SetVolume(int(DSBVOLUME_MIN * v - 100));
buffers[num]->SetPan(int(pan));
if( FAILED( hr = buffers[num]->Play( 0, 0, 0/*dwLooped*/ ) ) ){
}
POP_CODE_MODE;
}
#pragma pack(push, 1)
// Header copied from WavLib by Michael McTernan
struct WAVHeader
{
Uint8 riff[4]; // "RIFF"
Sint32 totalLength;
Uint8 wavefmt[8]; // WAVEfmt "
Sint32 length; // Remaining length 4 bytes
Sint16 format_tag;
Sint16 channels; // Mono=1 Stereo=2
Sint32 SamplesPerSec;
Sint32 AvgBytesPerSec;
Sint16 BlockAlign;
Sint16 BitsPerSample;
Uint8 data[4]; // "data"
Sint32 datalen; // Raw data length 4 bytes
};
#pragma pack(pop)
bool CDxSound::ReadWAV (const char *name, Uint8 *buf, int fileSize, Uint8 **soundData, Uint32* bufferSize, WAVEFORMATEX& wf)
{
WAVHeader *header = (WAVHeader *)buf;
if (memcmp (header->riff, "RIFF",4) || memcmp (header->wavefmt, "WAVEfmt", 7)) {
if (hardFail) {
handleerror(0, "ReadWAV: invalid header.", name, 0);
}
return false;
}
#define hswabword(c) header->c = swabword(header->c)
#define hswabdword(c) header->c = swabdword(header->c)
hswabword(format_tag);
hswabword(channels);
hswabword(BlockAlign);
hswabword(BitsPerSample);
hswabdword(totalLength);
hswabdword(length);
hswabdword(SamplesPerSec);
hswabdword(AvgBytesPerSec);
hswabdword(datalen);
#undef hswabword
#undef hswabdword
if (header->format_tag != 1) { // Microsoft PCM format?
if (hardFail) {
handleerror(0,"ReadWAV: invalid format tag.", name, 0);
}
return false;
}
wf.cbSize = 0;
wf.wFormatTag = WAVE_FORMAT_PCM;
wf.nChannels = header->channels;
wf.nSamplesPerSec = header->SamplesPerSec;
wf.wBitsPerSample = header->BitsPerSample;
wf.nBlockAlign = header->channels * header->BitsPerSample / 8;
wf.nAvgBytesPerSec = header->SamplesPerSec * wf.nBlockAlign;
*bufferSize = header->datalen > fileSize-sizeof(WAVHeader) ? fileSize-sizeof(WAVHeader) : header->datalen;
*soundData = buf + sizeof(WAVHeader);
return true;
}
bool CDxSound::CreateStaticBuffer(const string& path)
{
HRESULT hr;
// Open the wav file and copy it to a buffer
Uint8 *buf = 0;
CFileHandler file(path);
int fileSize = file.FileSize();
if(file.FileExists()){
buf = SAFE_NEW Uint8[fileSize];
file.Read(buf, fileSize);
} else {
//handleerror(0, "Couldnt open wav file",path.c_str(),0);
return false;
}
// Read the WAV file
Uint8* sampleData = 0;
Uint32 bufferSize;
WAVEFORMATEX wf;
if(!ReadWAV (path.c_str(), buf, fileSize, &sampleData, &bufferSize, wf))
{
delete[] buf;
return false;
}
LPDIRECTSOUNDBUFFER b=NULL;
buffers.push_back(b);
buffers.back()=0;
// Set up the direct sound buffer, and only request the flags needed
// since each requires some overhead and limits if the buffer can
// be hardware accelerated
DSBUFFERDESC dsbd;
ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME;
dsbd.dwBufferBytes = bufferSize;
dsbd.lpwfxFormat = &wf;
// Create the static DirectSound buffer
if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &buffers.back(), NULL ) ) ) {
delete[] buf;
return false;
}
VOID* pbData = NULL;
VOID* pbData2 = NULL;
DWORD dwLength;
DWORD dwLength2;
// Lock the buffer down
if( FAILED( hr = buffers.back()->Lock( 0, bufferSize, &pbData, &dwLength,
&pbData2, &dwLength2, 0L ) ) )
{
delete[] buf;
return false;
}
memcpy(pbData, sampleData, bufferSize);
// Unlock the buffer, we don't need it anymore.
buffers.back()->Unlock( pbData, bufferSize, NULL, 0 );
delete[] buf;
return true;
}
HRESULT CDxSound::RestoreBuffers(int num)
{
HRESULT hr;
if( NULL == buffers[num] )
return S_OK;
DWORD dwStatus;
if( FAILED( hr = buffers[num]->GetStatus( &dwStatus ) ) )
return hr;
if( dwStatus & DSBSTATUS_BUFFERLOST )
{
// Since the app could have just been activated, then
// DirectSound may not be giving us control yet, so
// the restoring the buffer may fail.
// If it does, sleep until DirectSound gives us control.
do
{
hr = buffers[num]->Restore();
if( hr == DSERR_BUFFERLOST )
SleepEx(10, true);
}
while( FAILED(hr) );
// if( FAILED( hr = FillBuffer() ) )
// return hr;
}
return S_OK;
}
void CDxSound::Update()
{
oggStream.update();
float total=wantedSounds*0.5f;
for(std::list<PlayingSound>::iterator pi=playingSounds.begin();pi!=playingSounds.end();){
int num=pi->num;
DWORD status;
buffers[num]->GetStatus(&status);
if(!status & DSBSTATUS_PLAYING){
pi=playingSounds.erase(pi);
loadedSounds[buf2id[num]]->freebufs.push_back(num);
} else {
total-=(0.5f-pi->volume);
++pi;
}
}
total/=wantedSounds;
curThreshhold=(curThreshhold+total)*0.5f;
// logOutput.Print("curt %.2f",curThreshhold);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?