Files
BT412/engine/MUNGA_L4/L4AUDIO.h
T
arcattackandClaude Opus 4.8 fc7f311771 Audio Phase 1 (AUDIO_FIDELITY F3/F4/F10/F15/F18/F20 + KB): the quick wins
F3 distance: alDistanceModel(AL_NONE); restored the commented authored
  distance multiply in Dynamic3D::CalculateSourceVolumeScale, added the same
  override to Static3D, dropped the (now inert) AL_MAX_DISTANCE writes.  Far
  battle audio follows the authored knee/rolloff curve again, and the volume
  cull / voice steal / ducking chains are distance-aware.
F4 volume law: AL_GAIN = volume_scale^2 at all 3 per-frame sites (Direct/
  Dyn3D/Static3D) -- the GM CC7 squared curve; linear was ~+6 dB at mids.
F10 doppler: alDopplerFactor(0) (AL's model ran wrong constants + sign-
  inverted velocity: approaching sources pitched DOWN); the AUTHORED
  dopplerCents (AUDIO.INI range/speed-of-sound model, decomp-proven consumer
  part_008.c:7466) now adds into the Dynamic3D pitch chain.
F15 ConfigureActivePress: published at the MechSubsystem BASE (binary id 2,
  descriptor @0x50de5c -> +0x110); renamed the misnamed vitalSubsystemIndex
  member (the weapon ConfigureMappables handler already drives it 0/-1).
  Removed the invented Sensor/Myomers duplicates and RESTORED their byte-
  exact layouts (0x328/0x358 allocs + asserts).  MechWeapon's pinned-id pad
  absorbed the +1 chain shift -- which matches the binary's own numbering.
F18 cook-off warning: AmmoBin FireCountdownStarted -> the existing
  cookOffArmed @0x18C (binary table @0x512600); the countdown klaxon can fire.
F20 zoom blip: L4MechControlsMapper publishes TargetRangeExponent -> the live
  @0x1a4 zoom member (own table chained to MechControlsMapper).
KB: replaced the bogus divisionParameters+0x10 rate read with
  SystemClock::GetTicksPerSecond() (FUN_0044e19c is GetFrameRate -- original
  audio frames were CLOCK TICKS).

Regression (35s drive+fire): stable; ConfigureActivePress binds real on all 9
subsystems (idle -1, zero pad redirects); FireCountdownStarted +
TargetRangeExponent bind live members; attrnull 53 -> 41; chirp still dead;
footfalls still fire (gain now correctly squared).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 10:43:38 -05:00

806 lines
16 KiB
C++

