2019-09-19 22:42:45 +00:00
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
/*
|
|
|
|
Copyright (C) 2010-2019 EDuke32 developers and contributors
|
|
|
|
Copyright (C) 2019 Nuke.YKT
|
|
|
|
|
|
|
|
This file is part of NBlood.
|
|
|
|
|
|
|
|
NBlood is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License version 2
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------
|
2019-09-21 18:59:54 +00:00
|
|
|
#include "ns.h" // Must come before everything else!
|
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include "build.h"
|
|
|
|
#include "compat.h"
|
|
|
|
#include "common_game.h"
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "gameutil.h"
|
|
|
|
#include "player.h"
|
|
|
|
#include "resource.h"
|
|
|
|
#include "sfx.h"
|
|
|
|
#include "sound.h"
|
|
|
|
#include "trig.h"
|
2020-04-12 06:09:38 +00:00
|
|
|
#include "raze_sound.h"
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2019-09-22 06:39:22 +00:00
|
|
|
BEGIN_BLD_NS
|
|
|
|
|
2019-12-17 18:37:05 +00:00
|
|
|
class BloodSoundEngine : public SoundEngine
|
|
|
|
{
|
|
|
|
// client specific parts of the sound engine go in this class.
|
2019-12-18 10:09:01 +00:00
|
|
|
void CalcPosVel(int type, const void* source, const float pt[3], int channum, int chanflags, FSoundID chanSound, FVector3* pos, FVector3* vel, FSoundChan *channel) override;
|
2020-01-06 01:41:47 +00:00
|
|
|
TArray<uint8_t> ReadSound(int lumpnum) override;
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2019-12-17 18:37:05 +00:00
|
|
|
public:
|
|
|
|
BloodSoundEngine()
|
|
|
|
{
|
|
|
|
S_Rolloff.RolloffType = ROLLOFF_Doom;
|
|
|
|
S_Rolloff.MinDistance = 170; // these are the numbers I got when uncrunching the original sound code.
|
|
|
|
S_Rolloff.MaxDistance = 850;
|
|
|
|
}
|
2020-04-12 06:09:38 +00:00
|
|
|
|
|
|
|
void StopChannel(FSoundChan* chan) override
|
|
|
|
{
|
|
|
|
if (chan && chan->SysChannel != NULL && !(chan->ChanFlags & CHANF_EVICTED) && chan->SourceType == SOURCE_Actor)
|
|
|
|
{
|
|
|
|
chan->Source = NULL;
|
|
|
|
chan->SourceType = SOURCE_Unattached;
|
|
|
|
}
|
|
|
|
SoundEngine::StopChannel(chan);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-12-17 18:37:05 +00:00
|
|
|
};
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
void sfxInit(void)
|
|
|
|
{
|
2019-12-17 18:37:05 +00:00
|
|
|
soundEngine = new BloodSoundEngine;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void sfxTerm()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-12-17 18:37:05 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2019-12-17 18:37:05 +00:00
|
|
|
TArray<uint8_t> BloodSoundEngine::ReadSound(int lumpnum)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-12-17 18:37:05 +00:00
|
|
|
auto wlump = fileSystem.OpenFileReader(lumpnum);
|
|
|
|
return wlump.Read();
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
2019-12-18 10:09:01 +00:00
|
|
|
void BloodSoundEngine::CalcPosVel(int type, const void* source, const float pt[3], int channum, int chanflags, FSoundID chanSound, FVector3* pos, FVector3* vel, FSoundChan *)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-12-17 18:37:05 +00:00
|
|
|
if (pos != nullptr && type != SOURCE_None)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-12-17 18:37:05 +00:00
|
|
|
FVector3 camera;
|
|
|
|
|
|
|
|
if (gMe && gMe->pSprite) camera = GetSoundPos(&gMe->pSprite->pos);
|
|
|
|
else camera = { 0, 0, 0 }; // don't crash if there is no player.
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2019-12-17 18:37:05 +00:00
|
|
|
if (vel) vel->Zero();
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2019-12-17 18:37:05 +00:00
|
|
|
if (type == SOURCE_Unattached)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-12-17 18:37:05 +00:00
|
|
|
pos->X = pt[0];
|
|
|
|
pos->Y = pt[1];
|
|
|
|
pos->Z = pt[2];
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2019-12-17 18:37:05 +00:00
|
|
|
else if (type == SOURCE_Actor)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-12-17 18:37:05 +00:00
|
|
|
auto actor = (spritetype*)source;
|
|
|
|
assert(actor != nullptr);
|
|
|
|
size_t index = actor - sprite;
|
|
|
|
// Engine expects velocity in units per second, not units per tic.
|
|
|
|
if (vel) *vel = { xvel[index] * (30 / 65536.f), zvel[index] * (-30 / 65536.f), yvel[index] * (-30 / 65536.f) };
|
|
|
|
*pos = GetSoundPos(&actor->pos);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2019-12-17 18:37:05 +00:00
|
|
|
else if (type == SOURCE_Ambient)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-12-17 18:37:05 +00:00
|
|
|
*pos = camera; // just to be safe. Ambient sounds are in the world but unpositioned
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2019-12-17 18:37:05 +00:00
|
|
|
if ((chanflags & CHANF_LISTENERZ))
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-12-17 18:37:05 +00:00
|
|
|
pos->Y = camera.Y;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-17 18:37:05 +00:00
|
|
|
|
|
|
|
void sfxUpdate3DSounds(void)
|
|
|
|
{
|
|
|
|
SoundListener listener;
|
|
|
|
|
|
|
|
listener.angle = -(float)gMe->pSprite->ang * pi::pi() / 1024; // Build uses a period of 2048.
|
|
|
|
listener.velocity.Zero();
|
|
|
|
listener.position = GetSoundPos(&gMe->pSprite->pos);
|
|
|
|
listener.underwater = false;
|
|
|
|
// This should probably use a real environment instead of the pitch hacking in S_PlaySound3D.
|
|
|
|
// listenactor->waterlevel == 3;
|
|
|
|
//assert(primaryLevel->Zones.Size() > listenactor->Sector->ZoneNumber);
|
|
|
|
listener.Environment = 0;// primaryLevel->Zones[listenactor->Sector->ZoneNumber].Environment;
|
|
|
|
listener.valid = true;
|
|
|
|
|
|
|
|
listener.ListenerObject = gMe->pSprite;
|
|
|
|
soundEngine->SetListener(listener);
|
|
|
|
soundEngine->UpdateSounds((int)totalclock);
|
|
|
|
}
|
|
|
|
|
2020-01-22 15:34:58 +00:00
|
|
|
FSoundID getSfx(FSoundID soundId, float &attenuation, int &pitch, int &relvol)
|
2019-12-17 18:37:05 +00:00
|
|
|
{
|
2020-02-23 17:30:48 +00:00
|
|
|
auto udata = soundEngine->GetUserData(soundId);
|
2019-12-17 18:37:05 +00:00
|
|
|
if (pitch < 0) pitch = udata ? udata[0] : 0x10000;
|
|
|
|
|
|
|
|
if (relvol < 0) relvol = udata && udata[2] ? udata[2] : 80;
|
|
|
|
if (relvol > 255) relvol = 255;
|
2020-01-22 15:34:58 +00:00
|
|
|
// Limit the attenuation. More than 2.0 is simply too much.
|
|
|
|
attenuation = relvol > 0 ? clamp(80.f / relvol, 0.f, 2.f) : 1.f;
|
2019-12-17 18:37:05 +00:00
|
|
|
return soundId;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sfxPlay3DSound(int x, int y, int z, int soundId, int nSector)
|
|
|
|
{
|
|
|
|
if (!SoundEnabled() || soundId < 0) return;
|
|
|
|
auto sid = soundEngine->FindSoundByResID(soundId);
|
|
|
|
if (sid == 0) return;
|
|
|
|
|
|
|
|
vec3_t xyz = { x, y, z };
|
|
|
|
auto svec = GetSoundPos(&xyz);
|
|
|
|
|
|
|
|
float attenuation;
|
|
|
|
int pitch = -1;
|
2020-01-22 15:34:58 +00:00
|
|
|
int relvol = -1;
|
|
|
|
sid = getSfx(sid, attenuation, pitch, relvol);
|
2019-12-17 18:37:05 +00:00
|
|
|
|
2020-01-22 15:34:58 +00:00
|
|
|
soundEngine->StartSound(SOURCE_Unattached, nullptr, &svec, -1, CHANF_OVERLAP, sid, (0.8f / 80.f) * relvol, attenuation, nullptr, pitch / 65536.f);
|
2019-12-17 18:37:05 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
enum EPlayFlags
|
|
|
|
{
|
|
|
|
FX_GlobalChannel = 1,
|
|
|
|
FX_SoundMatch = 2,
|
|
|
|
FX_ChannelMatch = 4,
|
|
|
|
};
|
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
void sfxPlay3DSoundCP(spritetype* pSprite, int soundId, int a3, int a4, int pitch, int volume)
|
|
|
|
{
|
2019-12-17 18:37:05 +00:00
|
|
|
if (!SoundEnabled() || soundId < 0 || !pSprite) return;
|
|
|
|
auto sid = soundEngine->FindSoundByResID(soundId);
|
|
|
|
if (sid == 0) return;
|
|
|
|
|
|
|
|
auto svec = GetSoundPos(&pSprite->pos);
|
|
|
|
|
|
|
|
float attenuation;
|
|
|
|
sid = getSfx(sid, attenuation, pitch, volume);
|
2020-01-22 15:34:58 +00:00
|
|
|
if (volume == -1) volume = 80;
|
2019-12-17 18:37:05 +00:00
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
if (a3 >= 0)
|
|
|
|
{
|
2019-12-17 18:37:05 +00:00
|
|
|
a3++; // This is to make 0 a valid channel value.
|
|
|
|
if (soundEngine->EnumerateChannels([=](FSoundChan* chan) -> int
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-12-17 18:37:05 +00:00
|
|
|
if (chan->SourceType != SOURCE_Actor) return false; // other source types are not our business.
|
|
|
|
if (chan->EntChannel == a3 && (chan->Source == pSprite || (a4 & FX_GlobalChannel) != 0))
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-12-17 18:37:05 +00:00
|
|
|
if ((a4 & FX_ChannelMatch) != 0 && chan->EntChannel == a3)
|
|
|
|
return true;
|
|
|
|
if ((a4 & FX_SoundMatch) != 0 && chan->OrgID == sid)
|
|
|
|
return true;
|
|
|
|
soundEngine->StopChannel(chan);
|
|
|
|
return -1;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2019-12-17 18:37:05 +00:00
|
|
|
return false;
|
|
|
|
})) return;
|
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2019-12-17 18:37:05 +00:00
|
|
|
|
2020-01-22 15:34:58 +00:00
|
|
|
soundEngine->StartSound(SOURCE_Actor, pSprite, &svec, a3, a3 == -1? CHANF_OVERLAP : CHANF_NONE , sid, volume * (0.8f / 80.f), attenuation, nullptr, pitch / 65536.f);
|
2019-12-17 18:37:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void sfxPlay3DSound(spritetype* pSprite, int soundId, int a3, int a4)
|
|
|
|
{
|
|
|
|
sfxPlay3DSoundCP(pSprite, soundId, a3, a4, -1, -1);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void sfxKill3DSound(spritetype *pSprite, int a2, int a3)
|
|
|
|
{
|
|
|
|
if (!pSprite)
|
|
|
|
return;
|
2019-12-17 18:37:05 +00:00
|
|
|
|
|
|
|
if (a2 >= 0) a2++;
|
2020-02-16 15:52:02 +00:00
|
|
|
auto sid = soundEngine->FindSoundByResID(a3);
|
2019-12-17 18:37:05 +00:00
|
|
|
soundEngine->EnumerateChannels([=](FSoundChan* channel)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-02-16 15:52:02 +00:00
|
|
|
if (channel->SourceType == SOURCE_Actor && channel->Source == pSprite && (a2 < 0 || a2 == channel->EntChannel) && (a3 < 0 || sid == channel->OrgID))
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-12-17 18:37:05 +00:00
|
|
|
soundEngine->StopChannel(channel);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2019-12-17 18:37:05 +00:00
|
|
|
return false;
|
|
|
|
});
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void sfxKillAllSounds(void)
|
|
|
|
{
|
2019-12-17 18:37:05 +00:00
|
|
|
soundEngine->EnumerateChannels([](FSoundChan* channel)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-12-17 18:37:05 +00:00
|
|
|
if (channel->SourceType == SOURCE_Actor || channel->SourceType == SOURCE_Unattached) soundEngine->StopChannel(channel);
|
|
|
|
return false;
|
|
|
|
});
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void sfxSetReverb(bool toggle)
|
|
|
|
{
|
|
|
|
if (toggle)
|
|
|
|
{
|
2019-12-17 18:37:05 +00:00
|
|
|
FX_SetReverb(128);
|
2019-09-19 22:42:45 +00:00
|
|
|
FX_SetReverbDelay(10);
|
|
|
|
}
|
|
|
|
else
|
2019-12-17 18:37:05 +00:00
|
|
|
FX_SetReverb(0);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void sfxSetReverb2(bool toggle)
|
|
|
|
{
|
|
|
|
if (toggle)
|
|
|
|
{
|
2019-12-17 18:37:05 +00:00
|
|
|
FX_SetReverb(128);
|
2019-09-19 22:42:45 +00:00
|
|
|
FX_SetReverbDelay(20);
|
|
|
|
}
|
|
|
|
else
|
2019-12-17 18:37:05 +00:00
|
|
|
FX_SetReverb(0);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2019-09-22 06:39:22 +00:00
|
|
|
|
|
|
|
END_BLD_NS
|