347 lines
11 KiB
C
347 lines
11 KiB
C
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
//=============================================================================//
|
|
|
|
#ifndef SOUNDINFO_H
|
|
#define SOUNDINFO_H
|
|
|
|
#ifdef _WIN32
|
|
#pragma once
|
|
#endif
|
|
|
|
#include "bitbuf.h"
|
|
#include "const.h"
|
|
#include "coordsize.h"
|
|
#include "mathlib/vector.h"
|
|
#include "soundflags.h"
|
|
|
|
#define WRITE_DELTA_UINT(name, length) \
|
|
if (name == delta->name) \
|
|
buffer.WriteOneBit(0); \
|
|
else { \
|
|
buffer.WriteOneBit(1); \
|
|
buffer.WriteUBitLong(name, length); \
|
|
}
|
|
|
|
#define READ_DELTA_UINT(name, length) \
|
|
if (buffer.ReadOneBit() != 0) { \
|
|
name = buffer.ReadUBitLong(length); \
|
|
} else { \
|
|
name = delta->name; \
|
|
}
|
|
|
|
#define WRITE_DELTA_SINT(name, length) \
|
|
if (name == delta->name) \
|
|
buffer.WriteOneBit(0); \
|
|
else { \
|
|
buffer.WriteOneBit(1); \
|
|
buffer.WriteSBitLong(name, length); \
|
|
}
|
|
|
|
#define WRITE_DELTA_SINT_SCALE(name, scale, length) \
|
|
if (name == delta->name) \
|
|
buffer.WriteOneBit(0); \
|
|
else { \
|
|
buffer.WriteOneBit(1); \
|
|
buffer.WriteSBitLong(name / scale, length); \
|
|
}
|
|
|
|
#define READ_DELTA_SINT(name, length) \
|
|
if (buffer.ReadOneBit() != 0) { \
|
|
name = buffer.ReadSBitLong(length); \
|
|
} else { \
|
|
name = delta->name; \
|
|
}
|
|
|
|
#define READ_DELTA_SINT_SCALE(name, scale, length) \
|
|
if (buffer.ReadOneBit() != 0) { \
|
|
name = scale * buffer.ReadSBitLong(length); \
|
|
} else { \
|
|
name = delta->name; \
|
|
}
|
|
|
|
#define SOUND_SEQNUMBER_BITS 10
|
|
#define SOUND_SEQNUMBER_MASK ((1 << SOUND_SEQNUMBER_BITS) - 1)
|
|
|
|
// offset sound delay encoding by 60ms since we encode negative sound delays
|
|
// with less precision This means any negative sound delay greater than -100ms
|
|
// will get encoded at full precision
|
|
#define SOUND_DELAY_OFFSET (0.100f)
|
|
|
|
#pragma pack(4)
|
|
//-----------------------------------------------------------------------------
|
|
struct SoundInfo_t {
|
|
int nSequenceNumber;
|
|
int nEntityIndex;
|
|
int nChannel;
|
|
const char *pszName; // UNDONE: Make this a FilenameHandle_t to avoid bugs
|
|
// with arrays of these
|
|
Vector vOrigin;
|
|
Vector vDirection;
|
|
float fVolume;
|
|
soundlevel_t Soundlevel;
|
|
bool bLooping;
|
|
int nPitch;
|
|
int nSpecialDSP;
|
|
Vector vListenerOrigin;
|
|
int nFlags;
|
|
int nSoundNum;
|
|
float fDelay;
|
|
bool bIsSentence;
|
|
bool bIsAmbient;
|
|
int nSpeakerEntity;
|
|
|
|
//---------------------------------
|
|
|
|
SoundInfo_t() { SetDefault(); }
|
|
|
|
void Set(int newEntity, int newChannel, const char *pszNewName,
|
|
const Vector &newOrigin, const Vector &newDirection,
|
|
float newVolume, soundlevel_t newSoundLevel, bool newLooping,
|
|
int newPitch, const Vector &vecListenerOrigin, int speakerentity) {
|
|
nEntityIndex = newEntity;
|
|
nChannel = newChannel;
|
|
pszName = pszNewName;
|
|
vOrigin = newOrigin;
|
|
vDirection = newDirection;
|
|
fVolume = newVolume;
|
|
Soundlevel = newSoundLevel;
|
|
bLooping = newLooping;
|
|
nPitch = newPitch;
|
|
vListenerOrigin = vecListenerOrigin;
|
|
nSpeakerEntity = speakerentity;
|
|
}
|
|
|
|
void SetDefault() {
|
|
fDelay = DEFAULT_SOUND_PACKET_DELAY;
|
|
fVolume = DEFAULT_SOUND_PACKET_VOLUME;
|
|
Soundlevel = SNDLVL_NORM;
|
|
nPitch = DEFAULT_SOUND_PACKET_PITCH;
|
|
nSpecialDSP = 0;
|
|
|
|
nEntityIndex = 0;
|
|
nSpeakerEntity = -1;
|
|
nChannel = CHAN_STATIC;
|
|
nSoundNum = 0;
|
|
nFlags = 0;
|
|
nSequenceNumber = 0;
|
|
|
|
pszName = NULL;
|
|
|
|
bLooping = false;
|
|
bIsSentence = false;
|
|
bIsAmbient = false;
|
|
|
|
vOrigin.Init();
|
|
vDirection.Init();
|
|
vListenerOrigin.Init();
|
|
}
|
|
|
|
void ClearStopFields() {
|
|
fVolume = 0;
|
|
Soundlevel = SNDLVL_NONE;
|
|
nPitch = PITCH_NORM;
|
|
nSpecialDSP = 0;
|
|
pszName = NULL;
|
|
fDelay = 0.0f;
|
|
nSequenceNumber = 0;
|
|
|
|
vOrigin.Init();
|
|
nSpeakerEntity = -1;
|
|
}
|
|
|
|
// this cries for Send/RecvTables:
|
|
void WriteDelta(SoundInfo_t *delta, bf_write &buffer) {
|
|
if (nEntityIndex == delta->nEntityIndex) {
|
|
buffer.WriteOneBit(0);
|
|
} else {
|
|
buffer.WriteOneBit(1);
|
|
|
|
if (nEntityIndex <= 31) {
|
|
buffer.WriteOneBit(1);
|
|
buffer.WriteUBitLong(nEntityIndex, 5);
|
|
} else {
|
|
buffer.WriteOneBit(0);
|
|
buffer.WriteUBitLong(nEntityIndex, MAX_EDICT_BITS);
|
|
}
|
|
}
|
|
|
|
WRITE_DELTA_UINT(nSoundNum, MAX_SOUND_INDEX_BITS);
|
|
|
|
WRITE_DELTA_UINT(nFlags, SND_FLAG_BITS_ENCODE);
|
|
|
|
WRITE_DELTA_UINT(nChannel, 3);
|
|
|
|
buffer.WriteOneBit(bIsAmbient ? 1 : 0);
|
|
buffer.WriteOneBit(
|
|
bIsSentence ? 1 : 0); // NOTE: SND_STOP behavior is different
|
|
// depending on this flag
|
|
|
|
if (nFlags != SND_STOP) {
|
|
if (nSequenceNumber == delta->nSequenceNumber) {
|
|
// didn't change, most often case
|
|
buffer.WriteOneBit(1);
|
|
} else if (nSequenceNumber == (delta->nSequenceNumber + 1)) {
|
|
// increased by one
|
|
buffer.WriteOneBit(0);
|
|
buffer.WriteOneBit(1);
|
|
} else {
|
|
// send full seqnr
|
|
buffer.WriteUBitLong(0, 2); // 2 zero bits
|
|
buffer.WriteUBitLong(nSequenceNumber, SOUND_SEQNUMBER_BITS);
|
|
}
|
|
|
|
if (fVolume == delta->fVolume) {
|
|
buffer.WriteOneBit(0);
|
|
} else {
|
|
buffer.WriteOneBit(1);
|
|
buffer.WriteUBitLong((unsigned int)(fVolume * 127.0f), 7);
|
|
}
|
|
|
|
WRITE_DELTA_UINT(Soundlevel, MAX_SNDLVL_BITS);
|
|
|
|
WRITE_DELTA_UINT(nPitch, 8);
|
|
|
|
WRITE_DELTA_UINT(nSpecialDSP, 8);
|
|
|
|
if (fDelay == delta->fDelay) {
|
|
buffer.WriteOneBit(0);
|
|
} else {
|
|
buffer.WriteOneBit(1);
|
|
|
|
// skipahead works in 10 ms increments
|
|
// bias results so that we only incur the precision loss on
|
|
// relatively large skipaheads
|
|
fDelay += SOUND_DELAY_OFFSET;
|
|
|
|
// Convert to msecs
|
|
int iDelay = fDelay * 1000.0f;
|
|
|
|
iDelay = clamp(iDelay, (int)(-10 * MAX_SOUND_DELAY_MSEC),
|
|
(int)(MAX_SOUND_DELAY_MSEC));
|
|
|
|
if (iDelay < 0) {
|
|
iDelay /= 10;
|
|
}
|
|
|
|
buffer.WriteSBitLong(iDelay, MAX_SOUND_DELAY_MSEC_ENCODE_BITS);
|
|
}
|
|
|
|
// don't transmit sounds with high precision
|
|
WRITE_DELTA_SINT_SCALE(vOrigin.x, 8.0f, COORD_INTEGER_BITS - 2);
|
|
WRITE_DELTA_SINT_SCALE(vOrigin.y, 8.0f, COORD_INTEGER_BITS - 2);
|
|
WRITE_DELTA_SINT_SCALE(vOrigin.z, 8.0f, COORD_INTEGER_BITS - 2);
|
|
|
|
WRITE_DELTA_SINT(nSpeakerEntity, MAX_EDICT_BITS + 1);
|
|
} else {
|
|
ClearStopFields();
|
|
}
|
|
};
|
|
|
|
void ReadDelta(SoundInfo_t *delta, bf_read &buffer, int nProtoVersion) {
|
|
if (!buffer.ReadOneBit()) {
|
|
nEntityIndex = delta->nEntityIndex;
|
|
} else {
|
|
if (buffer.ReadOneBit()) {
|
|
nEntityIndex = buffer.ReadUBitLong(5);
|
|
} else {
|
|
nEntityIndex = buffer.ReadUBitLong(MAX_EDICT_BITS);
|
|
}
|
|
}
|
|
|
|
if (nProtoVersion > 22) {
|
|
READ_DELTA_UINT(nSoundNum, MAX_SOUND_INDEX_BITS);
|
|
} else {
|
|
READ_DELTA_UINT(nSoundNum, 13);
|
|
}
|
|
|
|
if (nProtoVersion > 18) {
|
|
READ_DELTA_UINT(nFlags, SND_FLAG_BITS_ENCODE);
|
|
} else {
|
|
// There was 9 flag bits for version 18 and below (prior to
|
|
// Halloween 2011)
|
|
READ_DELTA_UINT(nFlags, 9);
|
|
}
|
|
|
|
READ_DELTA_UINT(nChannel, 3);
|
|
|
|
bIsAmbient = buffer.ReadOneBit() != 0;
|
|
bIsSentence =
|
|
buffer.ReadOneBit() !=
|
|
0; // NOTE: SND_STOP behavior is different depending on this flag
|
|
|
|
if (nFlags != SND_STOP) {
|
|
if (buffer.ReadOneBit() != 0) {
|
|
nSequenceNumber = delta->nSequenceNumber;
|
|
} else if (buffer.ReadOneBit() != 0) {
|
|
nSequenceNumber = delta->nSequenceNumber + 1;
|
|
} else {
|
|
nSequenceNumber = buffer.ReadUBitLong(SOUND_SEQNUMBER_BITS);
|
|
}
|
|
|
|
if (buffer.ReadOneBit() != 0) {
|
|
fVolume = (float)buffer.ReadUBitLong(7) / 127.0f;
|
|
} else {
|
|
fVolume = delta->fVolume;
|
|
}
|
|
|
|
if (buffer.ReadOneBit() != 0) {
|
|
Soundlevel = (soundlevel_t)buffer.ReadUBitLong(MAX_SNDLVL_BITS);
|
|
} else {
|
|
Soundlevel = delta->Soundlevel;
|
|
}
|
|
|
|
READ_DELTA_UINT(nPitch, 8);
|
|
|
|
if (nProtoVersion > 21) {
|
|
// These bit weren't written in version 19 and below
|
|
READ_DELTA_UINT(nSpecialDSP, 8);
|
|
}
|
|
|
|
if (buffer.ReadOneBit() != 0) {
|
|
// Up to 4096 msec delay
|
|
fDelay = (float)buffer.ReadSBitLong(
|
|
MAX_SOUND_DELAY_MSEC_ENCODE_BITS) /
|
|
1000.0f;
|
|
;
|
|
|
|
if (fDelay < 0) {
|
|
fDelay *= 10.0f;
|
|
}
|
|
// bias results so that we only incur the precision loss on
|
|
// relatively large skipaheads
|
|
fDelay -= SOUND_DELAY_OFFSET;
|
|
} else {
|
|
fDelay = delta->fDelay;
|
|
}
|
|
|
|
READ_DELTA_SINT_SCALE(vOrigin.x, 8.0f, COORD_INTEGER_BITS - 2);
|
|
READ_DELTA_SINT_SCALE(vOrigin.y, 8.0f, COORD_INTEGER_BITS - 2);
|
|
READ_DELTA_SINT_SCALE(vOrigin.z, 8.0f, COORD_INTEGER_BITS - 2);
|
|
|
|
READ_DELTA_SINT(nSpeakerEntity, MAX_EDICT_BITS + 1);
|
|
} else {
|
|
ClearStopFields();
|
|
}
|
|
}
|
|
};
|
|
|
|
struct SpatializationInfo_t {
|
|
typedef enum { SI_INCREATION = 0, SI_INSPATIALIZATION } SPATIALIZATIONTYPE;
|
|
|
|
// Inputs
|
|
SPATIALIZATIONTYPE type;
|
|
// Info about the sound, channel, origin, direction, etc.
|
|
SoundInfo_t info;
|
|
|
|
// Requested Outputs ( NULL == not requested )
|
|
Vector *pOrigin;
|
|
QAngle *pAngles;
|
|
float *pflRadius;
|
|
};
|
|
#pragma pack()
|
|
|
|
#endif // SOUNDINFO_H
|