//------------------------------------------------------------------------- /* 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. */ //------------------------------------------------------------------------- #include "ns.h" // Must come before everything else! #include #include "build.h" #include "compat.h" #include "common_game.h" #include "fx_man.h" #include "config.h" #include "gameutil.h" #include "player.h" #include "resource.h" #include "sfx.h" #include "sound.h" #include "trig.h" BEGIN_BLD_NS POINT2D earL, earR, earL0, earR0; // Ear position VECTOR2D earVL, earVR; // Ear velocity ? int lPhase, rPhase, lVol, rVol, lPitch, rPitch; struct BONKLE { int at0; int at4; DICTNODE *at8; int atc; spritetype *at10; int at14; int at18; int at1c; POINT3D at20; POINT3D at2c; //int at20; //int at24; //int at28; //int at2c; //int at30; //int at34; int at38; int at3c; }; BONKLE Bonkle[256]; BONKLE *BonkleCache[256]; int nBonkles; void sfxInit(void) { for (int i = 0; i < 256; i++) BonkleCache[i] = &Bonkle[i]; nBonkles = 0; } void sfxTerm() { } int Vol3d(int angle, int dist) { return dist - mulscale16(dist, 0x2000 - mulscale30(0x2000, Cos(angle))); } void Calc3DValues(BONKLE *pBonkle) { int dx = pBonkle->at20.x - gMe->pSprite->x; int dy = pBonkle->at20.y - gMe->pSprite->y; int dz = pBonkle->at20.z - gMe->pSprite->z; int angle = getangle(dx, dy); dx >>= 4; dy >>= 4; dz >>= 8; int distance = ksqrt(dx*dx + dy * dy + dz * dz); distance = ClipLow((distance >> 2) + (distance >> 3), 64); int v14, v18; v14 = v18 = scale(pBonkle->at1c, 80, distance); int sinVal = Sin(angle); int cosVal = Cos(angle); int v8 = dmulscale30r(cosVal, pBonkle->at20.x - pBonkle->at2c.x, sinVal, pBonkle->at20.y - pBonkle->at2c.y); int distanceL = approxDist(pBonkle->at20.x - earL.x, pBonkle->at20.y - earL.y); lVol = Vol3d(angle - (gMe->pSprite->ang - 85), v18); int phaseLeft = mulscale16r(distanceL, pBonkle->at3c == 1 ? 4114 : 8228); lPitch = scale(pBonkle->at18, dmulscale30r(cosVal, earVL.dx, sinVal, earVL.dy) + 5853, v8 + 5853); int distanceR = approxDist(pBonkle->at20.x - earR.x, pBonkle->at20.y - earR.y); rVol = Vol3d(angle - (gMe->pSprite->ang + 85), v14); int phaseRight = mulscale16r(distanceR, pBonkle->at3c == 1 ? 4114 : 8228); rPitch = scale(pBonkle->at18, dmulscale30r(cosVal, earVR.dx, sinVal, earVR.dy) + 5853, v8 + 5853); int phaseMin = ClipHigh(phaseLeft, phaseRight); lPhase = phaseRight - phaseMin; rPhase = phaseLeft - phaseMin; } void sfxPlay3DSound(int x, int y, int z, int soundId, int nSector) { if (!snd_enabled || soundId < 0) return; DICTNODE *hRes = gSoundRes.Lookup(soundId, "SFX"); if (!hRes)return; SFX *pEffect = (SFX*)gSoundRes.Load(hRes); hRes = gSoundRes.Lookup(pEffect->rawName, "RAW"); if (!hRes) return; int v1c, v18; v1c = v18 = mulscale16(pEffect->pitch, sndGetRate(pEffect->format)); if (nBonkles >= 256) return; BONKLE *pBonkle = BonkleCache[nBonkles++]; pBonkle->at10 = NULL; pBonkle->at20.x = x; pBonkle->at20.y = y; pBonkle->at20.z = z; pBonkle->at38 = nSector; FindSector(x, y, z, &pBonkle->at38); pBonkle->at2c = pBonkle->at20; pBonkle->atc = soundId; pBonkle->at8 = hRes; pBonkle->at1c = pEffect->relVol; pBonkle->at18 = v18; pBonkle->at3c = pEffect->format; int size = hRes->size; char *pData = (char*)gSoundRes.Lock(hRes); Calc3DValues(pBonkle); int priority = 1; if (priority < lVol) priority = lVol; if (priority < rVol) priority = rVol; if (snd_doppler) { MV_Lock(); pBonkle->at0 = FX_PlayRaw(pData + lPhase, size - lPhase, lPitch, 0, lVol, lVol, 0, priority, 1.f, (intptr_t)&pBonkle->at0); pBonkle->at4 = FX_PlayRaw(pData + rPhase, size - rPhase, rPitch, 0, rVol, 0, rVol, priority, 1.f, (intptr_t)&pBonkle->at4); MV_Unlock(); } else { pBonkle->at0 = FX_PlayRaw(pData + lPhase, size - lPhase, v1c, 0, lVol, lVol, rVol, priority, 1.f, (intptr_t)&pBonkle->at0); pBonkle->at4 = 0; } } void sfxPlay3DSound(spritetype *pSprite, int soundId, int a3, int a4) { if (!snd_enabled) return; if (!pSprite) return; if (soundId < 0) return; DICTNODE *hRes = gSoundRes.Lookup(soundId, "SFX"); if (!hRes) return; SFX *pEffect = (SFX*)gSoundRes.Load(hRes); hRes = gSoundRes.Lookup(pEffect->rawName, "RAW"); if (!hRes) return; int size = hRes->size; if (size <= 0) return; int v14; v14 = mulscale16(pEffect->pitch, sndGetRate(pEffect->format)); BONKLE *pBonkle = NULL; if (a3 >= 0) { int i; for (i = 0; i < nBonkles; i++) { pBonkle = BonkleCache[i]; if (pBonkle->at14 == a3 && (pBonkle->at10 == pSprite || (a4 & 1) != 0)) { if ((a4 & 4) != 0 && pBonkle->at14 == a3) return; if ((a4 & 2) != 0 && pBonkle->atc == soundId) return; if (pBonkle->at0 > 0) FX_StopSound(pBonkle->at0); if (pBonkle->at4 > 0) FX_StopSound(pBonkle->at4); if (pBonkle->at8) { gSoundRes.Unlock(pBonkle->at8); pBonkle->at8 = NULL; } break; } } if (i == nBonkles) { if (nBonkles >= 256) return; pBonkle = BonkleCache[nBonkles++]; } pBonkle->at10 = pSprite; pBonkle->at14 = a3; } else { if (nBonkles >= 256) return; pBonkle = BonkleCache[nBonkles++]; pBonkle->at10 = NULL; } pBonkle->at20.x = pSprite->x; pBonkle->at20.y = pSprite->y; pBonkle->at20.z = pSprite->z; pBonkle->at38 = pSprite->sectnum; pBonkle->at2c = pBonkle->at20; pBonkle->atc = soundId; pBonkle->at8 = hRes; pBonkle->at1c = pEffect->relVol; pBonkle->at18 = v14; Calc3DValues(pBonkle); int priority = 1; if (priority < lVol) priority = lVol; if (priority < rVol) priority = rVol; int loopStart = pEffect->loopStart; int loopEnd = ClipLow(size - 1, 0); if (a3 < 0) loopStart = -1; MV_Lock(); char *pData = (char*)gSoundRes.Lock(hRes); if (loopStart >= 0) { if (snd_doppler) { pBonkle->at0 = FX_PlayLoopedRaw(pData + lPhase, size - lPhase, pData + loopStart, pData + loopEnd, lPitch, 0, lVol, lVol, 0, priority, 1.f, (intptr_t)&pBonkle->at0); pBonkle->at4 = FX_PlayLoopedRaw(pData + rPhase, size - rPhase, pData + loopStart, pData + loopEnd, rPitch, 0, rVol, 0, rVol, priority, 1.f, (intptr_t)&pBonkle->at4); } else { pBonkle->at0 = FX_PlayLoopedRaw(pData + lPhase, size - lPhase, pData + loopStart, pData + loopEnd, v14, 0, lVol, lVol, rVol, priority, 1.f, (intptr_t)&pBonkle->at0); pBonkle->at4 = 0; } } else { pData = (char*)gSoundRes.Lock(pBonkle->at8); if (snd_doppler) { pBonkle->at0 = FX_PlayRaw(pData + lPhase, size - lPhase, lPitch, 0, lVol, lVol, 0, priority, 1.f, (intptr_t)&pBonkle->at0); pBonkle->at4 = FX_PlayRaw(pData + rPhase, size - rPhase, rPitch, 0, rVol, 0, rVol, priority, 1.f, (intptr_t)&pBonkle->at4); } else { pBonkle->at0 = FX_PlayRaw(pData + lPhase, size - lPhase, v14, 0, lVol, lVol, rVol, priority, 1.f, (intptr_t)&pBonkle->at0); pBonkle->at4 = 0; } } MV_Unlock(); } // By NoOne: same as previous, but allows to set custom pitch for sound AND volume. Used by SFX gen now. void sfxPlay3DSoundCP(spritetype* pSprite, int soundId, int a3, int a4, int pitch, int volume) { if (!snd_enabled || !pSprite || soundId < 0) return; DICTNODE* hRes = gSoundRes.Lookup(soundId, "SFX"); if (!hRes) return; SFX* pEffect = (SFX*)gSoundRes.Load(hRes); hRes = gSoundRes.Lookup(pEffect->rawName, "RAW"); if (!hRes) return; int size = hRes->size; if (size <= 0) return; if (pitch <= 0) pitch = pEffect->pitch; else pitch -= Random(pEffect->pitchRange); int v14; v14 = mulscale16(pitch, sndGetRate(pEffect->format)); BONKLE * pBonkle = NULL; if (a3 >= 0) { int i; for (i = 0; i < nBonkles; i++) { pBonkle = BonkleCache[i]; if (pBonkle->at14 == a3 && (pBonkle->at10 == pSprite || (a4 & 1) != 0)) { if ((a4 & 4) != 0 && pBonkle->at14 == a3) return; if ((a4 & 2) != 0 && pBonkle->atc == soundId) return; if (pBonkle->at0 > 0) FX_StopSound(pBonkle->at0); if (pBonkle->at4 > 0) FX_StopSound(pBonkle->at4); if (pBonkle->at8) { gSoundRes.Unlock(pBonkle->at8); pBonkle->at8 = NULL; } break; } } if (i == nBonkles) { if (nBonkles >= 256) return; pBonkle = BonkleCache[nBonkles++]; } pBonkle->at10 = pSprite; pBonkle->at14 = a3; } else { if (nBonkles >= 256) return; pBonkle = BonkleCache[nBonkles++]; pBonkle->at10 = NULL; } pBonkle->at20.x = pSprite->x; pBonkle->at20.y = pSprite->y; pBonkle->at20.z = pSprite->z; pBonkle->at38 = pSprite->sectnum; pBonkle->at2c = pBonkle->at20; pBonkle->atc = soundId; pBonkle->at8 = hRes; pBonkle->at1c = ((volume == 0) ? pEffect->relVol : ((volume == -1) ? 0 : ((volume > 255) ? 255 : volume))); pBonkle->at18 = v14; Calc3DValues(pBonkle); int priority = 1; if (priority < lVol) priority = lVol; if (priority < rVol) priority = rVol; int loopStart = pEffect->loopStart; int loopEnd = ClipLow(size - 1, 0); if (a3 < 0) loopStart = -1; MV_Lock(); char* pData = (char*)gSoundRes.Lock(hRes); if (loopStart >= 0) { if (snd_doppler) { pBonkle->at0 = FX_PlayLoopedRaw(pData + lPhase, size - lPhase, pData + loopStart, pData + loopEnd, lPitch, 0, lVol, lVol, 0, priority, 1.f, (intptr_t)& pBonkle->at0); pBonkle->at4 = FX_PlayLoopedRaw(pData + rPhase, size - rPhase, pData + loopStart, pData + loopEnd, rPitch, 0, rVol, 0, rVol, priority, 1.f, (intptr_t)& pBonkle->at4); } else { pBonkle->at0 = FX_PlayLoopedRaw(pData + lPhase, size - lPhase, pData + loopStart, pData + loopEnd, v14, 0, lVol, lVol, rVol, priority, 1.f, (intptr_t)& pBonkle->at0); pBonkle->at4 = 0; } } else { pData = (char*)gSoundRes.Lock(pBonkle->at8); if (snd_doppler) { pBonkle->at0 = FX_PlayRaw(pData + lPhase, size - lPhase, lPitch, 0, lVol, lVol, 0, priority, 1.f, (intptr_t)& pBonkle->at0); pBonkle->at4 = FX_PlayRaw(pData + rPhase, size - rPhase, rPitch, 0, rVol, 0, rVol, priority, 1.f, (intptr_t)& pBonkle->at4); } else { pBonkle->at0 = FX_PlayRaw(pData + lPhase, size - lPhase, v14, 0, lVol, lVol, rVol, priority, 1.f, (intptr_t)& pBonkle->at0); pBonkle->at4 = 0; } } MV_Unlock(); } void sfxKill3DSound(spritetype *pSprite, int a2, int a3) { if (!pSprite) return; for (int i = nBonkles - 1; i >= 0; i--) { BONKLE *pBonkle = BonkleCache[i]; if (pBonkle->at10 == pSprite && (a2 < 0 || a2 == pBonkle->at14) && (a3 < 0 || a3 == pBonkle->atc)) { if (pBonkle->at0 > 0) { FX_EndLooping(pBonkle->at0); FX_StopSound(pBonkle->at0); } if (pBonkle->at4 > 0) { FX_EndLooping(pBonkle->at4); FX_StopSound(pBonkle->at4); } if (pBonkle->at8) { gSoundRes.Unlock(pBonkle->at8); pBonkle->at8 = NULL; } BonkleCache[i] = BonkleCache[--nBonkles]; BonkleCache[nBonkles] = pBonkle; break; } } } void sfxKillAllSounds(void) { for (int i = nBonkles - 1; i >= 0; i--) { BONKLE *pBonkle = BonkleCache[i]; if (pBonkle->at0 > 0) { FX_EndLooping(pBonkle->at0); FX_StopSound(pBonkle->at0); } if (pBonkle->at4 > 0) { FX_EndLooping(pBonkle->at4); FX_StopSound(pBonkle->at4); } if (pBonkle->at8) { gSoundRes.Unlock(pBonkle->at8); pBonkle->at8 = NULL; } BonkleCache[i] = BonkleCache[--nBonkles]; BonkleCache[nBonkles] = pBonkle; } } void sfxUpdate3DSounds(void) { int dx = mulscale30(Cos(gMe->pSprite->ang + 512), 43); earL0 = earL; int dy = mulscale30(Sin(gMe->pSprite->ang + 512), 43); earR0 = earR; earL.x = gMe->pSprite->x - dx; earL.y = gMe->pSprite->y - dy; earR.x = gMe->pSprite->x + dx; earR.y = gMe->pSprite->y + dy; earVL.dx = earL.x - earL0.x; earVL.dy = earL.y - earL0.y; earVR.dx = earR.x - earR0.x; earVR.dy = earR.y - earR0.y; for (int i = nBonkles - 1; i >= 0; i--) { BONKLE *pBonkle = BonkleCache[i]; if (pBonkle->at0 > 0 || pBonkle->at4 > 0) { if (!pBonkle->at8) continue; if (pBonkle->at10) { pBonkle->at2c = pBonkle->at20; pBonkle->at20.x = pBonkle->at10->x; pBonkle->at20.y = pBonkle->at10->y; pBonkle->at20.z = pBonkle->at10->z; pBonkle->at38 = pBonkle->at10->sectnum; } Calc3DValues(pBonkle); MV_Lock(); if (pBonkle->at0 > 0) { if (pBonkle->at4 > 0) { FX_SetPan(pBonkle->at0, lVol, lVol, 0); FX_SetFrequency(pBonkle->at0, lPitch); } else FX_SetPan(pBonkle->at0, lVol, lVol, rVol); } if (pBonkle->at4 > 0) { FX_SetPan(pBonkle->at4, rVol, 0, rVol); FX_SetFrequency(pBonkle->at4, rPitch); } MV_Unlock(); } else { gSoundRes.Unlock(pBonkle->at8); pBonkle->at8 = NULL; BonkleCache[i] = BonkleCache[--nBonkles]; BonkleCache[nBonkles] = pBonkle; } } } void sfxSetReverb(bool toggle) { if (toggle) { FX_SetReverb(128); FX_SetReverbDelay(10); } else FX_SetReverb(0); } void sfxSetReverb2(bool toggle) { if (toggle) { FX_SetReverb(128); FX_SetReverbDelay(20); } else FX_SetReverb(0); } END_BLD_NS