123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709 |
- /* Copyright (c) 2002-2012 Croteam Ltd.
- This program is free software; you can redistribute it and/or modify
- it under the terms of version 2 of the GNU General Public License as published by
- the Free Software Foundation
- 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, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
- #include "stdh.h"
- #include <Engine/Base/Stream.h>
- #include <Engine/Base/Console.h>
- #include <Engine/Base/CRC.h>
- #include <Engine/Math/Vector.h>
- #include <Engine/Math/Functions.h>
- #include <Engine/Sound/SoundObject.h>
- #include <Engine/Sound/SoundDecoder.h>
- #include <Engine/Sound/SoundData.h>
- #include <Engine/Sound/SoundLibrary.h>
- #include <Engine/Sound/SoundListener.h>
- #include <Engine/Entities/Entity.h>
- #include <Engine/Entities/InternalClasses.h>
- #include <Engine/Base/ListIterator.inl>
- #include <Engine/Templates/Stock_CSoundData.h>
- // sound event codes for prediction
- #define EVENT_SOUNDPLAY 0x0101
- #define EVENT_SOUNDSTOP 0x0102
- #define EVENT_SOUNDSETOFFSET 0x0103
- extern FLOAT snd_fEarsDistance;
- extern FLOAT snd_fDelaySoundSpeed;
- extern FLOAT snd_fDopplerSoundSpeed;
- extern FLOAT snd_fPanStrength;
- extern FLOAT snd_fLRFilter;
- extern FLOAT snd_fBFilter;
- extern FLOAT snd_fUFilter;
- extern FLOAT snd_fDFilter;
- extern BOOL _bPredictionActive;
- // console variables for volume
- extern FLOAT snd_fSoundVolume;
- extern FLOAT snd_fMusicVolume;
- static CTString GetPred(CEntity*pen)
- {
- CTString str1;
- if (pen->IsPredictor()) {
- str1 = "predictor";
- } else if (pen->IsPredicted()) {
- str1 = "predicted";
- } else if (pen->en_ulFlags & ENF_WILLBEPREDICTED) {
- str1 = "will be predicted";
- } else {
- str1 = "???";
- }
- CTString str;
- str.PrintF("%08x-%s", pen, str1);
- return str;
- }
- /* ====================================================
- *
- * Class global methods
- */
- /*
- * Constructor
- */
- CSoundObject::CSoundObject()
- {
- so_pCsdLink = NULL;
- so_psdcDecoder = NULL;
- so_penEntity = NULL;
- so_slFlags = 0;
- // clear sound settings
- so_spNew.sp_fLeftVolume = 1.0f;
- so_spNew.sp_fRightVolume = 1.0f;
- so_spNew.sp_slLeftFilter = 0x7FFF;
- so_spNew.sp_slRightFilter = 0x7FFF;
- so_spNew.sp_fPitchShift = 1.0f;
- so_spNew.sp_fPhaseShift = 0.0f;
- so_spNew.sp_fDelay = 0.0f;
- so_sp = so_spNew;
- so_fLeftOffset = 0.0f;
- so_fRightOffset = 0.0f;
- so_fOffsetDelta = 0.0f;
- so_fDelayed = 0.0f;
- so_fLastLeftVolume = 1.0f;
- so_fLastRightVolume = 1.0f;
- so_swLastLeftSample = 0;
- so_swLastRightSample = 0;
- // 3d effects
- so_sp3.sp3_fFalloff = 0.0f;
- so_sp3.sp3_fHotSpot = 0.0f;
- so_sp3.sp3_fMaxVolume = 0.0f;
- so_sp3.sp3_fPitch = 1.0f;
- };
- /*
- * Destructor
- */
- CSoundObject::~CSoundObject()
- {
- Stop_internal();
- };
- // copy from another object of same class
- void CSoundObject::Copy(CSoundObject &soOther)
- {
- Stop_internal();
- so_sp = so_spNew = soOther.so_sp;
- so_sp3 = soOther.so_sp3;
- so_penEntity = NULL;
- so_slFlags = soOther.so_slFlags;
- if (soOther.so_slFlags&SOF_PLAY) {
- Play(soOther.so_pCsdLink, soOther.so_slFlags);
- }
- }
- // Set 3D parameters
- void CSoundObject::Set3DParameters( FLOAT fFalloff, FLOAT fHotSpot,
- FLOAT fMaxVolume, FLOAT fPitch)
- {
- ASSERT( (fFalloff > 0) && (fHotSpot >= 0));
- ASSERT( fMaxVolume >= 0);
- ASSERT( fFalloff >= fHotSpot);
- ASSERT( fPitch > 0);
- CSoundObject *pso = this;
- // if the sound's entity is a predictor
- if (_bPredictionActive && so_penEntity!=NULL) {
- if (so_penEntity->IsPredictionHead()) {
- // get your prediction tail
- //CPrintF("SET3D: ");
- CEntity *pen = so_penEntity->GetPredictionTail();
- if (pen!=so_penEntity) {
- pso = (CSoundObject *)( ((UBYTE*)pen) + (int(this)-int(so_penEntity)) );
- }
- }
- }
-
- pso->so_sp3.sp3_fFalloff = fFalloff;
- pso->so_sp3.sp3_fHotSpot = fHotSpot;
- pso->so_sp3.sp3_fMaxVolume = fMaxVolume;
- pso->so_sp3.sp3_fPitch = fPitch;
- };
- /* ====================================================
- * Sound control methods
- */
- // get proper sound object for predicted events - return NULL the event is already predicted
- CSoundObject *CSoundObject::GetPredictionTail(ULONG ulTypeID, ULONG ulEventID)
- {
- // if the sound has an entity
- if (so_penEntity!=NULL) {
- //CPrintF(" {%s}", GetPred(so_penEntity));
- // if the entity is temporary predictor
- if (so_penEntity->GetFlags()&ENF_TEMPPREDICTOR) {
- //CPrintF(" temppred\n");
- // it must not play the sound
- return NULL;
- }
- SLONG slOffset = int(this)-int(so_penEntity);
- ULONG ulCRC;
- CRC_Start(ulCRC);
- CRC_AddLONG(ulCRC, slOffset);
- CRC_AddLONG(ulCRC, ulTypeID);
- CRC_Finish(ulCRC);
- // if the event is predicted
- if (so_penEntity->CheckEventPrediction(ulCRC, ulEventID)) {
- //CPrintF(" predicted\n");
- // return nothing
- return NULL;
- }
- CEntity *pen = so_penEntity;
- // find eventual prediction tail sound object
- if (pen->IsPredictor()) {
- pen = pen->GetPredictionTail();
- if (pen!=so_penEntity) {
- //CPrintF(" ROUTED\n");
- return (CSoundObject *)( ((UBYTE*)pen) + slOffset );
- }
- }
- }
- // if no specific prediction states - use this object
- //CPrintF(" ORIGINAL\n");
- return this;
- }
- /*
- * Play
- */
- void CSoundObject::Play(CSoundData *pCsdLink, SLONG slFlags)
- {
- // synchronize access to sounds
- CTSingleLock slSounds( &_pSound->sl_csSound, TRUE);
- //CPrintF("PLAY: '%s'", (const char*)pCsdLink->GetName().FileName());
- // get prediction tail
- CSoundObject *psoTail = GetPredictionTail(EVENT_SOUNDPLAY, (ULONG)pCsdLink);
- // if the event is predicted
- if (psoTail==NULL) {
- // do nothing;
- return;
- }
- // play the sound in the given object
- psoTail->Play_internal(pCsdLink, slFlags);
- }
- // play sound - internal function - doesn't account for prediction
- void CSoundObject::Play_internal( CSoundData *pCsdLink, SLONG slFlags)
- {
- ASSERT(so_penEntity==NULL || !so_penEntity->IsPredictor());
- // check if should continue with new sound
- BOOL bContinue =
- ((slFlags&SOF_SMOOTHCHANGE) &&
- (so_slFlags&SOF_PREPARE) &&
- (so_slFlags&SOF_PLAY));
- Stop_internal();
- // mark new data as referenced once more
- pCsdLink->AddReference();
- // mark old data as referenced once less
- so_pCsdLink->RemReference();
- // store init SoundData
- so_pCsdLink = pCsdLink;
- // add to link list
- so_pCsdLink->AddObjectLink(*this);
- // store flags
- so_slFlags = slFlags;
- // if should continue with new sound
- if (bContinue) {
- // play buffer immediately
- so_slFlags = so_slFlags | SOF_PREPARE | SOF_PLAY;
- } else {
- // play buffer
- so_slFlags = (so_slFlags & ~(SOF_PREPARE|SOF_PAUSED)) | SOF_PLAY;
- }
- // if the sound data is encoded
- if (so_pCsdLink->sd_ulFlags&SDF_ENCODED) {
- // create decoder
- if (so_pCsdLink->sd_ulFlags&SDF_STREAMING) {
- so_psdcDecoder = new CSoundDecoder(so_pCsdLink->GetName());
- } else {
- ASSERT(FALSE); // nonstreaming not supported anymore
- }
- }
- // remember starting parameters
- so_sp = so_spNew;
- // initialize mixer temporary variables
- if (!(slFlags&SOF_LOADED)) {
- so_fLastLeftVolume = so_sp.sp_fLeftVolume;
- so_fLastRightVolume = so_sp.sp_fRightVolume;
- so_fLeftOffset = 0.0f;
- so_fRightOffset = 0.0f;
- so_fOffsetDelta = 0.0f;
- so_fDelayed = 0.0f;
- if (!bContinue) {
- so_swLastLeftSample = 0;
- so_swLastRightSample = 0;
- } else {
- // adjust for master volume
- if(so_slFlags&SOF_MUSIC) {
- so_fLastLeftVolume *= snd_fMusicVolume;
- so_fLastRightVolume *= snd_fMusicVolume;
- } else {
- so_fLastLeftVolume *= snd_fSoundVolume;
- so_fLastRightVolume *= snd_fSoundVolume;
- }
- }
- }
- }
- // hard set sound offset in seconds
- void CSoundObject::SetOffset( FLOAT fOffset)
- {
- // synchronize access to sounds
- CTSingleLock slSounds( &_pSound->sl_csSound, TRUE);
- // get prediction tail
- //CPrintF("SETOFF: ");
- CSoundObject *psoTail = GetPredictionTail(EVENT_SOUNDSETOFFSET, 0);
- // if the event is predicted
- if (psoTail==NULL) {
- // do nothing;
- return;
- }
- // if sound not playing
- if (psoTail->so_pCsdLink==NULL) {
- // do nothing
- return;
- }
- // safety check
- ASSERT( fOffset>=0);
- if( fOffset<0) {
- CPrintF( "BUG: Trying to set negative offset (%.2g) in sound '%s' !\n", fOffset, (CTString&)psoTail->so_pCsdLink->GetName());
- fOffset = 0.0f;
- }
- // on the other hand, don't set offset for real - might be source for some bugs!
- return;
-
- // update sound offsets
- CPrintF("Setting offset: %g\n", fOffset);
- psoTail->so_fLeftOffset = psoTail->so_fRightOffset = psoTail->so_pCsdLink->sd_wfeFormat.nSamplesPerSec*fOffset;
- }
- /*
- * Stop
- */
- void CSoundObject::Stop(void)
- {
- // synchronize access to sounds
- CTSingleLock slSounds( &_pSound->sl_csSound, TRUE);
- //CPrintF("STOP");
- if (so_pCsdLink!=NULL) {
- //CPrintF(" '%s'", (const char*)so_pCsdLink->GetName().FileName());
- }
- CSoundObject *psoTail = this;
- // get prediction tail
- psoTail = GetPredictionTail(EVENT_SOUNDSTOP, (ULONG)so_pCsdLink);
- // if the event is predicted
- if (psoTail==NULL) {
- // do nothing;
- return;
- }
- psoTail->Stop_internal();
- }
- void CSoundObject::Stop_internal(void)
- {
- // sound is stoped
- so_slFlags &= ~(SOF_PLAY|SOF_PREPARE|SOF_PAUSED);
- // destroy decoder if exists
- if( so_psdcDecoder!=NULL) {
- delete so_psdcDecoder;
- so_psdcDecoder = NULL;
- }
- // if added in link list, remove it from list
- if( IsHooked()) {
- ASSERT(so_pCsdLink != NULL);
- so_pCsdLink->RemoveObjectLink(*this);
- // remove reference from SoundData
- so_pCsdLink->RemReference();
- // clear SoundData link
- so_pCsdLink = NULL;
- }
- };
- // Update all 3d effects
- void CSoundObject::Update3DEffects(void)
- {
- // if not 3d sound
- if( !(so_slFlags & SOF_3D)) {
- // do nothing;
- return;
- }
- // if (!(so_slFlags&SOF_PREPARE)) {
- // if the sound's entity is a predictor
- /* if (so_penEntity!=NULL && so_penEntity->IsPredictor()) {
- // kill the sound
- so_slFlags&=~SOF_PLAY;
- //CPrintF("Update canceled %s (%s)\n", (const char*)so_pCsdLink->GetName(), GetPred(so_penEntity));
- // do nothing;
- return;
- }
- */
- //CPrintF("Update PASSED %s (%s)\n", (const char*)so_pCsdLink->GetName(), GetPred(so_penEntity));
- // }
- // total parameters (accounting for all listeners)
- FLOAT fTLVolume = 0, fTRVolume = 0;
- FLOAT fTLFilter = UpperLimit(0.0f), fTRFilter = UpperLimit(0.0f);
- FLOAT fTLDelay = UpperLimit(0.0f), fTRDelay = UpperLimit(0.0f);
- FLOAT fTPitchShift = 0;
- // get your position parameters
- FLOAT3D vPosition(0,0,0);
- FLOAT3D vSpeed(0,0,0);
- if (so_penEntity!=NULL) {
- vPosition = so_penEntity->en_plPlacement.pl_PositionVector;
- if (so_penEntity->en_ulPhysicsFlags&EPF_MOVABLE) {
- CMovableEntity *penMovable = (CMovableEntity *)so_penEntity;
- vSpeed = penMovable->en_vCurrentTranslationAbsolute;
- }
- }
- // for each listener
- INDEX ctEffectiveListeners = 0;
- {FOREACHINLIST( CSoundListener, sli_lnInActiveListeners, _pSound->sl_lhActiveListeners, itsli)
- {
- CSoundListener &sli = *itsli;
- // if local, but not of this listener
- if ((so_slFlags&SOF_LOCAL) && so_penEntity!=sli.sli_penEntity) {
- // don't add this listener
- continue;
- }
- // calculated parameters for this listener
- FLOAT fLVolume, fRVolume;
- FLOAT fLFilter, fRFilter;
- FLOAT fLDelay , fRDelay ;
- FLOAT fPitchShift;
- // calculate distance from listener
- FLOAT3D vAbsDelta = vPosition - sli.sli_vPosition;
- FLOAT fAbsDelta = vAbsDelta.Length();
- // if too far away
- if (fAbsDelta>so_sp3.sp3_fFalloff) {
- // don't add this listener
- continue;
- }
- // calculate distance falloff factor
- FLOAT fDistanceFactor;
- if( fAbsDelta <= so_sp3.sp3_fHotSpot) {
- fDistanceFactor = 1;
- } else {
- fDistanceFactor = (so_sp3.sp3_fFalloff - fAbsDelta) /
- (so_sp3.sp3_fFalloff - so_sp3.sp3_fHotSpot);
- }
- ASSERT(fDistanceFactor>=0 && fDistanceFactor<=+1);
- // calculate volumetric influence
- // NOTE: decoded sounds must be threated as volumetric
- FLOAT fNonVolumetric = 1.0f;
- FLOAT fNonVolumetricAdvanced = 1.0f;
- if( (so_slFlags & SOF_VOLUMETRIC) || so_psdcDecoder!=NULL) {
- fNonVolumetric = 1.0f-fDistanceFactor;
- fNonVolumetricAdvanced = 0.0f;
- }
- ASSERT(fNonVolumetric>=0 && fNonVolumetric<=+1);
- // find doppler effect pitch shift
- fPitchShift = 1.0f;
- if (fAbsDelta>0.001f) {
- FLOAT3D vObjectDirection = vAbsDelta/fAbsDelta;
- FLOAT fObjectSpeed = vSpeed%vObjectDirection; // negative towards listener
- FLOAT fListenerSpeed = sli.sli_vSpeed%vObjectDirection; // positive towards object
- fPitchShift =
- (snd_fDopplerSoundSpeed+fListenerSpeed*fNonVolumetricAdvanced)/
- (snd_fDopplerSoundSpeed+fObjectSpeed*fNonVolumetricAdvanced);
- }
- // find position of sound relative to viewer orientation
- FLOAT3D vRelative = vAbsDelta*!sli.sli_mRotation;
- // find distances from left and right ear
- FLOAT fLDistance = (FLOAT3D(-snd_fEarsDistance*fNonVolumetricAdvanced/2,0,0)-vRelative).Length();
- FLOAT fRDistance = (FLOAT3D(+snd_fEarsDistance*fNonVolumetricAdvanced/2,0,0)-vRelative).Length();
- // calculate sound delay to each ear
- fLDelay = fLDistance/snd_fDelaySoundSpeed;
- fRDelay = fRDistance/snd_fDelaySoundSpeed;
- // calculate relative sound directions
- FLOAT fLRFactor=0; // positive right
- FLOAT fFBFactor=0; // positive front
- FLOAT fUDFactor=0; // positive up
- if (fAbsDelta>0.001f) {
- FLOAT3D vDir = vRelative/fAbsDelta;
- fLRFactor = +vDir(1);
- fFBFactor = -vDir(3);
- fUDFactor = +vDir(2);
- }
- ASSERT(fLRFactor>=-1.1 && fLRFactor<=+1.1);
- ASSERT(fFBFactor>=-1.1 && fFBFactor<=+1.1);
- ASSERT(fUDFactor>=-1.1 && fUDFactor<=+1.1);
- // calculate panning influence factor
- FLOAT fPanningFactor= fNonVolumetric*snd_fPanStrength;
- ASSERT(fPanningFactor>=0 && fPanningFactor<=+1);
- // calc volume for left and right channel
- FLOAT fVolume = so_sp3.sp3_fMaxVolume * fDistanceFactor;
- if( fLRFactor > 0) {
- fLVolume = (1-fLRFactor*fPanningFactor) * fVolume;
- fRVolume = fVolume;
- } else {
- fLVolume = fVolume;
- fRVolume = (1+fLRFactor*fPanningFactor) * fVolume;
- }
- // calculate filters
- FLOAT fListenerFilter = sli.sli_fFilter;
- if (so_slFlags&SOF_NOFILTER) {
- fListenerFilter = 0.0f;
- }
- fLFilter = fRFilter = 1+fListenerFilter;
- if( fLRFactor > 0) {
- fLFilter += fLRFactor*snd_fLRFilter*fNonVolumetricAdvanced;
- } else {
- fRFilter -= fLRFactor*snd_fLRFilter*fNonVolumetricAdvanced;
- }
- if( fFBFactor<0) {
- fLFilter -= snd_fBFilter*fFBFactor*fNonVolumetricAdvanced;
- fRFilter -= snd_fBFilter*fFBFactor*fNonVolumetricAdvanced;
- }
- if( fUDFactor>0) {
- fLFilter += snd_fUFilter*fUDFactor*fNonVolumetricAdvanced;
- fRFilter += snd_fUFilter*fUDFactor*fNonVolumetricAdvanced;
- } else {
- fLFilter -= snd_fDFilter*fUDFactor*fNonVolumetricAdvanced;
- fRFilter -= snd_fDFilter*fUDFactor*fNonVolumetricAdvanced;
- }
- // adjust calculated volume to the one of listener
- fLVolume *= sli.sli_fVolume;
- fRVolume *= sli.sli_fVolume;
- // update parameters for all listener
- fTLVolume = Max( fTLVolume, fLVolume);
- fTRVolume = Max( fTRVolume, fRVolume);
- fTLDelay = Min( fTLDelay , fLDelay );
- fTRDelay = Min( fTRDelay , fRDelay );
- fTLFilter = Min( fTLFilter, fLFilter);
- fTRFilter = Min( fTRFilter, fRFilter);
- fTPitchShift += fPitchShift;
- ctEffectiveListeners++;
- }}
- fTPitchShift /= ctEffectiveListeners;
- // calculate 2d parameters
- FLOAT fPitchShift = fTPitchShift * so_sp3.sp3_fPitch;
- FLOAT fPhaseShift = fTLDelay-fTRDelay;
- FLOAT fDelay = Min( fTRDelay,fTLDelay);
- // CPrintF("V:%f %f F:%f %f P:%f S:%f\n",
- // fTLVolume, fTRVolume,
- // fTLFilter, fTRFilter,
- // fPhaseShift,
- // fPitchShift);
- // set sound parameters
- fTLVolume = Clamp( fTLVolume, SL_VOLUME_MIN, SL_VOLUME_MAX);
- fTRVolume = Clamp( fTRVolume, SL_VOLUME_MIN, SL_VOLUME_MAX);
- SetVolume( fTLVolume, fTRVolume);
- if( fTLVolume>0 || fTRVolume>0) {
- // do safety clamping
- fTLFilter = ClampDn( fTLFilter, 1.0f);
- fTRFilter = ClampDn( fTRFilter, 1.0f);
- fDelay = ClampDn( fDelay, 0.0f);
- fPitchShift = ClampDn( fPitchShift, 0.001f);
- fPhaseShift = Clamp( fPhaseShift, -1.0f, +1.0f);
- // set sound params
- SetFilter( fTLFilter, fTRFilter);
- SetDelay( fDelay);
- SetPitch( fPitchShift);
- SetPhase( fPhaseShift);
- }
- }
- // Prepare sound
- void CSoundObject::PrepareSound(void)
- {
- ASSERT(so_penEntity==NULL || !so_penEntity->IsPredictor());
- so_fLastLeftVolume = so_spNew.sp_fLeftVolume;
- so_fLastRightVolume = so_spNew.sp_fRightVolume;
- // adjust for master volume
- if(so_slFlags&SOF_MUSIC) {
- so_fLastLeftVolume *= snd_fMusicVolume;
- so_fLastRightVolume *= snd_fMusicVolume;
- } else {
- so_fLastLeftVolume *= snd_fSoundVolume;
- so_fLastRightVolume *= snd_fSoundVolume;
- }
- };
- // Obtain sound and play it for this object
- void CSoundObject::Play_t(const CTFileName &fnmSound, SLONG slFlags) // throw char *
- {
- // obtain it (adds one reference)
- CSoundData *ptd = _pSoundStock->Obtain_t(fnmSound);
- // set it as data (adds one more reference, and remove old reference)
- Play(ptd, slFlags);
- // release it (removes one reference)
- _pSoundStock->Release(ptd);
- // total reference count +1+1-1 = +1 for new data -1 for old data
- };
- // read/write functions
- void CSoundObject::Read_t(CTStream *pistr) // throw char *
- {
- int iDroppedOut;
- // load file name
- CTFileName fnmSound;
- *pistr >> fnmSound;
- // load object preferences
- *pistr >> iDroppedOut;
- *pistr >> so_slFlags;
- *pistr >> so_spNew.sp_fLeftVolume;
- *pistr >> so_spNew.sp_fRightVolume;
- *pistr >> so_spNew.sp_slLeftFilter;
- *pistr >> so_spNew.sp_slRightFilter;
- *pistr >> so_spNew.sp_fPitchShift;
- *pistr >> so_spNew.sp_fPhaseShift;
- *pistr >> so_spNew.sp_fDelay;
- *pistr >> so_fDelayed;
- *pistr >> so_fLastLeftVolume;
- *pistr >> so_fLastRightVolume;
- *pistr >> so_swLastLeftSample;
- *pistr >> so_swLastRightSample;
- *pistr >> so_fLeftOffset;
- *pistr >> so_fRightOffset;
- *pistr >> so_fOffsetDelta;
- // load 3D parameters
- so_penEntity = NULL;
- *pistr >> so_sp3.sp3_fFalloff;
- *pistr >> so_sp3.sp3_fHotSpot;
- *pistr >> so_sp3.sp3_fMaxVolume;
- *pistr >> so_sp3.sp3_fPitch;
- // update current state
- so_sp = so_spNew;
- // Obtain and play object (sound)
- if ( fnmSound != "" && (so_slFlags&SOF_PLAY)) {
- Play_t( fnmSound, so_slFlags|SOF_LOADED);
- }
- };
- void CSoundObject::Write_t(CTStream *pistr) // throw char *
- {
- int iDroppedOut=0;
- // save file name
- if (so_pCsdLink!=NULL) {
- *pistr << (so_pCsdLink->GetName());
- } else {
- *pistr << CTFILENAME("");
- }
- // save object preferences
- *pistr << iDroppedOut;
- *pistr << so_slFlags;
- *pistr << so_spNew.sp_fLeftVolume;
- *pistr << so_spNew.sp_fRightVolume;
- *pistr << so_spNew.sp_slLeftFilter;
- *pistr << so_spNew.sp_slRightFilter;
- *pistr << so_spNew.sp_fPitchShift;
- *pistr << so_spNew.sp_fPhaseShift;
- *pistr << so_spNew.sp_fDelay;
- *pistr << so_fDelayed;
- *pistr << so_fLastLeftVolume;
- *pistr << so_fLastRightVolume;
- *pistr << so_swLastLeftSample;
- *pistr << so_swLastRightSample;
- *pistr << so_fLeftOffset;
- *pistr << so_fRightOffset;
- *pistr << so_fOffsetDelta;
- // save 3D parameters
- *pistr << so_sp3.sp3_fFalloff;
- *pistr << so_sp3.sp3_fHotSpot;
- *pistr << so_sp3.sp3_fMaxVolume;
- *pistr << so_sp3.sp3_fPitch;
- };
|