You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
344 lines
9.3 KiB
344 lines
9.3 KiB
4 years ago
|
/*==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/>.
|
||
|
|
||
|
Additional permissions under GNU GPL version 3 section 7
|
||
|
|
||
|
If you modify this Program, or any covered work, by linking or
|
||
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||
|
(or a modified version of those libraries),
|
||
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||
|
licensors of this Program grant you additional
|
||
|
permission to convey the resulting work. Corresponding Source for a
|
||
|
non-source form of such a combination shall include the source code for
|
||
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||
|
work.
|
||
|
|
||
|
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 );
|
||
|
}
|