mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-14 02:27:40 -04:00
Fix line endings and tabs
This commit is contained in:
@ -1,51 +1,51 @@
|
||||
include_directories("../../CoreLib")
|
||||
include_directories("../../NucleusLib/inc")
|
||||
include_directories("../../NucleusLib")
|
||||
include_directories("../../PubUtilLib")
|
||||
|
||||
#TODO: This should probably be an external dependancy
|
||||
include_directories("../../../../SDKs/Win32/HawkVoice/src")
|
||||
|
||||
include_directories(${DirectX_INCLUDE_DIR})
|
||||
include_directories(${OPENAL_INCLUDE_DIR})
|
||||
include_directories(${Speex_INCLUDE_DIR})
|
||||
|
||||
set(plAudio_SOURCES
|
||||
plAudioCaps.cpp
|
||||
plAudioSystem.cpp
|
||||
plDSoundBuffer.cpp
|
||||
plEAXEffects.cpp
|
||||
plEAXListenerMod.cpp
|
||||
plSound.cpp
|
||||
plSoundEvent.cpp
|
||||
plVoiceChat.cpp
|
||||
plWAVClipBuffer.cpp
|
||||
plWin32GroupedSound.cpp
|
||||
plWin32Sound.cpp
|
||||
plWin32StaticSound.cpp
|
||||
plWin32StreamingSound.cpp
|
||||
plWinMicLevel.cpp
|
||||
)
|
||||
|
||||
set(plAudio_HEADERS
|
||||
plAudioCaps.h
|
||||
plAudioCreatable.h
|
||||
plAudioSystem.h
|
||||
plDSoundBuffer.h
|
||||
plEAXEffects.h
|
||||
plEAXListenerMod.h
|
||||
plSound.h
|
||||
plSoundEvent.h
|
||||
plVoiceChat.h
|
||||
plWAVClipBuffer.h
|
||||
plWin32GroupedSound.h
|
||||
plWin32Sound.h
|
||||
plWin32StaticSound.h
|
||||
plWin32StreamingSound.h
|
||||
plWinMicLevel.h
|
||||
)
|
||||
|
||||
add_library(plAudio STATIC ${plAudio_SOURCES} ${plAudio_HEADERS})
|
||||
|
||||
source_group("Source Files" FILES ${plAudio_SOURCES})
|
||||
include_directories("../../CoreLib")
|
||||
include_directories("../../NucleusLib/inc")
|
||||
include_directories("../../NucleusLib")
|
||||
include_directories("../../PubUtilLib")
|
||||
|
||||
#TODO: This should probably be an external dependancy
|
||||
include_directories("../../../../SDKs/Win32/HawkVoice/src")
|
||||
|
||||
include_directories(${DirectX_INCLUDE_DIR})
|
||||
include_directories(${OPENAL_INCLUDE_DIR})
|
||||
include_directories(${Speex_INCLUDE_DIR})
|
||||
|
||||
set(plAudio_SOURCES
|
||||
plAudioCaps.cpp
|
||||
plAudioSystem.cpp
|
||||
plDSoundBuffer.cpp
|
||||
plEAXEffects.cpp
|
||||
plEAXListenerMod.cpp
|
||||
plSound.cpp
|
||||
plSoundEvent.cpp
|
||||
plVoiceChat.cpp
|
||||
plWAVClipBuffer.cpp
|
||||
plWin32GroupedSound.cpp
|
||||
plWin32Sound.cpp
|
||||
plWin32StaticSound.cpp
|
||||
plWin32StreamingSound.cpp
|
||||
plWinMicLevel.cpp
|
||||
)
|
||||
|
||||
set(plAudio_HEADERS
|
||||
plAudioCaps.h
|
||||
plAudioCreatable.h
|
||||
plAudioSystem.h
|
||||
plDSoundBuffer.h
|
||||
plEAXEffects.h
|
||||
plEAXListenerMod.h
|
||||
plSound.h
|
||||
plSoundEvent.h
|
||||
plVoiceChat.h
|
||||
plWAVClipBuffer.h
|
||||
plWin32GroupedSound.h
|
||||
plWin32Sound.h
|
||||
plWin32StaticSound.h
|
||||
plWin32StreamingSound.h
|
||||
plWinMicLevel.h
|
||||
)
|
||||
|
||||
add_library(plAudio STATIC ${plAudio_SOURCES} ${plAudio_HEADERS})
|
||||
|
||||
source_group("Source Files" FILES ${plAudio_SOURCES})
|
||||
source_group("Header Files" FILES ${plAudio_HEADERS})
|
@ -1,227 +1,227 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plAudioCaps - Utility class to query and detect available audio options.//
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "HeadSpin.h"
|
||||
#include <al.h>
|
||||
#include <alc.h>
|
||||
#include "plEAXEffects.h"
|
||||
|
||||
#include "plAudioCaps.h"
|
||||
#ifdef EAX_SDK_AVAILABLE
|
||||
#include <eax.h>
|
||||
#include <eaxlegacy.h>
|
||||
#endif
|
||||
#include <DShow.h>
|
||||
|
||||
#include "plStatusLog/plStatusLog.h"
|
||||
|
||||
#define MAX_NUM_SOURCES 128
|
||||
#define kLogMe if( fLog != nil ) fLog->AddLineF(
|
||||
#define MAX_AUDIOCARD_NAME 256
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// Detector Functions //////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plAudioCaps plAudioCapsDetector::fCaps;
|
||||
hsBool plAudioCapsDetector::fGotCaps = false;
|
||||
|
||||
plStatusLog *plAudioCapsDetector::fLog = nil;
|
||||
|
||||
plAudioCapsDetector::plAudioCapsDetector()
|
||||
{
|
||||
}
|
||||
|
||||
plAudioCapsDetector::~plAudioCapsDetector()
|
||||
{
|
||||
}
|
||||
|
||||
//// Detect //////////////////////////////////////////////////////////////////
|
||||
// Our big function that does all of our work
|
||||
|
||||
plAudioCaps &plAudioCapsDetector::Detect( hsBool logIt, hsBool init )
|
||||
{
|
||||
// If we already have the device capabilities, just return them
|
||||
if(fGotCaps) return fCaps;
|
||||
fCaps.fIsAvailable = true;
|
||||
|
||||
ALCdevice * device;
|
||||
ALCcontext * context;
|
||||
|
||||
if(init)
|
||||
{
|
||||
device = alcOpenDevice(0);
|
||||
if(!device)
|
||||
{
|
||||
fCaps.fIsAvailable = false;
|
||||
}
|
||||
|
||||
context = alcCreateContext(device, 0);
|
||||
if(alGetError() != AL_NO_ERROR)
|
||||
{
|
||||
fCaps.fIsAvailable = false;
|
||||
}
|
||||
alcMakeContextCurrent(context);
|
||||
if(alGetError() != AL_NO_ERROR)
|
||||
{
|
||||
fCaps.fIsAvailable = false;
|
||||
}
|
||||
}
|
||||
|
||||
EnumerateAudioDevices();
|
||||
|
||||
if( logIt )
|
||||
fLog = plStatusLogMgr::GetInstance().CreateStatusLog( 30, "audioCaps.log" );
|
||||
else
|
||||
fLog = nil;
|
||||
|
||||
kLogMe 0xff00ff00, "Starting audio caps detection..." );
|
||||
|
||||
// find the max number of sources
|
||||
ALuint sources[MAX_NUM_SOURCES];
|
||||
ALuint i = 0;
|
||||
for(; i < MAX_NUM_SOURCES; i++)
|
||||
{
|
||||
alGenSources(1, &sources[i]);
|
||||
if(alGetError() != AL_NO_ERROR)
|
||||
break;
|
||||
fCaps.fMaxNumSources++;
|
||||
}
|
||||
alDeleteSources(i, sources);
|
||||
kLogMe 0xffffffff, "Max Number of sources: %d", i);
|
||||
plStatusLog::AddLineS("audio.log", "Max Number of sources: %d", i);
|
||||
|
||||
// Detect EAX support
|
||||
kLogMe 0xff00ff00, "Attempting to detect EAX support..." );
|
||||
fCaps.fEAXAvailable = IDetectEAX( );
|
||||
|
||||
kLogMe 0xff00ff00, "Audio caps detection COMPLETE." );
|
||||
delete fLog;
|
||||
|
||||
fGotCaps = true; // We've got the device capabilities
|
||||
|
||||
if(init)
|
||||
{
|
||||
alcMakeContextCurrent(nil);
|
||||
alcDestroyContext(context);
|
||||
alcCloseDevice(device);
|
||||
}
|
||||
return fCaps;
|
||||
}
|
||||
|
||||
void plAudioCapsDetector::EnumerateAudioDevices()
|
||||
{
|
||||
ICreateDevEnum *pDevEnum;
|
||||
IEnumMoniker *pEnumMon;
|
||||
IMoniker *pMoniker;
|
||||
ULONG cFetched;
|
||||
HRESULT hr;
|
||||
char audioCardName[MAX_AUDIOCARD_NAME];
|
||||
short *pShort;
|
||||
|
||||
// Enumerate audio devices
|
||||
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pDevEnum);
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
hr = pDevEnum->CreateClassEnumerator(CLSID_AudioRendererCategory, &pEnumMon, 0);
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
while(pEnumMon->Next(1, &pMoniker, &cFetched) == S_OK)
|
||||
{
|
||||
if(pMoniker)
|
||||
{
|
||||
IPropertyBag *pPropBag;
|
||||
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
VARIANT varName;
|
||||
VariantInit(&varName);
|
||||
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
|
||||
memset(audioCardName, 0, MAX_AUDIOCARD_NAME);
|
||||
pShort = varName.piVal;
|
||||
|
||||
// copy from wide character array to char array
|
||||
for(int i = 0; *pShort != 0 && i < MAX_AUDIOCARD_NAME; pShort++, i++)
|
||||
{
|
||||
audioCardName[i] = (char)*pShort;
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
plStatusLog::AddLineS("audiocaps.log", audioCardName );
|
||||
}
|
||||
VariantClear(&varName);
|
||||
pPropBag->Release();
|
||||
}
|
||||
pMoniker->Release();
|
||||
}
|
||||
}
|
||||
pEnumMon->Release();
|
||||
}
|
||||
pDevEnum->Release();
|
||||
}
|
||||
}
|
||||
|
||||
//// IDetectEAX //////////////////////////////////////////////////////////////
|
||||
// Attempt to actually init the EAX listener.Note that we can potentially do
|
||||
// this even if we didn't load the EAX Unified driver (we could just be
|
||||
// running EAX 3.0 native), so you can really just think of the EAX Unified
|
||||
// init code above as a way of trying to make sure this line here will
|
||||
// succeed as often as possible.
|
||||
|
||||
hsBool plAudioCapsDetector::IDetectEAX( )
|
||||
{
|
||||
#ifdef EAX_SDK_AVAILABLE
|
||||
hsBool gotSupport = true;
|
||||
|
||||
if(!alIsExtensionPresent((ALchar *)"EAX4.0")) // is eax 4 supported
|
||||
{
|
||||
if(!alIsExtensionPresent((ALchar *) "EAX4.0Emulated")) // is an earlier version of eax supported
|
||||
{
|
||||
kLogMe 0xff00ff00, "EAX not supported");
|
||||
gotSupport = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
fCaps.fEAXUnified = true;
|
||||
kLogMe 0xff00ff00, "EAX 4 Emulated supported");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
kLogMe 0xff00ff00, "EAX 4 available");
|
||||
}
|
||||
return gotSupport;
|
||||
#else
|
||||
kLogMe 0xff00ff00, "EAX disabled in this build");
|
||||
return false;
|
||||
#endif
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plAudioCaps - Utility class to query and detect available audio options.//
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "HeadSpin.h"
|
||||
#include <al.h>
|
||||
#include <alc.h>
|
||||
#include "plEAXEffects.h"
|
||||
|
||||
#include "plAudioCaps.h"
|
||||
#ifdef EAX_SDK_AVAILABLE
|
||||
#include <eax.h>
|
||||
#include <eaxlegacy.h>
|
||||
#endif
|
||||
#include <DShow.h>
|
||||
|
||||
#include "plStatusLog/plStatusLog.h"
|
||||
|
||||
#define MAX_NUM_SOURCES 128
|
||||
#define kLogMe if( fLog != nil ) fLog->AddLineF(
|
||||
#define MAX_AUDIOCARD_NAME 256
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// Detector Functions //////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plAudioCaps plAudioCapsDetector::fCaps;
|
||||
hsBool plAudioCapsDetector::fGotCaps = false;
|
||||
|
||||
plStatusLog *plAudioCapsDetector::fLog = nil;
|
||||
|
||||
plAudioCapsDetector::plAudioCapsDetector()
|
||||
{
|
||||
}
|
||||
|
||||
plAudioCapsDetector::~plAudioCapsDetector()
|
||||
{
|
||||
}
|
||||
|
||||
//// Detect //////////////////////////////////////////////////////////////////
|
||||
// Our big function that does all of our work
|
||||
|
||||
plAudioCaps &plAudioCapsDetector::Detect( hsBool logIt, hsBool init )
|
||||
{
|
||||
// If we already have the device capabilities, just return them
|
||||
if(fGotCaps) return fCaps;
|
||||
fCaps.fIsAvailable = true;
|
||||
|
||||
ALCdevice * device;
|
||||
ALCcontext * context;
|
||||
|
||||
if(init)
|
||||
{
|
||||
device = alcOpenDevice(0);
|
||||
if(!device)
|
||||
{
|
||||
fCaps.fIsAvailable = false;
|
||||
}
|
||||
|
||||
context = alcCreateContext(device, 0);
|
||||
if(alGetError() != AL_NO_ERROR)
|
||||
{
|
||||
fCaps.fIsAvailable = false;
|
||||
}
|
||||
alcMakeContextCurrent(context);
|
||||
if(alGetError() != AL_NO_ERROR)
|
||||
{
|
||||
fCaps.fIsAvailable = false;
|
||||
}
|
||||
}
|
||||
|
||||
EnumerateAudioDevices();
|
||||
|
||||
if( logIt )
|
||||
fLog = plStatusLogMgr::GetInstance().CreateStatusLog( 30, "audioCaps.log" );
|
||||
else
|
||||
fLog = nil;
|
||||
|
||||
kLogMe 0xff00ff00, "Starting audio caps detection..." );
|
||||
|
||||
// find the max number of sources
|
||||
ALuint sources[MAX_NUM_SOURCES];
|
||||
ALuint i = 0;
|
||||
for(; i < MAX_NUM_SOURCES; i++)
|
||||
{
|
||||
alGenSources(1, &sources[i]);
|
||||
if(alGetError() != AL_NO_ERROR)
|
||||
break;
|
||||
fCaps.fMaxNumSources++;
|
||||
}
|
||||
alDeleteSources(i, sources);
|
||||
kLogMe 0xffffffff, "Max Number of sources: %d", i);
|
||||
plStatusLog::AddLineS("audio.log", "Max Number of sources: %d", i);
|
||||
|
||||
// Detect EAX support
|
||||
kLogMe 0xff00ff00, "Attempting to detect EAX support..." );
|
||||
fCaps.fEAXAvailable = IDetectEAX( );
|
||||
|
||||
kLogMe 0xff00ff00, "Audio caps detection COMPLETE." );
|
||||
delete fLog;
|
||||
|
||||
fGotCaps = true; // We've got the device capabilities
|
||||
|
||||
if(init)
|
||||
{
|
||||
alcMakeContextCurrent(nil);
|
||||
alcDestroyContext(context);
|
||||
alcCloseDevice(device);
|
||||
}
|
||||
return fCaps;
|
||||
}
|
||||
|
||||
void plAudioCapsDetector::EnumerateAudioDevices()
|
||||
{
|
||||
ICreateDevEnum *pDevEnum;
|
||||
IEnumMoniker *pEnumMon;
|
||||
IMoniker *pMoniker;
|
||||
ULONG cFetched;
|
||||
HRESULT hr;
|
||||
char audioCardName[MAX_AUDIOCARD_NAME];
|
||||
short *pShort;
|
||||
|
||||
// Enumerate audio devices
|
||||
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pDevEnum);
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
hr = pDevEnum->CreateClassEnumerator(CLSID_AudioRendererCategory, &pEnumMon, 0);
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
while(pEnumMon->Next(1, &pMoniker, &cFetched) == S_OK)
|
||||
{
|
||||
if(pMoniker)
|
||||
{
|
||||
IPropertyBag *pPropBag;
|
||||
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
VARIANT varName;
|
||||
VariantInit(&varName);
|
||||
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
|
||||
memset(audioCardName, 0, MAX_AUDIOCARD_NAME);
|
||||
pShort = varName.piVal;
|
||||
|
||||
// copy from wide character array to char array
|
||||
for(int i = 0; *pShort != 0 && i < MAX_AUDIOCARD_NAME; pShort++, i++)
|
||||
{
|
||||
audioCardName[i] = (char)*pShort;
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
plStatusLog::AddLineS("audiocaps.log", audioCardName );
|
||||
}
|
||||
VariantClear(&varName);
|
||||
pPropBag->Release();
|
||||
}
|
||||
pMoniker->Release();
|
||||
}
|
||||
}
|
||||
pEnumMon->Release();
|
||||
}
|
||||
pDevEnum->Release();
|
||||
}
|
||||
}
|
||||
|
||||
//// IDetectEAX //////////////////////////////////////////////////////////////
|
||||
// Attempt to actually init the EAX listener.Note that we can potentially do
|
||||
// this even if we didn't load the EAX Unified driver (we could just be
|
||||
// running EAX 3.0 native), so you can really just think of the EAX Unified
|
||||
// init code above as a way of trying to make sure this line here will
|
||||
// succeed as often as possible.
|
||||
|
||||
hsBool plAudioCapsDetector::IDetectEAX( )
|
||||
{
|
||||
#ifdef EAX_SDK_AVAILABLE
|
||||
hsBool gotSupport = true;
|
||||
|
||||
if(!alIsExtensionPresent((ALchar *)"EAX4.0")) // is eax 4 supported
|
||||
{
|
||||
if(!alIsExtensionPresent((ALchar *) "EAX4.0Emulated")) // is an earlier version of eax supported
|
||||
{
|
||||
kLogMe 0xff00ff00, "EAX not supported");
|
||||
gotSupport = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
fCaps.fEAXUnified = true;
|
||||
kLogMe 0xff00ff00, "EAX 4 Emulated supported");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
kLogMe 0xff00ff00, "EAX 4 available");
|
||||
}
|
||||
return gotSupport;
|
||||
#else
|
||||
kLogMe 0xff00ff00, "EAX disabled in this build");
|
||||
return false;
|
||||
#endif
|
||||
}
|
@ -1,84 +1,84 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plAudioCaps - Utility class to query and detect available audio options.//
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _plAudioCaps_h
|
||||
#define _plAudioCaps_h
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "hsTemplates.h"
|
||||
|
||||
class plAudioCapsDetector;
|
||||
class plStatusLog;
|
||||
|
||||
class plAudioCaps
|
||||
{
|
||||
public:
|
||||
|
||||
plAudioCaps() { Clear(); }
|
||||
|
||||
void Clear( void )
|
||||
{
|
||||
fIsAvailable = false;
|
||||
fEAXAvailable = false;
|
||||
fEAXUnified = false;
|
||||
fMaxNumSources = 0;
|
||||
}
|
||||
|
||||
hsBool IsAvailable( void ) const { return fIsAvailable; }
|
||||
hsBool IsEAXAvailable( void ) const { return fEAXAvailable; }
|
||||
hsBool UsingEAXUnified( void ) const { return fEAXUnified; }
|
||||
unsigned GetMaxNumVoices() { return fMaxNumSources; }
|
||||
|
||||
protected:
|
||||
friend class plAudioCapsDetector;
|
||||
|
||||
hsBool fIsAvailable, fEAXAvailable, fEAXUnified;
|
||||
unsigned fMaxNumSources;
|
||||
};
|
||||
|
||||
class plAudioCapsDetector
|
||||
{
|
||||
public:
|
||||
plAudioCapsDetector();
|
||||
virtual ~plAudioCapsDetector();
|
||||
|
||||
static plAudioCaps &Detect( hsBool log = false, hsBool init = false );
|
||||
|
||||
protected:
|
||||
static plStatusLog *fLog;
|
||||
static plAudioCaps fCaps;
|
||||
static hsBool fGotCaps;
|
||||
|
||||
static hsBool IDetectEAX( );
|
||||
static void EnumerateAudioDevices();
|
||||
};
|
||||
|
||||
#endif //_plAudioCaps_h
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plAudioCaps - Utility class to query and detect available audio options.//
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _plAudioCaps_h
|
||||
#define _plAudioCaps_h
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "hsTemplates.h"
|
||||
|
||||
class plAudioCapsDetector;
|
||||
class plStatusLog;
|
||||
|
||||
class plAudioCaps
|
||||
{
|
||||
public:
|
||||
|
||||
plAudioCaps() { Clear(); }
|
||||
|
||||
void Clear( void )
|
||||
{
|
||||
fIsAvailable = false;
|
||||
fEAXAvailable = false;
|
||||
fEAXUnified = false;
|
||||
fMaxNumSources = 0;
|
||||
}
|
||||
|
||||
hsBool IsAvailable( void ) const { return fIsAvailable; }
|
||||
hsBool IsEAXAvailable( void ) const { return fEAXAvailable; }
|
||||
hsBool UsingEAXUnified( void ) const { return fEAXUnified; }
|
||||
unsigned GetMaxNumVoices() { return fMaxNumSources; }
|
||||
|
||||
protected:
|
||||
friend class plAudioCapsDetector;
|
||||
|
||||
hsBool fIsAvailable, fEAXAvailable, fEAXUnified;
|
||||
unsigned fMaxNumSources;
|
||||
};
|
||||
|
||||
class plAudioCapsDetector
|
||||
{
|
||||
public:
|
||||
plAudioCapsDetector();
|
||||
virtual ~plAudioCapsDetector();
|
||||
|
||||
static plAudioCaps &Detect( hsBool log = false, hsBool init = false );
|
||||
|
||||
protected:
|
||||
static plStatusLog *fLog;
|
||||
static plAudioCaps fCaps;
|
||||
static hsBool fGotCaps;
|
||||
|
||||
static hsBool IDetectEAX( );
|
||||
static void EnumerateAudioDevices();
|
||||
};
|
||||
|
||||
#endif //_plAudioCaps_h
|
||||
|
@ -1,57 +1,57 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plAudioCreatable_inc
|
||||
#define plAudioCreatable_inc
|
||||
|
||||
#include "pnFactory/plCreator.h"
|
||||
|
||||
#include "plAudioSystem.h"
|
||||
|
||||
REGISTER_CREATABLE( plAudioSystem );
|
||||
|
||||
#include "plSound.h"
|
||||
|
||||
REGISTER_NONCREATABLE( plSound );
|
||||
REGISTER_CREATABLE( plSoundVolumeApplicator );
|
||||
|
||||
#include "plWin32Sound.h"
|
||||
#include "plWin32StaticSound.h"
|
||||
#include "plWin32StreamingSound.h"
|
||||
#include "plWin32GroupedSound.h"
|
||||
|
||||
REGISTER_NONCREATABLE( plWin32Sound );
|
||||
REGISTER_CREATABLE( plWin32StaticSound );
|
||||
REGISTER_CREATABLE( plWin32LinkSound );
|
||||
REGISTER_CREATABLE( plWin32StreamingSound );
|
||||
REGISTER_CREATABLE( plWin32GroupedSound );
|
||||
|
||||
#include "plEAXListenerMod.h"
|
||||
REGISTER_CREATABLE( plEAXListenerMod );
|
||||
|
||||
#include "plAudioReaderCreatable.h"
|
||||
|
||||
#endif // plAudioCreatable_inc
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plAudioCreatable_inc
|
||||
#define plAudioCreatable_inc
|
||||
|
||||
#include "pnFactory/plCreator.h"
|
||||
|
||||
#include "plAudioSystem.h"
|
||||
|
||||
REGISTER_CREATABLE( plAudioSystem );
|
||||
|
||||
#include "plSound.h"
|
||||
|
||||
REGISTER_NONCREATABLE( plSound );
|
||||
REGISTER_CREATABLE( plSoundVolumeApplicator );
|
||||
|
||||
#include "plWin32Sound.h"
|
||||
#include "plWin32StaticSound.h"
|
||||
#include "plWin32StreamingSound.h"
|
||||
#include "plWin32GroupedSound.h"
|
||||
|
||||
REGISTER_NONCREATABLE( plWin32Sound );
|
||||
REGISTER_CREATABLE( plWin32StaticSound );
|
||||
REGISTER_CREATABLE( plWin32LinkSound );
|
||||
REGISTER_CREATABLE( plWin32StreamingSound );
|
||||
REGISTER_CREATABLE( plWin32GroupedSound );
|
||||
|
||||
#include "plEAXListenerMod.h"
|
||||
REGISTER_CREATABLE( plEAXListenerMod );
|
||||
|
||||
#include "plAudioReaderCreatable.h"
|
||||
|
||||
#endif // plAudioCreatable_inc
|
||||
|
@ -1,25 +1,25 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,264 +1,264 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#ifndef plAudioSystem_h
|
||||
#define plAudioSystem_h
|
||||
|
||||
#include "hsStlUtils.h"
|
||||
#include "hsWindowHndl.h"
|
||||
#include "hsTemplates.h"
|
||||
#include "hsGeometry3.h"
|
||||
#include "pnKeyedObject/hsKeyedObject.h"
|
||||
|
||||
#define DEFAULT_AUDIO_DEVICE_NAME "Generic Software"
|
||||
|
||||
typedef wchar_t WCHAR;
|
||||
|
||||
class plSound;
|
||||
class plSoftSoundNode;
|
||||
class plgAudioSys;
|
||||
class plStatusLog;
|
||||
class plEAXListenerMod;
|
||||
|
||||
typedef struct ALCdevice_struct ALCdevice;
|
||||
typedef struct ALCcontext_struct ALCcontext;
|
||||
|
||||
|
||||
class DeviceDescriptor
|
||||
{
|
||||
public:
|
||||
DeviceDescriptor(const char *name, hsBool supportsEAX):
|
||||
fDeviceName(name),
|
||||
fSupportsEAX(supportsEAX)
|
||||
{
|
||||
}
|
||||
const char *GetDeviceName() { return fDeviceName.c_str();}
|
||||
hsBool SupportsEAX() { return fSupportsEAX; }
|
||||
|
||||
private:
|
||||
std::string fDeviceName;
|
||||
hsBool fSupportsEAX;
|
||||
};
|
||||
|
||||
class plAudioSystem : public hsKeyedObject
|
||||
{
|
||||
public:
|
||||
plAudioSystem();
|
||||
~plAudioSystem();
|
||||
|
||||
CLASSNAME_REGISTER( plAudioSystem );
|
||||
GETINTERFACE_ANY( plAudioSystem, hsKeyedObject );
|
||||
|
||||
enum
|
||||
{
|
||||
kThreadSndRef = 0,
|
||||
kRefEAXRegion
|
||||
};
|
||||
|
||||
hsBool Init(hsWindowHndl hWnd);
|
||||
void Shutdown();
|
||||
|
||||
void SetActive( hsBool b );
|
||||
|
||||
void SetListenerPos(const hsPoint3 pos);
|
||||
void SetListenerVelocity(const hsVector3 vel);
|
||||
void SetListenerOrientation(const hsVector3 view, const hsVector3 up);
|
||||
void SetMaxNumberOfActiveSounds(); // sets the max number of active sounds based on the priority cutoff
|
||||
void SetDistanceModel(int i);
|
||||
|
||||
virtual hsBool MsgReceive(plMessage* msg);
|
||||
double GetTime();
|
||||
|
||||
void NextDebugSound( void );
|
||||
hsPoint3 GetCurrListenerPos( void ) const { return fCurrListenerPos; }
|
||||
|
||||
int GetNumAudioDevices();
|
||||
const char *GetAudioDeviceName(int index);
|
||||
hsBool SupportsEAX(const char *deviceName);
|
||||
|
||||
void SetFadeLength(float lengthSec);
|
||||
|
||||
protected:
|
||||
|
||||
friend class plgAudioSys;
|
||||
|
||||
ALCdevice * fDevice;
|
||||
ALCcontext * fContext;
|
||||
ALCdevice * fCaptureDevice;
|
||||
|
||||
plSoftSoundNode *fSoftRegionSounds;
|
||||
plSoftSoundNode *fActiveSofts;
|
||||
plStatusLog *fDebugActiveSoundDisplay;
|
||||
|
||||
static Int32 fMaxNumSounds, fNumSoundsSlop; // max number of sounds the engine is allowed to audibly play. Different than fMaxNumSources. That is the max number of sounds the audio card can play
|
||||
plSoftSoundNode *fCurrDebugSound;
|
||||
hsTArray<plKey> fPendingRegisters;
|
||||
|
||||
hsPoint3 fCurrListenerPos;//, fCommittedListenerPos;
|
||||
hsBool fActive, fUsingEAX, fRestartOnDestruct, fWaitingForShutdown;
|
||||
__int64 fStartTime;
|
||||
|
||||
hsTArray<hsKeyedObject *> fMyRefs;
|
||||
hsTArray<plEAXListenerMod *> fEAXRegions;
|
||||
|
||||
hsPoint3 fLastPos;
|
||||
hsBool fAvatarPosSet; // used for listener stuff
|
||||
|
||||
hsBool fDisplayNumBuffers;
|
||||
|
||||
std::vector<DeviceDescriptor> fDeviceList; // list of openal device names
|
||||
|
||||
double fStartFade;
|
||||
float fFadeLength;
|
||||
unsigned int fMaxNumSources; // max openal sources
|
||||
double fLastUpdateTimeMs;
|
||||
|
||||
void RegisterSoftSound( const plKey soundKey );
|
||||
void UnregisterSoftSound( const plKey soundKey );
|
||||
void IUpdateSoftSounds( const hsPoint3 &newPosition );
|
||||
UInt32 IScaleVolume(float volume);
|
||||
void IEnumerateDevices();
|
||||
|
||||
public:
|
||||
hsBool fListenerInit;
|
||||
};
|
||||
|
||||
class plgAudioSys
|
||||
{
|
||||
public:
|
||||
enum ASChannel
|
||||
{
|
||||
kSoundFX,
|
||||
kAmbience,
|
||||
kBgndMusic,
|
||||
kGUI,
|
||||
kNPCVoice,
|
||||
kVoice,
|
||||
kNumChannels
|
||||
};
|
||||
|
||||
enum DebugFlags
|
||||
{
|
||||
kDisableRightSelect = 0x00000001,
|
||||
kDisableLeftSelect = 0x00000002
|
||||
};
|
||||
|
||||
enum AudioMode
|
||||
{
|
||||
kDisabled,
|
||||
kSoftware,
|
||||
kHardware,
|
||||
kHardwarePlusEAX,
|
||||
};
|
||||
static void Init(hsWindowHndl hWnd);
|
||||
static hsBool Hardware() { return fUseHardware; }
|
||||
static void SetUseHardware(hsBool b);
|
||||
static void SetActive(hsBool b);
|
||||
static void SetMuted( hsBool b );
|
||||
static void EnableEAX( hsBool b );
|
||||
static hsBool Active() { return fInit; }
|
||||
static void Shutdown();
|
||||
static void Activate(hsBool b);
|
||||
static hsBool IsMuted( void ) { return fMuted; }
|
||||
static hsWindowHndl hWnd() { return fWnd; }
|
||||
static plAudioSystem* Sys() { return fSys; }
|
||||
static void Restart( void );
|
||||
static hsBool UsingEAX( void ) { return fSys->fUsingEAX; }
|
||||
|
||||
static void NextDebugSound( void );
|
||||
|
||||
static void SetChannelVolume( ASChannel chan, hsScalar vol );
|
||||
static hsScalar GetChannelVolume( ASChannel chan );
|
||||
|
||||
static void Set2D3DBias( hsScalar bias );
|
||||
static hsScalar Get2D3Dbias();
|
||||
|
||||
static void SetGlobalFadeVolume( hsScalar vol );
|
||||
static hsScalar GetGlobalFadeVolume( void ) { return fGlobalFadeVolume; }
|
||||
|
||||
static void SetDebugFlag( UInt32 flag, hsBool set = true ) { if( set ) fDebugFlags |= flag; else fDebugFlags &= ~flag; }
|
||||
static hsBool IsDebugFlagSet( UInt32 flag ) { return fDebugFlags & flag; }
|
||||
static void ClearDebugFlags( void ) { fDebugFlags = 0; }
|
||||
|
||||
static hsScalar GetStreamingBufferSize( void ) { return fStreamingBufferSize; }
|
||||
static void SetStreamingBufferSize( hsScalar size ) { fStreamingBufferSize = size; }
|
||||
|
||||
static UInt8 GetPriorityCutoff( void ) { return fPriorityCutoff; }
|
||||
static void SetPriorityCutoff( UInt8 cut ) { fPriorityCutoff = cut; if(fSys) fSys->SetMaxNumberOfActiveSounds(); }
|
||||
|
||||
static hsBool AreExtendedLogsEnabled( void ) { return fEnableExtendedLogs; }
|
||||
static void EnableExtendedLogs( hsBool e ) { fEnableExtendedLogs = e; }
|
||||
|
||||
static hsScalar GetStreamFromRAMCutoff( void ) { return fStreamFromRAMCutoff; }
|
||||
static void SetStreamFromRAMCutoff( hsScalar c ) { fStreamFromRAMCutoff = c; }
|
||||
|
||||
static void SetListenerPos(const hsPoint3 pos);
|
||||
static void SetListenerVelocity(const hsVector3 vel);
|
||||
static void SetListenerOrientation(const hsVector3 view, const hsVector3 up);
|
||||
|
||||
static void ShowNumBuffers(hsBool b) { if(fSys) fSys->fDisplayNumBuffers = b; }
|
||||
|
||||
static void SetAudioMode(AudioMode mode);
|
||||
static int GetAudioMode();
|
||||
static hsBool LogStreamingUpdates() { return fLogStreamingUpdates; }
|
||||
static void SetLogStreamingUpdates(hsBool logUpdates) { fLogStreamingUpdates = logUpdates; }
|
||||
static void SetDeviceName(const char *device, hsBool restart = false);
|
||||
static const char *GetDeviceName() { return fDeviceName.c_str(); }
|
||||
static int GetNumAudioDevices();
|
||||
static const char *GetAudioDeviceName(int index);
|
||||
static ALCdevice *GetCaptureDevice();
|
||||
static hsBool SupportsEAX(const char *deviceName);
|
||||
static void RegisterSoftSound( const plKey soundKey );
|
||||
static void UnregisterSoftSound( const plKey soundKey );
|
||||
|
||||
static hsBool IsRestarting() {return fRestarting;}
|
||||
|
||||
private:
|
||||
friend class plAudioSystem;
|
||||
|
||||
static plAudioSystem* fSys;
|
||||
static hsBool fInit;
|
||||
static hsBool fActive;
|
||||
static hsBool fMuted;
|
||||
static hsWindowHndl fWnd;
|
||||
static hsBool fUseHardware;
|
||||
static hsBool fDelayedActivate;
|
||||
static hsScalar fChannelVolumes[ kNumChannels ];
|
||||
static hsScalar fGlobalFadeVolume;
|
||||
static UInt32 fDebugFlags;
|
||||
static hsBool fEnableEAX;
|
||||
static hsScalar fStreamingBufferSize;
|
||||
static UInt8 fPriorityCutoff;
|
||||
static hsBool fEnableExtendedLogs;
|
||||
static hsScalar fStreamFromRAMCutoff;
|
||||
static hsScalar f2D3DBias;
|
||||
static hsBool fLogStreamingUpdates;
|
||||
static std::string fDeviceName;
|
||||
static hsBool fRestarting;
|
||||
static hsBool fMutedStateChange;
|
||||
|
||||
};
|
||||
|
||||
#endif //plAudioSystem_h
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#ifndef plAudioSystem_h
|
||||
#define plAudioSystem_h
|
||||
|
||||
#include "hsStlUtils.h"
|
||||
#include "hsWindowHndl.h"
|
||||
#include "hsTemplates.h"
|
||||
#include "hsGeometry3.h"
|
||||
#include "pnKeyedObject/hsKeyedObject.h"
|
||||
|
||||
#define DEFAULT_AUDIO_DEVICE_NAME "Generic Software"
|
||||
|
||||
typedef wchar_t WCHAR;
|
||||
|
||||
class plSound;
|
||||
class plSoftSoundNode;
|
||||
class plgAudioSys;
|
||||
class plStatusLog;
|
||||
class plEAXListenerMod;
|
||||
|
||||
typedef struct ALCdevice_struct ALCdevice;
|
||||
typedef struct ALCcontext_struct ALCcontext;
|
||||
|
||||
|
||||
class DeviceDescriptor
|
||||
{
|
||||
public:
|
||||
DeviceDescriptor(const char *name, hsBool supportsEAX):
|
||||
fDeviceName(name),
|
||||
fSupportsEAX(supportsEAX)
|
||||
{
|
||||
}
|
||||
const char *GetDeviceName() { return fDeviceName.c_str();}
|
||||
hsBool SupportsEAX() { return fSupportsEAX; }
|
||||
|
||||
private:
|
||||
std::string fDeviceName;
|
||||
hsBool fSupportsEAX;
|
||||
};
|
||||
|
||||
class plAudioSystem : public hsKeyedObject
|
||||
{
|
||||
public:
|
||||
plAudioSystem();
|
||||
~plAudioSystem();
|
||||
|
||||
CLASSNAME_REGISTER( plAudioSystem );
|
||||
GETINTERFACE_ANY( plAudioSystem, hsKeyedObject );
|
||||
|
||||
enum
|
||||
{
|
||||
kThreadSndRef = 0,
|
||||
kRefEAXRegion
|
||||
};
|
||||
|
||||
hsBool Init(hsWindowHndl hWnd);
|
||||
void Shutdown();
|
||||
|
||||
void SetActive( hsBool b );
|
||||
|
||||
void SetListenerPos(const hsPoint3 pos);
|
||||
void SetListenerVelocity(const hsVector3 vel);
|
||||
void SetListenerOrientation(const hsVector3 view, const hsVector3 up);
|
||||
void SetMaxNumberOfActiveSounds(); // sets the max number of active sounds based on the priority cutoff
|
||||
void SetDistanceModel(int i);
|
||||
|
||||
virtual hsBool MsgReceive(plMessage* msg);
|
||||
double GetTime();
|
||||
|
||||
void NextDebugSound( void );
|
||||
hsPoint3 GetCurrListenerPos( void ) const { return fCurrListenerPos; }
|
||||
|
||||
int GetNumAudioDevices();
|
||||
const char *GetAudioDeviceName(int index);
|
||||
hsBool SupportsEAX(const char *deviceName);
|
||||
|
||||
void SetFadeLength(float lengthSec);
|
||||
|
||||
protected:
|
||||
|
||||
friend class plgAudioSys;
|
||||
|
||||
ALCdevice * fDevice;
|
||||
ALCcontext * fContext;
|
||||
ALCdevice * fCaptureDevice;
|
||||
|
||||
plSoftSoundNode *fSoftRegionSounds;
|
||||
plSoftSoundNode *fActiveSofts;
|
||||
plStatusLog *fDebugActiveSoundDisplay;
|
||||
|
||||
static Int32 fMaxNumSounds, fNumSoundsSlop; // max number of sounds the engine is allowed to audibly play. Different than fMaxNumSources. That is the max number of sounds the audio card can play
|
||||
plSoftSoundNode *fCurrDebugSound;
|
||||
hsTArray<plKey> fPendingRegisters;
|
||||
|
||||
hsPoint3 fCurrListenerPos;//, fCommittedListenerPos;
|
||||
hsBool fActive, fUsingEAX, fRestartOnDestruct, fWaitingForShutdown;
|
||||
__int64 fStartTime;
|
||||
|
||||
hsTArray<hsKeyedObject *> fMyRefs;
|
||||
hsTArray<plEAXListenerMod *> fEAXRegions;
|
||||
|
||||
hsPoint3 fLastPos;
|
||||
hsBool fAvatarPosSet; // used for listener stuff
|
||||
|
||||
hsBool fDisplayNumBuffers;
|
||||
|
||||
std::vector<DeviceDescriptor> fDeviceList; // list of openal device names
|
||||
|
||||
double fStartFade;
|
||||
float fFadeLength;
|
||||
unsigned int fMaxNumSources; // max openal sources
|
||||
double fLastUpdateTimeMs;
|
||||
|
||||
void RegisterSoftSound( const plKey soundKey );
|
||||
void UnregisterSoftSound( const plKey soundKey );
|
||||
void IUpdateSoftSounds( const hsPoint3 &newPosition );
|
||||
UInt32 IScaleVolume(float volume);
|
||||
void IEnumerateDevices();
|
||||
|
||||
public:
|
||||
hsBool fListenerInit;
|
||||
};
|
||||
|
||||
class plgAudioSys
|
||||
{
|
||||
public:
|
||||
enum ASChannel
|
||||
{
|
||||
kSoundFX,
|
||||
kAmbience,
|
||||
kBgndMusic,
|
||||
kGUI,
|
||||
kNPCVoice,
|
||||
kVoice,
|
||||
kNumChannels
|
||||
};
|
||||
|
||||
enum DebugFlags
|
||||
{
|
||||
kDisableRightSelect = 0x00000001,
|
||||
kDisableLeftSelect = 0x00000002
|
||||
};
|
||||
|
||||
enum AudioMode
|
||||
{
|
||||
kDisabled,
|
||||
kSoftware,
|
||||
kHardware,
|
||||
kHardwarePlusEAX,
|
||||
};
|
||||
static void Init(hsWindowHndl hWnd);
|
||||
static hsBool Hardware() { return fUseHardware; }
|
||||
static void SetUseHardware(hsBool b);
|
||||
static void SetActive(hsBool b);
|
||||
static void SetMuted( hsBool b );
|
||||
static void EnableEAX( hsBool b );
|
||||
static hsBool Active() { return fInit; }
|
||||
static void Shutdown();
|
||||
static void Activate(hsBool b);
|
||||
static hsBool IsMuted( void ) { return fMuted; }
|
||||
static hsWindowHndl hWnd() { return fWnd; }
|
||||
static plAudioSystem* Sys() { return fSys; }
|
||||
static void Restart( void );
|
||||
static hsBool UsingEAX( void ) { return fSys->fUsingEAX; }
|
||||
|
||||
static void NextDebugSound( void );
|
||||
|
||||
static void SetChannelVolume( ASChannel chan, hsScalar vol );
|
||||
static hsScalar GetChannelVolume( ASChannel chan );
|
||||
|
||||
static void Set2D3DBias( hsScalar bias );
|
||||
static hsScalar Get2D3Dbias();
|
||||
|
||||
static void SetGlobalFadeVolume( hsScalar vol );
|
||||
static hsScalar GetGlobalFadeVolume( void ) { return fGlobalFadeVolume; }
|
||||
|
||||
static void SetDebugFlag( UInt32 flag, hsBool set = true ) { if( set ) fDebugFlags |= flag; else fDebugFlags &= ~flag; }
|
||||
static hsBool IsDebugFlagSet( UInt32 flag ) { return fDebugFlags & flag; }
|
||||
static void ClearDebugFlags( void ) { fDebugFlags = 0; }
|
||||
|
||||
static hsScalar GetStreamingBufferSize( void ) { return fStreamingBufferSize; }
|
||||
static void SetStreamingBufferSize( hsScalar size ) { fStreamingBufferSize = size; }
|
||||
|
||||
static UInt8 GetPriorityCutoff( void ) { return fPriorityCutoff; }
|
||||
static void SetPriorityCutoff( UInt8 cut ) { fPriorityCutoff = cut; if(fSys) fSys->SetMaxNumberOfActiveSounds(); }
|
||||
|
||||
static hsBool AreExtendedLogsEnabled( void ) { return fEnableExtendedLogs; }
|
||||
static void EnableExtendedLogs( hsBool e ) { fEnableExtendedLogs = e; }
|
||||
|
||||
static hsScalar GetStreamFromRAMCutoff( void ) { return fStreamFromRAMCutoff; }
|
||||
static void SetStreamFromRAMCutoff( hsScalar c ) { fStreamFromRAMCutoff = c; }
|
||||
|
||||
static void SetListenerPos(const hsPoint3 pos);
|
||||
static void SetListenerVelocity(const hsVector3 vel);
|
||||
static void SetListenerOrientation(const hsVector3 view, const hsVector3 up);
|
||||
|
||||
static void ShowNumBuffers(hsBool b) { if(fSys) fSys->fDisplayNumBuffers = b; }
|
||||
|
||||
static void SetAudioMode(AudioMode mode);
|
||||
static int GetAudioMode();
|
||||
static hsBool LogStreamingUpdates() { return fLogStreamingUpdates; }
|
||||
static void SetLogStreamingUpdates(hsBool logUpdates) { fLogStreamingUpdates = logUpdates; }
|
||||
static void SetDeviceName(const char *device, hsBool restart = false);
|
||||
static const char *GetDeviceName() { return fDeviceName.c_str(); }
|
||||
static int GetNumAudioDevices();
|
||||
static const char *GetAudioDeviceName(int index);
|
||||
static ALCdevice *GetCaptureDevice();
|
||||
static hsBool SupportsEAX(const char *deviceName);
|
||||
static void RegisterSoftSound( const plKey soundKey );
|
||||
static void UnregisterSoftSound( const plKey soundKey );
|
||||
|
||||
static hsBool IsRestarting() {return fRestarting;}
|
||||
|
||||
private:
|
||||
friend class plAudioSystem;
|
||||
|
||||
static plAudioSystem* fSys;
|
||||
static hsBool fInit;
|
||||
static hsBool fActive;
|
||||
static hsBool fMuted;
|
||||
static hsWindowHndl fWnd;
|
||||
static hsBool fUseHardware;
|
||||
static hsBool fDelayedActivate;
|
||||
static hsScalar fChannelVolumes[ kNumChannels ];
|
||||
static hsScalar fGlobalFadeVolume;
|
||||
static UInt32 fDebugFlags;
|
||||
static hsBool fEnableEAX;
|
||||
static hsScalar fStreamingBufferSize;
|
||||
static UInt8 fPriorityCutoff;
|
||||
static hsBool fEnableExtendedLogs;
|
||||
static hsScalar fStreamFromRAMCutoff;
|
||||
static hsScalar f2D3DBias;
|
||||
static hsBool fLogStreamingUpdates;
|
||||
static std::string fDeviceName;
|
||||
static hsBool fRestarting;
|
||||
static hsBool fMutedStateChange;
|
||||
|
||||
};
|
||||
|
||||
#endif //plAudioSystem_h
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,152 +1,152 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plDSoundBuffer - Simple wrapper class for a DirectSound buffer. //
|
||||
// Allows us to simplify all the work done behind the //
|
||||
// scenes in plWin32BufferThread. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _plDSoundBuffer_h
|
||||
#define _plDSoundBuffer_h
|
||||
|
||||
#include "hsStlUtils.h"
|
||||
#include "hsTemplates.h"
|
||||
#include "plEAXEffects.h"
|
||||
#define STREAMING_BUFFERS 16
|
||||
#define STREAM_BUFFER_SIZE 4608*4
|
||||
|
||||
//#define VOICE_BUFFERS 4
|
||||
//#define VOICE_BUFFER_SIZE 4608
|
||||
|
||||
class plWAVHeader;
|
||||
class plAudioFileReader;
|
||||
|
||||
typedef struct tWAVEFORMATEX WAVEFORMATEX;
|
||||
typedef struct _DSBUFFERDESC DSBUFFERDESC;
|
||||
|
||||
|
||||
// Ported to OpenAL from DirectSound May 2006. Idealy the openal sources would be seperate from this class.
|
||||
// OpenAl sound buffer, and source.
|
||||
class plDSoundBuffer
|
||||
{
|
||||
public:
|
||||
plDSoundBuffer( UInt32 size, plWAVHeader &bufferDesc, hsBool enable3D, hsBool looping, hsBool tryStatic = false, bool streaming = false );
|
||||
~plDSoundBuffer();
|
||||
|
||||
void Play( void );
|
||||
void Stop( void );
|
||||
void Rewind() ;
|
||||
|
||||
UInt32 GetLengthInBytes( void ) const;
|
||||
void SetScalarVolume( hsScalar volume ); // Sets the volume, but on a range from 0 to 1
|
||||
|
||||
unsigned GetSource() { return source; }
|
||||
void SetPosition(float x, float y, float z);
|
||||
void SetOrientation(float x, float y, float z);
|
||||
void SetVelocity(float x, float y, float z);
|
||||
void SetConeAngles(int inner, int outer);
|
||||
void SetConeOrientation(float x, float y, float z);
|
||||
void SetConeOutsideVolume(int vol);
|
||||
|
||||
void SetLooping( hsBool loop );
|
||||
void SetMinDistance( int dist);
|
||||
void SetMaxDistance( int dist );
|
||||
|
||||
hsBool IsValid( void ) const { return fValid; }
|
||||
hsBool IsPlaying( void );
|
||||
hsBool IsLooping( void ) const { return fLooping; }
|
||||
hsBool IsEAXAccelerated( void ) const;
|
||||
|
||||
bool FillBuffer(void *data, unsigned bytes, plWAVHeader *header);
|
||||
|
||||
// Streaming support
|
||||
bool SetupStreamingSource(plAudioFileReader *stream);
|
||||
bool SetupStreamingSource(void *data, unsigned bytes);
|
||||
int BuffersProcessed();
|
||||
bool StreamingFillBuffer(plAudioFileReader *stream);
|
||||
|
||||
bool SetupVoiceSource();
|
||||
bool VoiceFillBuffer(void *data, unsigned bytes, unsigned buferId);
|
||||
void UnQueueVoiceBuffers();
|
||||
|
||||
|
||||
unsigned GetByteOffset();
|
||||
UInt32 GetBufferBytePos( hsScalar timeInSecs ) const;
|
||||
UInt32 BytePosToMSecs( UInt32 bytePos ) const;
|
||||
|
||||
void SetEAXSettings( plEAXSourceSettings *settings, hsBool force = false );
|
||||
void SetTimeOffsetBytes(unsigned bytes);
|
||||
UInt8 GetBlockAlign( void ) const;
|
||||
static UInt32 GetNumBuffers() { return fNumBuffers; }
|
||||
float GetDefaultMinDistance() { return fDefaultMinDistance; }
|
||||
bool GetAvailableBufferId(unsigned *bufferId);
|
||||
unsigned GetNumQueuedBuffers(){ return fNumQueuedBuffers;} // returns the max number of buffers queued on a source
|
||||
|
||||
float GetTimeOffsetSec();
|
||||
void SetTimeOffsetSec(float seconds);
|
||||
int BuffersQueued();
|
||||
|
||||
protected:
|
||||
|
||||
enum BufferType
|
||||
{
|
||||
kStatic,
|
||||
kStreaming,
|
||||
kVoice,
|
||||
};
|
||||
|
||||
BufferType fType;
|
||||
hsBool fValid, fLooping;
|
||||
UInt32 fLockLength;
|
||||
void * fLockPtr;
|
||||
|
||||
hsTArray<UInt32> fPosNotifys;
|
||||
bool fStreaming;
|
||||
DSBUFFERDESC* fBufferDesc;
|
||||
|
||||
unsigned buffer; // used if this is not a streaming buffer
|
||||
unsigned streamingBuffers[STREAMING_BUFFERS]; // used if this is a streaming buffer
|
||||
std::list<unsigned> mAvailableBuffers; // used for doing our own buffer management. Specifically voice chat, since we dont want old buffers queued
|
||||
|
||||
unsigned source;
|
||||
unsigned int fStreamingBufferSize;
|
||||
|
||||
plEAXSource fEAXSource;
|
||||
|
||||
static UInt32 fNumBuffers;
|
||||
static float fDefaultMinDistance;
|
||||
|
||||
unsigned fNumQueuedBuffers;
|
||||
hsScalar fPrevVolume;
|
||||
|
||||
void IAllocate( UInt32 size, plWAVHeader &bufferDesc, hsBool enable3D, hsBool tryStatic );
|
||||
void IRelease( void );
|
||||
int IGetALFormat(unsigned bitsPerSample, unsigned int numChannels);
|
||||
};
|
||||
|
||||
#endif //_plDSoundBuffer_h
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plDSoundBuffer - Simple wrapper class for a DirectSound buffer. //
|
||||
// Allows us to simplify all the work done behind the //
|
||||
// scenes in plWin32BufferThread. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _plDSoundBuffer_h
|
||||
#define _plDSoundBuffer_h
|
||||
|
||||
#include "hsStlUtils.h"
|
||||
#include "hsTemplates.h"
|
||||
#include "plEAXEffects.h"
|
||||
#define STREAMING_BUFFERS 16
|
||||
#define STREAM_BUFFER_SIZE 4608*4
|
||||
|
||||
//#define VOICE_BUFFERS 4
|
||||
//#define VOICE_BUFFER_SIZE 4608
|
||||
|
||||
class plWAVHeader;
|
||||
class plAudioFileReader;
|
||||
|
||||
typedef struct tWAVEFORMATEX WAVEFORMATEX;
|
||||
typedef struct _DSBUFFERDESC DSBUFFERDESC;
|
||||
|
||||
|
||||
// Ported to OpenAL from DirectSound May 2006. Idealy the openal sources would be seperate from this class.
|
||||
// OpenAl sound buffer, and source.
|
||||
class plDSoundBuffer
|
||||
{
|
||||
public:
|
||||
plDSoundBuffer( UInt32 size, plWAVHeader &bufferDesc, hsBool enable3D, hsBool looping, hsBool tryStatic = false, bool streaming = false );
|
||||
~plDSoundBuffer();
|
||||
|
||||
void Play( void );
|
||||
void Stop( void );
|
||||
void Rewind() ;
|
||||
|
||||
UInt32 GetLengthInBytes( void ) const;
|
||||
void SetScalarVolume( hsScalar volume ); // Sets the volume, but on a range from 0 to 1
|
||||
|
||||
unsigned GetSource() { return source; }
|
||||
void SetPosition(float x, float y, float z);
|
||||
void SetOrientation(float x, float y, float z);
|
||||
void SetVelocity(float x, float y, float z);
|
||||
void SetConeAngles(int inner, int outer);
|
||||
void SetConeOrientation(float x, float y, float z);
|
||||
void SetConeOutsideVolume(int vol);
|
||||
|
||||
void SetLooping( hsBool loop );
|
||||
void SetMinDistance( int dist);
|
||||
void SetMaxDistance( int dist );
|
||||
|
||||
hsBool IsValid( void ) const { return fValid; }
|
||||
hsBool IsPlaying( void );
|
||||
hsBool IsLooping( void ) const { return fLooping; }
|
||||
hsBool IsEAXAccelerated( void ) const;
|
||||
|
||||
bool FillBuffer(void *data, unsigned bytes, plWAVHeader *header);
|
||||
|
||||
// Streaming support
|
||||
bool SetupStreamingSource(plAudioFileReader *stream);
|
||||
bool SetupStreamingSource(void *data, unsigned bytes);
|
||||
int BuffersProcessed();
|
||||
bool StreamingFillBuffer(plAudioFileReader *stream);
|
||||
|
||||
bool SetupVoiceSource();
|
||||
bool VoiceFillBuffer(void *data, unsigned bytes, unsigned buferId);
|
||||
void UnQueueVoiceBuffers();
|
||||
|
||||
|
||||
unsigned GetByteOffset();
|
||||
UInt32 GetBufferBytePos( hsScalar timeInSecs ) const;
|
||||
UInt32 BytePosToMSecs( UInt32 bytePos ) const;
|
||||
|
||||
void SetEAXSettings( plEAXSourceSettings *settings, hsBool force = false );
|
||||
void SetTimeOffsetBytes(unsigned bytes);
|
||||
UInt8 GetBlockAlign( void ) const;
|
||||
static UInt32 GetNumBuffers() { return fNumBuffers; }
|
||||
float GetDefaultMinDistance() { return fDefaultMinDistance; }
|
||||
bool GetAvailableBufferId(unsigned *bufferId);
|
||||
unsigned GetNumQueuedBuffers(){ return fNumQueuedBuffers;} // returns the max number of buffers queued on a source
|
||||
|
||||
float GetTimeOffsetSec();
|
||||
void SetTimeOffsetSec(float seconds);
|
||||
int BuffersQueued();
|
||||
|
||||
protected:
|
||||
|
||||
enum BufferType
|
||||
{
|
||||
kStatic,
|
||||
kStreaming,
|
||||
kVoice,
|
||||
};
|
||||
|
||||
BufferType fType;
|
||||
hsBool fValid, fLooping;
|
||||
UInt32 fLockLength;
|
||||
void * fLockPtr;
|
||||
|
||||
hsTArray<UInt32> fPosNotifys;
|
||||
bool fStreaming;
|
||||
DSBUFFERDESC* fBufferDesc;
|
||||
|
||||
unsigned buffer; // used if this is not a streaming buffer
|
||||
unsigned streamingBuffers[STREAMING_BUFFERS]; // used if this is a streaming buffer
|
||||
std::list<unsigned> mAvailableBuffers; // used for doing our own buffer management. Specifically voice chat, since we dont want old buffers queued
|
||||
|
||||
unsigned source;
|
||||
unsigned int fStreamingBufferSize;
|
||||
|
||||
plEAXSource fEAXSource;
|
||||
|
||||
static UInt32 fNumBuffers;
|
||||
static float fDefaultMinDistance;
|
||||
|
||||
unsigned fNumQueuedBuffers;
|
||||
hsScalar fPrevVolume;
|
||||
|
||||
void IAllocate( UInt32 size, plWAVHeader &bufferDesc, hsBool enable3D, hsBool tryStatic );
|
||||
void IRelease( void );
|
||||
int IGetALFormat(unsigned bitsPerSample, unsigned int numChannels);
|
||||
};
|
||||
|
||||
#endif //_plDSoundBuffer_h
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,196 +1,196 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plEAXEffects - Various classes and wrappers to support EAX //
|
||||
// acceleration. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _plEAXEffects_h
|
||||
#define _plEAXEffects_h
|
||||
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "hsTemplates.h"
|
||||
|
||||
|
||||
//// Listener Settings Class Definition ///////////////////////////////////////
|
||||
|
||||
class plDSoundBuffer;
|
||||
class plEAXListenerMod;
|
||||
|
||||
#ifdef EAX_SDK_AVAILABLE
|
||||
typedef struct _EAXREVERBPROPERTIES EAXREVERBPROPERTIES;
|
||||
#else
|
||||
#include <EFX-Util.h>
|
||||
#endif
|
||||
|
||||
class plEAXListener
|
||||
{
|
||||
public:
|
||||
~plEAXListener();
|
||||
static plEAXListener &GetInstance( void );
|
||||
|
||||
hsBool Init( void );
|
||||
void Shutdown( void );
|
||||
|
||||
bool SetGlobalEAXProperty(GUID guid, unsigned long ulProperty, void *pData, unsigned long ulDataSize );
|
||||
bool GetGlobalEAXProperty(GUID guid, unsigned long ulProperty, void *pData, unsigned long ulDataSize );
|
||||
|
||||
void ProcessMods( hsTArray<plEAXListenerMod *> &modArray );
|
||||
void ClearProcessCache( void );
|
||||
|
||||
protected:
|
||||
plEAXListener();
|
||||
void IFail( hsBool major );
|
||||
void IFail( const char *msg, hsBool major );
|
||||
void IRelease( void );
|
||||
|
||||
void IMuteProperties( EAXREVERBPROPERTIES *props, hsScalar percent );
|
||||
|
||||
hsBool fInited;
|
||||
|
||||
// Cache info
|
||||
Int32 fLastModCount;
|
||||
hsBool fLastWasEmpty;
|
||||
hsScalar fLastSingleStrength;
|
||||
plEAXListenerMod *fLastBigRegion;
|
||||
|
||||
};
|
||||
|
||||
//// Soft Buffer Settings Class Definition ////////////////////////////////////
|
||||
// Used to hold buffer settings that will be attenuated by a soft volume,
|
||||
// to make the main settings class a bit cleaner
|
||||
|
||||
class hsStream;
|
||||
class plEAXSourceSoftSettings
|
||||
{
|
||||
public:
|
||||
Int16 fOcclusion;
|
||||
hsScalar fOcclusionLFRatio, fOcclusionRoomRatio, fOcclusionDirectRatio;
|
||||
|
||||
void Read( hsStream *s );
|
||||
void Write( hsStream *s );
|
||||
|
||||
void SetOcclusion( Int16 occ, hsScalar lfRatio, hsScalar roomRatio, hsScalar directRatio );
|
||||
Int16 GetOcclusion( void ) const { return fOcclusion; }
|
||||
hsScalar GetOcclusionLFRatio( void ) const { return fOcclusionLFRatio; }
|
||||
hsScalar GetOcclusionRoomRatio( void ) const { return fOcclusionRoomRatio; }
|
||||
hsScalar GetOcclusionDirectRatio( void ) const { return fOcclusionDirectRatio; }
|
||||
|
||||
void Reset( void );
|
||||
};
|
||||
|
||||
//// Buffer Settings Class Definition /////////////////////////////////////////
|
||||
|
||||
class plEAXSource;
|
||||
|
||||
class plEAXSourceSettings
|
||||
{
|
||||
public:
|
||||
plEAXSourceSettings();
|
||||
virtual ~plEAXSourceSettings();
|
||||
|
||||
void Read( hsStream *s );
|
||||
void Write( hsStream *s );
|
||||
|
||||
void Enable( hsBool e );
|
||||
hsBool IsEnabled( void ) const { return fEnabled; }
|
||||
|
||||
void SetRoomParams( Int16 room, Int16 roomHF, hsBool roomAuto, hsBool roomHFAuto );
|
||||
Int16 GetRoom( void ) const { return fRoom; }
|
||||
Int16 GetRoomHF( void ) const { return fRoomHF; }
|
||||
hsBool GetRoomAuto( void ) const { return fRoomAuto; }
|
||||
hsBool GetRoomHFAuto( void ) const { return fRoomHFAuto; }
|
||||
|
||||
void SetOutsideVolHF( Int16 vol );
|
||||
Int16 GetOutsideVolHF( void ) const { return fOutsideVolHF; }
|
||||
|
||||
void SetFactors( hsScalar airAbsorption, hsScalar roomRolloff, hsScalar doppler, hsScalar rolloff );
|
||||
hsScalar GetAirAbsorptionFactor( void ) const { return fAirAbsorptionFactor; }
|
||||
hsScalar GetRoomRolloffFactor( void ) const { return fRoomRolloffFactor; }
|
||||
hsScalar GetDopplerFactor( void ) const { return fDopplerFactor; }
|
||||
hsScalar GetRolloffFactor( void ) const { return fRolloffFactor; }
|
||||
|
||||
plEAXSourceSoftSettings &GetSoftStarts( void ) { return fSoftStarts; }
|
||||
plEAXSourceSoftSettings &GetSoftEnds( void ) { return fSoftEnds; }
|
||||
|
||||
plEAXSourceSoftSettings &GetCurrSofts( void ) { return fCurrSoftValues; }
|
||||
|
||||
void SetOcclusionSoftValue( hsScalar value );
|
||||
hsScalar GetOcclusionSoftValue( void ) const { return fOcclusionSoftValue; }
|
||||
|
||||
void ClearDirtyParams( void ) const { fDirtyParams = 0; }
|
||||
|
||||
protected:
|
||||
friend class plEAXSource;
|
||||
friend plEAXSourceSoftSettings;
|
||||
|
||||
hsBool fEnabled;
|
||||
Int16 fRoom, fRoomHF;
|
||||
hsBool fRoomAuto, fRoomHFAuto;
|
||||
Int16 fOutsideVolHF;
|
||||
hsScalar fAirAbsorptionFactor, fRoomRolloffFactor, fDopplerFactor, fRolloffFactor;
|
||||
plEAXSourceSoftSettings fSoftStarts, fSoftEnds, fCurrSoftValues;
|
||||
hsScalar fOcclusionSoftValue;
|
||||
mutable UInt32 fDirtyParams;
|
||||
|
||||
enum ParamSets
|
||||
{
|
||||
kOcclusion = 0x01,
|
||||
kRoom = 0x02,
|
||||
kOutsideVolHF = 0x04,
|
||||
kFactors = 0x08,
|
||||
kAll = 0xff
|
||||
};
|
||||
|
||||
void IRecalcSofts( UInt8 whichOnes );
|
||||
};
|
||||
|
||||
//// Source Class Definition //////////////////////////////////////////////////
|
||||
|
||||
class plEAXSource
|
||||
{
|
||||
public:
|
||||
friend plEAXSourceSettings;
|
||||
friend plEAXSourceSoftSettings;
|
||||
|
||||
plEAXSource();
|
||||
virtual ~plEAXSource();
|
||||
|
||||
void Init( plDSoundBuffer *parent );
|
||||
void Release( void );
|
||||
hsBool IsValid( void ) const;
|
||||
bool SetSourceEAXProperty(unsigned source, GUID guid, unsigned long ulProperty, void *pData, unsigned long ulDataSize);
|
||||
bool GetSourceEAXProperty(unsigned source, GUID guid, unsigned long ulProperty, void *pData, unsigned long ulDataSize);
|
||||
void SetFrom( plEAXSourceSettings *settings, unsigned source, hsBool force = false );
|
||||
|
||||
private:
|
||||
hsBool fInit;
|
||||
};
|
||||
|
||||
#endif //_plEAXEffects_h
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plEAXEffects - Various classes and wrappers to support EAX //
|
||||
// acceleration. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _plEAXEffects_h
|
||||
#define _plEAXEffects_h
|
||||
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "hsTemplates.h"
|
||||
|
||||
|
||||
//// Listener Settings Class Definition ///////////////////////////////////////
|
||||
|
||||
class plDSoundBuffer;
|
||||
class plEAXListenerMod;
|
||||
|
||||
#ifdef EAX_SDK_AVAILABLE
|
||||
typedef struct _EAXREVERBPROPERTIES EAXREVERBPROPERTIES;
|
||||
#else
|
||||
#include <EFX-Util.h>
|
||||
#endif
|
||||
|
||||
class plEAXListener
|
||||
{
|
||||
public:
|
||||
~plEAXListener();
|
||||
static plEAXListener &GetInstance( void );
|
||||
|
||||
hsBool Init( void );
|
||||
void Shutdown( void );
|
||||
|
||||
bool SetGlobalEAXProperty(GUID guid, unsigned long ulProperty, void *pData, unsigned long ulDataSize );
|
||||
bool GetGlobalEAXProperty(GUID guid, unsigned long ulProperty, void *pData, unsigned long ulDataSize );
|
||||
|
||||
void ProcessMods( hsTArray<plEAXListenerMod *> &modArray );
|
||||
void ClearProcessCache( void );
|
||||
|
||||
protected:
|
||||
plEAXListener();
|
||||
void IFail( hsBool major );
|
||||
void IFail( const char *msg, hsBool major );
|
||||
void IRelease( void );
|
||||
|
||||
void IMuteProperties( EAXREVERBPROPERTIES *props, hsScalar percent );
|
||||
|
||||
hsBool fInited;
|
||||
|
||||
// Cache info
|
||||
Int32 fLastModCount;
|
||||
hsBool fLastWasEmpty;
|
||||
hsScalar fLastSingleStrength;
|
||||
plEAXListenerMod *fLastBigRegion;
|
||||
|
||||
};
|
||||
|
||||
//// Soft Buffer Settings Class Definition ////////////////////////////////////
|
||||
// Used to hold buffer settings that will be attenuated by a soft volume,
|
||||
// to make the main settings class a bit cleaner
|
||||
|
||||
class hsStream;
|
||||
class plEAXSourceSoftSettings
|
||||
{
|
||||
public:
|
||||
Int16 fOcclusion;
|
||||
hsScalar fOcclusionLFRatio, fOcclusionRoomRatio, fOcclusionDirectRatio;
|
||||
|
||||
void Read( hsStream *s );
|
||||
void Write( hsStream *s );
|
||||
|
||||
void SetOcclusion( Int16 occ, hsScalar lfRatio, hsScalar roomRatio, hsScalar directRatio );
|
||||
Int16 GetOcclusion( void ) const { return fOcclusion; }
|
||||
hsScalar GetOcclusionLFRatio( void ) const { return fOcclusionLFRatio; }
|
||||
hsScalar GetOcclusionRoomRatio( void ) const { return fOcclusionRoomRatio; }
|
||||
hsScalar GetOcclusionDirectRatio( void ) const { return fOcclusionDirectRatio; }
|
||||
|
||||
void Reset( void );
|
||||
};
|
||||
|
||||
//// Buffer Settings Class Definition /////////////////////////////////////////
|
||||
|
||||
class plEAXSource;
|
||||
|
||||
class plEAXSourceSettings
|
||||
{
|
||||
public:
|
||||
plEAXSourceSettings();
|
||||
virtual ~plEAXSourceSettings();
|
||||
|
||||
void Read( hsStream *s );
|
||||
void Write( hsStream *s );
|
||||
|
||||
void Enable( hsBool e );
|
||||
hsBool IsEnabled( void ) const { return fEnabled; }
|
||||
|
||||
void SetRoomParams( Int16 room, Int16 roomHF, hsBool roomAuto, hsBool roomHFAuto );
|
||||
Int16 GetRoom( void ) const { return fRoom; }
|
||||
Int16 GetRoomHF( void ) const { return fRoomHF; }
|
||||
hsBool GetRoomAuto( void ) const { return fRoomAuto; }
|
||||
hsBool GetRoomHFAuto( void ) const { return fRoomHFAuto; }
|
||||
|
||||
void SetOutsideVolHF( Int16 vol );
|
||||
Int16 GetOutsideVolHF( void ) const { return fOutsideVolHF; }
|
||||
|
||||
void SetFactors( hsScalar airAbsorption, hsScalar roomRolloff, hsScalar doppler, hsScalar rolloff );
|
||||
hsScalar GetAirAbsorptionFactor( void ) const { return fAirAbsorptionFactor; }
|
||||
hsScalar GetRoomRolloffFactor( void ) const { return fRoomRolloffFactor; }
|
||||
hsScalar GetDopplerFactor( void ) const { return fDopplerFactor; }
|
||||
hsScalar GetRolloffFactor( void ) const { return fRolloffFactor; }
|
||||
|
||||
plEAXSourceSoftSettings &GetSoftStarts( void ) { return fSoftStarts; }
|
||||
plEAXSourceSoftSettings &GetSoftEnds( void ) { return fSoftEnds; }
|
||||
|
||||
plEAXSourceSoftSettings &GetCurrSofts( void ) { return fCurrSoftValues; }
|
||||
|
||||
void SetOcclusionSoftValue( hsScalar value );
|
||||
hsScalar GetOcclusionSoftValue( void ) const { return fOcclusionSoftValue; }
|
||||
|
||||
void ClearDirtyParams( void ) const { fDirtyParams = 0; }
|
||||
|
||||
protected:
|
||||
friend class plEAXSource;
|
||||
friend plEAXSourceSoftSettings;
|
||||
|
||||
hsBool fEnabled;
|
||||
Int16 fRoom, fRoomHF;
|
||||
hsBool fRoomAuto, fRoomHFAuto;
|
||||
Int16 fOutsideVolHF;
|
||||
hsScalar fAirAbsorptionFactor, fRoomRolloffFactor, fDopplerFactor, fRolloffFactor;
|
||||
plEAXSourceSoftSettings fSoftStarts, fSoftEnds, fCurrSoftValues;
|
||||
hsScalar fOcclusionSoftValue;
|
||||
mutable UInt32 fDirtyParams;
|
||||
|
||||
enum ParamSets
|
||||
{
|
||||
kOcclusion = 0x01,
|
||||
kRoom = 0x02,
|
||||
kOutsideVolHF = 0x04,
|
||||
kFactors = 0x08,
|
||||
kAll = 0xff
|
||||
};
|
||||
|
||||
void IRecalcSofts( UInt8 whichOnes );
|
||||
};
|
||||
|
||||
//// Source Class Definition //////////////////////////////////////////////////
|
||||
|
||||
class plEAXSource
|
||||
{
|
||||
public:
|
||||
friend plEAXSourceSettings;
|
||||
friend plEAXSourceSoftSettings;
|
||||
|
||||
plEAXSource();
|
||||
virtual ~plEAXSource();
|
||||
|
||||
void Init( plDSoundBuffer *parent );
|
||||
void Release( void );
|
||||
hsBool IsValid( void ) const;
|
||||
bool SetSourceEAXProperty(unsigned source, GUID guid, unsigned long ulProperty, void *pData, unsigned long ulDataSize);
|
||||
bool GetSourceEAXProperty(unsigned source, GUID guid, unsigned long ulProperty, void *pData, unsigned long ulDataSize);
|
||||
void SetFrom( plEAXSourceSettings *settings, unsigned source, hsBool force = false );
|
||||
|
||||
private:
|
||||
hsBool fInit;
|
||||
};
|
||||
|
||||
#endif //_plEAXEffects_h
|
||||
|
@ -1,237 +1,237 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plEAXListenerMod //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EAX_SDK_AVAILABLE
|
||||
#include <EFX-Util.h>
|
||||
#endif
|
||||
#include "hsTypes.h"
|
||||
#include "plEAXListenerMod.h"
|
||||
#include "plIntersect/plSoftVolume.h"
|
||||
#include "hsResMgr.h"
|
||||
#include "plgDispatch.h"
|
||||
#include "plAudioSystem.h"
|
||||
#include "pnMessage/plAudioSysMsg.h"
|
||||
|
||||
#ifdef EAX_SDK_AVAILABLE
|
||||
#include <eax-util.h>
|
||||
#endif
|
||||
|
||||
|
||||
plEAXListenerMod::plEAXListenerMod()
|
||||
{
|
||||
fListenerProps = TRACKED_NEW EAXREVERBPROPERTIES;
|
||||
fSoftRegion = nil;
|
||||
fRegistered = false;
|
||||
fGetsMessages = false;
|
||||
|
||||
#ifdef EAX_SDK_AVAILABLE
|
||||
memcpy( fListenerProps, &REVERB_ORIGINAL_PRESETS[ ORIGINAL_GENERIC ], sizeof( EAXREVERBPROPERTIES ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
plEAXListenerMod::~plEAXListenerMod()
|
||||
{
|
||||
// Tell the audio sys we're going away
|
||||
IUnRegister();
|
||||
|
||||
// Unregister for audioSys messages
|
||||
if( fGetsMessages )
|
||||
{
|
||||
plgDispatch::Dispatch()->UnRegisterForExactType( plAudioSysMsg::Index(), GetKey() );
|
||||
fGetsMessages = false;
|
||||
}
|
||||
|
||||
delete fListenerProps;
|
||||
}
|
||||
|
||||
void plEAXListenerMod::IRegister( void )
|
||||
{
|
||||
if( !fGetsMessages )
|
||||
{
|
||||
plgDispatch::Dispatch()->RegisterForExactType( plAudioSysMsg::Index(), GetKey() );
|
||||
fGetsMessages = true;
|
||||
}
|
||||
|
||||
if( fRegistered || GetKey() == nil )
|
||||
return;
|
||||
|
||||
plKey sysKey = hsgResMgr::ResMgr()->FindKey( plUoid( kAudioSystem_KEY ) );
|
||||
if( sysKey != nil )
|
||||
{
|
||||
plGenRefMsg *refMsg = TRACKED_NEW plGenRefMsg( sysKey, plRefMsg::kOnCreate, 0, plAudioSystem::kRefEAXRegion );
|
||||
hsgResMgr::ResMgr()->AddViaNotify( GetKey(), refMsg, plRefFlags::kPassiveRef );
|
||||
fRegistered = true;
|
||||
}
|
||||
}
|
||||
|
||||
void plEAXListenerMod::IUnRegister( void )
|
||||
{
|
||||
if( !fRegistered || GetKey() == nil )
|
||||
return;
|
||||
|
||||
plKey sysKey = hsgResMgr::ResMgr()->FindKey( plUoid( kAudioSystem_KEY ) );
|
||||
if( sysKey != nil && GetKey() != nil )
|
||||
sysKey->Release( GetKey() );
|
||||
|
||||
fRegistered = false;
|
||||
}
|
||||
|
||||
hsBool plEAXListenerMod::IEval( double secs, hsScalar del, UInt32 dirty )
|
||||
{
|
||||
IRegister();
|
||||
return false;
|
||||
}
|
||||
|
||||
hsBool plEAXListenerMod::MsgReceive( plMessage* pMsg )
|
||||
{
|
||||
plGenRefMsg *refMsg = plGenRefMsg::ConvertNoRef( pMsg );
|
||||
if( refMsg != nil )
|
||||
{
|
||||
switch( refMsg->fType )
|
||||
{
|
||||
case kRefSoftRegion:
|
||||
if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
|
||||
{
|
||||
fSoftRegion = plSoftVolume::ConvertNoRef( refMsg->GetRef() );
|
||||
fSoftRegion->SetCheckListener();
|
||||
}
|
||||
else if( refMsg->GetContext() & ( plRefMsg::kOnRemove | plRefMsg::kOnDestroy ) )
|
||||
{
|
||||
fSoftRegion = nil;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
plAudioSysMsg *sysMsg = plAudioSysMsg::ConvertNoRef( pMsg );
|
||||
if( sysMsg != nil )
|
||||
{
|
||||
if( sysMsg->GetAudFlag() == plAudioSysMsg::kActivate )
|
||||
{
|
||||
IRegister();
|
||||
}
|
||||
else if( sysMsg->GetAudFlag() == plAudioSysMsg::kDeActivate )
|
||||
{
|
||||
IUnRegister();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return plSingleModifier::MsgReceive( pMsg );
|
||||
}
|
||||
|
||||
void plEAXListenerMod::Read( hsStream* s, hsResMgr* mgr )
|
||||
{
|
||||
plSingleModifier::Read( s, mgr );
|
||||
|
||||
// Read in the soft region
|
||||
mgr->ReadKeyNotifyMe( s, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, 0, kRefSoftRegion ), plRefFlags::kActiveRef );
|
||||
|
||||
// Read the listener params
|
||||
fListenerProps->ulEnvironment = s->ReadSwap32();
|
||||
fListenerProps->flEnvironmentSize = s->ReadSwapFloat();
|
||||
fListenerProps->flEnvironmentDiffusion = s->ReadSwapFloat();
|
||||
fListenerProps->lRoom = s->ReadSwap32();
|
||||
fListenerProps->lRoomHF = s->ReadSwap32();
|
||||
fListenerProps->lRoomLF = s->ReadSwap32();
|
||||
fListenerProps->flDecayTime = s->ReadSwapFloat();
|
||||
fListenerProps->flDecayHFRatio = s->ReadSwapFloat();
|
||||
fListenerProps->flDecayLFRatio = s->ReadSwapFloat();
|
||||
fListenerProps->lReflections = s->ReadSwap32();
|
||||
fListenerProps->flReflectionsDelay = s->ReadSwapFloat();
|
||||
//fListenerProps->vReflectionsPan; // early reflections panning vector
|
||||
fListenerProps->lReverb = s->ReadSwap32(); // late reverberation level relative to room effect
|
||||
fListenerProps->flReverbDelay = s->ReadSwapFloat();
|
||||
//fListenerProps->vReverbPan; // late reverberation panning vector
|
||||
fListenerProps->flEchoTime = s->ReadSwapFloat();
|
||||
fListenerProps->flEchoDepth = s->ReadSwapFloat();
|
||||
fListenerProps->flModulationTime = s->ReadSwapFloat();
|
||||
fListenerProps->flModulationDepth = s->ReadSwapFloat();
|
||||
fListenerProps->flAirAbsorptionHF = s->ReadSwapFloat();
|
||||
fListenerProps->flHFReference = s->ReadSwapFloat();
|
||||
fListenerProps->flLFReference = s->ReadSwapFloat();
|
||||
fListenerProps->flRoomRolloffFactor = s->ReadSwapFloat();
|
||||
fListenerProps->ulFlags = s->ReadSwap32();
|
||||
|
||||
// Done reading, time to tell the audio sys we exist
|
||||
IRegister();
|
||||
}
|
||||
|
||||
void plEAXListenerMod::Write( hsStream* s, hsResMgr* mgr )
|
||||
{
|
||||
plSingleModifier::Write( s, mgr );
|
||||
|
||||
// Write the soft region key
|
||||
mgr->WriteKey( s, fSoftRegion );
|
||||
|
||||
// Write the listener params
|
||||
s->WriteSwap32( fListenerProps->ulEnvironment );
|
||||
s->WriteSwapFloat( fListenerProps->flEnvironmentSize );
|
||||
s->WriteSwapFloat( fListenerProps->flEnvironmentDiffusion );
|
||||
s->WriteSwap32( fListenerProps->lRoom );
|
||||
s->WriteSwap32( fListenerProps->lRoomHF );
|
||||
s->WriteSwap32( fListenerProps->lRoomLF );
|
||||
s->WriteSwapFloat( fListenerProps->flDecayTime );
|
||||
s->WriteSwapFloat( fListenerProps->flDecayHFRatio );
|
||||
s->WriteSwapFloat( fListenerProps->flDecayLFRatio );
|
||||
s->WriteSwap32( fListenerProps->lReflections );
|
||||
s->WriteSwapFloat( fListenerProps->flReflectionsDelay );
|
||||
//s->WriteSwapFloat( fListenerProps->vReflectionsPan; // early reflections panning vector
|
||||
s->WriteSwap32( fListenerProps->lReverb ); // late reverberation level relative to room effect
|
||||
s->WriteSwapFloat( fListenerProps->flReverbDelay );
|
||||
//s->WriteSwapFloat( fListenerProps->vReverbPan; // late reverberation panning vector
|
||||
s->WriteSwapFloat( fListenerProps->flEchoTime );
|
||||
s->WriteSwapFloat( fListenerProps->flEchoDepth );
|
||||
s->WriteSwapFloat( fListenerProps->flModulationTime );
|
||||
s->WriteSwapFloat( fListenerProps->flModulationDepth );
|
||||
s->WriteSwapFloat( fListenerProps->flAirAbsorptionHF );
|
||||
s->WriteSwapFloat( fListenerProps->flHFReference );
|
||||
s->WriteSwapFloat( fListenerProps->flLFReference );
|
||||
s->WriteSwapFloat( fListenerProps->flRoomRolloffFactor );
|
||||
s->WriteSwap32( fListenerProps->ulFlags );
|
||||
}
|
||||
|
||||
|
||||
void plEAXListenerMod::SetFromPreset( UInt32 preset )
|
||||
{
|
||||
#ifdef EAX_SDK_AVAILABLE
|
||||
memcpy( fListenerProps, &REVERB_ORIGINAL_PRESETS[ preset ], sizeof( EAXREVERBPROPERTIES ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
float plEAXListenerMod::GetStrength( void )
|
||||
{
|
||||
if( fSoftRegion == nil )
|
||||
return 0.f;
|
||||
|
||||
return fSoftRegion->GetListenerStrength();
|
||||
}
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plEAXListenerMod //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EAX_SDK_AVAILABLE
|
||||
#include <EFX-Util.h>
|
||||
#endif
|
||||
#include "hsTypes.h"
|
||||
#include "plEAXListenerMod.h"
|
||||
#include "plIntersect/plSoftVolume.h"
|
||||
#include "hsResMgr.h"
|
||||
#include "plgDispatch.h"
|
||||
#include "plAudioSystem.h"
|
||||
#include "pnMessage/plAudioSysMsg.h"
|
||||
|
||||
#ifdef EAX_SDK_AVAILABLE
|
||||
#include <eax-util.h>
|
||||
#endif
|
||||
|
||||
|
||||
plEAXListenerMod::plEAXListenerMod()
|
||||
{
|
||||
fListenerProps = TRACKED_NEW EAXREVERBPROPERTIES;
|
||||
fSoftRegion = nil;
|
||||
fRegistered = false;
|
||||
fGetsMessages = false;
|
||||
|
||||
#ifdef EAX_SDK_AVAILABLE
|
||||
memcpy( fListenerProps, &REVERB_ORIGINAL_PRESETS[ ORIGINAL_GENERIC ], sizeof( EAXREVERBPROPERTIES ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
plEAXListenerMod::~plEAXListenerMod()
|
||||
{
|
||||
// Tell the audio sys we're going away
|
||||
IUnRegister();
|
||||
|
||||
// Unregister for audioSys messages
|
||||
if( fGetsMessages )
|
||||
{
|
||||
plgDispatch::Dispatch()->UnRegisterForExactType( plAudioSysMsg::Index(), GetKey() );
|
||||
fGetsMessages = false;
|
||||
}
|
||||
|
||||
delete fListenerProps;
|
||||
}
|
||||
|
||||
void plEAXListenerMod::IRegister( void )
|
||||
{
|
||||
if( !fGetsMessages )
|
||||
{
|
||||
plgDispatch::Dispatch()->RegisterForExactType( plAudioSysMsg::Index(), GetKey() );
|
||||
fGetsMessages = true;
|
||||
}
|
||||
|
||||
if( fRegistered || GetKey() == nil )
|
||||
return;
|
||||
|
||||
plKey sysKey = hsgResMgr::ResMgr()->FindKey( plUoid( kAudioSystem_KEY ) );
|
||||
if( sysKey != nil )
|
||||
{
|
||||
plGenRefMsg *refMsg = TRACKED_NEW plGenRefMsg( sysKey, plRefMsg::kOnCreate, 0, plAudioSystem::kRefEAXRegion );
|
||||
hsgResMgr::ResMgr()->AddViaNotify( GetKey(), refMsg, plRefFlags::kPassiveRef );
|
||||
fRegistered = true;
|
||||
}
|
||||
}
|
||||
|
||||
void plEAXListenerMod::IUnRegister( void )
|
||||
{
|
||||
if( !fRegistered || GetKey() == nil )
|
||||
return;
|
||||
|
||||
plKey sysKey = hsgResMgr::ResMgr()->FindKey( plUoid( kAudioSystem_KEY ) );
|
||||
if( sysKey != nil && GetKey() != nil )
|
||||
sysKey->Release( GetKey() );
|
||||
|
||||
fRegistered = false;
|
||||
}
|
||||
|
||||
hsBool plEAXListenerMod::IEval( double secs, hsScalar del, UInt32 dirty )
|
||||
{
|
||||
IRegister();
|
||||
return false;
|
||||
}
|
||||
|
||||
hsBool plEAXListenerMod::MsgReceive( plMessage* pMsg )
|
||||
{
|
||||
plGenRefMsg *refMsg = plGenRefMsg::ConvertNoRef( pMsg );
|
||||
if( refMsg != nil )
|
||||
{
|
||||
switch( refMsg->fType )
|
||||
{
|
||||
case kRefSoftRegion:
|
||||
if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
|
||||
{
|
||||
fSoftRegion = plSoftVolume::ConvertNoRef( refMsg->GetRef() );
|
||||
fSoftRegion->SetCheckListener();
|
||||
}
|
||||
else if( refMsg->GetContext() & ( plRefMsg::kOnRemove | plRefMsg::kOnDestroy ) )
|
||||
{
|
||||
fSoftRegion = nil;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
plAudioSysMsg *sysMsg = plAudioSysMsg::ConvertNoRef( pMsg );
|
||||
if( sysMsg != nil )
|
||||
{
|
||||
if( sysMsg->GetAudFlag() == plAudioSysMsg::kActivate )
|
||||
{
|
||||
IRegister();
|
||||
}
|
||||
else if( sysMsg->GetAudFlag() == plAudioSysMsg::kDeActivate )
|
||||
{
|
||||
IUnRegister();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return plSingleModifier::MsgReceive( pMsg );
|
||||
}
|
||||
|
||||
void plEAXListenerMod::Read( hsStream* s, hsResMgr* mgr )
|
||||
{
|
||||
plSingleModifier::Read( s, mgr );
|
||||
|
||||
// Read in the soft region
|
||||
mgr->ReadKeyNotifyMe( s, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, 0, kRefSoftRegion ), plRefFlags::kActiveRef );
|
||||
|
||||
// Read the listener params
|
||||
fListenerProps->ulEnvironment = s->ReadSwap32();
|
||||
fListenerProps->flEnvironmentSize = s->ReadSwapFloat();
|
||||
fListenerProps->flEnvironmentDiffusion = s->ReadSwapFloat();
|
||||
fListenerProps->lRoom = s->ReadSwap32();
|
||||
fListenerProps->lRoomHF = s->ReadSwap32();
|
||||
fListenerProps->lRoomLF = s->ReadSwap32();
|
||||
fListenerProps->flDecayTime = s->ReadSwapFloat();
|
||||
fListenerProps->flDecayHFRatio = s->ReadSwapFloat();
|
||||
fListenerProps->flDecayLFRatio = s->ReadSwapFloat();
|
||||
fListenerProps->lReflections = s->ReadSwap32();
|
||||
fListenerProps->flReflectionsDelay = s->ReadSwapFloat();
|
||||
//fListenerProps->vReflectionsPan; // early reflections panning vector
|
||||
fListenerProps->lReverb = s->ReadSwap32(); // late reverberation level relative to room effect
|
||||
fListenerProps->flReverbDelay = s->ReadSwapFloat();
|
||||
//fListenerProps->vReverbPan; // late reverberation panning vector
|
||||
fListenerProps->flEchoTime = s->ReadSwapFloat();
|
||||
fListenerProps->flEchoDepth = s->ReadSwapFloat();
|
||||
fListenerProps->flModulationTime = s->ReadSwapFloat();
|
||||
fListenerProps->flModulationDepth = s->ReadSwapFloat();
|
||||
fListenerProps->flAirAbsorptionHF = s->ReadSwapFloat();
|
||||
fListenerProps->flHFReference = s->ReadSwapFloat();
|
||||
fListenerProps->flLFReference = s->ReadSwapFloat();
|
||||
fListenerProps->flRoomRolloffFactor = s->ReadSwapFloat();
|
||||
fListenerProps->ulFlags = s->ReadSwap32();
|
||||
|
||||
// Done reading, time to tell the audio sys we exist
|
||||
IRegister();
|
||||
}
|
||||
|
||||
void plEAXListenerMod::Write( hsStream* s, hsResMgr* mgr )
|
||||
{
|
||||
plSingleModifier::Write( s, mgr );
|
||||
|
||||
// Write the soft region key
|
||||
mgr->WriteKey( s, fSoftRegion );
|
||||
|
||||
// Write the listener params
|
||||
s->WriteSwap32( fListenerProps->ulEnvironment );
|
||||
s->WriteSwapFloat( fListenerProps->flEnvironmentSize );
|
||||
s->WriteSwapFloat( fListenerProps->flEnvironmentDiffusion );
|
||||
s->WriteSwap32( fListenerProps->lRoom );
|
||||
s->WriteSwap32( fListenerProps->lRoomHF );
|
||||
s->WriteSwap32( fListenerProps->lRoomLF );
|
||||
s->WriteSwapFloat( fListenerProps->flDecayTime );
|
||||
s->WriteSwapFloat( fListenerProps->flDecayHFRatio );
|
||||
s->WriteSwapFloat( fListenerProps->flDecayLFRatio );
|
||||
s->WriteSwap32( fListenerProps->lReflections );
|
||||
s->WriteSwapFloat( fListenerProps->flReflectionsDelay );
|
||||
//s->WriteSwapFloat( fListenerProps->vReflectionsPan; // early reflections panning vector
|
||||
s->WriteSwap32( fListenerProps->lReverb ); // late reverberation level relative to room effect
|
||||
s->WriteSwapFloat( fListenerProps->flReverbDelay );
|
||||
//s->WriteSwapFloat( fListenerProps->vReverbPan; // late reverberation panning vector
|
||||
s->WriteSwapFloat( fListenerProps->flEchoTime );
|
||||
s->WriteSwapFloat( fListenerProps->flEchoDepth );
|
||||
s->WriteSwapFloat( fListenerProps->flModulationTime );
|
||||
s->WriteSwapFloat( fListenerProps->flModulationDepth );
|
||||
s->WriteSwapFloat( fListenerProps->flAirAbsorptionHF );
|
||||
s->WriteSwapFloat( fListenerProps->flHFReference );
|
||||
s->WriteSwapFloat( fListenerProps->flLFReference );
|
||||
s->WriteSwapFloat( fListenerProps->flRoomRolloffFactor );
|
||||
s->WriteSwap32( fListenerProps->ulFlags );
|
||||
}
|
||||
|
||||
|
||||
void plEAXListenerMod::SetFromPreset( UInt32 preset )
|
||||
{
|
||||
#ifdef EAX_SDK_AVAILABLE
|
||||
memcpy( fListenerProps, &REVERB_ORIGINAL_PRESETS[ preset ], sizeof( EAXREVERBPROPERTIES ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
float plEAXListenerMod::GetStrength( void )
|
||||
{
|
||||
if( fSoftRegion == nil )
|
||||
return 0.f;
|
||||
|
||||
return fSoftRegion->GetListenerStrength();
|
||||
}
|
||||
|
@ -1,77 +1,77 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plEAXListenerMod Header //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _plEAXListenerMod_h
|
||||
#define _plEAXListenerMod_h
|
||||
|
||||
|
||||
#include "pnModifier/plSingleModifier.h"
|
||||
|
||||
class plMessage;
|
||||
class plSoftVolume;
|
||||
#ifdef EAX_SDK_AVAILABLE
|
||||
typedef struct _EAXREVERBPROPERTIES EAXREVERBPROPERTIES;
|
||||
#endif
|
||||
|
||||
class plEAXListenerMod : public plSingleModifier
|
||||
{
|
||||
public:
|
||||
|
||||
plEAXListenerMod();
|
||||
virtual ~plEAXListenerMod();
|
||||
|
||||
CLASSNAME_REGISTER( plEAXListenerMod );
|
||||
GETINTERFACE_ANY( plEAXListenerMod, plSingleModifier );
|
||||
|
||||
enum Refs
|
||||
{
|
||||
kRefSoftRegion = 0,
|
||||
};
|
||||
|
||||
virtual hsBool MsgReceive( plMessage* pMsg );
|
||||
virtual void Read( hsStream* s, hsResMgr* mgr );
|
||||
virtual void Write( hsStream* s, hsResMgr* mgr );
|
||||
float GetStrength( void );
|
||||
|
||||
EAXREVERBPROPERTIES * GetListenerProps( void ) { return fListenerProps; }
|
||||
void SetFromPreset( UInt32 preset );
|
||||
|
||||
protected:
|
||||
plSoftVolume *fSoftRegion;
|
||||
EAXREVERBPROPERTIES *fListenerProps;
|
||||
hsBool fRegistered, fGetsMessages;
|
||||
|
||||
void IRegister( void );
|
||||
void IUnRegister( void );
|
||||
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ); // called only by owner object's Eval()
|
||||
};
|
||||
|
||||
#endif // _plEAXListenerMod_h
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plEAXListenerMod Header //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _plEAXListenerMod_h
|
||||
#define _plEAXListenerMod_h
|
||||
|
||||
|
||||
#include "pnModifier/plSingleModifier.h"
|
||||
|
||||
class plMessage;
|
||||
class plSoftVolume;
|
||||
#ifdef EAX_SDK_AVAILABLE
|
||||
typedef struct _EAXREVERBPROPERTIES EAXREVERBPROPERTIES;
|
||||
#endif
|
||||
|
||||
class plEAXListenerMod : public plSingleModifier
|
||||
{
|
||||
public:
|
||||
|
||||
plEAXListenerMod();
|
||||
virtual ~plEAXListenerMod();
|
||||
|
||||
CLASSNAME_REGISTER( plEAXListenerMod );
|
||||
GETINTERFACE_ANY( plEAXListenerMod, plSingleModifier );
|
||||
|
||||
enum Refs
|
||||
{
|
||||
kRefSoftRegion = 0,
|
||||
};
|
||||
|
||||
virtual hsBool MsgReceive( plMessage* pMsg );
|
||||
virtual void Read( hsStream* s, hsResMgr* mgr );
|
||||
virtual void Write( hsStream* s, hsResMgr* mgr );
|
||||
float GetStrength( void );
|
||||
|
||||
EAXREVERBPROPERTIES * GetListenerProps( void ) { return fListenerProps; }
|
||||
void SetFromPreset( UInt32 preset );
|
||||
|
||||
protected:
|
||||
plSoftVolume *fSoftRegion;
|
||||
EAXREVERBPROPERTIES *fListenerProps;
|
||||
hsBool fRegistered, fGetsMessages;
|
||||
|
||||
void IRegister( void );
|
||||
void IUnRegister( void );
|
||||
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ); // called only by owner object's Eval()
|
||||
};
|
||||
|
||||
#endif // _plEAXListenerMod_h
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,396 +1,396 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plSound.h - Base sound class header //
|
||||
// //
|
||||
//// History /////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// 10.12.01 mcn - Added preliminary soft region (volume) support. //
|
||||
// 7.12.02 mcn - Added EAX support //
|
||||
// 7.15.02 mcn - Added support for animated volumes //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef plSound_h
|
||||
#define plSound_h
|
||||
|
||||
#include "hsTemplates.h"
|
||||
#include "hsGeometry3.h"
|
||||
#include "plEAXEffects.h"
|
||||
#include "pnNetCommon/plSynchedObject.h"
|
||||
#include "plAvatar/plAGChannel.h"
|
||||
#include "plAvatar/plAGApplicator.h"
|
||||
#include "plAudioCore/plSoundBuffer.h"
|
||||
|
||||
class hsResMgr;
|
||||
class hsStream;
|
||||
class plSoundProxy;
|
||||
class plDrawableSpans;
|
||||
class hsGMaterial;
|
||||
class plSoundMsg;
|
||||
class plSoftVolume;
|
||||
class plGraphPlate;
|
||||
struct hsMatrix44;
|
||||
class plSoundBuffer;
|
||||
class plSceneObject;
|
||||
class plSoundVolumeApplicator;
|
||||
|
||||
// Set this to 1 to do our own distance attenuation (model doesn't work yet tho)
|
||||
#define MCN_HACK_OUR_ATTEN 0
|
||||
#define MAX_INCIDENTALS 4
|
||||
|
||||
class plSound : public plSynchedObject
|
||||
{
|
||||
friend class plSoundSDLModifier;
|
||||
friend class plSoundVolumeApplicator;
|
||||
|
||||
public:
|
||||
plSound();
|
||||
virtual ~plSound();
|
||||
|
||||
CLASSNAME_REGISTER( plSound );
|
||||
GETINTERFACE_ANY( plSound, plSynchedObject );
|
||||
|
||||
enum Property
|
||||
{
|
||||
kPropIs3DSound = 0x00000001,
|
||||
kPropDisableLOD = 0x00000002,
|
||||
kPropLooping = 0x00000004,
|
||||
kPropAutoStart = 0x00000008,
|
||||
kPropLocalOnly = 0x00000010, // Disables network synching and triggering
|
||||
kPropLoadOnlyOnCall = 0x00000020, // Only load and unload when we're told to
|
||||
kPropFullyDisabled = 0x00000040, // This sound should never play while this is set
|
||||
// Only plWin32LinkSound uses it. Placed here as a TODO though...
|
||||
kPropDontFade = 0x00000080,
|
||||
kPropIncidental = 0x00000100 // Incidental sound, will be played thru the incidental manager
|
||||
};
|
||||
|
||||
enum Type
|
||||
{
|
||||
kStartType,
|
||||
kSoundFX = kStartType, // For now, 3D sounds are always marked as this
|
||||
kAmbience,
|
||||
kBackgroundMusic,
|
||||
kGUISound,
|
||||
kNPCVoices,
|
||||
kNumTypes
|
||||
};
|
||||
|
||||
enum Refs
|
||||
{
|
||||
kRefSoftVolume = 0,
|
||||
kRefDataBuffer, // plugins only
|
||||
kRefParentSceneObject,
|
||||
kRefSoftOcclusionRegion
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
kSoftRegion = 0
|
||||
};
|
||||
|
||||
enum StreamType
|
||||
{
|
||||
kNoStream,
|
||||
kStreamFromRAM,
|
||||
kStreamFromDisk,
|
||||
kStreamCompressed
|
||||
};
|
||||
|
||||
class plFadeParams
|
||||
{
|
||||
friend class plSound;
|
||||
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
kLinear,
|
||||
kLogarithmic,
|
||||
kExponential
|
||||
};
|
||||
|
||||
hsScalar fLengthInSecs; // Time to take to fade
|
||||
hsScalar fVolStart; // Set one of these two for fade in/out,
|
||||
hsScalar fVolEnd; // the other becomes the current volume
|
||||
UInt8 fType;
|
||||
hsBool fStopWhenDone; // Actually stop the sound once the fade is complete
|
||||
hsBool fFadeSoftVol; // Fade the soft volume instead of fCurrVolume
|
||||
|
||||
plFadeParams() { fLengthInSecs = 0.f; fCurrTime = -1.f; fStopWhenDone = false; fFadeSoftVol = false; fVolStart = fVolEnd = 0.f; fType = kLinear; }
|
||||
|
||||
plFadeParams( Type type, hsScalar len, hsScalar start, hsScalar end )
|
||||
{
|
||||
fLengthInSecs = len; fVolStart = start; fVolEnd = end; fType = type;
|
||||
fStopWhenDone = false;
|
||||
fFadeSoftVol = false;
|
||||
}
|
||||
|
||||
void Read( hsStream *s );
|
||||
void Write( hsStream *s );
|
||||
|
||||
hsScalar InterpValue( void );
|
||||
|
||||
protected:
|
||||
hsScalar fCurrTime; // -1 if we aren't active, else it's how far we're into the animation
|
||||
};
|
||||
|
||||
virtual hsBool LoadSound( hsBool is3D ) = 0;
|
||||
hsScalar GetVirtualStartTime( void ) const { return (hsScalar)fVirtualStartTime; }
|
||||
|
||||
virtual void Play();
|
||||
void SynchedPlay( unsigned bytes );
|
||||
void SynchedPlay( hsScalar virtualStartTime );
|
||||
virtual void Stop();
|
||||
virtual void FastForwardPlay();
|
||||
virtual void FastForwardToggle();
|
||||
virtual void SetMin(const int m); // sets minimum falloff distance
|
||||
virtual void SetMax(const int m); // sets maximum falloff distance
|
||||
virtual int GetMin() const;
|
||||
virtual int GetMax() const;
|
||||
virtual void SetVolume(const float volume);
|
||||
virtual float GetVolume(void) const { return fCurrVolume; }
|
||||
hsScalar GetMaxVolume() { return fMaxVolume; }
|
||||
virtual hsBool IsPlaying() { return fPlaying; }
|
||||
void SetTime(double t);
|
||||
virtual double GetTime( void ) { return 0.f; }
|
||||
virtual void Activate(hsBool forcePlay = false);
|
||||
virtual void DeActivate();
|
||||
virtual void SetLength(double l) { fLength = l; }
|
||||
virtual void SetMuted( hsBool muted );
|
||||
virtual hsBool IsMuted( void ) { return fMuted; }
|
||||
void Disable() { fDistAttenuation = 0; }
|
||||
virtual plSoundMsg* GetStatus(plSoundMsg* pMsg){return NULL;}
|
||||
virtual void SetConeOrientation(hsScalar x, hsScalar y, hsScalar z);
|
||||
virtual void SetOuterVolume( const int v ); // volume for the outer cone (if applicable)
|
||||
virtual void SetConeAngles( int inner, int outer );
|
||||
virtual void SetPosition(const hsPoint3 pos);
|
||||
virtual void SetVelocity(const hsVector3 vel);
|
||||
virtual hsPoint3 GetPosition() const;
|
||||
virtual hsVector3 GetVelocity() const;
|
||||
|
||||
virtual void Update();
|
||||
|
||||
plSoundBuffer * GetDataBuffer( void ) const { return (plSoundBuffer *)fDataBufferKey->ObjectIsLoaded(); }
|
||||
hsScalar QueryCurrVolume( void ) const; // Returns the current volume, attenuated
|
||||
|
||||
const char * GetFileName( void ) const;
|
||||
virtual double GetLength();
|
||||
|
||||
void SetProperty( Property prop, hsBool on ) { if( on ) fProperties |= prop; else fProperties &= ~prop; }
|
||||
hsBool IsPropertySet( Property prop ) const { return ( fProperties & prop ) ? true : false; }
|
||||
|
||||
virtual void RefreshVolume( void );
|
||||
|
||||
virtual void SetStartPos(unsigned bytes) = 0;
|
||||
virtual unsigned GetByteOffset(){return 0;}
|
||||
virtual float GetActualTimeSec() = 0;
|
||||
|
||||
virtual void AddCallbacks(plSoundMsg* pMsg) = 0;
|
||||
virtual void RemoveCallbacks(plSoundMsg* pMsg) = 0;
|
||||
|
||||
virtual UInt8 GetChannelSelect( void ) const { return 0; } // Only defined on Win32Sound right now, should be here tho
|
||||
|
||||
virtual void Read(hsStream* s, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* s, hsResMgr* mgr);
|
||||
|
||||
virtual void SetFadeInEffect( plFadeParams::Type type, hsScalar length );
|
||||
virtual void SetFadeOutEffect( plFadeParams::Type type, hsScalar length );
|
||||
virtual hsScalar CalcSoftVolume( hsBool enable, hsScalar distToListenerSquared );
|
||||
virtual void UpdateSoftVolume( hsBool enable, hsBool firstTime = false );
|
||||
|
||||
virtual hsBool MsgReceive( plMessage* pMsg );
|
||||
virtual hsBool DirtySynchState( const char *sdlName = nil, UInt32 sendFlags = 0 ); // call when state has changed
|
||||
|
||||
// Tests whether this sound is within range of the given position, not counting soft regions
|
||||
hsBool IsWithinRange( const hsPoint3 &listenerPos, hsScalar *distSquared );
|
||||
|
||||
// Type setting and getting, from the Types enum
|
||||
void SetType( UInt8 type ) { fType = type; }
|
||||
UInt8 GetType( void ) const { return fType; }
|
||||
|
||||
// Priority stuff
|
||||
void SetPriority( UInt8 pri ) { fPriority = pri; }
|
||||
UInt8 GetPriority( void ) const { return fPriority; }
|
||||
|
||||
// Visualization
|
||||
virtual plDrawableSpans* CreateProxy(const hsMatrix44& l2w, hsGMaterial* mat, hsTArray<UInt32>& idx, plDrawableSpans* addTo);
|
||||
|
||||
// Forced loading/unloading (for when the audio system's LOD just doesn't cut it)
|
||||
virtual void ForceLoad( );
|
||||
virtual void ForceUnload( void );
|
||||
|
||||
// Note: ONLY THE AUDIOSYS SHOULD CALL THIS. If you're not the audioSys, get lost.
|
||||
static void SetCurrDebugPlate( const plKey soundKey );
|
||||
|
||||
void RegisterOnAudioSys( void );
|
||||
void UnregisterOnAudioSys( void );
|
||||
|
||||
// Also only for the audio system
|
||||
hsScalar GetVolumeRank( void );
|
||||
void ForceUnregisterFromAudioSys( void );
|
||||
|
||||
static void SetLoadOnDemand( hsBool activate ) { fLoadOnDemandFlag = activate; }
|
||||
static void SetLoadFromDiskOnDemand( hsBool activate ) { fLoadFromDiskOnDemand = activate; }
|
||||
|
||||
const plEAXSourceSettings &GetEAXSettings( void ) const { return fEAXSettings; }
|
||||
plEAXSourceSettings &GetEAXSettings( void ) { return fEAXSettings; }
|
||||
virtual StreamType GetStreamType() const { return kNoStream; }
|
||||
virtual void FreeSoundData();
|
||||
|
||||
|
||||
protected:
|
||||
hsBool fPlaying;
|
||||
hsBool fActive;
|
||||
double fTime;
|
||||
int fMaxFalloff;
|
||||
int fMinFalloff;
|
||||
hsScalar fCurrVolume;
|
||||
hsScalar fDesiredVol; // Equal to fCurrVolume except when we're fading or muted
|
||||
hsScalar fFadedVolume;
|
||||
hsScalar fMaxVolume;
|
||||
|
||||
int fOuterVol;
|
||||
int fInnerCone;
|
||||
int fOuterCone;
|
||||
double fLength;
|
||||
|
||||
int fProperties;
|
||||
UInt8 fType;
|
||||
UInt8 fPriority;
|
||||
|
||||
hsBool fMuted, fFading, fRegisteredForTime, fPlayOnReactivate, fFreeData;
|
||||
hsBool fNotHighEnoughPriority; // Set whenever the audioSys calls UpdateSoftVolume() with enable=false,
|
||||
// thus indicating that we slipped off the top 16 most wanted list.
|
||||
|
||||
// Do these need to be synched values? They weren't before...
|
||||
hsVector3 fConeOrientation;
|
||||
hsPoint3 f3DPosition;
|
||||
hsVector3 f3DVelocity;
|
||||
hsBool fPlayWhenLoaded;
|
||||
|
||||
double fSynchedStartTimeSec;
|
||||
|
||||
// Just around for reference and sending messages upward (synched state)
|
||||
plSceneObject *fOwningSceneObject;
|
||||
|
||||
// EAX Settings storage here
|
||||
plEAXSourceSettings fEAXSettings;
|
||||
hsBool fQueued;
|
||||
|
||||
plFadeParams fFadeInParams, fFadeOutParams;
|
||||
plFadeParams fCoolSoftVolumeTrickParams;
|
||||
plFadeParams *fCurrFadeParams;
|
||||
|
||||
plSoftVolume *fSoftRegion;
|
||||
hsScalar fSoftVolume;
|
||||
hsScalar fDistAttenuation, fDistToListenerSquared;
|
||||
double fVirtualStartTime;
|
||||
hsBool fRegistered;
|
||||
static unsigned fIncidentalsPlaying;
|
||||
|
||||
plSoftVolume *fSoftOcclusionRegion;
|
||||
|
||||
plSoundBuffer *fDataBuffer; // Not always around
|
||||
hsBool fDataBufferLoaded;
|
||||
plKey fDataBufferKey; // Always around
|
||||
|
||||
static plGraphPlate *fDebugPlate;
|
||||
static plSound *fCurrDebugPlateSound;
|
||||
|
||||
static hsBool fLoadOnDemandFlag, fLoadFromDiskOnDemand;
|
||||
hsBool fLoading;
|
||||
|
||||
void IUpdateDebugPlate( void );
|
||||
void IPrintDbgMessage( const char *msg, hsBool isErr = false );
|
||||
|
||||
virtual void ISetActualVolume(const float v) = 0;
|
||||
virtual void IActuallyStop( void );
|
||||
virtual hsBool IActuallyPlaying( void ) = 0;
|
||||
virtual void IActuallyPlay( void ) = 0;
|
||||
virtual void IFreeBuffers( void ) = 0;
|
||||
|
||||
//NOTE: if isIncidental is true the entire sound will be loaded.
|
||||
virtual plSoundBuffer::ELoadReturnVal IPreLoadBuffer( hsBool playWhenLoaded, hsBool isIncidental = false );
|
||||
virtual void ISetActualTime( double t ) = 0;
|
||||
|
||||
virtual hsBool IActuallyLoaded( void ) = 0;
|
||||
virtual void IRefreshEAXSettings( hsBool force = false ) = 0;
|
||||
|
||||
virtual hsScalar IGetChannelVolume( void ) const;
|
||||
|
||||
void ISynchToStartTime( void );
|
||||
void ISynchedPlay( double virtualStartTime );
|
||||
void IStartFade( plFadeParams *params, hsScalar offsetIntoFade = 0.f );
|
||||
void IStopFade( hsBool shuttingDown = false, hsBool SetVolEnd = true);
|
||||
|
||||
hsBool IWillBeAbleToPlay( void );
|
||||
|
||||
void ISetSoftRegion( plSoftVolume *region );
|
||||
hsScalar IAttenuateActualVolume( hsScalar volume ) const;
|
||||
void ISetSoftOcclusionRegion( plSoftVolume *region );
|
||||
|
||||
// Override to make sure the buffer is available before the base class is called
|
||||
virtual void IRefreshParams( void );
|
||||
|
||||
virtual bool ILoadDataBuffer( void );
|
||||
virtual void IUnloadDataBuffer( void );
|
||||
|
||||
//virtual void ISetMinDistance( const int m ) = 0;
|
||||
//virtual void ISetMaxDistance( const int m ) = 0;
|
||||
//virtual void ISetOuterVolume( const int v ) = 0;
|
||||
//virtual void ISetConeAngles( int inner, int outer ) = 0;
|
||||
//virtual void ISetActualConeOrient( hsVector3 &vector ) = 0;
|
||||
//virtual void ISetVelocity( const hsVector3 vel ) = 0;
|
||||
//virtual void ISetPosition( const hsPoint3 pos ) = 0;
|
||||
|
||||
virtual void IRead( hsStream *s, hsResMgr *mgr );
|
||||
virtual void IWrite( hsStream *s, hsResMgr *mgr );
|
||||
};
|
||||
|
||||
|
||||
//// plSoundVolumeApplicator /////////////////////////////////////////////////
|
||||
// Tiny helper for handling animated volumes
|
||||
|
||||
class plSoundVolumeApplicator : public plAGApplicator
|
||||
{
|
||||
public:
|
||||
plSoundVolumeApplicator() { }
|
||||
plSoundVolumeApplicator( UInt32 index ) { fIndex = index; }
|
||||
|
||||
CLASSNAME_REGISTER( plSoundVolumeApplicator );
|
||||
GETINTERFACE_ANY( plSoundVolumeApplicator, plAGApplicator );
|
||||
|
||||
virtual plAGApplicator *CloneWithChannel( plAGChannel *channel );
|
||||
virtual void Write( hsStream *stream, hsResMgr *mgr );
|
||||
virtual void Read( hsStream *s, hsResMgr *mgr );
|
||||
|
||||
protected:
|
||||
UInt32 fIndex;
|
||||
virtual void IApply( const plAGModifier *mod, double time );
|
||||
};
|
||||
|
||||
#endif //plWin32Sound_h
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plSound.h - Base sound class header //
|
||||
// //
|
||||
//// History /////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// 10.12.01 mcn - Added preliminary soft region (volume) support. //
|
||||
// 7.12.02 mcn - Added EAX support //
|
||||
// 7.15.02 mcn - Added support for animated volumes //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef plSound_h
|
||||
#define plSound_h
|
||||
|
||||
#include "hsTemplates.h"
|
||||
#include "hsGeometry3.h"
|
||||
#include "plEAXEffects.h"
|
||||
#include "pnNetCommon/plSynchedObject.h"
|
||||
#include "plAvatar/plAGChannel.h"
|
||||
#include "plAvatar/plAGApplicator.h"
|
||||
#include "plAudioCore/plSoundBuffer.h"
|
||||
|
||||
class hsResMgr;
|
||||
class hsStream;
|
||||
class plSoundProxy;
|
||||
class plDrawableSpans;
|
||||
class hsGMaterial;
|
||||
class plSoundMsg;
|
||||
class plSoftVolume;
|
||||
class plGraphPlate;
|
||||
struct hsMatrix44;
|
||||
class plSoundBuffer;
|
||||
class plSceneObject;
|
||||
class plSoundVolumeApplicator;
|
||||
|
||||
// Set this to 1 to do our own distance attenuation (model doesn't work yet tho)
|
||||
#define MCN_HACK_OUR_ATTEN 0
|
||||
#define MAX_INCIDENTALS 4
|
||||
|
||||
class plSound : public plSynchedObject
|
||||
{
|
||||
friend class plSoundSDLModifier;
|
||||
friend class plSoundVolumeApplicator;
|
||||
|
||||
public:
|
||||
plSound();
|
||||
virtual ~plSound();
|
||||
|
||||
CLASSNAME_REGISTER( plSound );
|
||||
GETINTERFACE_ANY( plSound, plSynchedObject );
|
||||
|
||||
enum Property
|
||||
{
|
||||
kPropIs3DSound = 0x00000001,
|
||||
kPropDisableLOD = 0x00000002,
|
||||
kPropLooping = 0x00000004,
|
||||
kPropAutoStart = 0x00000008,
|
||||
kPropLocalOnly = 0x00000010, // Disables network synching and triggering
|
||||
kPropLoadOnlyOnCall = 0x00000020, // Only load and unload when we're told to
|
||||
kPropFullyDisabled = 0x00000040, // This sound should never play while this is set
|
||||
// Only plWin32LinkSound uses it. Placed here as a TODO though...
|
||||
kPropDontFade = 0x00000080,
|
||||
kPropIncidental = 0x00000100 // Incidental sound, will be played thru the incidental manager
|
||||
};
|
||||
|
||||
enum Type
|
||||
{
|
||||
kStartType,
|
||||
kSoundFX = kStartType, // For now, 3D sounds are always marked as this
|
||||
kAmbience,
|
||||
kBackgroundMusic,
|
||||
kGUISound,
|
||||
kNPCVoices,
|
||||
kNumTypes
|
||||
};
|
||||
|
||||
enum Refs
|
||||
{
|
||||
kRefSoftVolume = 0,
|
||||
kRefDataBuffer, // plugins only
|
||||
kRefParentSceneObject,
|
||||
kRefSoftOcclusionRegion
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
kSoftRegion = 0
|
||||
};
|
||||
|
||||
enum StreamType
|
||||
{
|
||||
kNoStream,
|
||||
kStreamFromRAM,
|
||||
kStreamFromDisk,
|
||||
kStreamCompressed
|
||||
};
|
||||
|
||||
class plFadeParams
|
||||
{
|
||||
friend class plSound;
|
||||
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
kLinear,
|
||||
kLogarithmic,
|
||||
kExponential
|
||||
};
|
||||
|
||||
hsScalar fLengthInSecs; // Time to take to fade
|
||||
hsScalar fVolStart; // Set one of these two for fade in/out,
|
||||
hsScalar fVolEnd; // the other becomes the current volume
|
||||
UInt8 fType;
|
||||
hsBool fStopWhenDone; // Actually stop the sound once the fade is complete
|
||||
hsBool fFadeSoftVol; // Fade the soft volume instead of fCurrVolume
|
||||
|
||||
plFadeParams() { fLengthInSecs = 0.f; fCurrTime = -1.f; fStopWhenDone = false; fFadeSoftVol = false; fVolStart = fVolEnd = 0.f; fType = kLinear; }
|
||||
|
||||
plFadeParams( Type type, hsScalar len, hsScalar start, hsScalar end )
|
||||
{
|
||||
fLengthInSecs = len; fVolStart = start; fVolEnd = end; fType = type;
|
||||
fStopWhenDone = false;
|
||||
fFadeSoftVol = false;
|
||||
}
|
||||
|
||||
void Read( hsStream *s );
|
||||
void Write( hsStream *s );
|
||||
|
||||
hsScalar InterpValue( void );
|
||||
|
||||
protected:
|
||||
hsScalar fCurrTime; // -1 if we aren't active, else it's how far we're into the animation
|
||||
};
|
||||
|
||||
virtual hsBool LoadSound( hsBool is3D ) = 0;
|
||||
hsScalar GetVirtualStartTime( void ) const { return (hsScalar)fVirtualStartTime; }
|
||||
|
||||
virtual void Play();
|
||||
void SynchedPlay( unsigned bytes );
|
||||
void SynchedPlay( hsScalar virtualStartTime );
|
||||
virtual void Stop();
|
||||
virtual void FastForwardPlay();
|
||||
virtual void FastForwardToggle();
|
||||
virtual void SetMin(const int m); // sets minimum falloff distance
|
||||
virtual void SetMax(const int m); // sets maximum falloff distance
|
||||
virtual int GetMin() const;
|
||||
virtual int GetMax() const;
|
||||
virtual void SetVolume(const float volume);
|
||||
virtual float GetVolume(void) const { return fCurrVolume; }
|
||||
hsScalar GetMaxVolume() { return fMaxVolume; }
|
||||
virtual hsBool IsPlaying() { return fPlaying; }
|
||||
void SetTime(double t);
|
||||
virtual double GetTime( void ) { return 0.f; }
|
||||
virtual void Activate(hsBool forcePlay = false);
|
||||
virtual void DeActivate();
|
||||
virtual void SetLength(double l) { fLength = l; }
|
||||
virtual void SetMuted( hsBool muted );
|
||||
virtual hsBool IsMuted( void ) { return fMuted; }
|
||||
void Disable() { fDistAttenuation = 0; }
|
||||
virtual plSoundMsg* GetStatus(plSoundMsg* pMsg){return NULL;}
|
||||
virtual void SetConeOrientation(hsScalar x, hsScalar y, hsScalar z);
|
||||
virtual void SetOuterVolume( const int v ); // volume for the outer cone (if applicable)
|
||||
virtual void SetConeAngles( int inner, int outer );
|
||||
virtual void SetPosition(const hsPoint3 pos);
|
||||
virtual void SetVelocity(const hsVector3 vel);
|
||||
virtual hsPoint3 GetPosition() const;
|
||||
virtual hsVector3 GetVelocity() const;
|
||||
|
||||
virtual void Update();
|
||||
|
||||
plSoundBuffer * GetDataBuffer( void ) const { return (plSoundBuffer *)fDataBufferKey->ObjectIsLoaded(); }
|
||||
hsScalar QueryCurrVolume( void ) const; // Returns the current volume, attenuated
|
||||
|
||||
const char * GetFileName( void ) const;
|
||||
virtual double GetLength();
|
||||
|
||||
void SetProperty( Property prop, hsBool on ) { if( on ) fProperties |= prop; else fProperties &= ~prop; }
|
||||
hsBool IsPropertySet( Property prop ) const { return ( fProperties & prop ) ? true : false; }
|
||||
|
||||
virtual void RefreshVolume( void );
|
||||
|
||||
virtual void SetStartPos(unsigned bytes) = 0;
|
||||
virtual unsigned GetByteOffset(){return 0;}
|
||||
virtual float GetActualTimeSec() = 0;
|
||||
|
||||
virtual void AddCallbacks(plSoundMsg* pMsg) = 0;
|
||||
virtual void RemoveCallbacks(plSoundMsg* pMsg) = 0;
|
||||
|
||||
virtual UInt8 GetChannelSelect( void ) const { return 0; } // Only defined on Win32Sound right now, should be here tho
|
||||
|
||||
virtual void Read(hsStream* s, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* s, hsResMgr* mgr);
|
||||
|
||||
virtual void SetFadeInEffect( plFadeParams::Type type, hsScalar length );
|
||||
virtual void SetFadeOutEffect( plFadeParams::Type type, hsScalar length );
|
||||
virtual hsScalar CalcSoftVolume( hsBool enable, hsScalar distToListenerSquared );
|
||||
virtual void UpdateSoftVolume( hsBool enable, hsBool firstTime = false );
|
||||
|
||||
virtual hsBool MsgReceive( plMessage* pMsg );
|
||||
virtual hsBool DirtySynchState( const char *sdlName = nil, UInt32 sendFlags = 0 ); // call when state has changed
|
||||
|
||||
// Tests whether this sound is within range of the given position, not counting soft regions
|
||||
hsBool IsWithinRange( const hsPoint3 &listenerPos, hsScalar *distSquared );
|
||||
|
||||
// Type setting and getting, from the Types enum
|
||||
void SetType( UInt8 type ) { fType = type; }
|
||||
UInt8 GetType( void ) const { return fType; }
|
||||
|
||||
// Priority stuff
|
||||
void SetPriority( UInt8 pri ) { fPriority = pri; }
|
||||
UInt8 GetPriority( void ) const { return fPriority; }
|
||||
|
||||
// Visualization
|
||||
virtual plDrawableSpans* CreateProxy(const hsMatrix44& l2w, hsGMaterial* mat, hsTArray<UInt32>& idx, plDrawableSpans* addTo);
|
||||
|
||||
// Forced loading/unloading (for when the audio system's LOD just doesn't cut it)
|
||||
virtual void ForceLoad( );
|
||||
virtual void ForceUnload( void );
|
||||
|
||||
// Note: ONLY THE AUDIOSYS SHOULD CALL THIS. If you're not the audioSys, get lost.
|
||||
static void SetCurrDebugPlate( const plKey soundKey );
|
||||
|
||||
void RegisterOnAudioSys( void );
|
||||
void UnregisterOnAudioSys( void );
|
||||
|
||||
// Also only for the audio system
|
||||
hsScalar GetVolumeRank( void );
|
||||
void ForceUnregisterFromAudioSys( void );
|
||||
|
||||
static void SetLoadOnDemand( hsBool activate ) { fLoadOnDemandFlag = activate; }
|
||||
static void SetLoadFromDiskOnDemand( hsBool activate ) { fLoadFromDiskOnDemand = activate; }
|
||||
|
||||
const plEAXSourceSettings &GetEAXSettings( void ) const { return fEAXSettings; }
|
||||
plEAXSourceSettings &GetEAXSettings( void ) { return fEAXSettings; }
|
||||
virtual StreamType GetStreamType() const { return kNoStream; }
|
||||
virtual void FreeSoundData();
|
||||
|
||||
|
||||
protected:
|
||||
hsBool fPlaying;
|
||||
hsBool fActive;
|
||||
double fTime;
|
||||
int fMaxFalloff;
|
||||
int fMinFalloff;
|
||||
hsScalar fCurrVolume;
|
||||
hsScalar fDesiredVol; // Equal to fCurrVolume except when we're fading or muted
|
||||
hsScalar fFadedVolume;
|
||||
hsScalar fMaxVolume;
|
||||
|
||||
int fOuterVol;
|
||||
int fInnerCone;
|
||||
int fOuterCone;
|
||||
double fLength;
|
||||
|
||||
int fProperties;
|
||||
UInt8 fType;
|
||||
UInt8 fPriority;
|
||||
|
||||
hsBool fMuted, fFading, fRegisteredForTime, fPlayOnReactivate, fFreeData;
|
||||
hsBool fNotHighEnoughPriority; // Set whenever the audioSys calls UpdateSoftVolume() with enable=false,
|
||||
// thus indicating that we slipped off the top 16 most wanted list.
|
||||
|
||||
// Do these need to be synched values? They weren't before...
|
||||
hsVector3 fConeOrientation;
|
||||
hsPoint3 f3DPosition;
|
||||
hsVector3 f3DVelocity;
|
||||
hsBool fPlayWhenLoaded;
|
||||
|
||||
double fSynchedStartTimeSec;
|
||||
|
||||
// Just around for reference and sending messages upward (synched state)
|
||||
plSceneObject *fOwningSceneObject;
|
||||
|
||||
// EAX Settings storage here
|
||||
plEAXSourceSettings fEAXSettings;
|
||||
hsBool fQueued;
|
||||
|
||||
plFadeParams fFadeInParams, fFadeOutParams;
|
||||
plFadeParams fCoolSoftVolumeTrickParams;
|
||||
plFadeParams *fCurrFadeParams;
|
||||
|
||||
plSoftVolume *fSoftRegion;
|
||||
hsScalar fSoftVolume;
|
||||
hsScalar fDistAttenuation, fDistToListenerSquared;
|
||||
double fVirtualStartTime;
|
||||
hsBool fRegistered;
|
||||
static unsigned fIncidentalsPlaying;
|
||||
|
||||
plSoftVolume *fSoftOcclusionRegion;
|
||||
|
||||
plSoundBuffer *fDataBuffer; // Not always around
|
||||
hsBool fDataBufferLoaded;
|
||||
plKey fDataBufferKey; // Always around
|
||||
|
||||
static plGraphPlate *fDebugPlate;
|
||||
static plSound *fCurrDebugPlateSound;
|
||||
|
||||
static hsBool fLoadOnDemandFlag, fLoadFromDiskOnDemand;
|
||||
hsBool fLoading;
|
||||
|
||||
void IUpdateDebugPlate( void );
|
||||
void IPrintDbgMessage( const char *msg, hsBool isErr = false );
|
||||
|
||||
virtual void ISetActualVolume(const float v) = 0;
|
||||
virtual void IActuallyStop( void );
|
||||
virtual hsBool IActuallyPlaying( void ) = 0;
|
||||
virtual void IActuallyPlay( void ) = 0;
|
||||
virtual void IFreeBuffers( void ) = 0;
|
||||
|
||||
//NOTE: if isIncidental is true the entire sound will be loaded.
|
||||
virtual plSoundBuffer::ELoadReturnVal IPreLoadBuffer( hsBool playWhenLoaded, hsBool isIncidental = false );
|
||||
virtual void ISetActualTime( double t ) = 0;
|
||||
|
||||
virtual hsBool IActuallyLoaded( void ) = 0;
|
||||
virtual void IRefreshEAXSettings( hsBool force = false ) = 0;
|
||||
|
||||
virtual hsScalar IGetChannelVolume( void ) const;
|
||||
|
||||
void ISynchToStartTime( void );
|
||||
void ISynchedPlay( double virtualStartTime );
|
||||
void IStartFade( plFadeParams *params, hsScalar offsetIntoFade = 0.f );
|
||||
void IStopFade( hsBool shuttingDown = false, hsBool SetVolEnd = true);
|
||||
|
||||
hsBool IWillBeAbleToPlay( void );
|
||||
|
||||
void ISetSoftRegion( plSoftVolume *region );
|
||||
hsScalar IAttenuateActualVolume( hsScalar volume ) const;
|
||||
void ISetSoftOcclusionRegion( plSoftVolume *region );
|
||||
|
||||
// Override to make sure the buffer is available before the base class is called
|
||||
virtual void IRefreshParams( void );
|
||||
|
||||
virtual bool ILoadDataBuffer( void );
|
||||
virtual void IUnloadDataBuffer( void );
|
||||
|
||||
//virtual void ISetMinDistance( const int m ) = 0;
|
||||
//virtual void ISetMaxDistance( const int m ) = 0;
|
||||
//virtual void ISetOuterVolume( const int v ) = 0;
|
||||
//virtual void ISetConeAngles( int inner, int outer ) = 0;
|
||||
//virtual void ISetActualConeOrient( hsVector3 &vector ) = 0;
|
||||
//virtual void ISetVelocity( const hsVector3 vel ) = 0;
|
||||
//virtual void ISetPosition( const hsPoint3 pos ) = 0;
|
||||
|
||||
virtual void IRead( hsStream *s, hsResMgr *mgr );
|
||||
virtual void IWrite( hsStream *s, hsResMgr *mgr );
|
||||
};
|
||||
|
||||
|
||||
//// plSoundVolumeApplicator /////////////////////////////////////////////////
|
||||
// Tiny helper for handling animated volumes
|
||||
|
||||
class plSoundVolumeApplicator : public plAGApplicator
|
||||
{
|
||||
public:
|
||||
plSoundVolumeApplicator() { }
|
||||
plSoundVolumeApplicator( UInt32 index ) { fIndex = index; }
|
||||
|
||||
CLASSNAME_REGISTER( plSoundVolumeApplicator );
|
||||
GETINTERFACE_ANY( plSoundVolumeApplicator, plAGApplicator );
|
||||
|
||||
virtual plAGApplicator *CloneWithChannel( plAGChannel *channel );
|
||||
virtual void Write( hsStream *stream, hsResMgr *mgr );
|
||||
virtual void Read( hsStream *s, hsResMgr *mgr );
|
||||
|
||||
protected:
|
||||
UInt32 fIndex;
|
||||
virtual void IApply( const plAGModifier *mod, double time );
|
||||
};
|
||||
|
||||
#endif //plWin32Sound_h
|
||||
|
@ -1,183 +1,183 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plSoundEvent //
|
||||
// //
|
||||
//// Notes ///////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// 10.30.2001 - Created by mcn. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "plSoundEvent.h"
|
||||
|
||||
#include "plgDispatch.h"
|
||||
#include "pnMessage/plEventCallbackMsg.h"
|
||||
#include "pnMessage/plSoundMsg.h"
|
||||
#include "plSound.h"
|
||||
|
||||
plSoundEvent::plSoundEvent( Types type, plSound *owner )
|
||||
{
|
||||
fType = type;
|
||||
fBytePosTime = 0;
|
||||
fOwner = owner;
|
||||
fCallbacks.Reset();
|
||||
fCallbackEndingFlags.Reset();
|
||||
}
|
||||
|
||||
plSoundEvent::plSoundEvent( Types type, UInt32 bytePos, plSound *owner )
|
||||
{
|
||||
fType = type;
|
||||
fBytePosTime = bytePos;
|
||||
fOwner = owner;
|
||||
fCallbacks.Reset();
|
||||
fCallbackEndingFlags.Reset();
|
||||
}
|
||||
|
||||
plSoundEvent::plSoundEvent()
|
||||
{
|
||||
fType = kStart;
|
||||
fBytePosTime = 0;
|
||||
fOwner = nil;
|
||||
fCallbacks.Reset();
|
||||
fCallbackEndingFlags.Reset();
|
||||
}
|
||||
|
||||
plSoundEvent::~plSoundEvent()
|
||||
{
|
||||
int i;
|
||||
|
||||
|
||||
for( i = 0; i < fCallbacks.GetCount(); i++ )
|
||||
hsRefCnt_SafeUnRef( fCallbacks[ i ] );
|
||||
}
|
||||
|
||||
void plSoundEvent::AddCallback( plEventCallbackMsg *msg )
|
||||
{
|
||||
hsRefCnt_SafeRef( msg );
|
||||
fCallbacks.Append( msg );
|
||||
fCallbackEndingFlags.Append( 0 );
|
||||
}
|
||||
|
||||
hsBool plSoundEvent::RemoveCallback( plEventCallbackMsg *msg )
|
||||
{
|
||||
int idx = fCallbacks.Find( msg );
|
||||
if( idx != fCallbacks.kMissingIndex )
|
||||
{
|
||||
hsRefCnt_SafeUnRef( msg );
|
||||
fCallbacks.Remove( idx );
|
||||
fCallbackEndingFlags.Remove( idx );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void plSoundEvent::SendCallbacks( void )
|
||||
{
|
||||
int j;
|
||||
plSoundMsg *sMsg;
|
||||
|
||||
|
||||
for( j = fCallbacks.GetCount() - 1; j >= 0; j-- )
|
||||
{
|
||||
plEventCallbackMsg *msg = fCallbacks[ j ];
|
||||
|
||||
if (!msg->HasBCastFlag(plMessage::kNetPropagate) || !fOwner ||
|
||||
fOwner->IsLocallyOwned() == plSynchedObject::kYes )
|
||||
{
|
||||
/// Do this a bit differently so we can do our MsgSend last
|
||||
sMsg = nil;
|
||||
|
||||
// Ref to make sure the dispatcher doesn't delete it on us
|
||||
hsRefCnt_SafeRef( msg );
|
||||
if( msg->fRepeats == 0 && fCallbackEndingFlags[ j ] == 0 )
|
||||
{
|
||||
// Note: we get fancy here. We never want to remove the callback directly,
|
||||
// because the sound won't know about it. So instead, send it a message to
|
||||
// remove the callback for us
|
||||
sMsg = TRACKED_NEW plSoundMsg();
|
||||
sMsg->SetBCastFlag( plMessage::kLocalPropagate, true );
|
||||
sMsg->AddReceiver( fOwner->GetKey() );
|
||||
sMsg->SetCmd( plSoundMsg::kRemoveCallbacks );
|
||||
sMsg->AddCallback( msg );
|
||||
}
|
||||
|
||||
// If this isn't infinite, decrement the number of repeats
|
||||
if( msg->fRepeats > 0 )
|
||||
msg->fRepeats--;
|
||||
|
||||
// And finally...
|
||||
if( fCallbackEndingFlags[ j ] == 0 )
|
||||
{
|
||||
plgDispatch::MsgSend( msg, true );
|
||||
}
|
||||
|
||||
if( sMsg != nil )
|
||||
{
|
||||
plgDispatch::MsgSend( sMsg, true );
|
||||
fCallbackEndingFlags[ j ] = 0xff; // Our special flag to mean "hey, don't
|
||||
// process this, just waiting for
|
||||
// it to die"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 plSoundEvent::GetNumCallbacks( void ) const
|
||||
{
|
||||
return fCallbacks.GetCount();
|
||||
}
|
||||
|
||||
int plSoundEvent::GetType( void ) const
|
||||
{
|
||||
return (int)fType;
|
||||
}
|
||||
|
||||
void plSoundEvent::SetType( Types type )
|
||||
{
|
||||
fType = type;
|
||||
}
|
||||
|
||||
UInt32 plSoundEvent::GetTime( void ) const
|
||||
{
|
||||
return fBytePosTime;
|
||||
}
|
||||
|
||||
plSoundEvent::Types plSoundEvent::GetTypeFromCallbackMsg( plEventCallbackMsg *msg )
|
||||
{
|
||||
switch( msg->fEvent )
|
||||
{
|
||||
case ::kStart: return kStart;
|
||||
case ::kTime: return kTime;
|
||||
case ::kStop: return kStop;
|
||||
case ::kLoop: return kLoop;
|
||||
}
|
||||
|
||||
return kStop;
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plSoundEvent //
|
||||
// //
|
||||
//// Notes ///////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// 10.30.2001 - Created by mcn. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "plSoundEvent.h"
|
||||
|
||||
#include "plgDispatch.h"
|
||||
#include "pnMessage/plEventCallbackMsg.h"
|
||||
#include "pnMessage/plSoundMsg.h"
|
||||
#include "plSound.h"
|
||||
|
||||
plSoundEvent::plSoundEvent( Types type, plSound *owner )
|
||||
{
|
||||
fType = type;
|
||||
fBytePosTime = 0;
|
||||
fOwner = owner;
|
||||
fCallbacks.Reset();
|
||||
fCallbackEndingFlags.Reset();
|
||||
}
|
||||
|
||||
plSoundEvent::plSoundEvent( Types type, UInt32 bytePos, plSound *owner )
|
||||
{
|
||||
fType = type;
|
||||
fBytePosTime = bytePos;
|
||||
fOwner = owner;
|
||||
fCallbacks.Reset();
|
||||
fCallbackEndingFlags.Reset();
|
||||
}
|
||||
|
||||
plSoundEvent::plSoundEvent()
|
||||
{
|
||||
fType = kStart;
|
||||
fBytePosTime = 0;
|
||||
fOwner = nil;
|
||||
fCallbacks.Reset();
|
||||
fCallbackEndingFlags.Reset();
|
||||
}
|
||||
|
||||
plSoundEvent::~plSoundEvent()
|
||||
{
|
||||
int i;
|
||||
|
||||
|
||||
for( i = 0; i < fCallbacks.GetCount(); i++ )
|
||||
hsRefCnt_SafeUnRef( fCallbacks[ i ] );
|
||||
}
|
||||
|
||||
void plSoundEvent::AddCallback( plEventCallbackMsg *msg )
|
||||
{
|
||||
hsRefCnt_SafeRef( msg );
|
||||
fCallbacks.Append( msg );
|
||||
fCallbackEndingFlags.Append( 0 );
|
||||
}
|
||||
|
||||
hsBool plSoundEvent::RemoveCallback( plEventCallbackMsg *msg )
|
||||
{
|
||||
int idx = fCallbacks.Find( msg );
|
||||
if( idx != fCallbacks.kMissingIndex )
|
||||
{
|
||||
hsRefCnt_SafeUnRef( msg );
|
||||
fCallbacks.Remove( idx );
|
||||
fCallbackEndingFlags.Remove( idx );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void plSoundEvent::SendCallbacks( void )
|
||||
{
|
||||
int j;
|
||||
plSoundMsg *sMsg;
|
||||
|
||||
|
||||
for( j = fCallbacks.GetCount() - 1; j >= 0; j-- )
|
||||
{
|
||||
plEventCallbackMsg *msg = fCallbacks[ j ];
|
||||
|
||||
if (!msg->HasBCastFlag(plMessage::kNetPropagate) || !fOwner ||
|
||||
fOwner->IsLocallyOwned() == plSynchedObject::kYes )
|
||||
{
|
||||
/// Do this a bit differently so we can do our MsgSend last
|
||||
sMsg = nil;
|
||||
|
||||
// Ref to make sure the dispatcher doesn't delete it on us
|
||||
hsRefCnt_SafeRef( msg );
|
||||
if( msg->fRepeats == 0 && fCallbackEndingFlags[ j ] == 0 )
|
||||
{
|
||||
// Note: we get fancy here. We never want to remove the callback directly,
|
||||
// because the sound won't know about it. So instead, send it a message to
|
||||
// remove the callback for us
|
||||
sMsg = TRACKED_NEW plSoundMsg();
|
||||
sMsg->SetBCastFlag( plMessage::kLocalPropagate, true );
|
||||
sMsg->AddReceiver( fOwner->GetKey() );
|
||||
sMsg->SetCmd( plSoundMsg::kRemoveCallbacks );
|
||||
sMsg->AddCallback( msg );
|
||||
}
|
||||
|
||||
// If this isn't infinite, decrement the number of repeats
|
||||
if( msg->fRepeats > 0 )
|
||||
msg->fRepeats--;
|
||||
|
||||
// And finally...
|
||||
if( fCallbackEndingFlags[ j ] == 0 )
|
||||
{
|
||||
plgDispatch::MsgSend( msg, true );
|
||||
}
|
||||
|
||||
if( sMsg != nil )
|
||||
{
|
||||
plgDispatch::MsgSend( sMsg, true );
|
||||
fCallbackEndingFlags[ j ] = 0xff; // Our special flag to mean "hey, don't
|
||||
// process this, just waiting for
|
||||
// it to die"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 plSoundEvent::GetNumCallbacks( void ) const
|
||||
{
|
||||
return fCallbacks.GetCount();
|
||||
}
|
||||
|
||||
int plSoundEvent::GetType( void ) const
|
||||
{
|
||||
return (int)fType;
|
||||
}
|
||||
|
||||
void plSoundEvent::SetType( Types type )
|
||||
{
|
||||
fType = type;
|
||||
}
|
||||
|
||||
UInt32 plSoundEvent::GetTime( void ) const
|
||||
{
|
||||
return fBytePosTime;
|
||||
}
|
||||
|
||||
plSoundEvent::Types plSoundEvent::GetTypeFromCallbackMsg( plEventCallbackMsg *msg )
|
||||
{
|
||||
switch( msg->fEvent )
|
||||
{
|
||||
case ::kStart: return kStart;
|
||||
case ::kTime: return kTime;
|
||||
case ::kStop: return kStop;
|
||||
case ::kLoop: return kLoop;
|
||||
}
|
||||
|
||||
return kStop;
|
||||
}
|
@ -1,83 +1,83 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plSoundEvent - Event node for handling callback thread stuff //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _plSoundEvent_h
|
||||
#define _plSoundEvent_h
|
||||
|
||||
#include "hsTemplates.h"
|
||||
|
||||
class plEventCallbackMsg;
|
||||
class plSound;
|
||||
|
||||
//// plSoundEvent ////////////////////////////////////////////////////////////
|
||||
// Storage class for an event node.
|
||||
|
||||
class plSoundEvent
|
||||
{
|
||||
public:
|
||||
|
||||
enum Types
|
||||
{
|
||||
kStart,
|
||||
kStop,
|
||||
kTime,
|
||||
kLoop
|
||||
};
|
||||
|
||||
plSoundEvent( Types type, plSound *owner );
|
||||
plSoundEvent( Types type, UInt32 bytePos, plSound *owner );
|
||||
plSoundEvent();
|
||||
~plSoundEvent();
|
||||
|
||||
void AddCallback( plEventCallbackMsg *msg );
|
||||
hsBool RemoveCallback( plEventCallbackMsg *msg );
|
||||
|
||||
UInt32 GetNumCallbacks( void ) const;
|
||||
int GetType( void ) const;
|
||||
void SetType( Types type );
|
||||
UInt32 GetTime( void ) const;
|
||||
|
||||
void SendCallbacks( void );
|
||||
|
||||
static Types GetTypeFromCallbackMsg( plEventCallbackMsg *msg );
|
||||
|
||||
protected:
|
||||
|
||||
Types fType;
|
||||
UInt32 fBytePosTime;
|
||||
plSound *fOwner;
|
||||
|
||||
hsTArray<plEventCallbackMsg *> fCallbacks;
|
||||
hsTArray<UInt8> fCallbackEndingFlags;
|
||||
};
|
||||
|
||||
|
||||
#endif //_plSoundEvent_h
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plSoundEvent - Event node for handling callback thread stuff //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _plSoundEvent_h
|
||||
#define _plSoundEvent_h
|
||||
|
||||
#include "hsTemplates.h"
|
||||
|
||||
class plEventCallbackMsg;
|
||||
class plSound;
|
||||
|
||||
//// plSoundEvent ////////////////////////////////////////////////////////////
|
||||
// Storage class for an event node.
|
||||
|
||||
class plSoundEvent
|
||||
{
|
||||
public:
|
||||
|
||||
enum Types
|
||||
{
|
||||
kStart,
|
||||
kStop,
|
||||
kTime,
|
||||
kLoop
|
||||
};
|
||||
|
||||
plSoundEvent( Types type, plSound *owner );
|
||||
plSoundEvent( Types type, UInt32 bytePos, plSound *owner );
|
||||
plSoundEvent();
|
||||
~plSoundEvent();
|
||||
|
||||
void AddCallback( plEventCallbackMsg *msg );
|
||||
hsBool RemoveCallback( plEventCallbackMsg *msg );
|
||||
|
||||
UInt32 GetNumCallbacks( void ) const;
|
||||
int GetType( void ) const;
|
||||
void SetType( Types type );
|
||||
UInt32 GetTime( void ) const;
|
||||
|
||||
void SendCallbacks( void );
|
||||
|
||||
static Types GetTypeFromCallbackMsg( plEventCallbackMsg *msg );
|
||||
|
||||
protected:
|
||||
|
||||
Types fType;
|
||||
UInt32 fBytePosTime;
|
||||
plSound *fOwner;
|
||||
|
||||
hsTArray<plEventCallbackMsg *> fCallbacks;
|
||||
hsTArray<UInt8> fCallbackEndingFlags;
|
||||
};
|
||||
|
||||
|
||||
#endif //_plSoundEvent_h
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,196 +1,196 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#ifndef plVoiceChat_h
|
||||
#define plVoiceChat_h
|
||||
|
||||
#include "hsTemplates.h"
|
||||
#include "plWin32Sound.h"
|
||||
#include "hsThread.h"
|
||||
|
||||
// voice flags
|
||||
#define VOICE_ENCODED ( 1 << 0 )
|
||||
#define VOICE_NARROWBAND ( 1 << 1 )
|
||||
#define VOICE_ENH ( 1 << 2 )
|
||||
#define BUFFER_LEN_SECONDS 4
|
||||
#define FREQUENCY 8000
|
||||
|
||||
struct hsVector3;
|
||||
struct SpeexBits;
|
||||
class plWinAudible;
|
||||
class plPlate;
|
||||
class plStatusLog;
|
||||
class plSpeex;
|
||||
typedef struct ALCdevice_struct ALCdevice;
|
||||
|
||||
|
||||
// Sound used for playing back dynamic voice chat data. this allows us to hook voice chat into the audio system
|
||||
class plVoiceSound : public plWin32Sound
|
||||
{
|
||||
public:
|
||||
plVoiceSound();
|
||||
~plVoiceSound();
|
||||
hsBool LoadSound( hsBool is3D );
|
||||
void AddVoiceData(void *data, unsigned bytes);
|
||||
void Update();
|
||||
void Play();
|
||||
virtual void SetStartPos(unsigned bytes){}
|
||||
|
||||
private:
|
||||
virtual bool ILoadDataBuffer( void ){ return true; }
|
||||
virtual void IUnloadDataBuffer( void ){}
|
||||
|
||||
virtual void IDerivedActuallyPlay( void );
|
||||
virtual void ISetActualTime( double t ){}
|
||||
virtual float GetActualTimeSec() { return 0.0f; }
|
||||
virtual void IRefreshParams( void );
|
||||
static unsigned fCount;
|
||||
double fLastUpdate;
|
||||
};
|
||||
|
||||
class plVoicePlayer
|
||||
{
|
||||
public:
|
||||
plVoicePlayer();
|
||||
~plVoicePlayer();
|
||||
void PlaybackVoiceMessage(void* data, unsigned size, int numFramesInBuffer);
|
||||
void PlaybackUncompressedVoiceMessage(void* data, unsigned size);
|
||||
void SetVelocity(const hsVector3 vel);
|
||||
void SetPosition(const hsPoint3 pos);
|
||||
void SetOrientation(const hsPoint3 pos);
|
||||
|
||||
void SetTalkIcon(int index, UInt32 str){}
|
||||
void ClearTalkIcon(){}
|
||||
plVoiceSound *GetSoundPtr() { return &fSound; }
|
||||
static void Enable(hsBool enable) { fEnabled = enable; }
|
||||
|
||||
private:
|
||||
plVoiceSound fSound;
|
||||
static hsBool fEnabled;
|
||||
};
|
||||
|
||||
class plVoiceRecorder
|
||||
{
|
||||
public:
|
||||
plVoiceRecorder();
|
||||
~plVoiceRecorder();
|
||||
|
||||
void Update(double time);
|
||||
void SetMikeOpen(hsBool b);
|
||||
void DrawTalkIcon(hsBool b);
|
||||
void DrawDisabledIcon(hsBool b);
|
||||
|
||||
void SetTalkIcon(int index, UInt32 str);
|
||||
void ClearTalkIcon();
|
||||
|
||||
static hsBool RecordingEnabled() { return fRecording; }
|
||||
static hsBool NetVoiceEnabled() { return fNetVoice; }
|
||||
static hsBool CompressionEnabled() { return fCompress; }
|
||||
static void EnablePushToTalk(hsBool b) { fMicAlwaysOpen = !b; }
|
||||
static void EnableIcons(hsBool b) { fShowIcons = b; }
|
||||
static void EnableRecording(hsBool b) { fRecording = b; }
|
||||
static void EnableNetVoice(hsBool b) { fNetVoice = b; }
|
||||
static void EnableCompression(hsBool b) { fCompress = b; }
|
||||
static void SetSampleRate(short s) { fSampleRate = s; }
|
||||
static void SetSquelch(hsScalar f) { fRecordThreshhold = f; }
|
||||
|
||||
static void IncreaseRecordingThreshhold();
|
||||
static void DecreaseRecordingThreshhold();
|
||||
|
||||
static void SetQuality(int quality); // sets the quality of encoding
|
||||
static void SetMode(int mode); // sets nb or wb mode
|
||||
static void SetVBR(bool vbr);
|
||||
static void SetComplexity(int c);
|
||||
static void SetENH(hsBool b);
|
||||
static short GetSampleRate() { return fSampleRate; }
|
||||
|
||||
private:
|
||||
|
||||
hsBool fMikeOpen;
|
||||
hsBool fMikeJustClosed;
|
||||
static hsBool fMicAlwaysOpen;
|
||||
static hsBool fShowIcons;
|
||||
static hsBool fCompress;
|
||||
static hsBool fNetVoice;
|
||||
static hsBool fRecording;
|
||||
static short fSampleRate;
|
||||
plPlate* fDisabledIcon;
|
||||
plPlate* fTalkIcon;
|
||||
static hsScalar fRecordThreshhold;
|
||||
};
|
||||
|
||||
|
||||
// Speex voice encoder/decoder class
|
||||
class plSpeex
|
||||
{
|
||||
public:
|
||||
~plSpeex();
|
||||
|
||||
enum Mode
|
||||
{
|
||||
kNarrowband,
|
||||
kWideband,
|
||||
kUltraWideband
|
||||
};
|
||||
static plSpeex *GetInstance()
|
||||
{
|
||||
static plSpeex instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
hsBool Init(Mode mode);
|
||||
hsBool Shutdown();
|
||||
hsBool Encode(short *data, int numFrames, int *packedLength, hsRAMStream *out);
|
||||
hsBool Decode(UInt8 *data, int size, int numFrames, int *numOutputBytes, short *out);
|
||||
int GetFrameSize() { return fFrameSize; }
|
||||
void VBR(hsBool b); // turn variable bit rate on/off
|
||||
void SetVBR(UInt32 vbr); // Set variable bit rate quality
|
||||
void ABR(hsBool b); // turn average bit rate on/off
|
||||
void SetABR(UInt32 abr); // Set average bit rate quality
|
||||
void SetQuality(UInt32 quality); // Set encoder quality
|
||||
hsBool IsUsingVBR() { return fVBR; }
|
||||
int GetQuality() { return fQuality; }
|
||||
void SetENH(hsBool b);
|
||||
void SetComplexity(UInt8 c);
|
||||
|
||||
hsBool Initialized() { return fInitialized; }
|
||||
|
||||
private:
|
||||
plSpeex();
|
||||
SpeexBits* fBits; // main speex structure
|
||||
hsBool fBitsInit;
|
||||
void* fEncoderState;
|
||||
void* fDecoderState;
|
||||
int fSampleRate;
|
||||
int fFrameSize; // frame size from speex - 160 for nb
|
||||
int fQuality; // 0-10 speex encode quality
|
||||
hsBool fVBR; // toggle variable bit rate
|
||||
int fAverageBitrate; // n-bits per second
|
||||
UInt8 fComplexity; // 1-10 sets cpu resources allowed for encoder
|
||||
hsBool fENH; // perceptual enhancement
|
||||
hsBool fInitialized;
|
||||
};
|
||||
|
||||
#endif //plVoiceChat_h
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#ifndef plVoiceChat_h
|
||||
#define plVoiceChat_h
|
||||
|
||||
#include "hsTemplates.h"
|
||||
#include "plWin32Sound.h"
|
||||
#include "hsThread.h"
|
||||
|
||||
// voice flags
|
||||
#define VOICE_ENCODED ( 1 << 0 )
|
||||
#define VOICE_NARROWBAND ( 1 << 1 )
|
||||
#define VOICE_ENH ( 1 << 2 )
|
||||
#define BUFFER_LEN_SECONDS 4
|
||||
#define FREQUENCY 8000
|
||||
|
||||
struct hsVector3;
|
||||
struct SpeexBits;
|
||||
class plWinAudible;
|
||||
class plPlate;
|
||||
class plStatusLog;
|
||||
class plSpeex;
|
||||
typedef struct ALCdevice_struct ALCdevice;
|
||||
|
||||
|
||||
// Sound used for playing back dynamic voice chat data. this allows us to hook voice chat into the audio system
|
||||
class plVoiceSound : public plWin32Sound
|
||||
{
|
||||
public:
|
||||
plVoiceSound();
|
||||
~plVoiceSound();
|
||||
hsBool LoadSound( hsBool is3D );
|
||||
void AddVoiceData(void *data, unsigned bytes);
|
||||
void Update();
|
||||
void Play();
|
||||
virtual void SetStartPos(unsigned bytes){}
|
||||
|
||||
private:
|
||||
virtual bool ILoadDataBuffer( void ){ return true; }
|
||||
virtual void IUnloadDataBuffer( void ){}
|
||||
|
||||
virtual void IDerivedActuallyPlay( void );
|
||||
virtual void ISetActualTime( double t ){}
|
||||
virtual float GetActualTimeSec() { return 0.0f; }
|
||||
virtual void IRefreshParams( void );
|
||||
static unsigned fCount;
|
||||
double fLastUpdate;
|
||||
};
|
||||
|
||||
class plVoicePlayer
|
||||
{
|
||||
public:
|
||||
plVoicePlayer();
|
||||
~plVoicePlayer();
|
||||
void PlaybackVoiceMessage(void* data, unsigned size, int numFramesInBuffer);
|
||||
void PlaybackUncompressedVoiceMessage(void* data, unsigned size);
|
||||
void SetVelocity(const hsVector3 vel);
|
||||
void SetPosition(const hsPoint3 pos);
|
||||
void SetOrientation(const hsPoint3 pos);
|
||||
|
||||
void SetTalkIcon(int index, UInt32 str){}
|
||||
void ClearTalkIcon(){}
|
||||
plVoiceSound *GetSoundPtr() { return &fSound; }
|
||||
static void Enable(hsBool enable) { fEnabled = enable; }
|
||||
|
||||
private:
|
||||
plVoiceSound fSound;
|
||||
static hsBool fEnabled;
|
||||
};
|
||||
|
||||
class plVoiceRecorder
|
||||
{
|
||||
public:
|
||||
plVoiceRecorder();
|
||||
~plVoiceRecorder();
|
||||
|
||||
void Update(double time);
|
||||
void SetMikeOpen(hsBool b);
|
||||
void DrawTalkIcon(hsBool b);
|
||||
void DrawDisabledIcon(hsBool b);
|
||||
|
||||
void SetTalkIcon(int index, UInt32 str);
|
||||
void ClearTalkIcon();
|
||||
|
||||
static hsBool RecordingEnabled() { return fRecording; }
|
||||
static hsBool NetVoiceEnabled() { return fNetVoice; }
|
||||
static hsBool CompressionEnabled() { return fCompress; }
|
||||
static void EnablePushToTalk(hsBool b) { fMicAlwaysOpen = !b; }
|
||||
static void EnableIcons(hsBool b) { fShowIcons = b; }
|
||||
static void EnableRecording(hsBool b) { fRecording = b; }
|
||||
static void EnableNetVoice(hsBool b) { fNetVoice = b; }
|
||||
static void EnableCompression(hsBool b) { fCompress = b; }
|
||||
static void SetSampleRate(short s) { fSampleRate = s; }
|
||||
static void SetSquelch(hsScalar f) { fRecordThreshhold = f; }
|
||||
|
||||
static void IncreaseRecordingThreshhold();
|
||||
static void DecreaseRecordingThreshhold();
|
||||
|
||||
static void SetQuality(int quality); // sets the quality of encoding
|
||||
static void SetMode(int mode); // sets nb or wb mode
|
||||
static void SetVBR(bool vbr);
|
||||
static void SetComplexity(int c);
|
||||
static void SetENH(hsBool b);
|
||||
static short GetSampleRate() { return fSampleRate; }
|
||||
|
||||
private:
|
||||
|
||||
hsBool fMikeOpen;
|
||||
hsBool fMikeJustClosed;
|
||||
static hsBool fMicAlwaysOpen;
|
||||
static hsBool fShowIcons;
|
||||
static hsBool fCompress;
|
||||
static hsBool fNetVoice;
|
||||
static hsBool fRecording;
|
||||
static short fSampleRate;
|
||||
plPlate* fDisabledIcon;
|
||||
plPlate* fTalkIcon;
|
||||
static hsScalar fRecordThreshhold;
|
||||
};
|
||||
|
||||
|
||||
// Speex voice encoder/decoder class
|
||||
class plSpeex
|
||||
{
|
||||
public:
|
||||
~plSpeex();
|
||||
|
||||
enum Mode
|
||||
{
|
||||
kNarrowband,
|
||||
kWideband,
|
||||
kUltraWideband
|
||||
};
|
||||
static plSpeex *GetInstance()
|
||||
{
|
||||
static plSpeex instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
hsBool Init(Mode mode);
|
||||
hsBool Shutdown();
|
||||
hsBool Encode(short *data, int numFrames, int *packedLength, hsRAMStream *out);
|
||||
hsBool Decode(UInt8 *data, int size, int numFrames, int *numOutputBytes, short *out);
|
||||
int GetFrameSize() { return fFrameSize; }
|
||||
void VBR(hsBool b); // turn variable bit rate on/off
|
||||
void SetVBR(UInt32 vbr); // Set variable bit rate quality
|
||||
void ABR(hsBool b); // turn average bit rate on/off
|
||||
void SetABR(UInt32 abr); // Set average bit rate quality
|
||||
void SetQuality(UInt32 quality); // Set encoder quality
|
||||
hsBool IsUsingVBR() { return fVBR; }
|
||||
int GetQuality() { return fQuality; }
|
||||
void SetENH(hsBool b);
|
||||
void SetComplexity(UInt8 c);
|
||||
|
||||
hsBool Initialized() { return fInitialized; }
|
||||
|
||||
private:
|
||||
plSpeex();
|
||||
SpeexBits* fBits; // main speex structure
|
||||
hsBool fBitsInit;
|
||||
void* fEncoderState;
|
||||
void* fDecoderState;
|
||||
int fSampleRate;
|
||||
int fFrameSize; // frame size from speex - 160 for nb
|
||||
int fQuality; // 0-10 speex encode quality
|
||||
hsBool fVBR; // toggle variable bit rate
|
||||
int fAverageBitrate; // n-bits per second
|
||||
UInt8 fComplexity; // 1-10 sets cpu resources allowed for encoder
|
||||
hsBool fENH; // perceptual enhancement
|
||||
hsBool fInitialized;
|
||||
};
|
||||
|
||||
#endif //plVoiceChat_h
|
||||
|
@ -1,210 +1,210 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plWAVClipBuffer - Helper class for writing out WAV data in a buffered //
|
||||
// manner, with support for clipping off the specified //
|
||||
// amount at the end, but without knowing beforehand //
|
||||
// exactly how much data we'll have. //
|
||||
// //
|
||||
// The algorithm goes something like this: we keep two buffers, both the //
|
||||
// size of the amount we want to clip. We then start filling in the first //
|
||||
// buffer, overflowing into the second buffer and wrapping back to the //
|
||||
// first again in a circular fashion. When we fill up one buffer and are //
|
||||
// about to advance to the next, we write that next buffer out. Why? //
|
||||
// Because we know that, even if we got no more data in, we have enough //
|
||||
// data in the first buffer to clip out the amount we want, so the other //
|
||||
// half (which will have older data, being a circular buffer) can be //
|
||||
// written out safely. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "plWAVClipBuffer.h"
|
||||
#include "hsStream.h"
|
||||
#include "hsUtils.h"
|
||||
|
||||
#include "plAudioCore/plWavFile.h"
|
||||
|
||||
|
||||
//// Constructor/Destructor //////////////////////////////////////////////////
|
||||
|
||||
plWAVClipBuffer::plWAVClipBuffer( UInt32 clipSize, CWaveFile *outFile )
|
||||
{
|
||||
fBuffers[ 0 ] = fBuffers[ 1 ] = nil;
|
||||
fFlushCalled = true;
|
||||
Init( clipSize, outFile );
|
||||
}
|
||||
|
||||
plWAVClipBuffer::~plWAVClipBuffer()
|
||||
{
|
||||
IShutdown();
|
||||
}
|
||||
|
||||
//// Init & IShutdown ////////////////////////////////////////////////////////
|
||||
|
||||
void plWAVClipBuffer::Init( UInt32 clipSize, CWaveFile *outFile )
|
||||
{
|
||||
IShutdown();
|
||||
if( clipSize > 0 )
|
||||
{
|
||||
fBuffers[ 0 ] = TRACKED_NEW UInt8[ clipSize ];
|
||||
fBuffers[ 1 ] = TRACKED_NEW UInt8[ clipSize ];
|
||||
memset( fBuffers[ 0 ], 0, clipSize );
|
||||
memset( fBuffers[ 1 ], 0, clipSize );
|
||||
}
|
||||
fWhichBuffer = 0;
|
||||
fBufferSize = clipSize;
|
||||
fCursor = 0;
|
||||
fFirstFlip = true;
|
||||
fOutFile = outFile;
|
||||
fFlushCalled = false;
|
||||
}
|
||||
|
||||
void plWAVClipBuffer::IShutdown( void )
|
||||
{
|
||||
hsAssert( fFlushCalled, "WAVClipBuffer shut down without flushing it!!!" );
|
||||
|
||||
delete [] fBuffers[ 0 ];
|
||||
delete [] fBuffers[ 1 ];
|
||||
}
|
||||
|
||||
//// WriteData ///////////////////////////////////////////////////////////////
|
||||
// The main workhorse; call this to add data to the buffer.
|
||||
|
||||
hsBool plWAVClipBuffer::WriteData( UInt32 size, UInt8 *data )
|
||||
{
|
||||
while( size > 0 )
|
||||
{
|
||||
UInt32 toWrite = fBufferSize - fCursor;
|
||||
if( size < toWrite )
|
||||
{
|
||||
// Just write, haven't filled a buffer yet
|
||||
memcpy( fBuffers[ fWhichBuffer ] + fCursor, data, size );
|
||||
data += size;
|
||||
fCursor += size;
|
||||
return true; // All done!
|
||||
}
|
||||
|
||||
// Fill up to the end of a buffer, then flip
|
||||
memcpy( fBuffers[ fWhichBuffer ] + fCursor, data, toWrite );
|
||||
data += toWrite;
|
||||
fCursor += toWrite;
|
||||
size -= toWrite;
|
||||
|
||||
// Flip now...
|
||||
fWhichBuffer = 1 - fWhichBuffer;
|
||||
fCursor = 0;
|
||||
|
||||
// Now we can write out this buffer, since it'll be old data and
|
||||
// we have enough in the other buffer to clip with. The *only*
|
||||
// time we don't want to do this is the first time we flip, since
|
||||
// at that point, the buffer we just flipped to hasn't been filled yet.
|
||||
// (Every time afterwards, we'll always be flipping to a buffer with old
|
||||
// data).
|
||||
if( fFirstFlip )
|
||||
fFirstFlip = false;
|
||||
else
|
||||
{
|
||||
// Write it out before we overwrite it!
|
||||
UINT written;
|
||||
HRESULT hr = fOutFile->Write( fBufferSize, fBuffers[ fWhichBuffer ], &written );
|
||||
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
hsAssert( false, "ERROR writing WMA stream to WAV file" );
|
||||
return false;
|
||||
}
|
||||
else if( written != fBufferSize )
|
||||
{
|
||||
hsAssert( false, "Unable to write all of WMA stream to WAV file" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanly got here, so just return success
|
||||
return true;
|
||||
}
|
||||
|
||||
//// Flush ///////////////////////////////////////////////////////////////////
|
||||
// Writes out the remaining data, minus our clip value (which is fBufferSize)
|
||||
// So here's our situation: at this point, one of two things could be true:
|
||||
//
|
||||
// 1) We haven't received enough data to clip by, at which point we don't
|
||||
// write any more and bail (this will be true if fFirstFlip is still true)
|
||||
//
|
||||
// 2) Our cursor is at 0, which means we have one filled buffer that hasn't been
|
||||
// written out and our current buffer is empty. At this point, we discard the
|
||||
// filled buffer (which is precisely the length we want to clip by) and we're done.
|
||||
//
|
||||
// 3) The buffer we're on should be partially filled, while the other one is older
|
||||
// data. So, we want to write out the older data and the partial buffer all the way,
|
||||
// except for the clip size. Since we can therefore never write out any data in the
|
||||
// partial buffer (since that count will always be less than the clip size and thus be
|
||||
// the second half of what we clip), we simply figure out how much of the other one we
|
||||
// clip and write out the rest.
|
||||
|
||||
hsBool plWAVClipBuffer::Flush( void )
|
||||
{
|
||||
fFlushCalled = true;
|
||||
|
||||
if( fFirstFlip )
|
||||
return false; // We failed--not enough data to clip with
|
||||
|
||||
if( fCursor == 0 )
|
||||
{
|
||||
// Our current buffer is empty, so the other buffer is precisely what we clip.
|
||||
// So just discard and return successfully
|
||||
return true;
|
||||
}
|
||||
|
||||
// The hard case--we always discard the partial buffer we're on, so figure out
|
||||
// how much we want to save of the other buffer. The math is:
|
||||
// Partial buffer amount we're clipping = fCursor
|
||||
// Amount of other buffer we're clipping = fBufferSize - fCursor
|
||||
// Amount of other buffer we're writing = fBufferSize - ( fBufferSize - fCursor ) = fCursor
|
||||
// Go figure :)
|
||||
|
||||
UInt32 toWrite = fCursor;
|
||||
|
||||
UINT written;
|
||||
HRESULT hr = fOutFile->Write( toWrite, fBuffers[ 1 - fWhichBuffer ], &written );
|
||||
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
hsAssert( false, "ERROR writing WMA stream to WAV file" );
|
||||
return false;
|
||||
}
|
||||
else if( written != toWrite )
|
||||
{
|
||||
hsAssert( false, "Unable to write all of WMA stream to WAV file" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// All done!
|
||||
return true;
|
||||
}
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plWAVClipBuffer - Helper class for writing out WAV data in a buffered //
|
||||
// manner, with support for clipping off the specified //
|
||||
// amount at the end, but without knowing beforehand //
|
||||
// exactly how much data we'll have. //
|
||||
// //
|
||||
// The algorithm goes something like this: we keep two buffers, both the //
|
||||
// size of the amount we want to clip. We then start filling in the first //
|
||||
// buffer, overflowing into the second buffer and wrapping back to the //
|
||||
// first again in a circular fashion. When we fill up one buffer and are //
|
||||
// about to advance to the next, we write that next buffer out. Why? //
|
||||
// Because we know that, even if we got no more data in, we have enough //
|
||||
// data in the first buffer to clip out the amount we want, so the other //
|
||||
// half (which will have older data, being a circular buffer) can be //
|
||||
// written out safely. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "plWAVClipBuffer.h"
|
||||
#include "hsStream.h"
|
||||
#include "hsUtils.h"
|
||||
|
||||
#include "plAudioCore/plWavFile.h"
|
||||
|
||||
|
||||
//// Constructor/Destructor //////////////////////////////////////////////////
|
||||
|
||||
plWAVClipBuffer::plWAVClipBuffer( UInt32 clipSize, CWaveFile *outFile )
|
||||
{
|
||||
fBuffers[ 0 ] = fBuffers[ 1 ] = nil;
|
||||
fFlushCalled = true;
|
||||
Init( clipSize, outFile );
|
||||
}
|
||||
|
||||
plWAVClipBuffer::~plWAVClipBuffer()
|
||||
{
|
||||
IShutdown();
|
||||
}
|
||||
|
||||
//// Init & IShutdown ////////////////////////////////////////////////////////
|
||||
|
||||
void plWAVClipBuffer::Init( UInt32 clipSize, CWaveFile *outFile )
|
||||
{
|
||||
IShutdown();
|
||||
if( clipSize > 0 )
|
||||
{
|
||||
fBuffers[ 0 ] = TRACKED_NEW UInt8[ clipSize ];
|
||||
fBuffers[ 1 ] = TRACKED_NEW UInt8[ clipSize ];
|
||||
memset( fBuffers[ 0 ], 0, clipSize );
|
||||
memset( fBuffers[ 1 ], 0, clipSize );
|
||||
}
|
||||
fWhichBuffer = 0;
|
||||
fBufferSize = clipSize;
|
||||
fCursor = 0;
|
||||
fFirstFlip = true;
|
||||
fOutFile = outFile;
|
||||
fFlushCalled = false;
|
||||
}
|
||||
|
||||
void plWAVClipBuffer::IShutdown( void )
|
||||
{
|
||||
hsAssert( fFlushCalled, "WAVClipBuffer shut down without flushing it!!!" );
|
||||
|
||||
delete [] fBuffers[ 0 ];
|
||||
delete [] fBuffers[ 1 ];
|
||||
}
|
||||
|
||||
//// WriteData ///////////////////////////////////////////////////////////////
|
||||
// The main workhorse; call this to add data to the buffer.
|
||||
|
||||
hsBool plWAVClipBuffer::WriteData( UInt32 size, UInt8 *data )
|
||||
{
|
||||
while( size > 0 )
|
||||
{
|
||||
UInt32 toWrite = fBufferSize - fCursor;
|
||||
if( size < toWrite )
|
||||
{
|
||||
// Just write, haven't filled a buffer yet
|
||||
memcpy( fBuffers[ fWhichBuffer ] + fCursor, data, size );
|
||||
data += size;
|
||||
fCursor += size;
|
||||
return true; // All done!
|
||||
}
|
||||
|
||||
// Fill up to the end of a buffer, then flip
|
||||
memcpy( fBuffers[ fWhichBuffer ] + fCursor, data, toWrite );
|
||||
data += toWrite;
|
||||
fCursor += toWrite;
|
||||
size -= toWrite;
|
||||
|
||||
// Flip now...
|
||||
fWhichBuffer = 1 - fWhichBuffer;
|
||||
fCursor = 0;
|
||||
|
||||
// Now we can write out this buffer, since it'll be old data and
|
||||
// we have enough in the other buffer to clip with. The *only*
|
||||
// time we don't want to do this is the first time we flip, since
|
||||
// at that point, the buffer we just flipped to hasn't been filled yet.
|
||||
// (Every time afterwards, we'll always be flipping to a buffer with old
|
||||
// data).
|
||||
if( fFirstFlip )
|
||||
fFirstFlip = false;
|
||||
else
|
||||
{
|
||||
// Write it out before we overwrite it!
|
||||
UINT written;
|
||||
HRESULT hr = fOutFile->Write( fBufferSize, fBuffers[ fWhichBuffer ], &written );
|
||||
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
hsAssert( false, "ERROR writing WMA stream to WAV file" );
|
||||
return false;
|
||||
}
|
||||
else if( written != fBufferSize )
|
||||
{
|
||||
hsAssert( false, "Unable to write all of WMA stream to WAV file" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanly got here, so just return success
|
||||
return true;
|
||||
}
|
||||
|
||||
//// Flush ///////////////////////////////////////////////////////////////////
|
||||
// Writes out the remaining data, minus our clip value (which is fBufferSize)
|
||||
// So here's our situation: at this point, one of two things could be true:
|
||||
//
|
||||
// 1) We haven't received enough data to clip by, at which point we don't
|
||||
// write any more and bail (this will be true if fFirstFlip is still true)
|
||||
//
|
||||
// 2) Our cursor is at 0, which means we have one filled buffer that hasn't been
|
||||
// written out and our current buffer is empty. At this point, we discard the
|
||||
// filled buffer (which is precisely the length we want to clip by) and we're done.
|
||||
//
|
||||
// 3) The buffer we're on should be partially filled, while the other one is older
|
||||
// data. So, we want to write out the older data and the partial buffer all the way,
|
||||
// except for the clip size. Since we can therefore never write out any data in the
|
||||
// partial buffer (since that count will always be less than the clip size and thus be
|
||||
// the second half of what we clip), we simply figure out how much of the other one we
|
||||
// clip and write out the rest.
|
||||
|
||||
hsBool plWAVClipBuffer::Flush( void )
|
||||
{
|
||||
fFlushCalled = true;
|
||||
|
||||
if( fFirstFlip )
|
||||
return false; // We failed--not enough data to clip with
|
||||
|
||||
if( fCursor == 0 )
|
||||
{
|
||||
// Our current buffer is empty, so the other buffer is precisely what we clip.
|
||||
// So just discard and return successfully
|
||||
return true;
|
||||
}
|
||||
|
||||
// The hard case--we always discard the partial buffer we're on, so figure out
|
||||
// how much we want to save of the other buffer. The math is:
|
||||
// Partial buffer amount we're clipping = fCursor
|
||||
// Amount of other buffer we're clipping = fBufferSize - fCursor
|
||||
// Amount of other buffer we're writing = fBufferSize - ( fBufferSize - fCursor ) = fCursor
|
||||
// Go figure :)
|
||||
|
||||
UInt32 toWrite = fCursor;
|
||||
|
||||
UINT written;
|
||||
HRESULT hr = fOutFile->Write( toWrite, fBuffers[ 1 - fWhichBuffer ], &written );
|
||||
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
hsAssert( false, "ERROR writing WMA stream to WAV file" );
|
||||
return false;
|
||||
}
|
||||
else if( written != toWrite )
|
||||
{
|
||||
hsAssert( false, "Unable to write all of WMA stream to WAV file" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// All done!
|
||||
return true;
|
||||
}
|
||||
|
@ -1,78 +1,78 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plWAVClipBuffer - Helper class for writing out WAV data in a buffered //
|
||||
// manner, with support for clipping off the specified //
|
||||
// amount at the end, but without knowing beforehand //
|
||||
// exactly how much data we'll have. //
|
||||
// //
|
||||
// The algorithm goes something like this: we keep two buffers, both the //
|
||||
// size of the amount we want to clip. We then start filling in the first //
|
||||
// buffer, overflowing into the second buffer and wrapping back to the //
|
||||
// first again in a circular fashion. When we fill up one buffer and are //
|
||||
// about to advance to the next, we write that next buffer out. Why? //
|
||||
// Because we know that, even if we got no more data in, we have enough //
|
||||
// data in the first buffer to clip out the amount we want, so the other //
|
||||
// half (which will have older data, being a circular buffer) can be //
|
||||
// written out safely. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _plWAVClipBuffer_h
|
||||
#define _plWAVClipBuffer_h
|
||||
|
||||
//// Class Definition ////////////////////////////////////////////////////////
|
||||
|
||||
class CWaveFile;
|
||||
class plWAVClipBuffer
|
||||
{
|
||||
public:
|
||||
|
||||
plWAVClipBuffer( UInt32 clipSize, CWaveFile *outFile );
|
||||
~plWAVClipBuffer();
|
||||
|
||||
// Inits the buffer. Can re-init if you wish
|
||||
void Init( UInt32 clipSize, CWaveFile *outFile );
|
||||
|
||||
// Writes/adds data to the buffer
|
||||
hsBool WriteData( UInt32 size, UInt8 *data );
|
||||
|
||||
// Call at the end, flushes the buffer and performs the clipping
|
||||
hsBool Flush( void );
|
||||
|
||||
protected:
|
||||
UInt8 *fBuffers[ 2 ];
|
||||
UInt8 fWhichBuffer; // 0 or 1
|
||||
UInt32 fCursor, fBufferSize;
|
||||
hsBool fFirstFlip, fFlushCalled;
|
||||
|
||||
CWaveFile *fOutFile;
|
||||
|
||||
void IShutdown( void );
|
||||
};
|
||||
|
||||
#endif //_plWAVClipBuffer_h
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plWAVClipBuffer - Helper class for writing out WAV data in a buffered //
|
||||
// manner, with support for clipping off the specified //
|
||||
// amount at the end, but without knowing beforehand //
|
||||
// exactly how much data we'll have. //
|
||||
// //
|
||||
// The algorithm goes something like this: we keep two buffers, both the //
|
||||
// size of the amount we want to clip. We then start filling in the first //
|
||||
// buffer, overflowing into the second buffer and wrapping back to the //
|
||||
// first again in a circular fashion. When we fill up one buffer and are //
|
||||
// about to advance to the next, we write that next buffer out. Why? //
|
||||
// Because we know that, even if we got no more data in, we have enough //
|
||||
// data in the first buffer to clip out the amount we want, so the other //
|
||||
// half (which will have older data, being a circular buffer) can be //
|
||||
// written out safely. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _plWAVClipBuffer_h
|
||||
#define _plWAVClipBuffer_h
|
||||
|
||||
//// Class Definition ////////////////////////////////////////////////////////
|
||||
|
||||
class CWaveFile;
|
||||
class plWAVClipBuffer
|
||||
{
|
||||
public:
|
||||
|
||||
plWAVClipBuffer( UInt32 clipSize, CWaveFile *outFile );
|
||||
~plWAVClipBuffer();
|
||||
|
||||
// Inits the buffer. Can re-init if you wish
|
||||
void Init( UInt32 clipSize, CWaveFile *outFile );
|
||||
|
||||
// Writes/adds data to the buffer
|
||||
hsBool WriteData( UInt32 size, UInt8 *data );
|
||||
|
||||
// Call at the end, flushes the buffer and performs the clipping
|
||||
hsBool Flush( void );
|
||||
|
||||
protected:
|
||||
UInt8 *fBuffers[ 2 ];
|
||||
UInt8 fWhichBuffer; // 0 or 1
|
||||
UInt32 fCursor, fBufferSize;
|
||||
hsBool fFirstFlip, fFlushCalled;
|
||||
|
||||
CWaveFile *fOutFile;
|
||||
|
||||
void IShutdown( void );
|
||||
};
|
||||
|
||||
#endif //_plWAVClipBuffer_h
|
||||
|
@ -1,393 +1,393 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plWin32GroupedSound - Grouped version of a static sound. Lots of short //
|
||||
// sounds stored in the buffer, all share the same //
|
||||
// DSound playback buffer and only one plays at a //
|
||||
// time. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "hsTypes.h"
|
||||
|
||||
#include "plWin32GroupedSound.h"
|
||||
#include "plDSoundBuffer.h"
|
||||
|
||||
#include "plAudioSystem.h"
|
||||
#include "plAudioCore/plSoundBuffer.h"
|
||||
#include "plAudioCore/plSoundDeswizzler.h"
|
||||
#include "plgDispatch.h"
|
||||
#include "pnMessage/plSoundMsg.h"
|
||||
|
||||
#include "plStatusLog/plStatusLog.h"
|
||||
#include "plProfile.h"
|
||||
#include "hsResMgr.h"
|
||||
|
||||
plProfile_Extern( MemSounds );
|
||||
plProfile_Extern( StaticSndShoveTime );
|
||||
plProfile_Extern( StaticSwizzleTime );
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plWin32GroupedSound::plWin32GroupedSound()
|
||||
{
|
||||
fCurrentSound = 0;
|
||||
}
|
||||
|
||||
plWin32GroupedSound::~plWin32GroupedSound()
|
||||
{
|
||||
DeActivate();
|
||||
}
|
||||
|
||||
void plWin32GroupedSound::SetPositionArray( UInt16 numSounds, UInt32 *posArray, hsScalar *volumeArray )
|
||||
{
|
||||
UInt16 i;
|
||||
|
||||
|
||||
fStartPositions.SetCountAndZero( numSounds );
|
||||
fVolumes.SetCountAndZero( numSounds );
|
||||
for( i = 0; i < numSounds; i++ )
|
||||
{
|
||||
fStartPositions[ i ] = posArray[ i ];
|
||||
fVolumes[ i ] = volumeArray[ i ];
|
||||
}
|
||||
}
|
||||
|
||||
//// IRead/IWrite ////////////////////////////////////////////////////////////
|
||||
|
||||
void plWin32GroupedSound::IRead( hsStream *s, hsResMgr *mgr )
|
||||
{
|
||||
plWin32StaticSound::IRead( s, mgr );
|
||||
UInt16 i, n = s->ReadSwap16();
|
||||
fStartPositions.SetCountAndZero( n );
|
||||
fVolumes.SetCountAndZero( n );
|
||||
for( i = 0; i < n; i++ )
|
||||
{
|
||||
fStartPositions[ i ] = s->ReadSwap32();
|
||||
fVolumes[ i ] = s->ReadSwapScalar();
|
||||
}
|
||||
}
|
||||
|
||||
void plWin32GroupedSound::IWrite( hsStream *s, hsResMgr *mgr )
|
||||
{
|
||||
plWin32StaticSound::IWrite( s, mgr );
|
||||
|
||||
s->WriteSwap16( fStartPositions.GetCount() );
|
||||
UInt16 i;
|
||||
for( i = 0; i < fStartPositions.GetCount(); i++ )
|
||||
{
|
||||
s->WriteSwap32( fStartPositions[ i ] );
|
||||
s->WriteSwapScalar( fVolumes[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
//// LoadSound ///////////////////////////////////////////////////////////////
|
||||
|
||||
hsBool plWin32GroupedSound::LoadSound( hsBool is3D )
|
||||
{
|
||||
if( fFailed )
|
||||
return false;
|
||||
|
||||
if( fPriority > plgAudioSys::GetPriorityCutoff() )
|
||||
return false; // Don't set the failed flag, just return
|
||||
|
||||
if( !plgAudioSys::Active() || fDSoundBuffer != nil )
|
||||
return false;
|
||||
|
||||
|
||||
// Debug flag #1
|
||||
if( fChannelSelect > 0 && plgAudioSys::IsDebugFlagSet( plgAudioSys::kDisableRightSelect ) )
|
||||
{
|
||||
// Force a fail
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// We need it to be resident to read in
|
||||
plSoundBuffer::ELoadReturnVal retVal = IPreLoadBuffer(true);
|
||||
plSoundBuffer *buffer = (plSoundBuffer *)fDataBufferKey->ObjectIsLoaded();
|
||||
if(!buffer)
|
||||
{
|
||||
return plSoundBuffer::kError;
|
||||
}
|
||||
|
||||
if( retVal == plSoundBuffer::kPending) // we are still reading data.
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// We need it to be resident to read in
|
||||
if( retVal == plSoundBuffer::kError)
|
||||
{
|
||||
char str[ 256 ];
|
||||
sprintf( str, "Unable to open .wav file %s", fDataBufferKey ? fDataBufferKey->GetName() : "nil");
|
||||
IPrintDbgMessage( str, true );
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
SetProperty( kPropIs3DSound, is3D );
|
||||
|
||||
|
||||
plWAVHeader header = buffer->GetHeader();
|
||||
|
||||
// Debug flag #2
|
||||
if( fChannelSelect == 0 && header.fNumChannels > 1 && plgAudioSys::IsDebugFlagSet( plgAudioSys::kDisableLeftSelect ) )
|
||||
{
|
||||
// Force a fail
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate the maximum size for our buffer. This will be the length of the longest sound we're going to
|
||||
// have to play.
|
||||
UInt16 i;
|
||||
UInt32 maxSoundSize, len;
|
||||
for( i = 1, maxSoundSize = 0; i < fStartPositions.GetCount(); i++ )
|
||||
{
|
||||
len = fStartPositions[ i ] - fStartPositions[ i - 1 ];
|
||||
if( len > maxSoundSize )
|
||||
maxSoundSize = len;
|
||||
}
|
||||
len = buffer->GetDataLength() - fStartPositions[ fStartPositions.GetCount() - 1 ];
|
||||
if( len > maxSoundSize )
|
||||
maxSoundSize = len;
|
||||
|
||||
// Based on that, allocate our buffer
|
||||
UInt32 bufferSize = maxSoundSize - ( maxSoundSize % header.fBlockAlign );
|
||||
|
||||
if( header.fNumChannels > 1 && is3D )
|
||||
{
|
||||
// We can only do a single channel of 3D sound. So copy over one (later)
|
||||
bufferSize /= header.fNumChannels;
|
||||
header.fBlockAlign /= header.fNumChannels;
|
||||
header.fAvgBytesPerSec /= header.fNumChannels;
|
||||
header.fNumChannels = 1;
|
||||
}
|
||||
fNumDestChannels = (UInt8)(header.fNumChannels);
|
||||
fNumDestBytesPerSample = (UInt8)(header.fBlockAlign);
|
||||
|
||||
// Create our DSound buffer (or rather, the wrapper around it)
|
||||
fDSoundBuffer = TRACKED_NEW plDSoundBuffer( bufferSize, header, is3D, IsPropertySet( kPropLooping ), true );
|
||||
if( !fDSoundBuffer->IsValid() )
|
||||
{
|
||||
char str[256];
|
||||
sprintf(str, "Can't create sound buffer for %s.wav. This could happen if the wav file is a stereo file. Stereo files are not supported on 3D sounds. If the file is not stereo then please report this error.", GetFileName());
|
||||
IPrintDbgMessage( str, true );
|
||||
fFailed = true;
|
||||
|
||||
delete fDSoundBuffer;
|
||||
fDSoundBuffer = nil;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IRefreshEAXSettings( true );
|
||||
|
||||
// Fill the buffer with whatever our current sound is.
|
||||
IFillCurrentSound( 0 );
|
||||
|
||||
// Logging
|
||||
char str[ 256 ];
|
||||
sprintf( str, " Grouped %s %s allocated (%d msec).", buffer->GetFileName() != nil ? "file" : "buffer",
|
||||
buffer->GetFileName() != nil ? buffer->GetFileName() : buffer->GetKey()->GetUoid().GetObjectName(),
|
||||
//fDSoundBuffer->IsHardwareAccelerated() ? "hardware" : "software",
|
||||
//fDSoundBuffer->IsStaticVoice() ? "static" : "dynamic",
|
||||
#ifdef PL_PROFILE_ENABLED
|
||||
gProfileVarStaticSndShoveTime.GetValue() );
|
||||
#else
|
||||
0 );
|
||||
#endif
|
||||
IPrintDbgMessage( str );
|
||||
if( GetKey() != nil && GetKeyName() != nil && strstr( GetKeyName(), "Footstep" ) != nil )
|
||||
;
|
||||
else
|
||||
plStatusLog::AddLineS( "audioTimes.log", "%s (%s)", str, GetKey() ? GetKeyName() : "unkeyed" );
|
||||
|
||||
fTotalBytes = bufferSize;
|
||||
|
||||
plProfile_NewMem( MemSounds, fTotalBytes );
|
||||
|
||||
// All done!
|
||||
// if( fLoadFromDiskOnDemand )
|
||||
// IUnloadDataBuffer();
|
||||
FreeSoundData();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
//// GetSoundLength //////////////////////////////////////////////////////////
|
||||
// Gets the length (in seconds) of the given sound index from the group.
|
||||
|
||||
hsScalar plWin32GroupedSound::GetSoundLength( Int16 soundIndex )
|
||||
{
|
||||
plSoundBuffer *buffer = (plSoundBuffer *)fDataBufferKey->ObjectIsLoaded();
|
||||
if(buffer)
|
||||
{
|
||||
return (hsScalar)IGetSoundByteLength( soundIndex ) / buffer->GetHeader().fAvgBytesPerSec;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//// IGetSoundByteLength /////////////////////////////////////////////////////
|
||||
// Byte version of above.
|
||||
|
||||
UInt32 plWin32GroupedSound::IGetSoundByteLength( Int16 soundIndex )
|
||||
{
|
||||
|
||||
if( soundIndex == fStartPositions.GetCount() - 1 )
|
||||
return ((plSoundBuffer *)fDataBufferKey->ObjectIsLoaded())->GetDataLength() - fStartPositions[ soundIndex ];
|
||||
else
|
||||
return fStartPositions[ soundIndex + 1 ] - fStartPositions[ soundIndex ];
|
||||
}
|
||||
|
||||
//// IGetDataPointer/Length //////////////////////////////////////////////////
|
||||
// Abstracting a few things here for the incidentalMgr
|
||||
|
||||
void *plWin32GroupedSound::IGetDataPointer( void ) const
|
||||
{
|
||||
return ( fDataBufferKey->ObjectIsLoaded() ) ? (void *)( (UInt8 *)((plSoundBuffer *)fDataBufferKey->ObjectIsLoaded())->GetData() + fStartPositions[ fCurrentSound ] ) : nil;
|
||||
}
|
||||
|
||||
UInt32 plWin32GroupedSound::IGetDataLength( void ) const
|
||||
{
|
||||
return ( fDataBufferKey->ObjectIsLoaded() ) ? fCurrentSoundLength : 0;
|
||||
}
|
||||
|
||||
//// IFillCurrentSound ///////////////////////////////////////////////////////
|
||||
// Fills the DSoundBuffer with data from the current sound from our sound
|
||||
// group, optionally switching what our current sound is.
|
||||
|
||||
void plWin32GroupedSound::IFillCurrentSound( Int16 newCurrent /*= -1*/ )
|
||||
{
|
||||
//void *dataPtr;
|
||||
//UInt32 dataLength;
|
||||
|
||||
if( !fDSoundBuffer && plgAudioSys::Active() )
|
||||
LoadSound( IsPropertySet( kPropIs3DSound ) );
|
||||
|
||||
plProfile_BeginTiming( StaticSndShoveTime );
|
||||
|
||||
// Make sure we're stopped first. Don't want to be filling while we're playing
|
||||
Stop();
|
||||
|
||||
if( newCurrent != -1 )
|
||||
{
|
||||
fCurrentSound = (UInt16)newCurrent;
|
||||
|
||||
if( fCurrentSound >= fStartPositions.GetCount() )
|
||||
{
|
||||
// Invalid index!
|
||||
hsAssert( false, "Invalid index in plWin32GroupedSound::IFillCurrentSound()" );
|
||||
fCurrentSound = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set our length based on the current sound
|
||||
fCurrentSoundLength = IGetSoundByteLength( fCurrentSound );
|
||||
if( fDataBufferKey->ObjectIsLoaded() )
|
||||
SetLength( fCurrentSoundLength / ((plSoundBuffer *)fDataBufferKey->ObjectIsLoaded())->GetHeader().fAvgBytesPerSec );
|
||||
|
||||
// Update our volume as well
|
||||
SetVolume( fVolumes[ fCurrentSound ] );
|
||||
}
|
||||
|
||||
if( fDSoundBuffer != nil )
|
||||
{
|
||||
/// Lock our buffer
|
||||
//fDSoundBuffer->Lock( dataLength, dataPtr );
|
||||
|
||||
/// Copy or de-swizzle?
|
||||
//if( fDataBuffer->GetHeader().fNumChannels == fNumDestChannels )
|
||||
{
|
||||
// Just copy
|
||||
//memcpy( dataPtr, (Byte *)fDataBuffer->GetData() + fStartPositions[ fCurrentSound ], fCurrentSoundLength );
|
||||
//dataPtr = (Byte *)dataPtr + fCurrentSoundLength;
|
||||
//dataLength -= fCurrentSoundLength;
|
||||
}
|
||||
//else
|
||||
{
|
||||
// We're extracting a single channel of sound into our sound buffer, so it isn't a straight copy...
|
||||
|
||||
/*plProfile_BeginTiming( StaticSwizzleTime );
|
||||
|
||||
plSoundDeswizzler deswiz( (Byte *)fDataBuffer->GetData() + fStartPositions[ fCurrentSound ], fCurrentSoundLength,
|
||||
(UInt8)(fDataBuffer->GetHeader().fNumChannels), fNumDestBytesPerSample );
|
||||
|
||||
deswiz.Extract( fChannelSelect, dataPtr );
|
||||
|
||||
dataPtr = (Byte *)dataPtr + fCurrentSoundLength / fDataBuffer->GetHeader().fNumChannels;
|
||||
dataLength -= fCurrentSoundLength / fDataBuffer->GetHeader().fNumChannels;
|
||||
|
||||
plProfile_EndTiming( StaticSwizzleTime );*/
|
||||
}
|
||||
|
||||
/// Fill the remaining part with empty space
|
||||
//memset( dataPtr, 0, dataLength );
|
||||
|
||||
/// Finally, unlock!
|
||||
//fDSoundBuffer->Unlock();
|
||||
}
|
||||
|
||||
/// All done!
|
||||
plProfile_EndTiming( StaticSndShoveTime );
|
||||
}
|
||||
|
||||
void plWin32GroupedSound::IDerivedActuallyPlay( void )
|
||||
{
|
||||
// Ensure there's a stop notify for us
|
||||
if( !fReallyPlaying )
|
||||
{
|
||||
fDSoundBuffer->Play();
|
||||
fReallyPlaying = true;
|
||||
}
|
||||
|
||||
plSoundEvent *event = IFindEvent( plSoundEvent::kStart );
|
||||
if( event != nil )
|
||||
event->SendCallbacks();
|
||||
}
|
||||
|
||||
hsBool plWin32GroupedSound::MsgReceive( plMessage* pMsg )
|
||||
{
|
||||
plSoundMsg *soundMsg = plSoundMsg::ConvertNoRef( pMsg );
|
||||
if( soundMsg != nil && soundMsg->Cmd( plSoundMsg::kSelectFromGroup ) )
|
||||
{
|
||||
IFillCurrentSound( soundMsg->fIndex );
|
||||
return true;
|
||||
}
|
||||
else if( soundMsg != nil && soundMsg->Cmd( plSoundMsg::kPlay ) )
|
||||
{
|
||||
Play();
|
||||
//plIncidentalMgr::GetInstance()->Play( this, plIncidentalMgr::kNormal );
|
||||
return true;
|
||||
}
|
||||
|
||||
return plWin32StaticSound::MsgReceive( pMsg );
|
||||
}
|
||||
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plWin32GroupedSound - Grouped version of a static sound. Lots of short //
|
||||
// sounds stored in the buffer, all share the same //
|
||||
// DSound playback buffer and only one plays at a //
|
||||
// time. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "hsTypes.h"
|
||||
|
||||
#include "plWin32GroupedSound.h"
|
||||
#include "plDSoundBuffer.h"
|
||||
|
||||
#include "plAudioSystem.h"
|
||||
#include "plAudioCore/plSoundBuffer.h"
|
||||
#include "plAudioCore/plSoundDeswizzler.h"
|
||||
#include "plgDispatch.h"
|
||||
#include "pnMessage/plSoundMsg.h"
|
||||
|
||||
#include "plStatusLog/plStatusLog.h"
|
||||
#include "plProfile.h"
|
||||
#include "hsResMgr.h"
|
||||
|
||||
plProfile_Extern( MemSounds );
|
||||
plProfile_Extern( StaticSndShoveTime );
|
||||
plProfile_Extern( StaticSwizzleTime );
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plWin32GroupedSound::plWin32GroupedSound()
|
||||
{
|
||||
fCurrentSound = 0;
|
||||
}
|
||||
|
||||
plWin32GroupedSound::~plWin32GroupedSound()
|
||||
{
|
||||
DeActivate();
|
||||
}
|
||||
|
||||
void plWin32GroupedSound::SetPositionArray( UInt16 numSounds, UInt32 *posArray, hsScalar *volumeArray )
|
||||
{
|
||||
UInt16 i;
|
||||
|
||||
|
||||
fStartPositions.SetCountAndZero( numSounds );
|
||||
fVolumes.SetCountAndZero( numSounds );
|
||||
for( i = 0; i < numSounds; i++ )
|
||||
{
|
||||
fStartPositions[ i ] = posArray[ i ];
|
||||
fVolumes[ i ] = volumeArray[ i ];
|
||||
}
|
||||
}
|
||||
|
||||
//// IRead/IWrite ////////////////////////////////////////////////////////////
|
||||
|
||||
void plWin32GroupedSound::IRead( hsStream *s, hsResMgr *mgr )
|
||||
{
|
||||
plWin32StaticSound::IRead( s, mgr );
|
||||
UInt16 i, n = s->ReadSwap16();
|
||||
fStartPositions.SetCountAndZero( n );
|
||||
fVolumes.SetCountAndZero( n );
|
||||
for( i = 0; i < n; i++ )
|
||||
{
|
||||
fStartPositions[ i ] = s->ReadSwap32();
|
||||
fVolumes[ i ] = s->ReadSwapScalar();
|
||||
}
|
||||
}
|
||||
|
||||
void plWin32GroupedSound::IWrite( hsStream *s, hsResMgr *mgr )
|
||||
{
|
||||
plWin32StaticSound::IWrite( s, mgr );
|
||||
|
||||
s->WriteSwap16( fStartPositions.GetCount() );
|
||||
UInt16 i;
|
||||
for( i = 0; i < fStartPositions.GetCount(); i++ )
|
||||
{
|
||||
s->WriteSwap32( fStartPositions[ i ] );
|
||||
s->WriteSwapScalar( fVolumes[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
//// LoadSound ///////////////////////////////////////////////////////////////
|
||||
|
||||
hsBool plWin32GroupedSound::LoadSound( hsBool is3D )
|
||||
{
|
||||
if( fFailed )
|
||||
return false;
|
||||
|
||||
if( fPriority > plgAudioSys::GetPriorityCutoff() )
|
||||
return false; // Don't set the failed flag, just return
|
||||
|
||||
if( !plgAudioSys::Active() || fDSoundBuffer != nil )
|
||||
return false;
|
||||
|
||||
|
||||
// Debug flag #1
|
||||
if( fChannelSelect > 0 && plgAudioSys::IsDebugFlagSet( plgAudioSys::kDisableRightSelect ) )
|
||||
{
|
||||
// Force a fail
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// We need it to be resident to read in
|
||||
plSoundBuffer::ELoadReturnVal retVal = IPreLoadBuffer(true);
|
||||
plSoundBuffer *buffer = (plSoundBuffer *)fDataBufferKey->ObjectIsLoaded();
|
||||
if(!buffer)
|
||||
{
|
||||
return plSoundBuffer::kError;
|
||||
}
|
||||
|
||||
if( retVal == plSoundBuffer::kPending) // we are still reading data.
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// We need it to be resident to read in
|
||||
if( retVal == plSoundBuffer::kError)
|
||||
{
|
||||
char str[ 256 ];
|
||||
sprintf( str, "Unable to open .wav file %s", fDataBufferKey ? fDataBufferKey->GetName() : "nil");
|
||||
IPrintDbgMessage( str, true );
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
SetProperty( kPropIs3DSound, is3D );
|
||||
|
||||
|
||||
plWAVHeader header = buffer->GetHeader();
|
||||
|
||||
// Debug flag #2
|
||||
if( fChannelSelect == 0 && header.fNumChannels > 1 && plgAudioSys::IsDebugFlagSet( plgAudioSys::kDisableLeftSelect ) )
|
||||
{
|
||||
// Force a fail
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate the maximum size for our buffer. This will be the length of the longest sound we're going to
|
||||
// have to play.
|
||||
UInt16 i;
|
||||
UInt32 maxSoundSize, len;
|
||||
for( i = 1, maxSoundSize = 0; i < fStartPositions.GetCount(); i++ )
|
||||
{
|
||||
len = fStartPositions[ i ] - fStartPositions[ i - 1 ];
|
||||
if( len > maxSoundSize )
|
||||
maxSoundSize = len;
|
||||
}
|
||||
len = buffer->GetDataLength() - fStartPositions[ fStartPositions.GetCount() - 1 ];
|
||||
if( len > maxSoundSize )
|
||||
maxSoundSize = len;
|
||||
|
||||
// Based on that, allocate our buffer
|
||||
UInt32 bufferSize = maxSoundSize - ( maxSoundSize % header.fBlockAlign );
|
||||
|
||||
if( header.fNumChannels > 1 && is3D )
|
||||
{
|
||||
// We can only do a single channel of 3D sound. So copy over one (later)
|
||||
bufferSize /= header.fNumChannels;
|
||||
header.fBlockAlign /= header.fNumChannels;
|
||||
header.fAvgBytesPerSec /= header.fNumChannels;
|
||||
header.fNumChannels = 1;
|
||||
}
|
||||
fNumDestChannels = (UInt8)(header.fNumChannels);
|
||||
fNumDestBytesPerSample = (UInt8)(header.fBlockAlign);
|
||||
|
||||
// Create our DSound buffer (or rather, the wrapper around it)
|
||||
fDSoundBuffer = TRACKED_NEW plDSoundBuffer( bufferSize, header, is3D, IsPropertySet( kPropLooping ), true );
|
||||
if( !fDSoundBuffer->IsValid() )
|
||||
{
|
||||
char str[256];
|
||||
sprintf(str, "Can't create sound buffer for %s.wav. This could happen if the wav file is a stereo file. Stereo files are not supported on 3D sounds. If the file is not stereo then please report this error.", GetFileName());
|
||||
IPrintDbgMessage( str, true );
|
||||
fFailed = true;
|
||||
|
||||
delete fDSoundBuffer;
|
||||
fDSoundBuffer = nil;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IRefreshEAXSettings( true );
|
||||
|
||||
// Fill the buffer with whatever our current sound is.
|
||||
IFillCurrentSound( 0 );
|
||||
|
||||
// Logging
|
||||
char str[ 256 ];
|
||||
sprintf( str, " Grouped %s %s allocated (%d msec).", buffer->GetFileName() != nil ? "file" : "buffer",
|
||||
buffer->GetFileName() != nil ? buffer->GetFileName() : buffer->GetKey()->GetUoid().GetObjectName(),
|
||||
//fDSoundBuffer->IsHardwareAccelerated() ? "hardware" : "software",
|
||||
//fDSoundBuffer->IsStaticVoice() ? "static" : "dynamic",
|
||||
#ifdef PL_PROFILE_ENABLED
|
||||
gProfileVarStaticSndShoveTime.GetValue() );
|
||||
#else
|
||||
0 );
|
||||
#endif
|
||||
IPrintDbgMessage( str );
|
||||
if( GetKey() != nil && GetKeyName() != nil && strstr( GetKeyName(), "Footstep" ) != nil )
|
||||
;
|
||||
else
|
||||
plStatusLog::AddLineS( "audioTimes.log", "%s (%s)", str, GetKey() ? GetKeyName() : "unkeyed" );
|
||||
|
||||
fTotalBytes = bufferSize;
|
||||
|
||||
plProfile_NewMem( MemSounds, fTotalBytes );
|
||||
|
||||
// All done!
|
||||
// if( fLoadFromDiskOnDemand )
|
||||
// IUnloadDataBuffer();
|
||||
FreeSoundData();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
//// GetSoundLength //////////////////////////////////////////////////////////
|
||||
// Gets the length (in seconds) of the given sound index from the group.
|
||||
|
||||
hsScalar plWin32GroupedSound::GetSoundLength( Int16 soundIndex )
|
||||
{
|
||||
plSoundBuffer *buffer = (plSoundBuffer *)fDataBufferKey->ObjectIsLoaded();
|
||||
if(buffer)
|
||||
{
|
||||
return (hsScalar)IGetSoundByteLength( soundIndex ) / buffer->GetHeader().fAvgBytesPerSec;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//// IGetSoundByteLength /////////////////////////////////////////////////////
|
||||
// Byte version of above.
|
||||
|
||||
UInt32 plWin32GroupedSound::IGetSoundByteLength( Int16 soundIndex )
|
||||
{
|
||||
|
||||
if( soundIndex == fStartPositions.GetCount() - 1 )
|
||||
return ((plSoundBuffer *)fDataBufferKey->ObjectIsLoaded())->GetDataLength() - fStartPositions[ soundIndex ];
|
||||
else
|
||||
return fStartPositions[ soundIndex + 1 ] - fStartPositions[ soundIndex ];
|
||||
}
|
||||
|
||||
//// IGetDataPointer/Length //////////////////////////////////////////////////
|
||||
// Abstracting a few things here for the incidentalMgr
|
||||
|
||||
void *plWin32GroupedSound::IGetDataPointer( void ) const
|
||||
{
|
||||
return ( fDataBufferKey->ObjectIsLoaded() ) ? (void *)( (UInt8 *)((plSoundBuffer *)fDataBufferKey->ObjectIsLoaded())->GetData() + fStartPositions[ fCurrentSound ] ) : nil;
|
||||
}
|
||||
|
||||
UInt32 plWin32GroupedSound::IGetDataLength( void ) const
|
||||
{
|
||||
return ( fDataBufferKey->ObjectIsLoaded() ) ? fCurrentSoundLength : 0;
|
||||
}
|
||||
|
||||
//// IFillCurrentSound ///////////////////////////////////////////////////////
|
||||
// Fills the DSoundBuffer with data from the current sound from our sound
|
||||
// group, optionally switching what our current sound is.
|
||||
|
||||
void plWin32GroupedSound::IFillCurrentSound( Int16 newCurrent /*= -1*/ )
|
||||
{
|
||||
//void *dataPtr;
|
||||
//UInt32 dataLength;
|
||||
|
||||
if( !fDSoundBuffer && plgAudioSys::Active() )
|
||||
LoadSound( IsPropertySet( kPropIs3DSound ) );
|
||||
|
||||
plProfile_BeginTiming( StaticSndShoveTime );
|
||||
|
||||
// Make sure we're stopped first. Don't want to be filling while we're playing
|
||||
Stop();
|
||||
|
||||
if( newCurrent != -1 )
|
||||
{
|
||||
fCurrentSound = (UInt16)newCurrent;
|
||||
|
||||
if( fCurrentSound >= fStartPositions.GetCount() )
|
||||
{
|
||||
// Invalid index!
|
||||
hsAssert( false, "Invalid index in plWin32GroupedSound::IFillCurrentSound()" );
|
||||
fCurrentSound = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set our length based on the current sound
|
||||
fCurrentSoundLength = IGetSoundByteLength( fCurrentSound );
|
||||
if( fDataBufferKey->ObjectIsLoaded() )
|
||||
SetLength( fCurrentSoundLength / ((plSoundBuffer *)fDataBufferKey->ObjectIsLoaded())->GetHeader().fAvgBytesPerSec );
|
||||
|
||||
// Update our volume as well
|
||||
SetVolume( fVolumes[ fCurrentSound ] );
|
||||
}
|
||||
|
||||
if( fDSoundBuffer != nil )
|
||||
{
|
||||
/// Lock our buffer
|
||||
//fDSoundBuffer->Lock( dataLength, dataPtr );
|
||||
|
||||
/// Copy or de-swizzle?
|
||||
//if( fDataBuffer->GetHeader().fNumChannels == fNumDestChannels )
|
||||
{
|
||||
// Just copy
|
||||
//memcpy( dataPtr, (Byte *)fDataBuffer->GetData() + fStartPositions[ fCurrentSound ], fCurrentSoundLength );
|
||||
//dataPtr = (Byte *)dataPtr + fCurrentSoundLength;
|
||||
//dataLength -= fCurrentSoundLength;
|
||||
}
|
||||
//else
|
||||
{
|
||||
// We're extracting a single channel of sound into our sound buffer, so it isn't a straight copy...
|
||||
|
||||
/*plProfile_BeginTiming( StaticSwizzleTime );
|
||||
|
||||
plSoundDeswizzler deswiz( (Byte *)fDataBuffer->GetData() + fStartPositions[ fCurrentSound ], fCurrentSoundLength,
|
||||
(UInt8)(fDataBuffer->GetHeader().fNumChannels), fNumDestBytesPerSample );
|
||||
|
||||
deswiz.Extract( fChannelSelect, dataPtr );
|
||||
|
||||
dataPtr = (Byte *)dataPtr + fCurrentSoundLength / fDataBuffer->GetHeader().fNumChannels;
|
||||
dataLength -= fCurrentSoundLength / fDataBuffer->GetHeader().fNumChannels;
|
||||
|
||||
plProfile_EndTiming( StaticSwizzleTime );*/
|
||||
}
|
||||
|
||||
/// Fill the remaining part with empty space
|
||||
//memset( dataPtr, 0, dataLength );
|
||||
|
||||
/// Finally, unlock!
|
||||
//fDSoundBuffer->Unlock();
|
||||
}
|
||||
|
||||
/// All done!
|
||||
plProfile_EndTiming( StaticSndShoveTime );
|
||||
}
|
||||
|
||||
void plWin32GroupedSound::IDerivedActuallyPlay( void )
|
||||
{
|
||||
// Ensure there's a stop notify for us
|
||||
if( !fReallyPlaying )
|
||||
{
|
||||
fDSoundBuffer->Play();
|
||||
fReallyPlaying = true;
|
||||
}
|
||||
|
||||
plSoundEvent *event = IFindEvent( plSoundEvent::kStart );
|
||||
if( event != nil )
|
||||
event->SendCallbacks();
|
||||
}
|
||||
|
||||
hsBool plWin32GroupedSound::MsgReceive( plMessage* pMsg )
|
||||
{
|
||||
plSoundMsg *soundMsg = plSoundMsg::ConvertNoRef( pMsg );
|
||||
if( soundMsg != nil && soundMsg->Cmd( plSoundMsg::kSelectFromGroup ) )
|
||||
{
|
||||
IFillCurrentSound( soundMsg->fIndex );
|
||||
return true;
|
||||
}
|
||||
else if( soundMsg != nil && soundMsg->Cmd( plSoundMsg::kPlay ) )
|
||||
{
|
||||
Play();
|
||||
//plIncidentalMgr::GetInstance()->Play( this, plIncidentalMgr::kNormal );
|
||||
return true;
|
||||
}
|
||||
|
||||
return plWin32StaticSound::MsgReceive( pMsg );
|
||||
}
|
||||
|
||||
|
@ -1,83 +1,83 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plWin32GroupedSound - Grouped version of a static sound. Lots of short //
|
||||
// sounds stored in the buffer, all share the same //
|
||||
// DSound playback buffer and only one plays at a //
|
||||
// time. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef plWin32GroupedSound_h
|
||||
#define plWin32GroupedSound_h
|
||||
|
||||
#include "plWin32StaticSound.h"
|
||||
|
||||
class hsResMgr;
|
||||
class plDSoundBuffer;
|
||||
class plEventCallbackMsg;
|
||||
|
||||
#include "plSoundEvent.h"
|
||||
|
||||
class plWin32GroupedSound : public plWin32StaticSound
|
||||
{
|
||||
public:
|
||||
plWin32GroupedSound();
|
||||
~plWin32GroupedSound();
|
||||
|
||||
CLASSNAME_REGISTER( plWin32GroupedSound );
|
||||
GETINTERFACE_ANY( plWin32GroupedSound, plWin32StaticSound );
|
||||
|
||||
virtual hsBool LoadSound( hsBool is3D );
|
||||
virtual hsBool MsgReceive( plMessage *pMsg );
|
||||
void SetPositionArray( UInt16 numSounds, UInt32 *posArray, hsScalar *volumeArray );
|
||||
hsScalar GetSoundLength( Int16 soundIndex );
|
||||
virtual double GetLength() { return GetSoundLength( fCurrentSound ); }
|
||||
|
||||
protected:
|
||||
UInt16 fCurrentSound;
|
||||
UInt32 fCurrentSoundLength;
|
||||
hsTArray<UInt32> fStartPositions; // In bytes
|
||||
hsTArray<hsScalar> fVolumes;
|
||||
|
||||
// Some extra handy info for us
|
||||
UInt8 fNumDestChannels, fNumDestBytesPerSample;
|
||||
|
||||
virtual void IDerivedActuallyPlay( void );
|
||||
|
||||
virtual void IRead( hsStream *s, hsResMgr *mgr );
|
||||
virtual void IWrite( hsStream *s, hsResMgr *mgr );
|
||||
|
||||
UInt32 IGetSoundByteLength( Int16 soundIndex );
|
||||
void IFillCurrentSound( Int16 newCurrent = -1 );
|
||||
|
||||
// Abstracting a few things here for the incidentalMgr
|
||||
virtual void * IGetDataPointer( void ) const;
|
||||
virtual UInt32 IGetDataLength( void ) const;
|
||||
};
|
||||
|
||||
#endif //plWin32GroupedSound_h
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plWin32GroupedSound - Grouped version of a static sound. Lots of short //
|
||||
// sounds stored in the buffer, all share the same //
|
||||
// DSound playback buffer and only one plays at a //
|
||||
// time. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef plWin32GroupedSound_h
|
||||
#define plWin32GroupedSound_h
|
||||
|
||||
#include "plWin32StaticSound.h"
|
||||
|
||||
class hsResMgr;
|
||||
class plDSoundBuffer;
|
||||
class plEventCallbackMsg;
|
||||
|
||||
#include "plSoundEvent.h"
|
||||
|
||||
class plWin32GroupedSound : public plWin32StaticSound
|
||||
{
|
||||
public:
|
||||
plWin32GroupedSound();
|
||||
~plWin32GroupedSound();
|
||||
|
||||
CLASSNAME_REGISTER( plWin32GroupedSound );
|
||||
GETINTERFACE_ANY( plWin32GroupedSound, plWin32StaticSound );
|
||||
|
||||
virtual hsBool LoadSound( hsBool is3D );
|
||||
virtual hsBool MsgReceive( plMessage *pMsg );
|
||||
void SetPositionArray( UInt16 numSounds, UInt32 *posArray, hsScalar *volumeArray );
|
||||
hsScalar GetSoundLength( Int16 soundIndex );
|
||||
virtual double GetLength() { return GetSoundLength( fCurrentSound ); }
|
||||
|
||||
protected:
|
||||
UInt16 fCurrentSound;
|
||||
UInt32 fCurrentSoundLength;
|
||||
hsTArray<UInt32> fStartPositions; // In bytes
|
||||
hsTArray<hsScalar> fVolumes;
|
||||
|
||||
// Some extra handy info for us
|
||||
UInt8 fNumDestChannels, fNumDestBytesPerSample;
|
||||
|
||||
virtual void IDerivedActuallyPlay( void );
|
||||
|
||||
virtual void IRead( hsStream *s, hsResMgr *mgr );
|
||||
virtual void IWrite( hsStream *s, hsResMgr *mgr );
|
||||
|
||||
UInt32 IGetSoundByteLength( Int16 soundIndex );
|
||||
void IFillCurrentSound( Int16 newCurrent = -1 );
|
||||
|
||||
// Abstracting a few things here for the incidentalMgr
|
||||
virtual void * IGetDataPointer( void ) const;
|
||||
virtual UInt32 IGetDataLength( void ) const;
|
||||
};
|
||||
|
||||
#endif //plWin32GroupedSound_h
|
||||
|
@ -1,430 +1,430 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#include <hvdi.h>
|
||||
#include <direct.h>
|
||||
#include "HeadSpin.h"
|
||||
#include "hsGeometry3.h"
|
||||
#include "hsTimer.h"
|
||||
#include "hsResMgr.h"
|
||||
#include "plgDispatch.h"
|
||||
|
||||
#include "plProfile.h"
|
||||
#include "plWin32Sound.h"
|
||||
#include "plAudioSystem.h"
|
||||
#include "plDSoundBuffer.h"
|
||||
#include "plAudioCore/plWavFile.h"
|
||||
|
||||
#include "plAudible/plWinAudible.h"
|
||||
#include "plNetMessage/plNetMessage.h"
|
||||
#include "pnNetCommon/plNetApp.h"
|
||||
#include "pnMessage/plSoundMsg.h"
|
||||
#include "pnMessage/plEventCallbackMsg.h"
|
||||
#include "plPipeline/plPlates.h"
|
||||
#include "plStatusLog/plStatusLog.h"
|
||||
|
||||
plProfile_CreateMemCounter("Sounds", "Memory", MemSounds);
|
||||
plProfile_Extern(SoundPlaying);
|
||||
|
||||
plWin32Sound::plWin32Sound() :
|
||||
fFailed(false),
|
||||
fPositionInited(false),
|
||||
fAwaitingPosition(false),
|
||||
fTotalBytes(0),
|
||||
fReallyPlaying(false),
|
||||
fChannelSelect(0),
|
||||
fDSoundBuffer(nil)
|
||||
{
|
||||
}
|
||||
|
||||
plWin32Sound::~plWin32Sound()
|
||||
{
|
||||
}
|
||||
|
||||
void plWin32Sound::Activate( hsBool forcePlay )
|
||||
{
|
||||
if( fFailed )
|
||||
return;
|
||||
|
||||
plSound::Activate( forcePlay );
|
||||
}
|
||||
|
||||
void plWin32Sound::DeActivate()
|
||||
{
|
||||
plSound::DeActivate();
|
||||
IFreeBuffers();
|
||||
}
|
||||
|
||||
void plWin32Sound::IFreeBuffers( void )
|
||||
{
|
||||
if( fDSoundBuffer != nil )
|
||||
{
|
||||
delete fDSoundBuffer;
|
||||
fDSoundBuffer = nil;
|
||||
plProfile_DelMem(MemSounds, fTotalBytes);
|
||||
fTotalBytes = 0;
|
||||
}
|
||||
|
||||
fPositionInited = false;
|
||||
fAwaitingPosition = false;
|
||||
}
|
||||
|
||||
void plWin32Sound::Update()
|
||||
{
|
||||
plSound::Update();
|
||||
}
|
||||
|
||||
void plWin32Sound::IActuallyPlay( void )
|
||||
{
|
||||
//plSound::Play();
|
||||
if (!fDSoundBuffer && plgAudioSys::Active())
|
||||
LoadSound( IsPropertySet( kPropIs3DSound ) );
|
||||
if(!fLoading )
|
||||
{
|
||||
if (fDSoundBuffer && plgAudioSys::Active() )
|
||||
{
|
||||
|
||||
// Sometimes base/derived classes can be annoying
|
||||
IDerivedActuallyPlay();
|
||||
RefreshVolume();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we can't load (for ex., if audio is off), then we act like we played and then stopped
|
||||
// really fast. Thus, we need to send *all* of our callbacks off immediately and then Stop().
|
||||
UInt32 i;
|
||||
for( i = 0; i < fSoundEvents.GetCount(); i++ )
|
||||
{
|
||||
fSoundEvents[ i ]->SendCallbacks();
|
||||
}
|
||||
|
||||
// Now stop, 'cause we played really really really really fast
|
||||
fPlaying = false;
|
||||
fPlayOnReactivate = IsPropertySet( kPropLooping );
|
||||
IActuallyStop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void plWin32Sound::IActuallyStop()
|
||||
{
|
||||
if( fReallyPlaying )
|
||||
{
|
||||
if( fDSoundBuffer != nil )
|
||||
{
|
||||
if(IsPropertySet(kPropIncidental))
|
||||
{
|
||||
--fIncidentalsPlaying;
|
||||
}
|
||||
fDSoundBuffer->Stop();
|
||||
plStatusLog::AddLineS("impacts.log", "Stopping %s", GetKeyName());
|
||||
|
||||
}
|
||||
fReallyPlaying = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( fDSoundBuffer != nil && fDSoundBuffer->IsPlaying() )
|
||||
{
|
||||
plStatusLog::AddLineS( "audio.log", 0xffff0000, "WARNING: BUFFER FLAGGED AS STOPPED BUT NOT STOPPED - %s", GetKey() ? GetKeyName() : nil );
|
||||
fDSoundBuffer->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
// send callbacks
|
||||
plSoundEvent *event = IFindEvent( plSoundEvent::kStop );
|
||||
if( event != nil )
|
||||
{
|
||||
event->SendCallbacks();
|
||||
}
|
||||
|
||||
plSound::IActuallyStop();
|
||||
}
|
||||
|
||||
plSoundMsg* plWin32Sound::GetStatus(plSoundMsg* pMsg)
|
||||
{
|
||||
plSoundMsg* pReply = TRACKED_NEW plSoundMsg;
|
||||
pReply->AddReceiver( pMsg->GetSender() );
|
||||
pReply->SetCmd(plSoundMsg::kStatusReply);
|
||||
pReply->fLoop = IsPropertySet( kPropLooping );
|
||||
pReply->fPlaying = IsPlaying();
|
||||
return pReply;
|
||||
}
|
||||
|
||||
void plWin32Sound::SetMin( const int m )
|
||||
{
|
||||
plSound::SetMin(m);
|
||||
if(fDSoundBuffer)
|
||||
{
|
||||
fDSoundBuffer->SetMinDistance(m);
|
||||
}
|
||||
}
|
||||
|
||||
void plWin32Sound::SetMax( const int m )
|
||||
{
|
||||
plSound::SetMax(m);
|
||||
if( fDSoundBuffer )
|
||||
{
|
||||
fDSoundBuffer->SetMaxDistance( m );
|
||||
}
|
||||
}
|
||||
|
||||
void plWin32Sound::SetOuterVolume( const int v )
|
||||
{
|
||||
plSound::SetOuterVolume(v);
|
||||
if(fDSoundBuffer)
|
||||
{
|
||||
fDSoundBuffer->SetConeOutsideVolume(v);
|
||||
}
|
||||
}
|
||||
|
||||
void plWin32Sound::SetConeAngles( int inner, int outer )
|
||||
{
|
||||
plSound::SetConeAngles(inner, outer);
|
||||
if(fDSoundBuffer)
|
||||
{
|
||||
fDSoundBuffer->SetConeAngles(inner, outer);
|
||||
}
|
||||
}
|
||||
|
||||
void plWin32Sound::SetConeOrientation( hsScalar x, hsScalar y, hsScalar z )
|
||||
{
|
||||
plSound::SetConeOrientation(x, y, z);
|
||||
if(fDSoundBuffer)
|
||||
{
|
||||
fDSoundBuffer->SetConeOrientation(x, z, y);
|
||||
}
|
||||
}
|
||||
|
||||
void plWin32Sound::SetVelocity( const hsVector3 vel )
|
||||
{
|
||||
plSound::SetVelocity(vel);
|
||||
if( fDSoundBuffer)
|
||||
fDSoundBuffer->SetVelocity(vel.fX, vel.fZ, vel.fY);
|
||||
}
|
||||
|
||||
void plWin32Sound::SetPosition( const hsPoint3 pos )
|
||||
{
|
||||
plSound::SetPosition(pos);
|
||||
if(fDSoundBuffer)
|
||||
{
|
||||
// in openal sounds that are mono are played as positional. Since gui's may be positioned way off in space, the sound may not be audible.
|
||||
// doing this allows us to play mono gui sounds and still hear them, since this attaches the sound to the listener.
|
||||
if(fType == kGUISound)
|
||||
{
|
||||
hsPoint3 listenerPos = plgAudioSys::Sys()->GetCurrListenerPos();
|
||||
fDSoundBuffer->SetPosition(listenerPos.fX, listenerPos.fZ, listenerPos.fY);
|
||||
}
|
||||
else
|
||||
{
|
||||
fDSoundBuffer->SetPosition(pos.fX, pos.fZ, pos.fY);
|
||||
}
|
||||
}
|
||||
|
||||
fPositionInited = true;
|
||||
if( fAwaitingPosition )
|
||||
{
|
||||
// If this is set, then we tried to set the volume before the position. Since
|
||||
// this results in some ghastly sound popping, we wait until we set the position
|
||||
// (here), and then call our volume again
|
||||
RefreshVolume();
|
||||
fAwaitingPosition = false;
|
||||
}
|
||||
}
|
||||
|
||||
void plWin32Sound::ISetActualVolume(const float volume)
|
||||
{
|
||||
float vol = IAttenuateActualVolume( volume ) * IGetChannelVolume();
|
||||
if( fDSoundBuffer )
|
||||
{
|
||||
if( fPositionInited || !IsPropertySet( kPropIs3DSound ) )
|
||||
{
|
||||
fDSoundBuffer->SetScalarVolume( vol );
|
||||
}
|
||||
else
|
||||
{
|
||||
// If position isn't inited, we don't want to set the volume yet,
|
||||
// so set this flag so we know to set the volume once we DO get the position
|
||||
fAwaitingPosition = true;
|
||||
}
|
||||
}
|
||||
IUpdateDebugPlate(); // Byte me.
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// The base class will make sure all our params are correct and up-to-date,
|
||||
// but before it does its work, we have to make sure our buffer is ready to
|
||||
// be updated.
|
||||
void plWin32Sound::IRefreshParams( void )
|
||||
{
|
||||
if (!fDSoundBuffer && plgAudioSys::Active())
|
||||
LoadSound( IsPropertySet( kPropIs3DSound ) );
|
||||
|
||||
else
|
||||
{
|
||||
// There is a gap between the ds buffer stopping and the sound being marked as stopped.
|
||||
// If the sound is asked to play again during this time frame it will never actually be
|
||||
// played because it is still marked as playing. Not only that, but we'll lose a hardware voice too.
|
||||
// This will fix that by starting it up again.
|
||||
if(plgAudioSys::Active())
|
||||
fDSoundBuffer->Play();
|
||||
}
|
||||
plSound::IRefreshParams();
|
||||
}
|
||||
|
||||
void plWin32Sound::IRefreshEAXSettings( hsBool force )
|
||||
{
|
||||
if( fDSoundBuffer != nil )
|
||||
fDSoundBuffer->SetEAXSettings( &GetEAXSettings(), force );
|
||||
}
|
||||
|
||||
void plWin32Sound::IAddCallback( plEventCallbackMsg *pMsg )
|
||||
{
|
||||
plSoundEvent::Types type = plSoundEvent::GetTypeFromCallbackMsg( pMsg );
|
||||
plSoundEvent *event;
|
||||
|
||||
if( type == plSoundEvent::kTime )
|
||||
{
|
||||
UInt32 byteTime = ( fDSoundBuffer != nil ) ? fDSoundBuffer->GetBufferBytePos( pMsg->fEventTime ) : 0;
|
||||
|
||||
event = IFindEvent( type, byteTime );
|
||||
|
||||
if( event == nil )
|
||||
{
|
||||
// Add a new sound event for this guy
|
||||
event = TRACKED_NEW plSoundEvent( type, byteTime, this );
|
||||
//fDSoundBuffer->AddPosNotify( byteTime );
|
||||
fSoundEvents.Append( event );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
event = IFindEvent( type );
|
||||
|
||||
if( event == nil )
|
||||
{
|
||||
// Add a new sound event for this guy
|
||||
event = TRACKED_NEW plSoundEvent( type, this );
|
||||
fSoundEvents.Append( event );
|
||||
}
|
||||
}
|
||||
|
||||
event->AddCallback( pMsg );
|
||||
}
|
||||
|
||||
void plWin32Sound::IRemoveCallback( plEventCallbackMsg *pMsg )
|
||||
{
|
||||
plSoundEvent::Types type = plSoundEvent::GetTypeFromCallbackMsg( pMsg );
|
||||
|
||||
for(int i = 0; i < fSoundEvents.GetCount(); ++i)
|
||||
{
|
||||
if( fSoundEvents[ i ]->GetType() == type )
|
||||
{
|
||||
if( fSoundEvents[ i ]->RemoveCallback( pMsg ) )
|
||||
{
|
||||
if( fSoundEvents[ i ]->GetNumCallbacks() == 0 )
|
||||
{
|
||||
//if( fSoundEvents[ i ]->GetType() == plSoundEvent::kTime )
|
||||
//fDSoundBuffer->RemovePosNotify( fSoundEvents[ i ]->GetTime() );
|
||||
|
||||
delete fSoundEvents[ i ];
|
||||
fSoundEvents.Remove( i );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plSoundEvent *plWin32Sound::IFindEvent( plSoundEvent::Types type, UInt32 bytePos )
|
||||
{
|
||||
for(int i = 0; i < fSoundEvents.GetCount(); ++i )
|
||||
{
|
||||
if( fSoundEvents[ i ]->GetType() == type )
|
||||
{
|
||||
if( type != plSoundEvent::kTime || bytePos == fSoundEvents[ i ]->GetTime() )
|
||||
return fSoundEvents[ i ];
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
void plWin32Sound::RemoveCallbacks(plSoundMsg* pSoundMsg)
|
||||
{
|
||||
for(int i = 0; i < pSoundMsg->GetNumCallbacks(); ++i )
|
||||
IRemoveCallback( pSoundMsg->GetEventCallback( i ) );
|
||||
}
|
||||
|
||||
void plWin32Sound::AddCallbacks(plSoundMsg* pSoundMsg)
|
||||
{
|
||||
for(int i = 0; i < pSoundMsg->GetNumCallbacks(); ++i )
|
||||
IAddCallback( pSoundMsg->GetEventCallback( i ) );
|
||||
}
|
||||
|
||||
hsBool plWin32Sound::MsgReceive( plMessage* pMsg )
|
||||
{
|
||||
plEventCallbackMsg *e = plEventCallbackMsg::ConvertNoRef( pMsg );
|
||||
if( e != nil )
|
||||
{
|
||||
if( e->fEvent == kStop )
|
||||
{
|
||||
fPlaying = false;
|
||||
fPlayOnReactivate = false; // Just to make sure...
|
||||
|
||||
// Do we have an ending fade?
|
||||
if( fFadeOutParams.fLengthInSecs > 0 )
|
||||
{
|
||||
IStartFade( &fFadeOutParams );
|
||||
plSoundEvent *event = IFindEvent( plSoundEvent::kStop );
|
||||
if( event != nil )
|
||||
event->SendCallbacks();
|
||||
}
|
||||
else
|
||||
{
|
||||
if( fFading )
|
||||
IStopFade();
|
||||
|
||||
fCurrVolume = 0.f;
|
||||
this->ISetActualVolume( fCurrVolume );
|
||||
}
|
||||
this->IActuallyStop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return plSound::MsgReceive( pMsg );
|
||||
}
|
||||
|
||||
void plWin32Sound::IRead( hsStream *s, hsResMgr *mgr )
|
||||
{
|
||||
plSound::IRead( s, mgr );
|
||||
fChannelSelect = s->ReadByte();
|
||||
}
|
||||
|
||||
void plWin32Sound::IWrite( hsStream *s, hsResMgr *mgr )
|
||||
{
|
||||
plSound::IWrite( s, mgr );
|
||||
s->WriteByte( fChannelSelect );
|
||||
}
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#include <hvdi.h>
|
||||
#include <direct.h>
|
||||
#include "HeadSpin.h"
|
||||
#include "hsGeometry3.h"
|
||||
#include "hsTimer.h"
|
||||
#include "hsResMgr.h"
|
||||
#include "plgDispatch.h"
|
||||
|
||||
#include "plProfile.h"
|
||||
#include "plWin32Sound.h"
|
||||
#include "plAudioSystem.h"
|
||||
#include "plDSoundBuffer.h"
|
||||
#include "plAudioCore/plWavFile.h"
|
||||
|
||||
#include "plAudible/plWinAudible.h"
|
||||
#include "plNetMessage/plNetMessage.h"
|
||||
#include "pnNetCommon/plNetApp.h"
|
||||
#include "pnMessage/plSoundMsg.h"
|
||||
#include "pnMessage/plEventCallbackMsg.h"
|
||||
#include "plPipeline/plPlates.h"
|
||||
#include "plStatusLog/plStatusLog.h"
|
||||
|
||||
plProfile_CreateMemCounter("Sounds", "Memory", MemSounds);
|
||||
plProfile_Extern(SoundPlaying);
|
||||
|
||||
plWin32Sound::plWin32Sound() :
|
||||
fFailed(false),
|
||||
fPositionInited(false),
|
||||
fAwaitingPosition(false),
|
||||
fTotalBytes(0),
|
||||
fReallyPlaying(false),
|
||||
fChannelSelect(0),
|
||||
fDSoundBuffer(nil)
|
||||
{
|
||||
}
|
||||
|
||||
plWin32Sound::~plWin32Sound()
|
||||
{
|
||||
}
|
||||
|
||||
void plWin32Sound::Activate( hsBool forcePlay )
|
||||
{
|
||||
if( fFailed )
|
||||
return;
|
||||
|
||||
plSound::Activate( forcePlay );
|
||||
}
|
||||
|
||||
void plWin32Sound::DeActivate()
|
||||
{
|
||||
plSound::DeActivate();
|
||||
IFreeBuffers();
|
||||
}
|
||||
|
||||
void plWin32Sound::IFreeBuffers( void )
|
||||
{
|
||||
if( fDSoundBuffer != nil )
|
||||
{
|
||||
delete fDSoundBuffer;
|
||||
fDSoundBuffer = nil;
|
||||
plProfile_DelMem(MemSounds, fTotalBytes);
|
||||
fTotalBytes = 0;
|
||||
}
|
||||
|
||||
fPositionInited = false;
|
||||
fAwaitingPosition = false;
|
||||
}
|
||||
|
||||
void plWin32Sound::Update()
|
||||
{
|
||||
plSound::Update();
|
||||
}
|
||||
|
||||
void plWin32Sound::IActuallyPlay( void )
|
||||
{
|
||||
//plSound::Play();
|
||||
if (!fDSoundBuffer && plgAudioSys::Active())
|
||||
LoadSound( IsPropertySet( kPropIs3DSound ) );
|
||||
if(!fLoading )
|
||||
{
|
||||
if (fDSoundBuffer && plgAudioSys::Active() )
|
||||
{
|
||||
|
||||
// Sometimes base/derived classes can be annoying
|
||||
IDerivedActuallyPlay();
|
||||
RefreshVolume();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we can't load (for ex., if audio is off), then we act like we played and then stopped
|
||||
// really fast. Thus, we need to send *all* of our callbacks off immediately and then Stop().
|
||||
UInt32 i;
|
||||
for( i = 0; i < fSoundEvents.GetCount(); i++ )
|
||||
{
|
||||
fSoundEvents[ i ]->SendCallbacks();
|
||||
}
|
||||
|
||||
// Now stop, 'cause we played really really really really fast
|
||||
fPlaying = false;
|
||||
fPlayOnReactivate = IsPropertySet( kPropLooping );
|
||||
IActuallyStop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void plWin32Sound::IActuallyStop()
|
||||
{
|
||||
if( fReallyPlaying )
|
||||
{
|
||||
if( fDSoundBuffer != nil )
|
||||
{
|
||||
if(IsPropertySet(kPropIncidental))
|
||||
{
|
||||
--fIncidentalsPlaying;
|
||||
}
|
||||
fDSoundBuffer->Stop();
|
||||
plStatusLog::AddLineS("impacts.log", "Stopping %s", GetKeyName());
|
||||
|
||||
}
|
||||
fReallyPlaying = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( fDSoundBuffer != nil && fDSoundBuffer->IsPlaying() )
|
||||
{
|
||||
plStatusLog::AddLineS( "audio.log", 0xffff0000, "WARNING: BUFFER FLAGGED AS STOPPED BUT NOT STOPPED - %s", GetKey() ? GetKeyName() : nil );
|
||||
fDSoundBuffer->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
// send callbacks
|
||||
plSoundEvent *event = IFindEvent( plSoundEvent::kStop );
|
||||
if( event != nil )
|
||||
{
|
||||
event->SendCallbacks();
|
||||
}
|
||||
|
||||
plSound::IActuallyStop();
|
||||
}
|
||||
|
||||
plSoundMsg* plWin32Sound::GetStatus(plSoundMsg* pMsg)
|
||||
{
|
||||
plSoundMsg* pReply = TRACKED_NEW plSoundMsg;
|
||||
pReply->AddReceiver( pMsg->GetSender() );
|
||||
pReply->SetCmd(plSoundMsg::kStatusReply);
|
||||
pReply->fLoop = IsPropertySet( kPropLooping );
|
||||
pReply->fPlaying = IsPlaying();
|
||||
return pReply;
|
||||
}
|
||||
|
||||
void plWin32Sound::SetMin( const int m )
|
||||
{
|
||||
plSound::SetMin(m);
|
||||
if(fDSoundBuffer)
|
||||
{
|
||||
fDSoundBuffer->SetMinDistance(m);
|
||||
}
|
||||
}
|
||||
|
||||
void plWin32Sound::SetMax( const int m )
|
||||
{
|
||||
plSound::SetMax(m);
|
||||
if( fDSoundBuffer )
|
||||
{
|
||||
fDSoundBuffer->SetMaxDistance( m );
|
||||
}
|
||||
}
|
||||
|
||||
void plWin32Sound::SetOuterVolume( const int v )
|
||||
{
|
||||
plSound::SetOuterVolume(v);
|
||||
if(fDSoundBuffer)
|
||||
{
|
||||
fDSoundBuffer->SetConeOutsideVolume(v);
|
||||
}
|
||||
}
|
||||
|
||||
void plWin32Sound::SetConeAngles( int inner, int outer )
|
||||
{
|
||||
plSound::SetConeAngles(inner, outer);
|
||||
if(fDSoundBuffer)
|
||||
{
|
||||
fDSoundBuffer->SetConeAngles(inner, outer);
|
||||
}
|
||||
}
|
||||
|
||||
void plWin32Sound::SetConeOrientation( hsScalar x, hsScalar y, hsScalar z )
|
||||
{
|
||||
plSound::SetConeOrientation(x, y, z);
|
||||
if(fDSoundBuffer)
|
||||
{
|
||||
fDSoundBuffer->SetConeOrientation(x, z, y);
|
||||
}
|
||||
}
|
||||
|
||||
void plWin32Sound::SetVelocity( const hsVector3 vel )
|
||||
{
|
||||
plSound::SetVelocity(vel);
|
||||
if( fDSoundBuffer)
|
||||
fDSoundBuffer->SetVelocity(vel.fX, vel.fZ, vel.fY);
|
||||
}
|
||||
|
||||
void plWin32Sound::SetPosition( const hsPoint3 pos )
|
||||
{
|
||||
plSound::SetPosition(pos);
|
||||
if(fDSoundBuffer)
|
||||
{
|
||||
// in openal sounds that are mono are played as positional. Since gui's may be positioned way off in space, the sound may not be audible.
|
||||
// doing this allows us to play mono gui sounds and still hear them, since this attaches the sound to the listener.
|
||||
if(fType == kGUISound)
|
||||
{
|
||||
hsPoint3 listenerPos = plgAudioSys::Sys()->GetCurrListenerPos();
|
||||
fDSoundBuffer->SetPosition(listenerPos.fX, listenerPos.fZ, listenerPos.fY);
|
||||
}
|
||||
else
|
||||
{
|
||||
fDSoundBuffer->SetPosition(pos.fX, pos.fZ, pos.fY);
|
||||
}
|
||||
}
|
||||
|
||||
fPositionInited = true;
|
||||
if( fAwaitingPosition )
|
||||
{
|
||||
// If this is set, then we tried to set the volume before the position. Since
|
||||
// this results in some ghastly sound popping, we wait until we set the position
|
||||
// (here), and then call our volume again
|
||||
RefreshVolume();
|
||||
fAwaitingPosition = false;
|
||||
}
|
||||
}
|
||||
|
||||
void plWin32Sound::ISetActualVolume(const float volume)
|
||||
{
|
||||
float vol = IAttenuateActualVolume( volume ) * IGetChannelVolume();
|
||||
if( fDSoundBuffer )
|
||||
{
|
||||
if( fPositionInited || !IsPropertySet( kPropIs3DSound ) )
|
||||
{
|
||||
fDSoundBuffer->SetScalarVolume( vol );
|
||||
}
|
||||
else
|
||||
{
|
||||
// If position isn't inited, we don't want to set the volume yet,
|
||||
// so set this flag so we know to set the volume once we DO get the position
|
||||
fAwaitingPosition = true;
|
||||
}
|
||||
}
|
||||
IUpdateDebugPlate(); // Byte me.
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// The base class will make sure all our params are correct and up-to-date,
|
||||
// but before it does its work, we have to make sure our buffer is ready to
|
||||
// be updated.
|
||||
void plWin32Sound::IRefreshParams( void )
|
||||
{
|
||||
if (!fDSoundBuffer && plgAudioSys::Active())
|
||||
LoadSound( IsPropertySet( kPropIs3DSound ) );
|
||||
|
||||
else
|
||||
{
|
||||
// There is a gap between the ds buffer stopping and the sound being marked as stopped.
|
||||
// If the sound is asked to play again during this time frame it will never actually be
|
||||
// played because it is still marked as playing. Not only that, but we'll lose a hardware voice too.
|
||||
// This will fix that by starting it up again.
|
||||
if(plgAudioSys::Active())
|
||||
fDSoundBuffer->Play();
|
||||
}
|
||||
plSound::IRefreshParams();
|
||||
}
|
||||
|
||||
void plWin32Sound::IRefreshEAXSettings( hsBool force )
|
||||
{
|
||||
if( fDSoundBuffer != nil )
|
||||
fDSoundBuffer->SetEAXSettings( &GetEAXSettings(), force );
|
||||
}
|
||||
|
||||
void plWin32Sound::IAddCallback( plEventCallbackMsg *pMsg )
|
||||
{
|
||||
plSoundEvent::Types type = plSoundEvent::GetTypeFromCallbackMsg( pMsg );
|
||||
plSoundEvent *event;
|
||||
|
||||
if( type == plSoundEvent::kTime )
|
||||
{
|
||||
UInt32 byteTime = ( fDSoundBuffer != nil ) ? fDSoundBuffer->GetBufferBytePos( pMsg->fEventTime ) : 0;
|
||||
|
||||
event = IFindEvent( type, byteTime );
|
||||
|
||||
if( event == nil )
|
||||
{
|
||||
// Add a new sound event for this guy
|
||||
event = TRACKED_NEW plSoundEvent( type, byteTime, this );
|
||||
//fDSoundBuffer->AddPosNotify( byteTime );
|
||||
fSoundEvents.Append( event );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
event = IFindEvent( type );
|
||||
|
||||
if( event == nil )
|
||||
{
|
||||
// Add a new sound event for this guy
|
||||
event = TRACKED_NEW plSoundEvent( type, this );
|
||||
fSoundEvents.Append( event );
|
||||
}
|
||||
}
|
||||
|
||||
event->AddCallback( pMsg );
|
||||
}
|
||||
|
||||
void plWin32Sound::IRemoveCallback( plEventCallbackMsg *pMsg )
|
||||
{
|
||||
plSoundEvent::Types type = plSoundEvent::GetTypeFromCallbackMsg( pMsg );
|
||||
|
||||
for(int i = 0; i < fSoundEvents.GetCount(); ++i)
|
||||
{
|
||||
if( fSoundEvents[ i ]->GetType() == type )
|
||||
{
|
||||
if( fSoundEvents[ i ]->RemoveCallback( pMsg ) )
|
||||
{
|
||||
if( fSoundEvents[ i ]->GetNumCallbacks() == 0 )
|
||||
{
|
||||
//if( fSoundEvents[ i ]->GetType() == plSoundEvent::kTime )
|
||||
//fDSoundBuffer->RemovePosNotify( fSoundEvents[ i ]->GetTime() );
|
||||
|
||||
delete fSoundEvents[ i ];
|
||||
fSoundEvents.Remove( i );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plSoundEvent *plWin32Sound::IFindEvent( plSoundEvent::Types type, UInt32 bytePos )
|
||||
{
|
||||
for(int i = 0; i < fSoundEvents.GetCount(); ++i )
|
||||
{
|
||||
if( fSoundEvents[ i ]->GetType() == type )
|
||||
{
|
||||
if( type != plSoundEvent::kTime || bytePos == fSoundEvents[ i ]->GetTime() )
|
||||
return fSoundEvents[ i ];
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
void plWin32Sound::RemoveCallbacks(plSoundMsg* pSoundMsg)
|
||||
{
|
||||
for(int i = 0; i < pSoundMsg->GetNumCallbacks(); ++i )
|
||||
IRemoveCallback( pSoundMsg->GetEventCallback( i ) );
|
||||
}
|
||||
|
||||
void plWin32Sound::AddCallbacks(plSoundMsg* pSoundMsg)
|
||||
{
|
||||
for(int i = 0; i < pSoundMsg->GetNumCallbacks(); ++i )
|
||||
IAddCallback( pSoundMsg->GetEventCallback( i ) );
|
||||
}
|
||||
|
||||
hsBool plWin32Sound::MsgReceive( plMessage* pMsg )
|
||||
{
|
||||
plEventCallbackMsg *e = plEventCallbackMsg::ConvertNoRef( pMsg );
|
||||
if( e != nil )
|
||||
{
|
||||
if( e->fEvent == kStop )
|
||||
{
|
||||
fPlaying = false;
|
||||
fPlayOnReactivate = false; // Just to make sure...
|
||||
|
||||
// Do we have an ending fade?
|
||||
if( fFadeOutParams.fLengthInSecs > 0 )
|
||||
{
|
||||
IStartFade( &fFadeOutParams );
|
||||
plSoundEvent *event = IFindEvent( plSoundEvent::kStop );
|
||||
if( event != nil )
|
||||
event->SendCallbacks();
|
||||
}
|
||||
else
|
||||
{
|
||||
if( fFading )
|
||||
IStopFade();
|
||||
|
||||
fCurrVolume = 0.f;
|
||||
this->ISetActualVolume( fCurrVolume );
|
||||
}
|
||||
this->IActuallyStop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return plSound::MsgReceive( pMsg );
|
||||
}
|
||||
|
||||
void plWin32Sound::IRead( hsStream *s, hsResMgr *mgr )
|
||||
{
|
||||
plSound::IRead( s, mgr );
|
||||
fChannelSelect = s->ReadByte();
|
||||
}
|
||||
|
||||
void plWin32Sound::IWrite( hsStream *s, hsResMgr *mgr )
|
||||
{
|
||||
plSound::IWrite( s, mgr );
|
||||
s->WriteByte( fChannelSelect );
|
||||
}
|
||||
|
@ -1,120 +1,120 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#ifndef plWin32Sound_h
|
||||
#define plWin32Sound_h
|
||||
|
||||
#include "hsTemplates.h"
|
||||
#include "plSound.h"
|
||||
#include "hsThread.h"
|
||||
#include "plSoundEvent.h"
|
||||
|
||||
#define NUM_MAX_HANDLES 16
|
||||
#define REPEAT_INFINITE 0xffffffff
|
||||
|
||||
struct hsVector3;
|
||||
class hsResMgr;
|
||||
class plEventCallbackMsg;
|
||||
class plSoundMsg;
|
||||
class DSoundCallbackHandle;
|
||||
class plSoundEvent;
|
||||
class plDSoundBuffer;
|
||||
|
||||
class plWin32Sound : public plSound
|
||||
{
|
||||
public:
|
||||
|
||||
plWin32Sound();
|
||||
virtual ~plWin32Sound();
|
||||
|
||||
CLASSNAME_REGISTER( plWin32Sound );
|
||||
GETINTERFACE_ANY( plWin32Sound, plSound );
|
||||
|
||||
virtual void Activate(hsBool forcePlay = false);
|
||||
virtual void DeActivate();
|
||||
|
||||
virtual void AddCallbacks(plSoundMsg* pMsg);
|
||||
virtual void RemoveCallbacks(plSoundMsg* pMsg);
|
||||
|
||||
virtual plSoundMsg* GetStatus(plSoundMsg* pMsg);
|
||||
virtual hsBool MsgReceive(plMessage* pMsg);
|
||||
virtual void Update();
|
||||
|
||||
virtual void SetMin(const int m); // sets minimum falloff distance
|
||||
virtual void SetMax(const int m); // sets maximum falloff distance
|
||||
virtual void SetConeOrientation(hsScalar x, hsScalar y, hsScalar z);
|
||||
virtual void SetOuterVolume( const int v ); // volume for the outer cone (if applicable)
|
||||
virtual void SetConeAngles( int inner, int outer );
|
||||
virtual void SetPosition(const hsPoint3 pos);
|
||||
virtual void SetVelocity(const hsVector3 vel);
|
||||
|
||||
enum ChannelSelect
|
||||
{
|
||||
kLeftChannel,
|
||||
kRightChannel
|
||||
};
|
||||
|
||||
// Selects a channel source from a multi-channel (stereo) file. Ignored if source is mono
|
||||
void SetChannelSelect( ChannelSelect source ) { fChannelSelect = (UInt8)source; }
|
||||
virtual UInt8 GetChannelSelect( void ) const { return fChannelSelect; }
|
||||
|
||||
protected:
|
||||
|
||||
plDSoundBuffer * fDSoundBuffer;
|
||||
|
||||
hsBool fFailed;
|
||||
hsBool fPositionInited, fAwaitingPosition;
|
||||
hsBool fReallyPlaying;
|
||||
UInt32 fTotalBytes;
|
||||
|
||||
hsBool fWasPlaying;
|
||||
|
||||
UInt8 fChannelSelect; // For selecting a mono channel from a stereo file
|
||||
|
||||
hsTArray<plSoundEvent *> fSoundEvents;
|
||||
|
||||
virtual void ISetActualVolume(const float v);
|
||||
virtual void IActuallyStop( void );
|
||||
virtual hsBool IActuallyPlaying( void ) { return fReallyPlaying; }
|
||||
virtual void IActuallyPlay( void );
|
||||
virtual void IFreeBuffers( void );
|
||||
virtual hsBool IActuallyLoaded( void ) { return ( fDSoundBuffer != nil ) ? true : false; }
|
||||
|
||||
// Override to make sure the buffer is available before the base class is called
|
||||
virtual void IRefreshParams( void );
|
||||
|
||||
virtual void IDerivedActuallyPlay( void ) = 0;
|
||||
|
||||
virtual void IAddCallback( plEventCallbackMsg *pMsg );
|
||||
virtual void IRemoveCallback( plEventCallbackMsg *pMsg );
|
||||
plSoundEvent *IFindEvent( plSoundEvent::Types type, UInt32 bytePos = 0 );
|
||||
|
||||
virtual void IRead( hsStream *s, hsResMgr *mgr );
|
||||
virtual void IWrite( hsStream *s, hsResMgr *mgr );
|
||||
|
||||
virtual void IRefreshEAXSettings( hsBool force = false );
|
||||
};
|
||||
|
||||
#endif //plWin32Sound_h
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#ifndef plWin32Sound_h
|
||||
#define plWin32Sound_h
|
||||
|
||||
#include "hsTemplates.h"
|
||||
#include "plSound.h"
|
||||
#include "hsThread.h"
|
||||
#include "plSoundEvent.h"
|
||||
|
||||
#define NUM_MAX_HANDLES 16
|
||||
#define REPEAT_INFINITE 0xffffffff
|
||||
|
||||
struct hsVector3;
|
||||
class hsResMgr;
|
||||
class plEventCallbackMsg;
|
||||
class plSoundMsg;
|
||||
class DSoundCallbackHandle;
|
||||
class plSoundEvent;
|
||||
class plDSoundBuffer;
|
||||
|
||||
class plWin32Sound : public plSound
|
||||
{
|
||||
public:
|
||||
|
||||
plWin32Sound();
|
||||
virtual ~plWin32Sound();
|
||||
|
||||
CLASSNAME_REGISTER( plWin32Sound );
|
||||
GETINTERFACE_ANY( plWin32Sound, plSound );
|
||||
|
||||
virtual void Activate(hsBool forcePlay = false);
|
||||
virtual void DeActivate();
|
||||
|
||||
virtual void AddCallbacks(plSoundMsg* pMsg);
|
||||
virtual void RemoveCallbacks(plSoundMsg* pMsg);
|
||||
|
||||
virtual plSoundMsg* GetStatus(plSoundMsg* pMsg);
|
||||
virtual hsBool MsgReceive(plMessage* pMsg);
|
||||
virtual void Update();
|
||||
|
||||
virtual void SetMin(const int m); // sets minimum falloff distance
|
||||
virtual void SetMax(const int m); // sets maximum falloff distance
|
||||
virtual void SetConeOrientation(hsScalar x, hsScalar y, hsScalar z);
|
||||
virtual void SetOuterVolume( const int v ); // volume for the outer cone (if applicable)
|
||||
virtual void SetConeAngles( int inner, int outer );
|
||||
virtual void SetPosition(const hsPoint3 pos);
|
||||
virtual void SetVelocity(const hsVector3 vel);
|
||||
|
||||
enum ChannelSelect
|
||||
{
|
||||
kLeftChannel,
|
||||
kRightChannel
|
||||
};
|
||||
|
||||
// Selects a channel source from a multi-channel (stereo) file. Ignored if source is mono
|
||||
void SetChannelSelect( ChannelSelect source ) { fChannelSelect = (UInt8)source; }
|
||||
virtual UInt8 GetChannelSelect( void ) const { return fChannelSelect; }
|
||||
|
||||
protected:
|
||||
|
||||
plDSoundBuffer * fDSoundBuffer;
|
||||
|
||||
hsBool fFailed;
|
||||
hsBool fPositionInited, fAwaitingPosition;
|
||||
hsBool fReallyPlaying;
|
||||
UInt32 fTotalBytes;
|
||||
|
||||
hsBool fWasPlaying;
|
||||
|
||||
UInt8 fChannelSelect; // For selecting a mono channel from a stereo file
|
||||
|
||||
hsTArray<plSoundEvent *> fSoundEvents;
|
||||
|
||||
virtual void ISetActualVolume(const float v);
|
||||
virtual void IActuallyStop( void );
|
||||
virtual hsBool IActuallyPlaying( void ) { return fReallyPlaying; }
|
||||
virtual void IActuallyPlay( void );
|
||||
virtual void IFreeBuffers( void );
|
||||
virtual hsBool IActuallyLoaded( void ) { return ( fDSoundBuffer != nil ) ? true : false; }
|
||||
|
||||
// Override to make sure the buffer is available before the base class is called
|
||||
virtual void IRefreshParams( void );
|
||||
|
||||
virtual void IDerivedActuallyPlay( void ) = 0;
|
||||
|
||||
virtual void IAddCallback( plEventCallbackMsg *pMsg );
|
||||
virtual void IRemoveCallback( plEventCallbackMsg *pMsg );
|
||||
plSoundEvent *IFindEvent( plSoundEvent::Types type, UInt32 bytePos = 0 );
|
||||
|
||||
virtual void IRead( hsStream *s, hsResMgr *mgr );
|
||||
virtual void IWrite( hsStream *s, hsResMgr *mgr );
|
||||
|
||||
virtual void IRefreshEAXSettings( hsBool force = false );
|
||||
};
|
||||
|
||||
#endif //plWin32Sound_h
|
||||
|
@ -1,327 +1,327 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#include "HeadSpin.h"
|
||||
#include "hsGeometry3.h"
|
||||
#include "hsResMgr.h"
|
||||
#include "plgDispatch.h"
|
||||
#include "plProfile.h"
|
||||
#include "plWin32StaticSound.h"
|
||||
#include "plWin32Sound.h"
|
||||
#include "plDSoundBuffer.h"
|
||||
#include "plAudioSystem.h"
|
||||
#include "plAudioCore/plSoundBuffer.h"
|
||||
#include "plAudioCore/plSoundDeswizzler.h"
|
||||
#include "pnMessage/plEventCallbackMsg.h"
|
||||
#include "pnMessage/plAudioSysMsg.h"
|
||||
#include "plMessage/plLinkToAgeMsg.h"
|
||||
#include "plMessage/plAvatarMsg.h"
|
||||
|
||||
#include "plPipeline/plPlates.h"
|
||||
#include "plStatusLog/plStatusLog.h"
|
||||
|
||||
plProfile_Extern(MemSounds);
|
||||
plProfile_CreateAsynchTimer( "Static Shove Time", "Sound", StaticSndShoveTime );
|
||||
plProfile_CreateAsynchTimer( "Static Swizzle Time", "Sound", StaticSwizzleTime );
|
||||
|
||||
plWin32StaticSound::plWin32StaticSound()
|
||||
{
|
||||
}
|
||||
|
||||
plWin32StaticSound::~plWin32StaticSound()
|
||||
{
|
||||
DeActivate();
|
||||
IUnloadDataBuffer();
|
||||
}
|
||||
|
||||
void plWin32StaticSound::Activate( hsBool forcePlay )
|
||||
{
|
||||
plWin32Sound::Activate( forcePlay );
|
||||
}
|
||||
|
||||
void plWin32StaticSound::DeActivate()
|
||||
{
|
||||
plWin32Sound::DeActivate();
|
||||
}
|
||||
|
||||
hsBool plWin32StaticSound::LoadSound( hsBool is3D )
|
||||
{
|
||||
if (fFailed)
|
||||
return false;
|
||||
|
||||
if( fPriority > plgAudioSys::GetPriorityCutoff() )
|
||||
return false; // Don't set the failed flag, just return
|
||||
|
||||
if (plgAudioSys::Active() && !fDSoundBuffer)
|
||||
{
|
||||
// Debug flag #1
|
||||
if( fChannelSelect > 0 && plgAudioSys::IsDebugFlagSet( plgAudioSys::kDisableRightSelect ) )
|
||||
{
|
||||
// Force a fail
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// We need it to be resident to read in
|
||||
plSoundBuffer::ELoadReturnVal retVal = IPreLoadBuffer(true);
|
||||
plSoundBuffer *buffer = (plSoundBuffer *)fDataBufferKey->ObjectIsLoaded();
|
||||
if(!buffer)
|
||||
{
|
||||
return plSoundBuffer::kError;
|
||||
}
|
||||
|
||||
if( retVal == plSoundBuffer::kPending) // we are still reading data.
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if( retVal == plSoundBuffer::kError )
|
||||
{
|
||||
char str[ 256 ];
|
||||
sprintf( str, "Unable to open .wav file %s", fDataBufferKey ? fDataBufferKey->GetName() : "nil");
|
||||
IPrintDbgMessage( str, true );
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
SetProperty( kPropIs3DSound, is3D );
|
||||
|
||||
plWAVHeader header = buffer->GetHeader();
|
||||
|
||||
// Debug flag #2
|
||||
if( fChannelSelect == 0 && header.fNumChannels > 1 && plgAudioSys::IsDebugFlagSet( plgAudioSys::kDisableLeftSelect ) )
|
||||
{
|
||||
// Force a fail
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
UInt32 bufferSize = buffer->GetDataLength();
|
||||
|
||||
if( header.fNumChannels > 1 && is3D )
|
||||
{
|
||||
// We can only do a single channel of 3D sound. So copy over one (later)
|
||||
bufferSize /= header.fNumChannels;
|
||||
header.fBlockAlign /= header.fNumChannels;
|
||||
header.fAvgBytesPerSec /= header.fNumChannels;
|
||||
header.fNumChannels = 1;
|
||||
}
|
||||
|
||||
hsBool tryStatic = true;
|
||||
// If we want FX, we can't use a static voice, but EAX doesn't fit under that limitation :)
|
||||
if( 0 )
|
||||
tryStatic = false;
|
||||
|
||||
// Create our DSound buffer (or rather, the wrapper around it)
|
||||
fDSoundBuffer = TRACKED_NEW plDSoundBuffer( bufferSize, header, is3D, IsPropertySet( kPropLooping ), tryStatic );
|
||||
if( !fDSoundBuffer->IsValid() )
|
||||
{
|
||||
char str[256];
|
||||
sprintf(str, "Can't create sound buffer for %s.wav. This could happen if the wav file is a stereo file. Stereo files are not supported on 3D sounds. If the file is not stereo then please report this error.", GetFileName());
|
||||
IPrintDbgMessage( str, true );
|
||||
fFailed = true;
|
||||
|
||||
delete fDSoundBuffer;
|
||||
fDSoundBuffer = nil;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
plProfile_BeginTiming( StaticSndShoveTime );
|
||||
|
||||
if(!fDSoundBuffer->FillBuffer(buffer->GetData(), buffer->GetDataLength(), &header))
|
||||
{
|
||||
delete fDSoundBuffer;
|
||||
fDSoundBuffer = nil;
|
||||
plStatusLog::AddLineS("audio.log", "Could not play static sound, no voices left %s", GetKeyName());
|
||||
return false;
|
||||
}
|
||||
|
||||
plProfile_EndTiming( StaticSndShoveTime );
|
||||
IRefreshEAXSettings( true );
|
||||
|
||||
fTotalBytes = bufferSize;
|
||||
|
||||
plProfile_NewMem(MemSounds, fTotalBytes);
|
||||
|
||||
// get pertinent info
|
||||
hsScalar length = (hsScalar)bufferSize / (hsScalar)header.fAvgBytesPerSec;
|
||||
SetLength(length);
|
||||
|
||||
if( fLoadFromDiskOnDemand && !IsPropertySet( kPropLoadOnlyOnCall ) )
|
||||
FreeSoundData();
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void plWin32StaticSound::Update()
|
||||
{
|
||||
plWin32Sound::Update();
|
||||
if(fDSoundBuffer)
|
||||
{
|
||||
if(fPlaying) // we think we are playing
|
||||
{
|
||||
if(!fDSoundBuffer->IsPlaying()) // are we actually playing
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void plWin32StaticSound::IDerivedActuallyPlay( void )
|
||||
{
|
||||
// Ensure there's a stop notify for us
|
||||
if( !fReallyPlaying )
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
if(IsPropertySet(kPropIncidental))
|
||||
{
|
||||
if(fIncidentalsPlaying >= MAX_INCIDENTALS)
|
||||
break;
|
||||
++fIncidentalsPlaying;
|
||||
}
|
||||
|
||||
fDSoundBuffer->Play();
|
||||
fReallyPlaying = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
plSoundEvent *event = IFindEvent( plSoundEvent::kStart );
|
||||
if( event != nil )
|
||||
event->SendCallbacks();
|
||||
}
|
||||
|
||||
float plWin32StaticSound::GetActualTimeSec()
|
||||
{
|
||||
if(fDSoundBuffer)
|
||||
return fDSoundBuffer->GetTimeOffsetSec();
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void plWin32StaticSound::ISetActualTime(double t)
|
||||
{
|
||||
if( !fDSoundBuffer && plgAudioSys::Active())
|
||||
LoadSound( IsPropertySet( kPropIs3DSound ) );
|
||||
if( fDSoundBuffer )
|
||||
{
|
||||
if(!t)
|
||||
fDSoundBuffer->SetTimeOffsetSec((float)t);
|
||||
}
|
||||
}
|
||||
|
||||
hsBool plWin32StaticSound::MsgReceive( plMessage* pMsg )
|
||||
{
|
||||
return plWin32Sound::MsgReceive( pMsg );
|
||||
}
|
||||
|
||||
void plWin32StaticSound::IRemoveCallback( plEventCallbackMsg *pCBMsg )
|
||||
{
|
||||
plWin32Sound::IRemoveCallback( pCBMsg );
|
||||
}
|
||||
|
||||
void plWin32StaticSound::IAddCallback( plEventCallbackMsg *pCBMsg )
|
||||
{
|
||||
if( plSoundEvent::GetTypeFromCallbackMsg( pCBMsg ) != plSoundEvent::kStop &&
|
||||
plSoundEvent::GetTypeFromCallbackMsg( pCBMsg ) != plSoundEvent::kStart )
|
||||
{
|
||||
hsAssert( false, "Static sounds only support start and stop callbacks at this time." );
|
||||
return;
|
||||
}
|
||||
plWin32Sound::IAddCallback( pCBMsg );
|
||||
}
|
||||
|
||||
|
||||
plWin32LinkSound::plWin32LinkSound()
|
||||
{
|
||||
SetLocalOnly(true); // linking sounds already synch at a higher level
|
||||
SetProperty( kPropDontFade, true );
|
||||
}
|
||||
|
||||
void plWin32LinkSound::Read(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
plWin32StaticSound::Read(s, mgr);
|
||||
|
||||
plgDispatch::Dispatch()->RegisterForExactType(plLinkEffectBCMsg::Index(), GetKey());
|
||||
plgDispatch::Dispatch()->RegisterForExactType(plAvatarStealthModeMsg::Index(), GetKey());
|
||||
plgDispatch::Dispatch()->RegisterForExactType(plPseudoLinkEffectMsg::Index(), GetKey());
|
||||
|
||||
SetLocalOnly(true); // linking sounds already synch at a higher level
|
||||
SetProperty( kPropDontFade, true );
|
||||
}
|
||||
|
||||
void plWin32LinkSound::Write(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
plWin32StaticSound::Write(s, mgr);
|
||||
}
|
||||
|
||||
hsBool plWin32LinkSound::MsgReceive( plMessage* pMsg )
|
||||
{
|
||||
plLinkEffectBCMsg *msg = plLinkEffectBCMsg::ConvertNoRef( pMsg );
|
||||
if( msg != nil && !msg->HasLinkFlag(plLinkEffectBCMsg::kMute))
|
||||
{
|
||||
if (msg->fLinkKey->GetUoid().GetClonePlayerID() == GetKey()->GetUoid().GetClonePlayerID())
|
||||
{
|
||||
if (!IsPropertySet(kPropFullyDisabled))
|
||||
{
|
||||
ISetActualTime(0);
|
||||
Play();
|
||||
//Activate(true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
plPseudoLinkEffectMsg *psmsg = plPseudoLinkEffectMsg::ConvertNoRef( pMsg );
|
||||
if( psmsg != nil)
|
||||
{
|
||||
if (psmsg->fAvatarKey->GetUoid().GetClonePlayerID() == GetKey()->GetUoid().GetClonePlayerID())
|
||||
{
|
||||
if (!IsPropertySet(kPropFullyDisabled))
|
||||
{
|
||||
ISetActualTime(0);
|
||||
//Play();
|
||||
Activate(true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
plAvatarStealthModeMsg *sMsg = plAvatarStealthModeMsg::ConvertNoRef(pMsg);
|
||||
if (sMsg)
|
||||
{
|
||||
if (sMsg->GetSender()->GetUoid().GetClonePlayerID() == GetKey()->GetUoid().GetClonePlayerID())
|
||||
{
|
||||
SetProperty(kPropFullyDisabled, (sMsg->fMode == plAvatarStealthModeMsg::kStealthCloaked));
|
||||
plNetApp::StaticDebugMsg("plWin32LinkSound: rcvd avatarStealth msg, cloaked=%d", sMsg->fMode == plAvatarStealthModeMsg::kStealthCloaked);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return plWin32StaticSound::MsgReceive( pMsg );
|
||||
}
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#include "HeadSpin.h"
|
||||
#include "hsGeometry3.h"
|
||||
#include "hsResMgr.h"
|
||||
#include "plgDispatch.h"
|
||||
#include "plProfile.h"
|
||||
#include "plWin32StaticSound.h"
|
||||
#include "plWin32Sound.h"
|
||||
#include "plDSoundBuffer.h"
|
||||
#include "plAudioSystem.h"
|
||||
#include "plAudioCore/plSoundBuffer.h"
|
||||
#include "plAudioCore/plSoundDeswizzler.h"
|
||||
#include "pnMessage/plEventCallbackMsg.h"
|
||||
#include "pnMessage/plAudioSysMsg.h"
|
||||
#include "plMessage/plLinkToAgeMsg.h"
|
||||
#include "plMessage/plAvatarMsg.h"
|
||||
|
||||
#include "plPipeline/plPlates.h"
|
||||
#include "plStatusLog/plStatusLog.h"
|
||||
|
||||
plProfile_Extern(MemSounds);
|
||||
plProfile_CreateAsynchTimer( "Static Shove Time", "Sound", StaticSndShoveTime );
|
||||
plProfile_CreateAsynchTimer( "Static Swizzle Time", "Sound", StaticSwizzleTime );
|
||||
|
||||
plWin32StaticSound::plWin32StaticSound()
|
||||
{
|
||||
}
|
||||
|
||||
plWin32StaticSound::~plWin32StaticSound()
|
||||
{
|
||||
DeActivate();
|
||||
IUnloadDataBuffer();
|
||||
}
|
||||
|
||||
void plWin32StaticSound::Activate( hsBool forcePlay )
|
||||
{
|
||||
plWin32Sound::Activate( forcePlay );
|
||||
}
|
||||
|
||||
void plWin32StaticSound::DeActivate()
|
||||
{
|
||||
plWin32Sound::DeActivate();
|
||||
}
|
||||
|
||||
hsBool plWin32StaticSound::LoadSound( hsBool is3D )
|
||||
{
|
||||
if (fFailed)
|
||||
return false;
|
||||
|
||||
if( fPriority > plgAudioSys::GetPriorityCutoff() )
|
||||
return false; // Don't set the failed flag, just return
|
||||
|
||||
if (plgAudioSys::Active() && !fDSoundBuffer)
|
||||
{
|
||||
// Debug flag #1
|
||||
if( fChannelSelect > 0 && plgAudioSys::IsDebugFlagSet( plgAudioSys::kDisableRightSelect ) )
|
||||
{
|
||||
// Force a fail
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// We need it to be resident to read in
|
||||
plSoundBuffer::ELoadReturnVal retVal = IPreLoadBuffer(true);
|
||||
plSoundBuffer *buffer = (plSoundBuffer *)fDataBufferKey->ObjectIsLoaded();
|
||||
if(!buffer)
|
||||
{
|
||||
return plSoundBuffer::kError;
|
||||
}
|
||||
|
||||
if( retVal == plSoundBuffer::kPending) // we are still reading data.
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if( retVal == plSoundBuffer::kError )
|
||||
{
|
||||
char str[ 256 ];
|
||||
sprintf( str, "Unable to open .wav file %s", fDataBufferKey ? fDataBufferKey->GetName() : "nil");
|
||||
IPrintDbgMessage( str, true );
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
SetProperty( kPropIs3DSound, is3D );
|
||||
|
||||
plWAVHeader header = buffer->GetHeader();
|
||||
|
||||
// Debug flag #2
|
||||
if( fChannelSelect == 0 && header.fNumChannels > 1 && plgAudioSys::IsDebugFlagSet( plgAudioSys::kDisableLeftSelect ) )
|
||||
{
|
||||
// Force a fail
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
UInt32 bufferSize = buffer->GetDataLength();
|
||||
|
||||
if( header.fNumChannels > 1 && is3D )
|
||||
{
|
||||
// We can only do a single channel of 3D sound. So copy over one (later)
|
||||
bufferSize /= header.fNumChannels;
|
||||
header.fBlockAlign /= header.fNumChannels;
|
||||
header.fAvgBytesPerSec /= header.fNumChannels;
|
||||
header.fNumChannels = 1;
|
||||
}
|
||||
|
||||
hsBool tryStatic = true;
|
||||
// If we want FX, we can't use a static voice, but EAX doesn't fit under that limitation :)
|
||||
if( 0 )
|
||||
tryStatic = false;
|
||||
|
||||
// Create our DSound buffer (or rather, the wrapper around it)
|
||||
fDSoundBuffer = TRACKED_NEW plDSoundBuffer( bufferSize, header, is3D, IsPropertySet( kPropLooping ), tryStatic );
|
||||
if( !fDSoundBuffer->IsValid() )
|
||||
{
|
||||
char str[256];
|
||||
sprintf(str, "Can't create sound buffer for %s.wav. This could happen if the wav file is a stereo file. Stereo files are not supported on 3D sounds. If the file is not stereo then please report this error.", GetFileName());
|
||||
IPrintDbgMessage( str, true );
|
||||
fFailed = true;
|
||||
|
||||
delete fDSoundBuffer;
|
||||
fDSoundBuffer = nil;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
plProfile_BeginTiming( StaticSndShoveTime );
|
||||
|
||||
if(!fDSoundBuffer->FillBuffer(buffer->GetData(), buffer->GetDataLength(), &header))
|
||||
{
|
||||
delete fDSoundBuffer;
|
||||
fDSoundBuffer = nil;
|
||||
plStatusLog::AddLineS("audio.log", "Could not play static sound, no voices left %s", GetKeyName());
|
||||
return false;
|
||||
}
|
||||
|
||||
plProfile_EndTiming( StaticSndShoveTime );
|
||||
IRefreshEAXSettings( true );
|
||||
|
||||
fTotalBytes = bufferSize;
|
||||
|
||||
plProfile_NewMem(MemSounds, fTotalBytes);
|
||||
|
||||
// get pertinent info
|
||||
hsScalar length = (hsScalar)bufferSize / (hsScalar)header.fAvgBytesPerSec;
|
||||
SetLength(length);
|
||||
|
||||
if( fLoadFromDiskOnDemand && !IsPropertySet( kPropLoadOnlyOnCall ) )
|
||||
FreeSoundData();
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void plWin32StaticSound::Update()
|
||||
{
|
||||
plWin32Sound::Update();
|
||||
if(fDSoundBuffer)
|
||||
{
|
||||
if(fPlaying) // we think we are playing
|
||||
{
|
||||
if(!fDSoundBuffer->IsPlaying()) // are we actually playing
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void plWin32StaticSound::IDerivedActuallyPlay( void )
|
||||
{
|
||||
// Ensure there's a stop notify for us
|
||||
if( !fReallyPlaying )
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
if(IsPropertySet(kPropIncidental))
|
||||
{
|
||||
if(fIncidentalsPlaying >= MAX_INCIDENTALS)
|
||||
break;
|
||||
++fIncidentalsPlaying;
|
||||
}
|
||||
|
||||
fDSoundBuffer->Play();
|
||||
fReallyPlaying = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
plSoundEvent *event = IFindEvent( plSoundEvent::kStart );
|
||||
if( event != nil )
|
||||
event->SendCallbacks();
|
||||
}
|
||||
|
||||
float plWin32StaticSound::GetActualTimeSec()
|
||||
{
|
||||
if(fDSoundBuffer)
|
||||
return fDSoundBuffer->GetTimeOffsetSec();
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void plWin32StaticSound::ISetActualTime(double t)
|
||||
{
|
||||
if( !fDSoundBuffer && plgAudioSys::Active())
|
||||
LoadSound( IsPropertySet( kPropIs3DSound ) );
|
||||
if( fDSoundBuffer )
|
||||
{
|
||||
if(!t)
|
||||
fDSoundBuffer->SetTimeOffsetSec((float)t);
|
||||
}
|
||||
}
|
||||
|
||||
hsBool plWin32StaticSound::MsgReceive( plMessage* pMsg )
|
||||
{
|
||||
return plWin32Sound::MsgReceive( pMsg );
|
||||
}
|
||||
|
||||
void plWin32StaticSound::IRemoveCallback( plEventCallbackMsg *pCBMsg )
|
||||
{
|
||||
plWin32Sound::IRemoveCallback( pCBMsg );
|
||||
}
|
||||
|
||||
void plWin32StaticSound::IAddCallback( plEventCallbackMsg *pCBMsg )
|
||||
{
|
||||
if( plSoundEvent::GetTypeFromCallbackMsg( pCBMsg ) != plSoundEvent::kStop &&
|
||||
plSoundEvent::GetTypeFromCallbackMsg( pCBMsg ) != plSoundEvent::kStart )
|
||||
{
|
||||
hsAssert( false, "Static sounds only support start and stop callbacks at this time." );
|
||||
return;
|
||||
}
|
||||
plWin32Sound::IAddCallback( pCBMsg );
|
||||
}
|
||||
|
||||
|
||||
plWin32LinkSound::plWin32LinkSound()
|
||||
{
|
||||
SetLocalOnly(true); // linking sounds already synch at a higher level
|
||||
SetProperty( kPropDontFade, true );
|
||||
}
|
||||
|
||||
void plWin32LinkSound::Read(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
plWin32StaticSound::Read(s, mgr);
|
||||
|
||||
plgDispatch::Dispatch()->RegisterForExactType(plLinkEffectBCMsg::Index(), GetKey());
|
||||
plgDispatch::Dispatch()->RegisterForExactType(plAvatarStealthModeMsg::Index(), GetKey());
|
||||
plgDispatch::Dispatch()->RegisterForExactType(plPseudoLinkEffectMsg::Index(), GetKey());
|
||||
|
||||
SetLocalOnly(true); // linking sounds already synch at a higher level
|
||||
SetProperty( kPropDontFade, true );
|
||||
}
|
||||
|
||||
void plWin32LinkSound::Write(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
plWin32StaticSound::Write(s, mgr);
|
||||
}
|
||||
|
||||
hsBool plWin32LinkSound::MsgReceive( plMessage* pMsg )
|
||||
{
|
||||
plLinkEffectBCMsg *msg = plLinkEffectBCMsg::ConvertNoRef( pMsg );
|
||||
if( msg != nil && !msg->HasLinkFlag(plLinkEffectBCMsg::kMute))
|
||||
{
|
||||
if (msg->fLinkKey->GetUoid().GetClonePlayerID() == GetKey()->GetUoid().GetClonePlayerID())
|
||||
{
|
||||
if (!IsPropertySet(kPropFullyDisabled))
|
||||
{
|
||||
ISetActualTime(0);
|
||||
Play();
|
||||
//Activate(true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
plPseudoLinkEffectMsg *psmsg = plPseudoLinkEffectMsg::ConvertNoRef( pMsg );
|
||||
if( psmsg != nil)
|
||||
{
|
||||
if (psmsg->fAvatarKey->GetUoid().GetClonePlayerID() == GetKey()->GetUoid().GetClonePlayerID())
|
||||
{
|
||||
if (!IsPropertySet(kPropFullyDisabled))
|
||||
{
|
||||
ISetActualTime(0);
|
||||
//Play();
|
||||
Activate(true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
plAvatarStealthModeMsg *sMsg = plAvatarStealthModeMsg::ConvertNoRef(pMsg);
|
||||
if (sMsg)
|
||||
{
|
||||
if (sMsg->GetSender()->GetUoid().GetClonePlayerID() == GetKey()->GetUoid().GetClonePlayerID())
|
||||
{
|
||||
SetProperty(kPropFullyDisabled, (sMsg->fMode == plAvatarStealthModeMsg::kStealthCloaked));
|
||||
plNetApp::StaticDebugMsg("plWin32LinkSound: rcvd avatarStealth msg, cloaked=%d", sMsg->fMode == plAvatarStealthModeMsg::kStealthCloaked);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return plWin32StaticSound::MsgReceive( pMsg );
|
||||
}
|
||||
|
@ -1,80 +1,80 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#ifndef plWin32StaticSound_h
|
||||
#define plWin32StaticSound_h
|
||||
|
||||
#include "plWin32Sound.h"
|
||||
|
||||
class hsResMgr;
|
||||
class plDSoundBuffer;
|
||||
class plEventCallbackMsg;
|
||||
|
||||
#include "plSoundEvent.h"
|
||||
|
||||
class plWin32StaticSound : public plWin32Sound
|
||||
{
|
||||
public:
|
||||
plWin32StaticSound();
|
||||
~plWin32StaticSound();
|
||||
|
||||
CLASSNAME_REGISTER( plWin32StaticSound );
|
||||
GETINTERFACE_ANY( plWin32StaticSound, plWin32Sound );
|
||||
|
||||
virtual void Activate( hsBool forcePlay = false );
|
||||
virtual void DeActivate();
|
||||
virtual hsBool LoadSound( hsBool is3D );
|
||||
virtual void Update();
|
||||
virtual hsBool MsgReceive(plMessage* pMsg);
|
||||
virtual void SetStartPos(unsigned bytes){}
|
||||
|
||||
protected:
|
||||
hsBool fRegisteredOnThread;
|
||||
|
||||
virtual void IDerivedActuallyPlay( void );
|
||||
virtual void ISetActualTime( double t );
|
||||
virtual float GetActualTimeSec();
|
||||
|
||||
virtual void IAddCallback( plEventCallbackMsg *pCBMsg );
|
||||
virtual void IRemoveCallback( plEventCallbackMsg *pCBMsg );
|
||||
|
||||
};
|
||||
|
||||
// Same as a plWin32StaticSound, except this registers for a plLinkEffectBCMsg to play the sound on linking.
|
||||
class plWin32LinkSound : public plWin32StaticSound
|
||||
{
|
||||
public:
|
||||
plWin32LinkSound();
|
||||
~plWin32LinkSound() { }
|
||||
|
||||
CLASSNAME_REGISTER( plWin32LinkSound );
|
||||
GETINTERFACE_ANY( plWin32LinkSound, plWin32StaticSound );
|
||||
|
||||
virtual void Read(hsStream* s, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* s, hsResMgr* mgr);
|
||||
virtual hsBool MsgReceive(plMessage* pMsg);
|
||||
};
|
||||
|
||||
#endif //plWin32StaticSound_h
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#ifndef plWin32StaticSound_h
|
||||
#define plWin32StaticSound_h
|
||||
|
||||
#include "plWin32Sound.h"
|
||||
|
||||
class hsResMgr;
|
||||
class plDSoundBuffer;
|
||||
class plEventCallbackMsg;
|
||||
|
||||
#include "plSoundEvent.h"
|
||||
|
||||
class plWin32StaticSound : public plWin32Sound
|
||||
{
|
||||
public:
|
||||
plWin32StaticSound();
|
||||
~plWin32StaticSound();
|
||||
|
||||
CLASSNAME_REGISTER( plWin32StaticSound );
|
||||
GETINTERFACE_ANY( plWin32StaticSound, plWin32Sound );
|
||||
|
||||
virtual void Activate( hsBool forcePlay = false );
|
||||
virtual void DeActivate();
|
||||
virtual hsBool LoadSound( hsBool is3D );
|
||||
virtual void Update();
|
||||
virtual hsBool MsgReceive(plMessage* pMsg);
|
||||
virtual void SetStartPos(unsigned bytes){}
|
||||
|
||||
protected:
|
||||
hsBool fRegisteredOnThread;
|
||||
|
||||
virtual void IDerivedActuallyPlay( void );
|
||||
virtual void ISetActualTime( double t );
|
||||
virtual float GetActualTimeSec();
|
||||
|
||||
virtual void IAddCallback( plEventCallbackMsg *pCBMsg );
|
||||
virtual void IRemoveCallback( plEventCallbackMsg *pCBMsg );
|
||||
|
||||
};
|
||||
|
||||
// Same as a plWin32StaticSound, except this registers for a plLinkEffectBCMsg to play the sound on linking.
|
||||
class plWin32LinkSound : public plWin32StaticSound
|
||||
{
|
||||
public:
|
||||
plWin32LinkSound();
|
||||
~plWin32LinkSound() { }
|
||||
|
||||
CLASSNAME_REGISTER( plWin32LinkSound );
|
||||
GETINTERFACE_ANY( plWin32LinkSound, plWin32StaticSound );
|
||||
|
||||
virtual void Read(hsStream* s, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* s, hsResMgr* mgr);
|
||||
virtual hsBool MsgReceive(plMessage* pMsg);
|
||||
};
|
||||
|
||||
#endif //plWin32StaticSound_h
|
||||
|
@ -1,493 +1,493 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#include <direct.h>
|
||||
#include "HeadSpin.h"
|
||||
#include "hsTimer.h"
|
||||
#include "hsGeometry3.h"
|
||||
#include "plgDispatch.h"
|
||||
#include "plProfile.h"
|
||||
|
||||
#include "plWin32Sound.h"
|
||||
#include "plWin32StreamingSound.h"
|
||||
#include "plDSoundBuffer.h"
|
||||
#include "plAudioSystem.h"
|
||||
|
||||
#include "plAudioCore/plAudioFileReader.h"
|
||||
#include "plAudioCore/plSoundBuffer.h"
|
||||
#include "plAudioCore/plSoundDeswizzler.h"
|
||||
#include "pnMessage/plSoundMsg.h"
|
||||
#include "pnMessage/plEventCallbackMsg.h"
|
||||
#include "plStatusLog/plStatusLog.h"
|
||||
|
||||
#define STREAMING_UPDATE_MS 200
|
||||
|
||||
plProfile_Extern(MemSounds);
|
||||
plProfile_CreateAsynchTimer( "Stream Shove Time", "Sound", StreamSndShoveTime );
|
||||
plProfile_CreateAsynchTimer( "Stream Swizzle Time", "Sound", StreamSwizzleTime );
|
||||
plProfile_Extern( SoundLoadTime );
|
||||
|
||||
plWin32StreamingSound::plWin32StreamingSound() :
|
||||
fDataStream(nil),
|
||||
fBlankBufferFillCounter(0),
|
||||
fDeswizzler(nil),
|
||||
fStreamType(kNoStream),
|
||||
fLastStreamingUpdate(0),
|
||||
fStopping(false),
|
||||
fPlayWhenStopped(false),
|
||||
fStartPos(0)
|
||||
{
|
||||
fBufferLengthInSecs = plgAudioSys::GetStreamingBufferSize();
|
||||
}
|
||||
|
||||
plWin32StreamingSound::~plWin32StreamingSound()
|
||||
{
|
||||
/// Call before we delete our dataStream
|
||||
DeActivate();
|
||||
IUnloadDataBuffer();
|
||||
|
||||
delete fDataStream;
|
||||
fDataStream = nil;
|
||||
fSrcFilename[ 0 ] = 0;
|
||||
|
||||
delete fDeswizzler;
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::DeActivate()
|
||||
{
|
||||
plWin32Sound::DeActivate();
|
||||
}
|
||||
|
||||
// Change the filename used by this streaming sound, so we can play a different file
|
||||
void plWin32StreamingSound::SetFilename(const char *filename, bool isCompressed)
|
||||
{
|
||||
fNewFilename = filename;
|
||||
fIsCompressed = isCompressed;
|
||||
fFailed = false; // just in case the last sound failed to load turn this off so it can try to load the new sound
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// Override, 'cause we don't want to actually LOAD the sound for streaming,
|
||||
// just make sure it's decompressed and such and ready to stream.
|
||||
plSoundBuffer::ELoadReturnVal plWin32StreamingSound::IPreLoadBuffer( hsBool playWhenLoaded, hsBool isIncidental /* = false */ )
|
||||
{
|
||||
if(fPlayWhenStopped)
|
||||
return plSoundBuffer::kPending;
|
||||
hsBool sfxPath = fNewFilename.size() ? false : true;
|
||||
|
||||
if( fDataStream != nil && fNewFilename.size() == 0)
|
||||
return plSoundBuffer::kSuccess; // Already loaded
|
||||
|
||||
if(!ILoadDataBuffer())
|
||||
{
|
||||
return plSoundBuffer::kError;
|
||||
}
|
||||
plSoundBuffer *buffer = (plSoundBuffer *)fDataBufferKey->ObjectIsLoaded();
|
||||
if(!buffer)
|
||||
return plSoundBuffer::kError;
|
||||
|
||||
// The databuffer also needs to know if the source is compressed or not
|
||||
if(fNewFilename.length())
|
||||
{
|
||||
buffer->SetFileName(fNewFilename.c_str());
|
||||
buffer->SetFlag(plSoundBuffer::kStreamCompressed, fIsCompressed);
|
||||
fNewFilename.clear();
|
||||
if(fReallyPlaying)
|
||||
{
|
||||
fPlayWhenStopped = true;
|
||||
return plSoundBuffer::kPending;
|
||||
}
|
||||
}
|
||||
|
||||
if( buffer->IsValid() )
|
||||
{
|
||||
plAudioFileReader::StreamType type = plAudioFileReader::kStreamNative;
|
||||
fStreamType = kStreamCompressed;
|
||||
|
||||
if(!buffer->HasFlag(plSoundBuffer::kStreamCompressed))
|
||||
{
|
||||
if(buffer->GetDataLengthInSecs() > plgAudioSys::GetStreamFromRAMCutoff( ))
|
||||
{
|
||||
fStreamType = kStreamFromDisk;
|
||||
type = plAudioFileReader::kStreamWAV;
|
||||
}
|
||||
else
|
||||
{
|
||||
fStreamType = kStreamFromRAM;
|
||||
type = plAudioFileReader::kStreamRAM;
|
||||
}
|
||||
}
|
||||
|
||||
if(!fStartPos)
|
||||
{
|
||||
if(buffer->AsyncLoad(type, isIncidental ? 0 : STREAMING_BUFFERS * STREAM_BUFFER_SIZE ) == plSoundBuffer::kPending)
|
||||
{
|
||||
fPlayWhenLoaded = playWhenLoaded;
|
||||
fLoading = true;
|
||||
return plSoundBuffer::kPending;
|
||||
}
|
||||
}
|
||||
|
||||
char str[ 256 ];
|
||||
strncpy( fSrcFilename, buffer->GetFileName(), sizeof( fSrcFilename ) );
|
||||
bool streamCompressed = (buffer->HasFlag(plSoundBuffer::kStreamCompressed) != 0);
|
||||
|
||||
delete fDataStream;
|
||||
fDataStream = buffer->GetAudioReader();
|
||||
if(!fDataStream)
|
||||
{
|
||||
plAudioCore::ChannelSelect select = buffer->GetReaderSelect();
|
||||
|
||||
bool streamCompressed = (buffer->HasFlag(plSoundBuffer::kStreamCompressed) != 0);
|
||||
|
||||
/// Open da file
|
||||
CHAR strPath[ MAX_PATH ];
|
||||
|
||||
_getcwd(strPath, MAX_PATH);
|
||||
if(sfxPath)
|
||||
strcat( strPath, "\\sfx\\" );
|
||||
else
|
||||
{
|
||||
// if we've changing the filename don't append 'sfx', just append a '\' since a path to the folder is expected
|
||||
strcat( strPath, "\\");
|
||||
}
|
||||
strcat( strPath, fSrcFilename );
|
||||
fDataStream = plAudioFileReader::CreateReader(strPath, select,type);
|
||||
}
|
||||
|
||||
if( fDataStream == nil || !fDataStream->IsValid() )
|
||||
{
|
||||
delete fDataStream;
|
||||
fDataStream = nil;
|
||||
return plSoundBuffer::kError;
|
||||
}
|
||||
|
||||
sprintf( str, " Readied file %s for streaming", fSrcFilename );
|
||||
IPrintDbgMessage( str );
|
||||
|
||||
// dont free sound data until we have a chance to use it in load sound
|
||||
|
||||
return fDataStream ? plSoundBuffer::kSuccess : plSoundBuffer::kError;
|
||||
}
|
||||
|
||||
plStatusLog::AddLineS("audio.log", "EnsureLoadable failed for streaming sound %d", fDataBufferKey->GetName());
|
||||
return plSoundBuffer::kError;
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::IFreeBuffers( void )
|
||||
{
|
||||
plWin32Sound::IFreeBuffers();
|
||||
if( fLoadFromDiskOnDemand && !IsPropertySet( kPropLoadOnlyOnCall ) )
|
||||
{
|
||||
// if the audio system has just restarted, dont delete the datastream. This way we can pick up where we left off instead of restarting the sound.
|
||||
if(!plgAudioSys::IsRestarting())
|
||||
{
|
||||
// we are deleting the stream, we must release the sound data.
|
||||
FreeSoundData();
|
||||
delete fDataStream;
|
||||
fDataStream = nil;
|
||||
}
|
||||
fSrcFilename[ 0 ] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Overload from plSound. Basically sets up the streaming file and fills the
|
||||
// first half of our buffer. We'll fill the rest of the buffer as we get
|
||||
// notifications for such.
|
||||
|
||||
hsBool plWin32StreamingSound::LoadSound( hsBool is3D )
|
||||
{
|
||||
if( fFailed )
|
||||
return false;
|
||||
if( !plgAudioSys::Active() || fDSoundBuffer )
|
||||
return false;
|
||||
|
||||
if( fPriority > plgAudioSys::GetPriorityCutoff() )
|
||||
return false; // Don't set the failed flag, just return
|
||||
|
||||
// Debug flag #1
|
||||
if( is3D && fChannelSelect > 0 && plgAudioSys::IsDebugFlagSet( plgAudioSys::kDisableRightSelect ) )
|
||||
{
|
||||
// Force a fail
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
plSoundBuffer::ELoadReturnVal retVal = IPreLoadBuffer(true);
|
||||
if(retVal == plSoundBuffer::kPending)
|
||||
return true;
|
||||
|
||||
if( retVal == plSoundBuffer::kError )
|
||||
{
|
||||
char str[ 256 ];
|
||||
sprintf( str, "Unable to open streaming source %s", fDataBufferKey->GetName() );
|
||||
IPrintDbgMessage( str, true );
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
SetProperty( kPropIs3DSound, is3D );
|
||||
|
||||
plWAVHeader header = fDataStream->GetHeader();
|
||||
UInt32 bufferSize = (UInt32)(fBufferLengthInSecs * header.fAvgBytesPerSec);
|
||||
|
||||
// Debug flag #2
|
||||
if( is3D && fChannelSelect == 0 && header.fNumChannels > 1 && plgAudioSys::IsDebugFlagSet( plgAudioSys::kDisableLeftSelect ) )
|
||||
{
|
||||
// Force a fail
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( header.fNumChannels > 1 && is3D )
|
||||
{
|
||||
// We can only do a single channel of 3D sound. So copy over one (later)
|
||||
bufferSize /= header.fNumChannels;
|
||||
header.fBlockAlign /= header.fNumChannels;
|
||||
header.fAvgBytesPerSec /= header.fNumChannels;
|
||||
header.fNumChannels = 1;
|
||||
}
|
||||
|
||||
// Actually create the buffer now (always looping)
|
||||
fDSoundBuffer = TRACKED_NEW plDSoundBuffer( bufferSize, header, is3D, IsPropertySet(kPropLooping), false, true );
|
||||
if( !fDSoundBuffer->IsValid() )
|
||||
{
|
||||
fDataStream->Close();
|
||||
delete fDataStream;
|
||||
fDataStream = nil;
|
||||
|
||||
delete fDSoundBuffer;
|
||||
fDSoundBuffer = nil;
|
||||
|
||||
char str[256];
|
||||
sprintf(str, "Can't create sound buffer for %s.wav. This could happen if the wav file is a stereo file. Stereo files are not supported on 3D sounds. If the file is not stereo then please report this error.", GetFileName());
|
||||
IPrintDbgMessage( str, true );
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
fTotalBytes = (UInt32)bufferSize;
|
||||
plProfile_NewMem(MemSounds, fTotalBytes);
|
||||
|
||||
plSoundBuffer *buffer = (plSoundBuffer *)fDataBufferKey->ObjectIsLoaded();
|
||||
if(!buffer)
|
||||
return false;
|
||||
|
||||
bool setupSource = true;
|
||||
if(!buffer->GetData() || fStartPos)
|
||||
{
|
||||
if(fStartPos && fStartPos <= fDataStream->NumBytesLeft())
|
||||
{
|
||||
fDataStream->SetPosition(fStartPos);
|
||||
plStatusLog::AddLineS("syncaudio.log", "startpos %d", fStartPos);
|
||||
}
|
||||
|
||||
// if we get here we are not starting from the beginning of the sound. We still have an audio loaded and need to pick up where we left off
|
||||
if(!fDSoundBuffer->SetupStreamingSource(fDataStream))
|
||||
{
|
||||
setupSource = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// this sound is starting from the beginning. Get the data and start it.
|
||||
if(!fDSoundBuffer->SetupStreamingSource(buffer->GetData(), buffer->GetAsyncLoadLength()))
|
||||
{
|
||||
setupSource = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!setupSource)
|
||||
{
|
||||
fDataStream->Close();
|
||||
delete fDataStream;
|
||||
fDataStream = nil;
|
||||
delete fDSoundBuffer;
|
||||
fDSoundBuffer = nil;
|
||||
|
||||
plStatusLog::AddLineS("audio.log", "Could not play streaming sound, no voices left %s", GetKeyName());
|
||||
return false;
|
||||
}
|
||||
FreeSoundData();
|
||||
|
||||
IRefreshEAXSettings( true );
|
||||
|
||||
// Debug info
|
||||
char str[ 256 ];
|
||||
sprintf( str, " Streaming %s.", fSrcFilename);
|
||||
IPrintDbgMessage( str );
|
||||
|
||||
plStatusLog::AddLineS( "audioTimes.log", 0xffffffff, "Streaming %4.2f secs of %s", fDataStream->GetLengthInSecs(), GetKey()->GetUoid().GetObjectName() );
|
||||
|
||||
// Get pertinent info
|
||||
SetLength( (hsScalar)fDataStream->GetLengthInSecs() );
|
||||
|
||||
// Set up our deswizzler, if necessary
|
||||
delete fDeswizzler;
|
||||
if( fDataStream->GetHeader().fNumChannels != header.fNumChannels )
|
||||
fDeswizzler = TRACKED_NEW plSoundDeswizzler( (UInt32)(fBufferLengthInSecs * fDataStream->GetHeader().fAvgBytesPerSec),
|
||||
(UInt8)(fDataStream->GetHeader().fNumChannels),
|
||||
header.fBitsPerSample / 8 );
|
||||
else
|
||||
fDeswizzler = nil;
|
||||
|
||||
// LEAVE THE WAV FILE OPEN! (We *are* streaming, after all :)
|
||||
return true;
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::IStreamUpdate()
|
||||
{
|
||||
if(!fReallyPlaying)
|
||||
return;
|
||||
|
||||
if(hsTimer::GetMilliSeconds() - fLastStreamingUpdate < STREAMING_UPDATE_MS) // filter out update requests so we aren't doing this more that we need to
|
||||
return;
|
||||
|
||||
plProfile_BeginTiming( StreamSndShoveTime );
|
||||
if(fDSoundBuffer)
|
||||
{
|
||||
if(fDSoundBuffer->BuffersQueued() == 0 && fDataStream->NumBytesLeft() == 0 && !fDSoundBuffer->IsLooping())
|
||||
{
|
||||
// If we are fading out it's possible that we will hit this multiple times causing this sound to try and fade out multiple times, never allowing it to actually stop
|
||||
if(!fStopping)
|
||||
{
|
||||
fStopping = true;
|
||||
Stop();
|
||||
plProfile_EndTiming( StreamSndShoveTime );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(!fDSoundBuffer->StreamingFillBuffer(fDataStream))
|
||||
{
|
||||
plStatusLog::AddLineS("audio.log", "%s Streaming buffer fill failed", GetKeyName());
|
||||
}
|
||||
}
|
||||
plProfile_EndTiming( StreamSndShoveTime );
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::Update()
|
||||
{
|
||||
plWin32Sound::Update();
|
||||
IStreamUpdate();
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::IDerivedActuallyPlay( void )
|
||||
{
|
||||
fStopping = false;
|
||||
if( !fReallyPlaying )
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
if(fSynchedStartTimeSec)
|
||||
{
|
||||
// if we are synching to another sound this is our latency time
|
||||
fDSoundBuffer->SetTimeOffsetSec((float)(hsTimer::GetSeconds() - fSynchedStartTimeSec));
|
||||
fSynchedStartTimeSec = 0;
|
||||
}
|
||||
|
||||
if(IsPropertySet(kPropIncidental))
|
||||
{
|
||||
if(fIncidentalsPlaying >= MAX_INCIDENTALS)
|
||||
break;
|
||||
++fIncidentalsPlaying;
|
||||
}
|
||||
fDSoundBuffer->Play();
|
||||
fReallyPlaying = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Send start callbacks
|
||||
plSoundEvent *event = IFindEvent( plSoundEvent::kStart );
|
||||
if( event != nil )
|
||||
event->SendCallbacks();
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::IActuallyStop()
|
||||
{
|
||||
fStopping = false;
|
||||
plWin32Sound::IActuallyStop();
|
||||
if(fPlayWhenStopped)
|
||||
{
|
||||
fPlayWhenStopped = false;
|
||||
Play();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned plWin32StreamingSound::GetByteOffset()
|
||||
{
|
||||
if(fDataStream && fDSoundBuffer)
|
||||
{
|
||||
unsigned bytesQueued = fDSoundBuffer->BuffersQueued() * STREAM_BUFFER_SIZE;
|
||||
unsigned offset = fDSoundBuffer->GetByteOffset();
|
||||
long byteoffset = ((fDataStream->GetDataSize() - fDataStream->NumBytesLeft()) - bytesQueued) + offset;
|
||||
|
||||
return byteoffset < 0 ? fDataStream->GetDataSize() - abs(byteoffset) : byteoffset;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
float plWin32StreamingSound::GetActualTimeSec()
|
||||
{
|
||||
if(fDataStream && fDSoundBuffer)
|
||||
return fDSoundBuffer->BytePosToMSecs(fDataStream->NumBytesLeft()) / 1000.0f;
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::SetStartPos(unsigned bytes)
|
||||
{
|
||||
fStartPos = bytes;
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::ISetActualTime( double t )
|
||||
{
|
||||
//fStartTimeSec = 0;
|
||||
if(fDataStream && fDSoundBuffer)
|
||||
fDataStream->SetPosition(fDSoundBuffer->GetBufferBytePos((float)t));
|
||||
//else
|
||||
// fStartTimeSec = t;
|
||||
}
|
||||
|
||||
hsBool plWin32StreamingSound::MsgReceive( plMessage* pMsg )
|
||||
{
|
||||
return plWin32Sound::MsgReceive( pMsg );
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::IRemoveCallback( plEventCallbackMsg *pCBMsg )
|
||||
{
|
||||
plWin32Sound::IRemoveCallback( pCBMsg );
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::IAddCallback( plEventCallbackMsg *pCBMsg )
|
||||
{
|
||||
if( plSoundEvent::GetTypeFromCallbackMsg( pCBMsg ) != plSoundEvent::kStop &&
|
||||
plSoundEvent::GetTypeFromCallbackMsg( pCBMsg ) != plSoundEvent::kStart )
|
||||
{
|
||||
hsAssert( false, "Streaming sounds only support start and stop callbacks at this time." );
|
||||
return;
|
||||
}
|
||||
plWin32Sound::IAddCallback( pCBMsg );
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#include <direct.h>
|
||||
#include "HeadSpin.h"
|
||||
#include "hsTimer.h"
|
||||
#include "hsGeometry3.h"
|
||||
#include "plgDispatch.h"
|
||||
#include "plProfile.h"
|
||||
|
||||
#include "plWin32Sound.h"
|
||||
#include "plWin32StreamingSound.h"
|
||||
#include "plDSoundBuffer.h"
|
||||
#include "plAudioSystem.h"
|
||||
|
||||
#include "plAudioCore/plAudioFileReader.h"
|
||||
#include "plAudioCore/plSoundBuffer.h"
|
||||
#include "plAudioCore/plSoundDeswizzler.h"
|
||||
#include "pnMessage/plSoundMsg.h"
|
||||
#include "pnMessage/plEventCallbackMsg.h"
|
||||
#include "plStatusLog/plStatusLog.h"
|
||||
|
||||
#define STREAMING_UPDATE_MS 200
|
||||
|
||||
plProfile_Extern(MemSounds);
|
||||
plProfile_CreateAsynchTimer( "Stream Shove Time", "Sound", StreamSndShoveTime );
|
||||
plProfile_CreateAsynchTimer( "Stream Swizzle Time", "Sound", StreamSwizzleTime );
|
||||
plProfile_Extern( SoundLoadTime );
|
||||
|
||||
plWin32StreamingSound::plWin32StreamingSound() :
|
||||
fDataStream(nil),
|
||||
fBlankBufferFillCounter(0),
|
||||
fDeswizzler(nil),
|
||||
fStreamType(kNoStream),
|
||||
fLastStreamingUpdate(0),
|
||||
fStopping(false),
|
||||
fPlayWhenStopped(false),
|
||||
fStartPos(0)
|
||||
{
|
||||
fBufferLengthInSecs = plgAudioSys::GetStreamingBufferSize();
|
||||
}
|
||||
|
||||
plWin32StreamingSound::~plWin32StreamingSound()
|
||||
{
|
||||
/// Call before we delete our dataStream
|
||||
DeActivate();
|
||||
IUnloadDataBuffer();
|
||||
|
||||
delete fDataStream;
|
||||
fDataStream = nil;
|
||||
fSrcFilename[ 0 ] = 0;
|
||||
|
||||
delete fDeswizzler;
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::DeActivate()
|
||||
{
|
||||
plWin32Sound::DeActivate();
|
||||
}
|
||||
|
||||
// Change the filename used by this streaming sound, so we can play a different file
|
||||
void plWin32StreamingSound::SetFilename(const char *filename, bool isCompressed)
|
||||
{
|
||||
fNewFilename = filename;
|
||||
fIsCompressed = isCompressed;
|
||||
fFailed = false; // just in case the last sound failed to load turn this off so it can try to load the new sound
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// Override, 'cause we don't want to actually LOAD the sound for streaming,
|
||||
// just make sure it's decompressed and such and ready to stream.
|
||||
plSoundBuffer::ELoadReturnVal plWin32StreamingSound::IPreLoadBuffer( hsBool playWhenLoaded, hsBool isIncidental /* = false */ )
|
||||
{
|
||||
if(fPlayWhenStopped)
|
||||
return plSoundBuffer::kPending;
|
||||
hsBool sfxPath = fNewFilename.size() ? false : true;
|
||||
|
||||
if( fDataStream != nil && fNewFilename.size() == 0)
|
||||
return plSoundBuffer::kSuccess; // Already loaded
|
||||
|
||||
if(!ILoadDataBuffer())
|
||||
{
|
||||
return plSoundBuffer::kError;
|
||||
}
|
||||
plSoundBuffer *buffer = (plSoundBuffer *)fDataBufferKey->ObjectIsLoaded();
|
||||
if(!buffer)
|
||||
return plSoundBuffer::kError;
|
||||
|
||||
// The databuffer also needs to know if the source is compressed or not
|
||||
if(fNewFilename.length())
|
||||
{
|
||||
buffer->SetFileName(fNewFilename.c_str());
|
||||
buffer->SetFlag(plSoundBuffer::kStreamCompressed, fIsCompressed);
|
||||
fNewFilename.clear();
|
||||
if(fReallyPlaying)
|
||||
{
|
||||
fPlayWhenStopped = true;
|
||||
return plSoundBuffer::kPending;
|
||||
}
|
||||
}
|
||||
|
||||
if( buffer->IsValid() )
|
||||
{
|
||||
plAudioFileReader::StreamType type = plAudioFileReader::kStreamNative;
|
||||
fStreamType = kStreamCompressed;
|
||||
|
||||
if(!buffer->HasFlag(plSoundBuffer::kStreamCompressed))
|
||||
{
|
||||
if(buffer->GetDataLengthInSecs() > plgAudioSys::GetStreamFromRAMCutoff( ))
|
||||
{
|
||||
fStreamType = kStreamFromDisk;
|
||||
type = plAudioFileReader::kStreamWAV;
|
||||
}
|
||||
else
|
||||
{
|
||||
fStreamType = kStreamFromRAM;
|
||||
type = plAudioFileReader::kStreamRAM;
|
||||
}
|
||||
}
|
||||
|
||||
if(!fStartPos)
|
||||
{
|
||||
if(buffer->AsyncLoad(type, isIncidental ? 0 : STREAMING_BUFFERS * STREAM_BUFFER_SIZE ) == plSoundBuffer::kPending)
|
||||
{
|
||||
fPlayWhenLoaded = playWhenLoaded;
|
||||
fLoading = true;
|
||||
return plSoundBuffer::kPending;
|
||||
}
|
||||
}
|
||||
|
||||
char str[ 256 ];
|
||||
strncpy( fSrcFilename, buffer->GetFileName(), sizeof( fSrcFilename ) );
|
||||
bool streamCompressed = (buffer->HasFlag(plSoundBuffer::kStreamCompressed) != 0);
|
||||
|
||||
delete fDataStream;
|
||||
fDataStream = buffer->GetAudioReader();
|
||||
if(!fDataStream)
|
||||
{
|
||||
plAudioCore::ChannelSelect select = buffer->GetReaderSelect();
|
||||
|
||||
bool streamCompressed = (buffer->HasFlag(plSoundBuffer::kStreamCompressed) != 0);
|
||||
|
||||
/// Open da file
|
||||
CHAR strPath[ MAX_PATH ];
|
||||
|
||||
_getcwd(strPath, MAX_PATH);
|
||||
if(sfxPath)
|
||||
strcat( strPath, "\\sfx\\" );
|
||||
else
|
||||
{
|
||||
// if we've changing the filename don't append 'sfx', just append a '\' since a path to the folder is expected
|
||||
strcat( strPath, "\\");
|
||||
}
|
||||
strcat( strPath, fSrcFilename );
|
||||
fDataStream = plAudioFileReader::CreateReader(strPath, select,type);
|
||||
}
|
||||
|
||||
if( fDataStream == nil || !fDataStream->IsValid() )
|
||||
{
|
||||
delete fDataStream;
|
||||
fDataStream = nil;
|
||||
return plSoundBuffer::kError;
|
||||
}
|
||||
|
||||
sprintf( str, " Readied file %s for streaming", fSrcFilename );
|
||||
IPrintDbgMessage( str );
|
||||
|
||||
// dont free sound data until we have a chance to use it in load sound
|
||||
|
||||
return fDataStream ? plSoundBuffer::kSuccess : plSoundBuffer::kError;
|
||||
}
|
||||
|
||||
plStatusLog::AddLineS("audio.log", "EnsureLoadable failed for streaming sound %d", fDataBufferKey->GetName());
|
||||
return plSoundBuffer::kError;
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::IFreeBuffers( void )
|
||||
{
|
||||
plWin32Sound::IFreeBuffers();
|
||||
if( fLoadFromDiskOnDemand && !IsPropertySet( kPropLoadOnlyOnCall ) )
|
||||
{
|
||||
// if the audio system has just restarted, dont delete the datastream. This way we can pick up where we left off instead of restarting the sound.
|
||||
if(!plgAudioSys::IsRestarting())
|
||||
{
|
||||
// we are deleting the stream, we must release the sound data.
|
||||
FreeSoundData();
|
||||
delete fDataStream;
|
||||
fDataStream = nil;
|
||||
}
|
||||
fSrcFilename[ 0 ] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Overload from plSound. Basically sets up the streaming file and fills the
|
||||
// first half of our buffer. We'll fill the rest of the buffer as we get
|
||||
// notifications for such.
|
||||
|
||||
hsBool plWin32StreamingSound::LoadSound( hsBool is3D )
|
||||
{
|
||||
if( fFailed )
|
||||
return false;
|
||||
if( !plgAudioSys::Active() || fDSoundBuffer )
|
||||
return false;
|
||||
|
||||
if( fPriority > plgAudioSys::GetPriorityCutoff() )
|
||||
return false; // Don't set the failed flag, just return
|
||||
|
||||
// Debug flag #1
|
||||
if( is3D && fChannelSelect > 0 && plgAudioSys::IsDebugFlagSet( plgAudioSys::kDisableRightSelect ) )
|
||||
{
|
||||
// Force a fail
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
plSoundBuffer::ELoadReturnVal retVal = IPreLoadBuffer(true);
|
||||
if(retVal == plSoundBuffer::kPending)
|
||||
return true;
|
||||
|
||||
if( retVal == plSoundBuffer::kError )
|
||||
{
|
||||
char str[ 256 ];
|
||||
sprintf( str, "Unable to open streaming source %s", fDataBufferKey->GetName() );
|
||||
IPrintDbgMessage( str, true );
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
SetProperty( kPropIs3DSound, is3D );
|
||||
|
||||
plWAVHeader header = fDataStream->GetHeader();
|
||||
UInt32 bufferSize = (UInt32)(fBufferLengthInSecs * header.fAvgBytesPerSec);
|
||||
|
||||
// Debug flag #2
|
||||
if( is3D && fChannelSelect == 0 && header.fNumChannels > 1 && plgAudioSys::IsDebugFlagSet( plgAudioSys::kDisableLeftSelect ) )
|
||||
{
|
||||
// Force a fail
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( header.fNumChannels > 1 && is3D )
|
||||
{
|
||||
// We can only do a single channel of 3D sound. So copy over one (later)
|
||||
bufferSize /= header.fNumChannels;
|
||||
header.fBlockAlign /= header.fNumChannels;
|
||||
header.fAvgBytesPerSec /= header.fNumChannels;
|
||||
header.fNumChannels = 1;
|
||||
}
|
||||
|
||||
// Actually create the buffer now (always looping)
|
||||
fDSoundBuffer = TRACKED_NEW plDSoundBuffer( bufferSize, header, is3D, IsPropertySet(kPropLooping), false, true );
|
||||
if( !fDSoundBuffer->IsValid() )
|
||||
{
|
||||
fDataStream->Close();
|
||||
delete fDataStream;
|
||||
fDataStream = nil;
|
||||
|
||||
delete fDSoundBuffer;
|
||||
fDSoundBuffer = nil;
|
||||
|
||||
char str[256];
|
||||
sprintf(str, "Can't create sound buffer for %s.wav. This could happen if the wav file is a stereo file. Stereo files are not supported on 3D sounds. If the file is not stereo then please report this error.", GetFileName());
|
||||
IPrintDbgMessage( str, true );
|
||||
fFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
fTotalBytes = (UInt32)bufferSize;
|
||||
plProfile_NewMem(MemSounds, fTotalBytes);
|
||||
|
||||
plSoundBuffer *buffer = (plSoundBuffer *)fDataBufferKey->ObjectIsLoaded();
|
||||
if(!buffer)
|
||||
return false;
|
||||
|
||||
bool setupSource = true;
|
||||
if(!buffer->GetData() || fStartPos)
|
||||
{
|
||||
if(fStartPos && fStartPos <= fDataStream->NumBytesLeft())
|
||||
{
|
||||
fDataStream->SetPosition(fStartPos);
|
||||
plStatusLog::AddLineS("syncaudio.log", "startpos %d", fStartPos);
|
||||
}
|
||||
|
||||
// if we get here we are not starting from the beginning of the sound. We still have an audio loaded and need to pick up where we left off
|
||||
if(!fDSoundBuffer->SetupStreamingSource(fDataStream))
|
||||
{
|
||||
setupSource = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// this sound is starting from the beginning. Get the data and start it.
|
||||
if(!fDSoundBuffer->SetupStreamingSource(buffer->GetData(), buffer->GetAsyncLoadLength()))
|
||||
{
|
||||
setupSource = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!setupSource)
|
||||
{
|
||||
fDataStream->Close();
|
||||
delete fDataStream;
|
||||
fDataStream = nil;
|
||||
delete fDSoundBuffer;
|
||||
fDSoundBuffer = nil;
|
||||
|
||||
plStatusLog::AddLineS("audio.log", "Could not play streaming sound, no voices left %s", GetKeyName());
|
||||
return false;
|
||||
}
|
||||
FreeSoundData();
|
||||
|
||||
IRefreshEAXSettings( true );
|
||||
|
||||
// Debug info
|
||||
char str[ 256 ];
|
||||
sprintf( str, " Streaming %s.", fSrcFilename);
|
||||
IPrintDbgMessage( str );
|
||||
|
||||
plStatusLog::AddLineS( "audioTimes.log", 0xffffffff, "Streaming %4.2f secs of %s", fDataStream->GetLengthInSecs(), GetKey()->GetUoid().GetObjectName() );
|
||||
|
||||
// Get pertinent info
|
||||
SetLength( (hsScalar)fDataStream->GetLengthInSecs() );
|
||||
|
||||
// Set up our deswizzler, if necessary
|
||||
delete fDeswizzler;
|
||||
if( fDataStream->GetHeader().fNumChannels != header.fNumChannels )
|
||||
fDeswizzler = TRACKED_NEW plSoundDeswizzler( (UInt32)(fBufferLengthInSecs * fDataStream->GetHeader().fAvgBytesPerSec),
|
||||
(UInt8)(fDataStream->GetHeader().fNumChannels),
|
||||
header.fBitsPerSample / 8 );
|
||||
else
|
||||
fDeswizzler = nil;
|
||||
|
||||
// LEAVE THE WAV FILE OPEN! (We *are* streaming, after all :)
|
||||
return true;
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::IStreamUpdate()
|
||||
{
|
||||
if(!fReallyPlaying)
|
||||
return;
|
||||
|
||||
if(hsTimer::GetMilliSeconds() - fLastStreamingUpdate < STREAMING_UPDATE_MS) // filter out update requests so we aren't doing this more that we need to
|
||||
return;
|
||||
|
||||
plProfile_BeginTiming( StreamSndShoveTime );
|
||||
if(fDSoundBuffer)
|
||||
{
|
||||
if(fDSoundBuffer->BuffersQueued() == 0 && fDataStream->NumBytesLeft() == 0 && !fDSoundBuffer->IsLooping())
|
||||
{
|
||||
// If we are fading out it's possible that we will hit this multiple times causing this sound to try and fade out multiple times, never allowing it to actually stop
|
||||
if(!fStopping)
|
||||
{
|
||||
fStopping = true;
|
||||
Stop();
|
||||
plProfile_EndTiming( StreamSndShoveTime );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(!fDSoundBuffer->StreamingFillBuffer(fDataStream))
|
||||
{
|
||||
plStatusLog::AddLineS("audio.log", "%s Streaming buffer fill failed", GetKeyName());
|
||||
}
|
||||
}
|
||||
plProfile_EndTiming( StreamSndShoveTime );
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::Update()
|
||||
{
|
||||
plWin32Sound::Update();
|
||||
IStreamUpdate();
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::IDerivedActuallyPlay( void )
|
||||
{
|
||||
fStopping = false;
|
||||
if( !fReallyPlaying )
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
if(fSynchedStartTimeSec)
|
||||
{
|
||||
// if we are synching to another sound this is our latency time
|
||||
fDSoundBuffer->SetTimeOffsetSec((float)(hsTimer::GetSeconds() - fSynchedStartTimeSec));
|
||||
fSynchedStartTimeSec = 0;
|
||||
}
|
||||
|
||||
if(IsPropertySet(kPropIncidental))
|
||||
{
|
||||
if(fIncidentalsPlaying >= MAX_INCIDENTALS)
|
||||
break;
|
||||
++fIncidentalsPlaying;
|
||||
}
|
||||
fDSoundBuffer->Play();
|
||||
fReallyPlaying = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Send start callbacks
|
||||
plSoundEvent *event = IFindEvent( plSoundEvent::kStart );
|
||||
if( event != nil )
|
||||
event->SendCallbacks();
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::IActuallyStop()
|
||||
{
|
||||
fStopping = false;
|
||||
plWin32Sound::IActuallyStop();
|
||||
if(fPlayWhenStopped)
|
||||
{
|
||||
fPlayWhenStopped = false;
|
||||
Play();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned plWin32StreamingSound::GetByteOffset()
|
||||
{
|
||||
if(fDataStream && fDSoundBuffer)
|
||||
{
|
||||
unsigned bytesQueued = fDSoundBuffer->BuffersQueued() * STREAM_BUFFER_SIZE;
|
||||
unsigned offset = fDSoundBuffer->GetByteOffset();
|
||||
long byteoffset = ((fDataStream->GetDataSize() - fDataStream->NumBytesLeft()) - bytesQueued) + offset;
|
||||
|
||||
return byteoffset < 0 ? fDataStream->GetDataSize() - abs(byteoffset) : byteoffset;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
float plWin32StreamingSound::GetActualTimeSec()
|
||||
{
|
||||
if(fDataStream && fDSoundBuffer)
|
||||
return fDSoundBuffer->BytePosToMSecs(fDataStream->NumBytesLeft()) / 1000.0f;
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::SetStartPos(unsigned bytes)
|
||||
{
|
||||
fStartPos = bytes;
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::ISetActualTime( double t )
|
||||
{
|
||||
//fStartTimeSec = 0;
|
||||
if(fDataStream && fDSoundBuffer)
|
||||
fDataStream->SetPosition(fDSoundBuffer->GetBufferBytePos((float)t));
|
||||
//else
|
||||
// fStartTimeSec = t;
|
||||
}
|
||||
|
||||
hsBool plWin32StreamingSound::MsgReceive( plMessage* pMsg )
|
||||
{
|
||||
return plWin32Sound::MsgReceive( pMsg );
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::IRemoveCallback( plEventCallbackMsg *pCBMsg )
|
||||
{
|
||||
plWin32Sound::IRemoveCallback( pCBMsg );
|
||||
}
|
||||
|
||||
void plWin32StreamingSound::IAddCallback( plEventCallbackMsg *pCBMsg )
|
||||
{
|
||||
if( plSoundEvent::GetTypeFromCallbackMsg( pCBMsg ) != plSoundEvent::kStop &&
|
||||
plSoundEvent::GetTypeFromCallbackMsg( pCBMsg ) != plSoundEvent::kStart )
|
||||
{
|
||||
hsAssert( false, "Streaming sounds only support start and stop callbacks at this time." );
|
||||
return;
|
||||
}
|
||||
plWin32Sound::IAddCallback( pCBMsg );
|
||||
}
|
@ -1,90 +1,90 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#ifndef plWin32StreamingSound_h
|
||||
#define plWin32StreamingSound_h
|
||||
|
||||
#include "plWin32Sound.h"
|
||||
#include "pnUtils/pnUtils.h"
|
||||
|
||||
class plDSoundBuffer;
|
||||
class DSoundCallbackHandle;
|
||||
class plAudioFileReader;
|
||||
class plStreamingSoundThread;
|
||||
enum CallbackHandleType;
|
||||
class plSoundDeswizzler;
|
||||
|
||||
class plWin32StreamingSound : public plWin32Sound
|
||||
{
|
||||
public:
|
||||
plWin32StreamingSound();
|
||||
~plWin32StreamingSound();
|
||||
|
||||
CLASSNAME_REGISTER( plWin32StreamingSound );
|
||||
GETINTERFACE_ANY( plWin32StreamingSound, plWin32Sound );
|
||||
|
||||
virtual void DeActivate();
|
||||
virtual hsBool LoadSound( hsBool is3D );
|
||||
virtual float GetActualTimeSec();
|
||||
virtual unsigned GetByteOffset();
|
||||
virtual StreamType GetStreamType() const { return fStreamType; }
|
||||
virtual void SetFilename(const char *filename, bool isCompressed);
|
||||
virtual void Update(); // temp
|
||||
void StreamUpdate();
|
||||
virtual hsBool MsgReceive( plMessage *pMsg );
|
||||
|
||||
protected:
|
||||
hsScalar fTimeAtBufferStart;
|
||||
plAudioFileReader *fDataStream;
|
||||
hsScalar fBufferLengthInSecs;
|
||||
UInt8 fBlankBufferFillCounter;
|
||||
plSoundDeswizzler *fDeswizzler;
|
||||
char fSrcFilename[ 256 ];
|
||||
StreamType fStreamType;
|
||||
bool fIsCompressed; // this applies only to the new sound file specified in fNewFilename, so we can play both ogg's and wav's
|
||||
std::string fNewFilename; // allow the filename to be changed so we can play from a different source.
|
||||
// ultimately this filename will be given to fDataBuffer, but since it's not always around we'll store it here
|
||||
hsBool fStopping;
|
||||
|
||||
double fLastStreamingUpdate;
|
||||
bool fPlayWhenStopped;
|
||||
unsigned fStartPos;
|
||||
|
||||
hsScalar IGetTimeAtBufferStart( void ) { return fTimeAtBufferStart; }
|
||||
virtual void SetStartPos(unsigned bytes);
|
||||
|
||||
virtual void IDerivedActuallyPlay( void );
|
||||
void IActuallyStop();
|
||||
virtual void ISetActualTime( double t );
|
||||
|
||||
virtual void IAddCallback( plEventCallbackMsg *pMsg );
|
||||
virtual void IRemoveCallback( plEventCallbackMsg *pMsg );
|
||||
|
||||
virtual void IFreeBuffers( void );
|
||||
void IStreamUpdate();
|
||||
virtual plSoundBuffer::ELoadReturnVal IPreLoadBuffer( hsBool playWhenLoaded, hsBool isIncidental = false );
|
||||
};
|
||||
|
||||
#endif //plWin32StreamingSound_h
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#ifndef plWin32StreamingSound_h
|
||||
#define plWin32StreamingSound_h
|
||||
|
||||
#include "plWin32Sound.h"
|
||||
#include "pnUtils/pnUtils.h"
|
||||
|
||||
class plDSoundBuffer;
|
||||
class DSoundCallbackHandle;
|
||||
class plAudioFileReader;
|
||||
class plStreamingSoundThread;
|
||||
enum CallbackHandleType;
|
||||
class plSoundDeswizzler;
|
||||
|
||||
class plWin32StreamingSound : public plWin32Sound
|
||||
{
|
||||
public:
|
||||
plWin32StreamingSound();
|
||||
~plWin32StreamingSound();
|
||||
|
||||
CLASSNAME_REGISTER( plWin32StreamingSound );
|
||||
GETINTERFACE_ANY( plWin32StreamingSound, plWin32Sound );
|
||||
|
||||
virtual void DeActivate();
|
||||
virtual hsBool LoadSound( hsBool is3D );
|
||||
virtual float GetActualTimeSec();
|
||||
virtual unsigned GetByteOffset();
|
||||
virtual StreamType GetStreamType() const { return fStreamType; }
|
||||
virtual void SetFilename(const char *filename, bool isCompressed);
|
||||
virtual void Update(); // temp
|
||||
void StreamUpdate();
|
||||
virtual hsBool MsgReceive( plMessage *pMsg );
|
||||
|
||||
protected:
|
||||
hsScalar fTimeAtBufferStart;
|
||||
plAudioFileReader *fDataStream;
|
||||
hsScalar fBufferLengthInSecs;
|
||||
UInt8 fBlankBufferFillCounter;
|
||||
plSoundDeswizzler *fDeswizzler;
|
||||
char fSrcFilename[ 256 ];
|
||||
StreamType fStreamType;
|
||||
bool fIsCompressed; // this applies only to the new sound file specified in fNewFilename, so we can play both ogg's and wav's
|
||||
std::string fNewFilename; // allow the filename to be changed so we can play from a different source.
|
||||
// ultimately this filename will be given to fDataBuffer, but since it's not always around we'll store it here
|
||||
hsBool fStopping;
|
||||
|
||||
double fLastStreamingUpdate;
|
||||
bool fPlayWhenStopped;
|
||||
unsigned fStartPos;
|
||||
|
||||
hsScalar IGetTimeAtBufferStart( void ) { return fTimeAtBufferStart; }
|
||||
virtual void SetStartPos(unsigned bytes);
|
||||
|
||||
virtual void IDerivedActuallyPlay( void );
|
||||
void IActuallyStop();
|
||||
virtual void ISetActualTime( double t );
|
||||
|
||||
virtual void IAddCallback( plEventCallbackMsg *pMsg );
|
||||
virtual void IRemoveCallback( plEventCallbackMsg *pMsg );
|
||||
|
||||
virtual void IFreeBuffers( void );
|
||||
void IStreamUpdate();
|
||||
virtual plSoundBuffer::ELoadReturnVal IPreLoadBuffer( hsBool playWhenLoaded, hsBool isIncidental = false );
|
||||
};
|
||||
|
||||
#endif //plWin32StreamingSound_h
|
||||
|
@ -1,361 +1,361 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plWinMicLevel - Annoying class to deal with the annoying problem of //
|
||||
// setting the microphone recording volume in Windows. //
|
||||
// Yeah, you'd THINK there'd be some easier way... //
|
||||
// //
|
||||
//// Notes ///////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// 5.8.2001 - Created by mcn. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "plWinMicLevel.h"
|
||||
#include "hsWindows.h"
|
||||
#include <mmsystem.h>
|
||||
|
||||
|
||||
//// Our Local Static Data ///////////////////////////////////////////////////
|
||||
|
||||
int sNumMixers = 0;
|
||||
HMIXER sMixerHandle = nil;
|
||||
MIXERCAPS sMixerCaps;
|
||||
|
||||
DWORD sMinValue = 0, sMaxValue = 0;
|
||||
DWORD sVolControlID = 0;
|
||||
|
||||
|
||||
//// Local Static Helpers ////////////////////////////////////////////////////
|
||||
|
||||
hsBool IGetMuxMicVolumeControl( void );
|
||||
hsBool IGetBaseMicVolumeControl( void );
|
||||
|
||||
hsBool IGetControlValue( DWORD &value );
|
||||
hsBool ISetControlValue( DWORD value );
|
||||
|
||||
MIXERLINE *IGetLineByType( DWORD type );
|
||||
MIXERLINE *IGetLineByID( DWORD id );
|
||||
MIXERCONTROL *IGetControlByType( MIXERLINE *line, DWORD type );
|
||||
MIXERLINE *IGetMixerSubLineByType( MIXERCONTROL *mux, DWORD type );
|
||||
|
||||
|
||||
//// The Publics /////////////////////////////////////////////////////////////
|
||||
|
||||
hsScalar plWinMicLevel::GetLevel( void )
|
||||
{
|
||||
if( !CanSetLevel() )
|
||||
return -1;
|
||||
|
||||
DWORD rawValue;
|
||||
if( !IGetControlValue( rawValue ) )
|
||||
return -1;
|
||||
|
||||
return (hsScalar)( rawValue - sMinValue ) / (hsScalar)( sMaxValue - sMinValue );
|
||||
}
|
||||
|
||||
void plWinMicLevel::SetLevel( hsScalar level )
|
||||
{
|
||||
if( !CanSetLevel() )
|
||||
return;
|
||||
|
||||
DWORD rawValue = (DWORD)(( level * ( sMaxValue - sMinValue ) ) + sMinValue);
|
||||
|
||||
ISetControlValue( rawValue );
|
||||
}
|
||||
|
||||
hsBool plWinMicLevel::CanSetLevel( void )
|
||||
{
|
||||
// Just to init
|
||||
plWinMicLevel &instance = IGetInstance();
|
||||
|
||||
return ( sMixerHandle != nil ) ? true : false;
|
||||
}
|
||||
|
||||
|
||||
//// Protected Init Stuff ////////////////////////////////////////////////////
|
||||
|
||||
plWinMicLevel &plWinMicLevel::IGetInstance( void )
|
||||
{
|
||||
static plWinMicLevel sInstance;
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
plWinMicLevel::plWinMicLevel()
|
||||
{
|
||||
sMixerHandle = nil;
|
||||
memset( &sMixerCaps, 0, sizeof( sMixerCaps ) );
|
||||
|
||||
// Get the number of mixers in the system
|
||||
sNumMixers = ::mixerGetNumDevs();
|
||||
|
||||
// So long as we have one, open the first one
|
||||
if( sNumMixers == 0 )
|
||||
return;
|
||||
|
||||
if( ::mixerOpen( &sMixerHandle, 0,
|
||||
nil, // Window handle to receive callback messages
|
||||
nil, MIXER_OBJECTF_MIXER ) != MMSYSERR_NOERROR )
|
||||
{
|
||||
sMixerHandle = nil; // Just to be sure
|
||||
return;
|
||||
}
|
||||
|
||||
if( ::mixerGetDevCaps( (UINT)sMixerHandle, &sMixerCaps, sizeof( sMixerCaps ) ) != MMSYSERR_NOERROR )
|
||||
{
|
||||
// Oh well, who cares
|
||||
}
|
||||
|
||||
// Try to get the Mux/mixer-based mic volume control first, since that seems to work better/more often/at all
|
||||
if( !IGetMuxMicVolumeControl() )
|
||||
{
|
||||
// Failed, so try getting the volume control from the base mic-in line
|
||||
if( !IGetBaseMicVolumeControl() )
|
||||
{
|
||||
IShutdown();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plWinMicLevel::~plWinMicLevel()
|
||||
{
|
||||
IShutdown();
|
||||
}
|
||||
|
||||
void plWinMicLevel::IShutdown( void )
|
||||
{
|
||||
if( sMixerHandle != nil )
|
||||
::mixerClose( sMixerHandle );
|
||||
|
||||
sMixerHandle = nil;
|
||||
}
|
||||
|
||||
//// IGetMuxMicVolumeControl /////////////////////////////////////////////////
|
||||
// Tries to get the volume control of the microphone subline of the MUX or
|
||||
// mixer control of the WaveIn destination line of the audio system (whew!)
|
||||
// Note: testing indcates that this works but the direct SRC_MICROPHONE
|
||||
// doesn't, hence we try this one first.
|
||||
|
||||
hsBool IGetMuxMicVolumeControl( void )
|
||||
{
|
||||
if( sMixerHandle == nil )
|
||||
return false;
|
||||
|
||||
// Get the WaveIn destination line
|
||||
MIXERLINE *waveInLine = IGetLineByType( MIXERLINE_COMPONENTTYPE_DST_WAVEIN );
|
||||
if( waveInLine == nil )
|
||||
return false;
|
||||
|
||||
// Get the mixer or MUX controller from the line
|
||||
MIXERCONTROL *control = IGetControlByType( waveInLine, MIXERCONTROL_CONTROLTYPE_MIXER );
|
||||
if( control == nil )
|
||||
control = IGetControlByType( waveInLine, MIXERCONTROL_CONTROLTYPE_MUX );
|
||||
if( control == nil )
|
||||
return false;
|
||||
|
||||
// Get the microphone sub-component
|
||||
// Note: this eventually calls IGetLineByType(), which destroys the waveInLine pointer we had before
|
||||
MIXERLINE *micLine = IGetMixerSubLineByType( control, MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE );
|
||||
if( micLine == nil )
|
||||
return false;
|
||||
|
||||
// Get the volume subcontroller
|
||||
MIXERCONTROL *micVolCtrl = IGetControlByType( micLine, MIXERCONTROL_CONTROLTYPE_VOLUME );
|
||||
if( micVolCtrl == nil )
|
||||
return false;
|
||||
|
||||
// Found it! store our values
|
||||
char *dbgLineName = micLine->szName;
|
||||
char *dbgControlName = micVolCtrl->szName;
|
||||
sMinValue = micVolCtrl->Bounds.dwMinimum;
|
||||
sMaxValue = micVolCtrl->Bounds.dwMaximum;
|
||||
sVolControlID = micVolCtrl->dwControlID;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//// IGetBaseMicVolumeControl ////////////////////////////////////////////////
|
||||
// Tries to get the volume control of the mic-in line. See
|
||||
// IGetMuxMicVolumeControl for why we don't do this one first.
|
||||
|
||||
hsBool IGetBaseMicVolumeControl( void )
|
||||
{
|
||||
if( sMixerHandle == nil )
|
||||
return false;
|
||||
|
||||
// Get the mic source line
|
||||
MIXERLINE *micLine = IGetLineByType( MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE );
|
||||
if( micLine == nil )
|
||||
return false;
|
||||
|
||||
// Get the volume subcontroller
|
||||
MIXERCONTROL *micVolCtrl = IGetControlByType( micLine, MIXERCONTROL_CONTROLTYPE_VOLUME );
|
||||
if( micVolCtrl == nil )
|
||||
return false;
|
||||
|
||||
// Found it! store our values
|
||||
char *dbgLineName = micLine->szName;
|
||||
char *dbgControlName = micVolCtrl->szName;
|
||||
sMinValue = micVolCtrl->Bounds.dwMinimum;
|
||||
sMaxValue = micVolCtrl->Bounds.dwMaximum;
|
||||
sVolControlID = micVolCtrl->dwControlID;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//// IGetControlValue ////////////////////////////////////////////////////////
|
||||
// Gets the raw value of the current volume control.
|
||||
|
||||
hsBool IGetControlValue( DWORD &value )
|
||||
{
|
||||
if( sMixerHandle == nil )
|
||||
return false;
|
||||
|
||||
MIXERCONTROLDETAILS_UNSIGNED mxcdVolume;
|
||||
MIXERCONTROLDETAILS mxcd;
|
||||
mxcd.cbStruct = sizeof( MIXERCONTROLDETAILS );
|
||||
mxcd.dwControlID = sVolControlID;
|
||||
mxcd.cChannels = 1;
|
||||
mxcd.cMultipleItems = 0;
|
||||
mxcd.cbDetails = sizeof( MIXERCONTROLDETAILS_UNSIGNED );
|
||||
mxcd.paDetails = &mxcdVolume;
|
||||
|
||||
if( ::mixerGetControlDetails( (HMIXEROBJ)sMixerHandle, &mxcd,
|
||||
MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE ) != MMSYSERR_NOERROR )
|
||||
return false;
|
||||
|
||||
value = mxcdVolume.dwValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
//// ISetControlValue ////////////////////////////////////////////////////////
|
||||
// Sets the raw value of the current volume control.
|
||||
|
||||
hsBool ISetControlValue( DWORD value )
|
||||
{
|
||||
if( sMixerHandle == nil )
|
||||
return false;
|
||||
|
||||
MIXERCONTROLDETAILS_UNSIGNED mxcdVolume = { value };
|
||||
MIXERCONTROLDETAILS mxcd;
|
||||
mxcd.cbStruct = sizeof( MIXERCONTROLDETAILS );
|
||||
mxcd.dwControlID = sVolControlID;
|
||||
mxcd.cChannels = 1;
|
||||
mxcd.cMultipleItems = 0;
|
||||
mxcd.cbDetails = sizeof( MIXERCONTROLDETAILS_UNSIGNED );
|
||||
mxcd.paDetails = &mxcdVolume;
|
||||
|
||||
if( ::mixerSetControlDetails( (HMIXEROBJ)sMixerHandle, &mxcd,
|
||||
MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE ) != MMSYSERR_NOERROR )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//// Helper Functions ////////////////////////////////////////////////////////
|
||||
|
||||
MIXERLINE *IGetLineByType( DWORD type )
|
||||
{
|
||||
static MIXERLINE mxl;
|
||||
|
||||
mxl.cbStruct = sizeof( MIXERLINE );
|
||||
mxl.dwComponentType = type;
|
||||
if( ::mixerGetLineInfo( (HMIXEROBJ)sMixerHandle, &mxl, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE ) != MMSYSERR_NOERROR )
|
||||
return nil;
|
||||
|
||||
return &mxl;
|
||||
}
|
||||
|
||||
MIXERLINE *IGetLineByID( DWORD id )
|
||||
{
|
||||
static MIXERLINE mxl;
|
||||
|
||||
mxl.cbStruct = sizeof( MIXERLINE );
|
||||
mxl.dwLineID = id;
|
||||
if( ::mixerGetLineInfo( (HMIXEROBJ)sMixerHandle, &mxl, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_LINEID ) != MMSYSERR_NOERROR )
|
||||
return nil;
|
||||
|
||||
return &mxl;
|
||||
}
|
||||
|
||||
MIXERCONTROL *IGetControlByType( MIXERLINE *line, DWORD type )
|
||||
{
|
||||
static MIXERCONTROL mxc;
|
||||
|
||||
MIXERLINECONTROLS mxlc;
|
||||
mxlc.cbStruct = sizeof( MIXERLINECONTROLS );
|
||||
mxlc.dwLineID = line->dwLineID;
|
||||
mxlc.dwControlType = type;
|
||||
mxlc.cControls = 1;
|
||||
mxlc.cbmxctrl = sizeof( MIXERCONTROL );
|
||||
mxlc.pamxctrl = &mxc;
|
||||
if( ::mixerGetLineControls( (HMIXEROBJ)sMixerHandle, &mxlc, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE ) != MMSYSERR_NOERROR )
|
||||
return nil;
|
||||
|
||||
return &mxc;
|
||||
}
|
||||
|
||||
MIXERLINE *IGetMixerSubLineByType( MIXERCONTROL *mux, DWORD type )
|
||||
{
|
||||
// A mixer or MUX is really a combination of MORE lines. And beautifully, you can't
|
||||
// just ask for a single one off of it, you have to ask for them all and search through yourself
|
||||
MIXERCONTROLDETAILS_LISTTEXT *lineInfo = TRACKED_NEW MIXERCONTROLDETAILS_LISTTEXT[ mux->cMultipleItems ];
|
||||
if( lineInfo == nil )
|
||||
return nil;
|
||||
|
||||
MIXERCONTROLDETAILS details;
|
||||
details.cbStruct = sizeof( MIXERCONTROLDETAILS );
|
||||
details.dwControlID = mux->dwControlID;
|
||||
details.cChannels = 1;
|
||||
details.cMultipleItems = mux->cMultipleItems;
|
||||
details.cbDetails = sizeof( MIXERCONTROLDETAILS_LISTTEXT );
|
||||
details.paDetails = lineInfo;
|
||||
if( ::mixerGetControlDetails( (HMIXEROBJ)sMixerHandle, &details, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_LISTTEXT ) != MMSYSERR_NOERROR )
|
||||
{
|
||||
delete [] lineInfo;
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Loop through and find the one with the right component type. But of course it doesn't give us that offhand...
|
||||
for( unsigned int i = 0; i < mux->cMultipleItems; i++ )
|
||||
{
|
||||
MIXERLINE *line = IGetLineByID( lineInfo[ i ].dwParam1 );
|
||||
if( line->dwComponentType == type )
|
||||
{
|
||||
delete [] lineInfo;
|
||||
return line;
|
||||
}
|
||||
}
|
||||
|
||||
delete [] lineInfo;
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plWinMicLevel - Annoying class to deal with the annoying problem of //
|
||||
// setting the microphone recording volume in Windows. //
|
||||
// Yeah, you'd THINK there'd be some easier way... //
|
||||
// //
|
||||
//// Notes ///////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// 5.8.2001 - Created by mcn. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "plWinMicLevel.h"
|
||||
#include "hsWindows.h"
|
||||
#include <mmsystem.h>
|
||||
|
||||
|
||||
//// Our Local Static Data ///////////////////////////////////////////////////
|
||||
|
||||
int sNumMixers = 0;
|
||||
HMIXER sMixerHandle = nil;
|
||||
MIXERCAPS sMixerCaps;
|
||||
|
||||
DWORD sMinValue = 0, sMaxValue = 0;
|
||||
DWORD sVolControlID = 0;
|
||||
|
||||
|
||||
//// Local Static Helpers ////////////////////////////////////////////////////
|
||||
|
||||
hsBool IGetMuxMicVolumeControl( void );
|
||||
hsBool IGetBaseMicVolumeControl( void );
|
||||
|
||||
hsBool IGetControlValue( DWORD &value );
|
||||
hsBool ISetControlValue( DWORD value );
|
||||
|
||||
MIXERLINE *IGetLineByType( DWORD type );
|
||||
MIXERLINE *IGetLineByID( DWORD id );
|
||||
MIXERCONTROL *IGetControlByType( MIXERLINE *line, DWORD type );
|
||||
MIXERLINE *IGetMixerSubLineByType( MIXERCONTROL *mux, DWORD type );
|
||||
|
||||
|
||||
//// The Publics /////////////////////////////////////////////////////////////
|
||||
|
||||
hsScalar plWinMicLevel::GetLevel( void )
|
||||
{
|
||||
if( !CanSetLevel() )
|
||||
return -1;
|
||||
|
||||
DWORD rawValue;
|
||||
if( !IGetControlValue( rawValue ) )
|
||||
return -1;
|
||||
|
||||
return (hsScalar)( rawValue - sMinValue ) / (hsScalar)( sMaxValue - sMinValue );
|
||||
}
|
||||
|
||||
void plWinMicLevel::SetLevel( hsScalar level )
|
||||
{
|
||||
if( !CanSetLevel() )
|
||||
return;
|
||||
|
||||
DWORD rawValue = (DWORD)(( level * ( sMaxValue - sMinValue ) ) + sMinValue);
|
||||
|
||||
ISetControlValue( rawValue );
|
||||
}
|
||||
|
||||
hsBool plWinMicLevel::CanSetLevel( void )
|
||||
{
|
||||
// Just to init
|
||||
plWinMicLevel &instance = IGetInstance();
|
||||
|
||||
return ( sMixerHandle != nil ) ? true : false;
|
||||
}
|
||||
|
||||
|
||||
//// Protected Init Stuff ////////////////////////////////////////////////////
|
||||
|
||||
plWinMicLevel &plWinMicLevel::IGetInstance( void )
|
||||
{
|
||||
static plWinMicLevel sInstance;
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
plWinMicLevel::plWinMicLevel()
|
||||
{
|
||||
sMixerHandle = nil;
|
||||
memset( &sMixerCaps, 0, sizeof( sMixerCaps ) );
|
||||
|
||||
// Get the number of mixers in the system
|
||||
sNumMixers = ::mixerGetNumDevs();
|
||||
|
||||
// So long as we have one, open the first one
|
||||
if( sNumMixers == 0 )
|
||||
return;
|
||||
|
||||
if( ::mixerOpen( &sMixerHandle, 0,
|
||||
nil, // Window handle to receive callback messages
|
||||
nil, MIXER_OBJECTF_MIXER ) != MMSYSERR_NOERROR )
|
||||
{
|
||||
sMixerHandle = nil; // Just to be sure
|
||||
return;
|
||||
}
|
||||
|
||||
if( ::mixerGetDevCaps( (UINT)sMixerHandle, &sMixerCaps, sizeof( sMixerCaps ) ) != MMSYSERR_NOERROR )
|
||||
{
|
||||
// Oh well, who cares
|
||||
}
|
||||
|
||||
// Try to get the Mux/mixer-based mic volume control first, since that seems to work better/more often/at all
|
||||
if( !IGetMuxMicVolumeControl() )
|
||||
{
|
||||
// Failed, so try getting the volume control from the base mic-in line
|
||||
if( !IGetBaseMicVolumeControl() )
|
||||
{
|
||||
IShutdown();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plWinMicLevel::~plWinMicLevel()
|
||||
{
|
||||
IShutdown();
|
||||
}
|
||||
|
||||
void plWinMicLevel::IShutdown( void )
|
||||
{
|
||||
if( sMixerHandle != nil )
|
||||
::mixerClose( sMixerHandle );
|
||||
|
||||
sMixerHandle = nil;
|
||||
}
|
||||
|
||||
//// IGetMuxMicVolumeControl /////////////////////////////////////////////////
|
||||
// Tries to get the volume control of the microphone subline of the MUX or
|
||||
// mixer control of the WaveIn destination line of the audio system (whew!)
|
||||
// Note: testing indcates that this works but the direct SRC_MICROPHONE
|
||||
// doesn't, hence we try this one first.
|
||||
|
||||
hsBool IGetMuxMicVolumeControl( void )
|
||||
{
|
||||
if( sMixerHandle == nil )
|
||||
return false;
|
||||
|
||||
// Get the WaveIn destination line
|
||||
MIXERLINE *waveInLine = IGetLineByType( MIXERLINE_COMPONENTTYPE_DST_WAVEIN );
|
||||
if( waveInLine == nil )
|
||||
return false;
|
||||
|
||||
// Get the mixer or MUX controller from the line
|
||||
MIXERCONTROL *control = IGetControlByType( waveInLine, MIXERCONTROL_CONTROLTYPE_MIXER );
|
||||
if( control == nil )
|
||||
control = IGetControlByType( waveInLine, MIXERCONTROL_CONTROLTYPE_MUX );
|
||||
if( control == nil )
|
||||
return false;
|
||||
|
||||
// Get the microphone sub-component
|
||||
// Note: this eventually calls IGetLineByType(), which destroys the waveInLine pointer we had before
|
||||
MIXERLINE *micLine = IGetMixerSubLineByType( control, MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE );
|
||||
if( micLine == nil )
|
||||
return false;
|
||||
|
||||
// Get the volume subcontroller
|
||||
MIXERCONTROL *micVolCtrl = IGetControlByType( micLine, MIXERCONTROL_CONTROLTYPE_VOLUME );
|
||||
if( micVolCtrl == nil )
|
||||
return false;
|
||||
|
||||
// Found it! store our values
|
||||
char *dbgLineName = micLine->szName;
|
||||
char *dbgControlName = micVolCtrl->szName;
|
||||
sMinValue = micVolCtrl->Bounds.dwMinimum;
|
||||
sMaxValue = micVolCtrl->Bounds.dwMaximum;
|
||||
sVolControlID = micVolCtrl->dwControlID;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//// IGetBaseMicVolumeControl ////////////////////////////////////////////////
|
||||
// Tries to get the volume control of the mic-in line. See
|
||||
// IGetMuxMicVolumeControl for why we don't do this one first.
|
||||
|
||||
hsBool IGetBaseMicVolumeControl( void )
|
||||
{
|
||||
if( sMixerHandle == nil )
|
||||
return false;
|
||||
|
||||
// Get the mic source line
|
||||
MIXERLINE *micLine = IGetLineByType( MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE );
|
||||
if( micLine == nil )
|
||||
return false;
|
||||
|
||||
// Get the volume subcontroller
|
||||
MIXERCONTROL *micVolCtrl = IGetControlByType( micLine, MIXERCONTROL_CONTROLTYPE_VOLUME );
|
||||
if( micVolCtrl == nil )
|
||||
return false;
|
||||
|
||||
// Found it! store our values
|
||||
char *dbgLineName = micLine->szName;
|
||||
char *dbgControlName = micVolCtrl->szName;
|
||||
sMinValue = micVolCtrl->Bounds.dwMinimum;
|
||||
sMaxValue = micVolCtrl->Bounds.dwMaximum;
|
||||
sVolControlID = micVolCtrl->dwControlID;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//// IGetControlValue ////////////////////////////////////////////////////////
|
||||
// Gets the raw value of the current volume control.
|
||||
|
||||
hsBool IGetControlValue( DWORD &value )
|
||||
{
|
||||
if( sMixerHandle == nil )
|
||||
return false;
|
||||
|
||||
MIXERCONTROLDETAILS_UNSIGNED mxcdVolume;
|
||||
MIXERCONTROLDETAILS mxcd;
|
||||
mxcd.cbStruct = sizeof( MIXERCONTROLDETAILS );
|
||||
mxcd.dwControlID = sVolControlID;
|
||||
mxcd.cChannels = 1;
|
||||
mxcd.cMultipleItems = 0;
|
||||
mxcd.cbDetails = sizeof( MIXERCONTROLDETAILS_UNSIGNED );
|
||||
mxcd.paDetails = &mxcdVolume;
|
||||
|
||||
if( ::mixerGetControlDetails( (HMIXEROBJ)sMixerHandle, &mxcd,
|
||||
MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE ) != MMSYSERR_NOERROR )
|
||||
return false;
|
||||
|
||||
value = mxcdVolume.dwValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
//// ISetControlValue ////////////////////////////////////////////////////////
|
||||
// Sets the raw value of the current volume control.
|
||||
|
||||
hsBool ISetControlValue( DWORD value )
|
||||
{
|
||||
if( sMixerHandle == nil )
|
||||
return false;
|
||||
|
||||
MIXERCONTROLDETAILS_UNSIGNED mxcdVolume = { value };
|
||||
MIXERCONTROLDETAILS mxcd;
|
||||
mxcd.cbStruct = sizeof( MIXERCONTROLDETAILS );
|
||||
mxcd.dwControlID = sVolControlID;
|
||||
mxcd.cChannels = 1;
|
||||
mxcd.cMultipleItems = 0;
|
||||
mxcd.cbDetails = sizeof( MIXERCONTROLDETAILS_UNSIGNED );
|
||||
mxcd.paDetails = &mxcdVolume;
|
||||
|
||||
if( ::mixerSetControlDetails( (HMIXEROBJ)sMixerHandle, &mxcd,
|
||||
MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE ) != MMSYSERR_NOERROR )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//// Helper Functions ////////////////////////////////////////////////////////
|
||||
|
||||
MIXERLINE *IGetLineByType( DWORD type )
|
||||
{
|
||||
static MIXERLINE mxl;
|
||||
|
||||
mxl.cbStruct = sizeof( MIXERLINE );
|
||||
mxl.dwComponentType = type;
|
||||
if( ::mixerGetLineInfo( (HMIXEROBJ)sMixerHandle, &mxl, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE ) != MMSYSERR_NOERROR )
|
||||
return nil;
|
||||
|
||||
return &mxl;
|
||||
}
|
||||
|
||||
MIXERLINE *IGetLineByID( DWORD id )
|
||||
{
|
||||
static MIXERLINE mxl;
|
||||
|
||||
mxl.cbStruct = sizeof( MIXERLINE );
|
||||
mxl.dwLineID = id;
|
||||
if( ::mixerGetLineInfo( (HMIXEROBJ)sMixerHandle, &mxl, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_LINEID ) != MMSYSERR_NOERROR )
|
||||
return nil;
|
||||
|
||||
return &mxl;
|
||||
}
|
||||
|
||||
MIXERCONTROL *IGetControlByType( MIXERLINE *line, DWORD type )
|
||||
{
|
||||
static MIXERCONTROL mxc;
|
||||
|
||||
MIXERLINECONTROLS mxlc;
|
||||
mxlc.cbStruct = sizeof( MIXERLINECONTROLS );
|
||||
mxlc.dwLineID = line->dwLineID;
|
||||
mxlc.dwControlType = type;
|
||||
mxlc.cControls = 1;
|
||||
mxlc.cbmxctrl = sizeof( MIXERCONTROL );
|
||||
mxlc.pamxctrl = &mxc;
|
||||
if( ::mixerGetLineControls( (HMIXEROBJ)sMixerHandle, &mxlc, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE ) != MMSYSERR_NOERROR )
|
||||
return nil;
|
||||
|
||||
return &mxc;
|
||||
}
|
||||
|
||||
MIXERLINE *IGetMixerSubLineByType( MIXERCONTROL *mux, DWORD type )
|
||||
{
|
||||
// A mixer or MUX is really a combination of MORE lines. And beautifully, you can't
|
||||
// just ask for a single one off of it, you have to ask for them all and search through yourself
|
||||
MIXERCONTROLDETAILS_LISTTEXT *lineInfo = TRACKED_NEW MIXERCONTROLDETAILS_LISTTEXT[ mux->cMultipleItems ];
|
||||
if( lineInfo == nil )
|
||||
return nil;
|
||||
|
||||
MIXERCONTROLDETAILS details;
|
||||
details.cbStruct = sizeof( MIXERCONTROLDETAILS );
|
||||
details.dwControlID = mux->dwControlID;
|
||||
details.cChannels = 1;
|
||||
details.cMultipleItems = mux->cMultipleItems;
|
||||
details.cbDetails = sizeof( MIXERCONTROLDETAILS_LISTTEXT );
|
||||
details.paDetails = lineInfo;
|
||||
if( ::mixerGetControlDetails( (HMIXEROBJ)sMixerHandle, &details, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_LISTTEXT ) != MMSYSERR_NOERROR )
|
||||
{
|
||||
delete [] lineInfo;
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Loop through and find the one with the right component type. But of course it doesn't give us that offhand...
|
||||
for( unsigned int i = 0; i < mux->cMultipleItems; i++ )
|
||||
{
|
||||
MIXERLINE *line = IGetLineByID( lineInfo[ i ].dwParam1 );
|
||||
if( line->dwComponentType == type )
|
||||
{
|
||||
delete [] lineInfo;
|
||||
return line;
|
||||
}
|
||||
}
|
||||
|
||||
delete [] lineInfo;
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
@ -1,64 +1,64 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#ifndef _plWinMicLevel_h
|
||||
#define _plWinMicLevel_h
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plWinMicLevel - Annoying class to deal with the annoying problem of //
|
||||
// setting the microphone recording volume in Windows. //
|
||||
// Yeah, you'd THINK there'd be some easier way... //
|
||||
// //
|
||||
//// Notes ///////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// 5.8.2001 - Created by mcn. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
//// Class Definition ////////////////////////////////////////////////////////
|
||||
|
||||
class plWinMicLevel
|
||||
{
|
||||
public:
|
||||
|
||||
~plWinMicLevel();
|
||||
// Gets the microphone volume, range 0-1, -1 if error
|
||||
static hsScalar GetLevel( void );
|
||||
|
||||
// Sets the microphone volume, range 0-1
|
||||
static void SetLevel( hsScalar level );
|
||||
|
||||
// Returns whether we can set the level
|
||||
static hsBool CanSetLevel( void );
|
||||
|
||||
protected:
|
||||
plWinMicLevel(); // Protected constructor for IGetInstance. Just to init some stuff
|
||||
static plWinMicLevel &IGetInstance( void );
|
||||
void IShutdown( void );
|
||||
};
|
||||
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#ifndef _plWinMicLevel_h
|
||||
#define _plWinMicLevel_h
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plWinMicLevel - Annoying class to deal with the annoying problem of //
|
||||
// setting the microphone recording volume in Windows. //
|
||||
// Yeah, you'd THINK there'd be some easier way... //
|
||||
// //
|
||||
//// Notes ///////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// 5.8.2001 - Created by mcn. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
//// Class Definition ////////////////////////////////////////////////////////
|
||||
|
||||
class plWinMicLevel
|
||||
{
|
||||
public:
|
||||
|
||||
~plWinMicLevel();
|
||||
// Gets the microphone volume, range 0-1, -1 if error
|
||||
static hsScalar GetLevel( void );
|
||||
|
||||
// Sets the microphone volume, range 0-1
|
||||
static void SetLevel( hsScalar level );
|
||||
|
||||
// Returns whether we can set the level
|
||||
static hsBool CanSetLevel( void );
|
||||
|
||||
protected:
|
||||
plWinMicLevel(); // Protected constructor for IGetInstance. Just to init some stuff
|
||||
static plWinMicLevel &IGetInstance( void );
|
||||
void IShutdown( void );
|
||||
};
|
||||
|
||||
#endif // _plWinMicLevel_h
|
Reference in New Issue
Block a user