#pragma once
#include "l4audhdw.h"
#include "..\munga\audio.h"
#include "..\munga\audloc.h"
#include "..\munga\audsrc.h"
//##########################################################################
//####################### L4AudioSpatialization ######################
//##########################################################################
class L4AudioSpatialization SIGNATURED
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Public types
//
public:
enum Quadrant
{
Quadrant1,
Quadrant2,
Quadrant3,
Quadrant4
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Contstruction, Destruction, & Testing
//
public:
L4AudioSpatialization();
~L4AudioSpatialization();
Logical
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Spatialization calculations & results
//
public:
void
CalculateSpatialization(Radian azimuth_of_source);
Radian
azimuthOfSource;
Scalar
frontLeftScale,
frontRightScale,
rearLeftScale,
rearRightScale;
Scalar
frontLeftDelay,
frontRightDelay,
rearLeftDelay,
rearRightDelay;
Quadrant
quadrant;
};
//~~~~~~~~~~~~~~~~~~~~~~~ L4AudioSpatialization inlines ~~~~~~~~~~~~~~~~~~~~
inline MemoryStream&
MemoryStream_Read(
MemoryStream* stream,
L4AudioSpatialization::Quadrant *ptr
)
{
return stream->ReadBytes(ptr, sizeof(*ptr));
}
inline MemoryStream&
MemoryStream_Write(
MemoryStream* stream,
const L4AudioSpatialization::Quadrant *ptr
)
{
return stream->WriteBytes(ptr, sizeof(*ptr));
}
//##########################################################################
//######################### L4AudioLocation ##########################
//##########################################################################
class L4AudioLocation:
public AudioLocation
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, Testing
//
public:
L4AudioLocation(
PlugStream *stream,
Entity *entity
);
void
L4AudioLocationX();
~L4AudioLocation();
Logical
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Spatialization Accessors
//
public:
void
GetSpatialization(L4AudioSpatialization *the_spatialization)
{*the_spatialization = spatialization;}
L4AudioSpatialization::Quadrant
GetQuadrant()
{return spatialization.quadrant;}
Scalar
GetFrontLeftScale()
{return spatialization.frontLeftScale;}
Scalar
GetFrontRightScale()
{return spatialization.frontRightScale;}
Scalar
GetRearLeftScale()
{return spatialization.rearLeftScale;}
Scalar
GetRearRightScale()
{return spatialization.rearRightScale;}
Scalar
GetFrontLeftITDPitchOffset()
{return frontLeftITDPitchOffset;}
Scalar
GetFrontRightITDPitchOffset()
{return frontRightITDPitchOffset;}
Scalar
GetRearLeftITDPitchOffset()
{return rearLeftITDPitchOffset;}
Scalar
GetRearRightITDPitchOffset()
{return rearRightITDPitchOffset;}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Spatialization Implementation
//
public:
void
UpdateSpatialModelImplementation(AudioHead *audio_head);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private data
//
private:
L4AudioSpatialization
spatialization;
Time
lastITDFrameTime;
Scalar
currentFrontLeftDelay,
currentFrontRightDelay,
currentRearLeftDelay,
currentRearRightDelay;
AudioPitchCents
frontLeftITDPitchOffset,
frontRightITDPitchOffset,
rearLeftITDPitchOffset,
rearRightITDPitchOffset;
};
//##########################################################################
//######################### AudioChannelSet ##########################
//##########################################################################
/*#define AUDIO_CHANNEL_SET_LENGTH (4)
typedef int AudioChannelSetIndex;
const AudioChannelSetIndex AudioChannelSetSize = AUDIO_CHANNEL_SET_LENGTH;
class AudioChannelSet SIGNATURED
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, & Testing
//
public:
AudioChannelSet();
~AudioChannelSet() {}
Logical
TestInstance() const;
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
RegisteredClass::ClassID class_ID,
ObjectID object_ID
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Channel accesors
//
public:
void
SetFrontLeft(AudioChannel *audio_channel);
void
SetFrontRight(AudioChannel *audio_channel);
void
SetRearLeft(AudioChannel *audio_channel);
void
SetRearRight(AudioChannel *audio_channel);
AudioChannel*
GetFrontLeft();
AudioChannel*
GetFrontRight();
AudioChannel*
GetRearLeft();
AudioChannel*
GetRearRight();
void
SetNth(
AudioChannelSetIndex index,
AudioChannel *audio_channel
);
AudioChannel*
GetNth(AudioChannelSetIndex index);
void
ReleaseAll();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Enable accesors
//
public:
void
EnableFrontLeft(Logical flag);
void
EnableFrontRight(Logical flag);
void
EnableRearLeft(Logical flag);
void
EnableRearRight(Logical flag);
Logical
IsFrontLeftEnabled();
Logical
IsFrontRightEnabled();
Logical
IsRearLeftEnabled();
Logical
IsRearRightEnabled();
void
EnableNth(
AudioChannelSetIndex index,
Logical flag
);
void
EnableAll();
Logical
IsNthEnabled(AudioChannelSetIndex index);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Null channel set
//
public:
static AudioChannelSet
Null;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private data
//
private:
AudioChannel
*channels[AUDIO_CHANNEL_SET_LENGTH];
Logical
enables[AUDIO_CHANNEL_SET_LENGTH];
};*/
//##########################################################################
//########################## L4AudioSource ###########################
//##########################################################################
class L4AudioSource:
public AudioSource
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Destruction, Testing
//
public:
~L4AudioSource();
Logical
TestInstance() const;
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// AudioChannelSet methods
//
public:
/* void
SetAudioChannelSet(const AudioChannelSet &audio_channel_set);
const AudioChannelSet*
GetAudioChannelSet();
void
ReleaseChannels();*/
void SetAudioChannelSet(const SourceSet &source_set);
SourceSet *GetAudioChannelSet();
void ReleaseChannels();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Protected Constuction
//
protected:
L4AudioSource(
PlugStream *stream,
Entity *entity
);
void
L4AudioSourceX();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Protected Implementations
//
protected:
void
StopMessageImplementation();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Protected Data
//
protected:
/*AudioChannelSet
channelSet;*/
SourceSet channelSet;
};
//##########################################################################
//######################## DirectPatchSource #########################
//##########################################################################
enum DirectPatchPosition
{
FrontDirectPatchPosition = 0,
RearDirectPatchPosition = 1,
FrontLeftDirectPatchPosition = 2,
FrontRightDirectPatchPosition = 3,
RearLeftDirectPatchPosition = 4,
RearRightDirectPatchPosition = 5
};
class DirectPatchSource:
public L4AudioSource
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, Testing
//
public:
DirectPatchSource(
PlugStream *stream,
Entity *entity
);
~DirectPatchSource();
Logical
TestInstance() const;
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// State implementations
//
public:
void
StartImplementation();
void
StopImplementation();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Protected Implementations
//
protected:
void
StartMessageImplementation();
void
ExecuteModel(Logical force_update);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private data
//
private:
DirectPatchPosition
audioPosition;
/* AudioChannel
*channel;*/
MIDIValue
lastMIDIVolume;
MIDIPitchBend
lastMIDIPitchBend;
MIDINRPNValue
lastMIDIFilterCutoff;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ DirectPatchSource inlines ~~~~~~~~~~~~~~~~~~~~
inline MemoryStream&
MemoryStream_Read(
MemoryStream *stream,
DirectPatchPosition *ptr
)
{
return stream->ReadBytes(ptr, sizeof(*ptr));
}
inline MemoryStream&
MemoryStream_Write(
MemoryStream *stream,
const DirectPatchPosition *ptr
)
{
return stream->WriteBytes(ptr, sizeof(*ptr));
}
//##########################################################################
//###################### Dynamic3DPatchSource ########################
//##########################################################################
class Dynamic3DPatchSource:
public L4AudioSource
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, Testing
//
public:
Dynamic3DPatchSource(
PlugStream *stream,
Entity *entity
);
~Dynamic3DPatchSource();
Logical
TestInstance() const;
virtual Logical IsAudioSourceClipped(AudioHead *audio_head);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Mix levels
//
public:
AudioControlValue
CalculateSourceVolumeScale();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// State implementations
//
public:
void
StartImplementation();
void
StopImplementation();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Protected implementations
//
protected:
void
StartMessageImplementation();
void
ExecuteModel(Logical force_update);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private data
//
private:
MIDIValue
lastFrontLeftMIDIVolume,
lastFrontRightMIDIVolume,
lastRearLeftMIDIVolume,
lastRearRightMIDIVolume;
MIDIPitchBend
lastFrontLeftMIDIPitchBend,
lastFrontRightMIDIPitchBend,
lastRearLeftMIDIPitchBend,
lastRearRightMIDIPitchBend;
MIDINRPNValue
lastMIDIFilterCutoff;
};
//##########################################################################
//####################### Static3DPatchSource ########################
//##########################################################################
class Static3DPatchSource:
public L4AudioSource
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, Testing
//
public:
Static3DPatchSource(
PlugStream *stream,
Entity *entity
);
~Static3DPatchSource();
Logical
TestInstance() const;
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
);
virtual Logical IsAudioSourceClipped(AudioHead *audio_head);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// SetPosition
//
public:
void
SetPosition(const Vector3D &vector3D);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// State implementations
//
public:
// FIDELITY (AUDIO_FIDELITY.md F3): statics get the authored distance curve too
AudioControlValue
CalculateSourceVolumeScale();
void
StartImplementation();
void
StopImplementation();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Protected implementations
//
protected:
void
StartMessageImplementation();
void
ExecuteModel(Logical force_update);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private Methods
//
private:
L4AudioSpatialization::Quadrant
GetQuadrant();
Radian
GetAzimuthOfSource();
Scalar
GetFrontLeftScale();
Scalar
GetFrontRightScale();
Scalar
GetRearLeftScale();
Scalar
GetRearRightScale();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private data
//
private:
Vector3D
position;
Logical
useInternalSpatialization;
L4AudioSpatialization
internalSpatialization;
MIDIValue
lastFrontLeftMIDIVolume,
lastFrontRightMIDIVolume,
lastRearLeftMIDIVolume,
lastRearRightMIDIVolume;
MIDIPitchBend
lastMIDIPitchBend;
MIDINRPNValue
lastMIDIFilterCutoff;
};
//~~~~~~~~~~~~~~~~~~~~~~~~ Static3DPatchSource inlines ~~~~~~~~~~~~~~~~~~~~~
inline L4AudioSpatialization::Quadrant
Static3DPatchSource::GetQuadrant()
{
return internalSpatialization.quadrant;
}
inline Radian
Static3DPatchSource::GetAzimuthOfSource()
{
return internalSpatialization.azimuthOfSource;
}
inline Scalar
Static3DPatchSource::GetFrontLeftScale()
{
return internalSpatialization.frontLeftScale;
}
inline Scalar
Static3DPatchSource::GetFrontRightScale()
{
return internalSpatialization.frontRightScale;
}
inline Scalar
Static3DPatchSource::GetRearLeftScale()
{
return internalSpatialization.rearLeftScale;
}
inline Scalar
Static3DPatchSource::GetRearRightScale()
{
return internalSpatialization.rearRightScale;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioChannelSet inlines ~~~~~~~~~~~~~~~~~~~~~~
/*inline void
AudioChannelSet::SetFrontLeft(AudioChannel *audio_channel)
{
Check(this);
channels[0] = audio_channel;
}
inline void
AudioChannelSet::SetFrontRight(AudioChannel *audio_channel)
{
Check(this);
channels[1] = audio_channel;
}
inline void
AudioChannelSet::SetRearLeft(AudioChannel *audio_channel)
{
Check(this);
channels[2] = audio_channel;
}
inline void
AudioChannelSet::SetRearRight(AudioChannel *audio_channel)
{
Check(this);
channels[3] = audio_channel;
}
inline AudioChannel*
AudioChannelSet::GetFrontLeft()
{
Check(this);
return channels[0];
}
inline AudioChannel*
AudioChannelSet::GetFrontRight()
{
Check(this);
return channels[1];
}
inline AudioChannel*
AudioChannelSet::GetRearLeft()
{
Check(this);
return channels[2];
}
inline AudioChannel*
AudioChannelSet::GetRearRight()
{
Check(this);
return channels[3];
}
inline void
AudioChannelSet::SetNth(
AudioChannelSetIndex index,
AudioChannel *audio_channel
)
{
Check(this);
Verify(index >=0 && index < AUDIO_CHANNEL_SET_LENGTH);
channels[index] = audio_channel;
}
inline AudioChannel*
AudioChannelSet::GetNth(AudioChannelSetIndex index)
{
Check(this);
Verify(index >=0 && index < AUDIO_CHANNEL_SET_LENGTH);
return channels[index];
}
inline void
AudioChannelSet::EnableFrontLeft(Logical flag)
{
Check(this);
enables[0] = flag;
}
inline void
AudioChannelSet::EnableFrontRight(Logical flag)
{
Check(this);
enables[1] = flag;
}
inline void
AudioChannelSet::EnableRearLeft(Logical flag)
{
Check(this);
enables[2] = flag;
}
inline void
AudioChannelSet::EnableRearRight(Logical flag)
{
Check(this);
enables[3] = flag;
}
inline Logical
AudioChannelSet::IsFrontLeftEnabled()
{
Check(this);
return enables[0];
}
inline Logical
AudioChannelSet::IsFrontRightEnabled()
{
Check(this);
return enables[1];
}
inline Logical
AudioChannelSet::IsRearLeftEnabled()
{
Check(this);
return enables[2];
}
inline Logical
AudioChannelSet::IsRearRightEnabled()
{
Check(this);
return enables[3];
}
inline void
AudioChannelSet::EnableNth(
AudioChannelSetIndex index,
Logical flag
)
{
Check(this);
Verify(index >=0 && index < AUDIO_CHANNEL_SET_LENGTH);
enables[index] = flag;
}
inline Logical
AudioChannelSet::IsNthEnabled(AudioChannelSetIndex index)
{
Check(this);
Verify(index >=0 && index < AUDIO_CHANNEL_SET_LENGTH);
return enables[index];
}*/