Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.
Layout:
engine/ MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
models) + image codec; the minimal rp/ headers the audio HAL needs
game/ reconstructed BT logic + surviving-original BT source + fwd shims
+ WinMain launcher
content/ full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
docs/ format specs + reconstruction ledgers
reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
tools/ MP console emulator + map/resource scanners
One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2191 lines
58 KiB
C++
2191 lines
58 KiB
C++
#include "mungal4.h"
|
|
#pragma hdrstop
|
|
|
|
#include "l4audio.h"
|
|
#include "l4audlvl.h"
|
|
#include "l4app.h"
|
|
#include "l4audrnd.h"
|
|
#include "..\munga\namelist.h"
|
|
#include "..\munga\player.h"
|
|
#include "..\rp\vtv.h"
|
|
|
|
//#############################################################################
|
|
//####################### L4AudioSpatialization #########################
|
|
//#############################################################################
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
L4AudioSpatialization::L4AudioSpatialization()
|
|
{
|
|
azimuthOfSource = 0.0f;
|
|
|
|
frontLeftScale = 0.0f;
|
|
frontRightScale = 0.0f;
|
|
rearLeftScale = 0.0f;
|
|
rearRightScale = 0.0f;
|
|
|
|
frontLeftDelay = 0.0f;
|
|
frontRightDelay = 0.0f;
|
|
rearLeftDelay = 0.0f;
|
|
rearRightDelay = 0.0f;
|
|
|
|
quadrant = Quadrant1;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
L4AudioSpatialization::~L4AudioSpatialization()
|
|
{
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
Logical
|
|
L4AudioSpatialization::TestInstance() const
|
|
{
|
|
return True;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
L4AudioSpatialization::CalculateSpatialization(Radian azimuth_of_source)
|
|
{
|
|
azimuthOfSource = azimuth_of_source;
|
|
|
|
//
|
|
//---------------------------------------------------------------
|
|
// Make azimuth usable for channel volume calculations
|
|
//---------------------------------------------------------------
|
|
//
|
|
#define DEG_90 (90.0f*(RAD_PER_DEG))
|
|
#define DEG_180 (180.0f*(RAD_PER_DEG))
|
|
#define DEG_360 (360.0f*(RAD_PER_DEG))
|
|
|
|
azimuthOfSource = DEG_180 + azimuthOfSource;
|
|
if (azimuthOfSource > DEG_180)
|
|
azimuthOfSource = azimuthOfSource - DEG_360;
|
|
Verify(
|
|
azimuthOfSource <= DEG_180 &&
|
|
azimuthOfSource >= -DEG_180
|
|
);
|
|
|
|
//
|
|
//---------------------------------------------------------------
|
|
// Channel volume scale and ITD calculations
|
|
//---------------------------------------------------------------
|
|
//
|
|
|
|
//
|
|
// Get audio head constants
|
|
//
|
|
L4AudioRenderer *audio_renderer;
|
|
AudioHead *audio_head;
|
|
|
|
Check(application);
|
|
audio_renderer =
|
|
Cast_Object(L4AudioRenderer*, application->GetAudioRenderer());
|
|
Check(audio_renderer);
|
|
audio_head = audio_renderer->GetAudioHead();
|
|
Check(audio_head);
|
|
|
|
//
|
|
// Init channel volume scale variables
|
|
//
|
|
const Radian azimuth_max = 45.0*RAD_PER_DEG; // HACK - should come from audio.ini
|
|
Scalar tangent_ratio;
|
|
|
|
frontLeftScale = 0.0f;
|
|
frontRightScale = 0.0f;
|
|
rearLeftScale = 0.0f;
|
|
rearRightScale = 0.0f;
|
|
|
|
//
|
|
// Init ITD parameters
|
|
//
|
|
const Scalar itd_delay = audio_head->GetITDDifference();
|
|
|
|
frontLeftDelay = 0.0f;
|
|
frontRightDelay = 0.0f;
|
|
rearLeftDelay = 0.0f;
|
|
rearRightDelay = 0.0f;
|
|
|
|
//
|
|
//---------------------------------------------------------------
|
|
// Quadrant 1
|
|
//---------------------------------------------------------------
|
|
//
|
|
if (
|
|
azimuthOfSource > -azimuth_max &&
|
|
azimuthOfSource < azimuth_max
|
|
)
|
|
{
|
|
quadrant = Quadrant1;
|
|
|
|
// volume scale
|
|
Verify(!Small_Enough(tan(azimuth_max)));
|
|
tangent_ratio =
|
|
(tan(azimuthOfSource) / tan(azimuth_max)) * 0.5f;
|
|
|
|
frontLeftScale = Sqrt(0.5f + tangent_ratio);
|
|
frontRightScale = Sqrt(0.5f - tangent_ratio);
|
|
Verify(frontLeftScale >= 0.0f && frontLeftScale <= 1.0f);
|
|
Verify(frontRightScale >= 0.0f && frontRightScale <= 1.0f);
|
|
|
|
// pitch offset
|
|
if (azimuthOfSource > 0.0f)
|
|
{
|
|
frontLeftDelay = itd_delay * tangent_ratio * 2.0f;
|
|
}
|
|
else
|
|
{
|
|
frontRightDelay = itd_delay * -tangent_ratio * 2.0f;
|
|
}
|
|
}
|
|
//
|
|
//---------------------------------------------------------------
|
|
// Quadrant 2
|
|
//---------------------------------------------------------------
|
|
//
|
|
else if (
|
|
azimuthOfSource > azimuth_max &&
|
|
azimuthOfSource < (DEG_180 - azimuth_max)
|
|
)
|
|
{
|
|
quadrant = Quadrant2;
|
|
|
|
// volume scale
|
|
azimuthOfSource = azimuthOfSource - DEG_90;
|
|
|
|
Verify(!Small_Enough(tan(DEG_90 - azimuth_max)));
|
|
tangent_ratio =
|
|
(tan(azimuthOfSource) / tan(DEG_90 - azimuth_max)) * 0.5f;
|
|
|
|
rearLeftScale = Sqrt(0.5f + tangent_ratio);
|
|
frontLeftScale = Sqrt(0.5f - tangent_ratio);
|
|
Verify(rearLeftScale >= 0.0f && rearLeftScale <= 1.0f);
|
|
Verify(frontLeftScale >= 0.0f && frontLeftScale <= 1.0f);
|
|
|
|
// pitch offset
|
|
if (azimuthOfSource > 0.0f)
|
|
{
|
|
rearLeftDelay = itd_delay * tangent_ratio * 2.0f;
|
|
}
|
|
else
|
|
{
|
|
frontLeftDelay = itd_delay * -tangent_ratio * 2.0f;
|
|
}
|
|
}
|
|
//
|
|
//---------------------------------------------------------------
|
|
// Quadrant 3
|
|
//---------------------------------------------------------------
|
|
//
|
|
else if (
|
|
azimuthOfSource > (DEG_180 - azimuth_max) ||
|
|
azimuthOfSource < (-DEG_180 + azimuth_max)
|
|
)
|
|
{
|
|
quadrant = Quadrant3;
|
|
|
|
// volume scale
|
|
azimuthOfSource = azimuthOfSource - DEG_180;
|
|
|
|
Verify(!Small_Enough(tan(azimuth_max)));
|
|
tangent_ratio =
|
|
(tan(azimuthOfSource) / tan(azimuth_max)) * 0.5f;
|
|
|
|
rearRightScale = Sqrt(0.5f + tangent_ratio);
|
|
rearLeftScale = Sqrt(0.5f - tangent_ratio);
|
|
Verify(rearRightScale >= 0.0f && rearRightScale <= 1.0f);
|
|
Verify(rearLeftScale >= 0.0f && rearLeftScale <= 1.0f);
|
|
|
|
// pitch offset
|
|
if (azimuthOfSource > -azimuth_max)
|
|
{
|
|
rearLeftDelay = -(itd_delay * tangent_ratio * 2.0f);
|
|
}
|
|
else
|
|
{
|
|
rearRightDelay = -(itd_delay * -tangent_ratio * 2.0f);
|
|
}
|
|
|
|
#if 0
|
|
Tell(
|
|
"azimuthOfSource " << azimuthOfSource <<
|
|
" rearRightDelay " << rearRightDelay <<
|
|
" rearLeftDelay " << rearLeftDelay <<
|
|
"\n"
|
|
);
|
|
#endif
|
|
}
|
|
//
|
|
//---------------------------------------------------------------
|
|
// Quadrant 4
|
|
//---------------------------------------------------------------
|
|
//
|
|
else
|
|
{
|
|
quadrant = Quadrant4;
|
|
|
|
Verify(
|
|
azimuthOfSource > (-DEG_180 + azimuth_max) &&
|
|
azimuthOfSource < -azimuth_max
|
|
);
|
|
|
|
// volume scale
|
|
azimuthOfSource = azimuthOfSource + DEG_90;
|
|
|
|
Verify(!Small_Enough(tan(DEG_90 - azimuth_max)));
|
|
tangent_ratio =
|
|
(tan(azimuthOfSource) / tan(DEG_90 - azimuth_max)) * 0.5f;
|
|
|
|
frontRightScale = Sqrt(0.5f + tangent_ratio);
|
|
rearRightScale = Sqrt(0.5f - tangent_ratio);
|
|
Verify(frontRightScale >= 0.0f && frontRightScale <= 1.0f);
|
|
Verify(rearRightScale >= 0.0f && rearRightScale <= 1.0f);
|
|
|
|
// pitch offset
|
|
if (azimuthOfSource > 0.0f)
|
|
{
|
|
frontRightDelay = itd_delay * tangent_ratio * 2.0f;
|
|
}
|
|
else
|
|
{
|
|
rearRightDelay = itd_delay * -tangent_ratio * 2.0f;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
Tell(
|
|
"FL " << frontLeftScale <<
|
|
" FR " << frontRightScale <<
|
|
" RL " << rearLeftScale <<
|
|
" RR " << rearRightScale <<
|
|
"\n"
|
|
);
|
|
#endif
|
|
|
|
#if 0
|
|
Tell(
|
|
"Quadrant " << quadrant <<
|
|
" FL " << frontLeftDelay <<
|
|
" FR " << frontRightDelay <<
|
|
" RL " << rearLeftDelay <<
|
|
" RR " << rearRightDelay <<
|
|
"\n"
|
|
);
|
|
#endif
|
|
|
|
Verify(frontLeftScale >= 0.0f && frontLeftScale <= 1.0f);
|
|
Verify(frontRightScale >= 0.0f && frontRightScale <= 1.0f);
|
|
Verify(rearLeftScale >= 0.0f && rearLeftScale <= 1.0f);
|
|
Verify(rearRightScale >= 0.0f && rearRightScale <= 1.0f);
|
|
}
|
|
|
|
//#############################################################################
|
|
//######################### L4AudioLocation #############################
|
|
//#############################################################################
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
L4AudioLocation::L4AudioLocation(
|
|
PlugStream *stream,
|
|
Entity *entity
|
|
):
|
|
AudioLocation(stream, entity)
|
|
{
|
|
L4AudioLocationX();
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
L4AudioLocation::L4AudioLocationX()
|
|
{
|
|
//
|
|
// Get audio renderer frame duration
|
|
//
|
|
Check(application)
|
|
L4AudioRenderer *audio_renderer =
|
|
Cast_Object(L4AudioRenderer*, application->GetAudioRenderer());
|
|
Check(audio_renderer);
|
|
|
|
Time frame_duration =
|
|
audio_renderer->GetCalibrationFrameDuration();
|
|
|
|
//
|
|
// Init ITD pitch offset variables
|
|
//
|
|
lastITDFrameTime = Now();
|
|
lastITDFrameTime -= frame_duration;
|
|
|
|
currentFrontLeftDelay = 0.0f;
|
|
currentFrontRightDelay = 0.0f;
|
|
currentRearLeftDelay = 0.0f;
|
|
currentRearRightDelay = 0.0f;
|
|
|
|
frontLeftITDPitchOffset = 0.0f;
|
|
frontRightITDPitchOffset = 0.0f;
|
|
rearLeftITDPitchOffset = 0.0f;
|
|
rearRightITDPitchOffset = 0.0f;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
L4AudioLocation::~L4AudioLocation()
|
|
{
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
Logical
|
|
L4AudioLocation::TestInstance() const
|
|
{
|
|
AudioLocation::TestInstance();
|
|
Check(&spatialization);
|
|
return True;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
L4AudioLocation::UpdateSpatialModelImplementation(AudioHead *audio_head)
|
|
{
|
|
Check(this);
|
|
Check(audio_head);
|
|
|
|
//
|
|
//---------------------------------------------------------------
|
|
// Call inherited method
|
|
//---------------------------------------------------------------
|
|
//
|
|
AudioLocation::UpdateSpatialModelImplementation(audio_head);
|
|
|
|
//
|
|
//---------------------------------------------------------------
|
|
// Catch case of head == source
|
|
//---------------------------------------------------------------
|
|
//
|
|
if (IsHeadSource())
|
|
{
|
|
spatialization.frontLeftScale = 1.0f;
|
|
spatialization.frontRightScale = 1.0f;
|
|
spatialization.rearLeftScale = 1.0f;
|
|
spatialization.rearRightScale = 1.0f;
|
|
|
|
frontLeftITDPitchOffset = 0.0f;
|
|
frontRightITDPitchOffset = 0.0f;
|
|
rearLeftITDPitchOffset = 0.0f;
|
|
rearRightITDPitchOffset = 0.0f;
|
|
return;
|
|
}
|
|
|
|
//
|
|
//---------------------------------------------------------------
|
|
// Calculate channel spatialization
|
|
//---------------------------------------------------------------
|
|
//
|
|
spatialization.CalculateSpatialization(GetAzimuthOfSource());
|
|
|
|
//
|
|
//---------------------------------------------------------------
|
|
// Calculate ITD pitch offsets
|
|
//---------------------------------------------------------------
|
|
//
|
|
const Scalar itd_pitch_offset_constant =
|
|
0.003831f / 0.000002f; // period / delay // HACK - should come from audio head
|
|
|
|
Time itd_delta_time;
|
|
|
|
itd_delta_time = Now();
|
|
itd_delta_time -= lastITDFrameTime;
|
|
lastITDFrameTime = Now();
|
|
|
|
frontLeftITDPitchOffset = 0.0f;
|
|
frontRightITDPitchOffset = 0.0f;
|
|
rearLeftITDPitchOffset = 0.0f;
|
|
rearRightITDPitchOffset = 0.0f;
|
|
|
|
if (!Small_Enough((Scalar)itd_delta_time))
|
|
{
|
|
if (currentFrontLeftDelay != spatialization.frontLeftDelay)
|
|
{
|
|
Verify(!Small_Enough((Scalar)itd_delta_time));
|
|
|
|
frontLeftITDPitchOffset =
|
|
itd_pitch_offset_constant *
|
|
(spatialization.frontLeftDelay - currentFrontLeftDelay) /
|
|
(Scalar)itd_delta_time;
|
|
currentFrontLeftDelay = spatialization.frontLeftDelay;
|
|
}
|
|
if (currentFrontRightDelay != spatialization.frontRightDelay)
|
|
{
|
|
Verify(!Small_Enough((Scalar)itd_delta_time));
|
|
|
|
frontRightITDPitchOffset =
|
|
itd_pitch_offset_constant *
|
|
(spatialization.frontRightDelay - currentFrontRightDelay) /
|
|
(Scalar)itd_delta_time;
|
|
currentFrontRightDelay = spatialization.frontRightDelay;
|
|
}
|
|
if (currentRearLeftDelay != spatialization.rearLeftDelay)
|
|
{
|
|
Verify(!Small_Enough((Scalar)itd_delta_time));
|
|
|
|
rearLeftITDPitchOffset =
|
|
itd_pitch_offset_constant *
|
|
(spatialization.rearLeftDelay - currentRearLeftDelay) /
|
|
(Scalar)itd_delta_time;
|
|
currentRearLeftDelay = spatialization.rearLeftDelay;
|
|
}
|
|
if (currentRearRightDelay != spatialization.rearRightDelay)
|
|
{
|
|
Verify(!Small_Enough((Scalar)itd_delta_time));
|
|
|
|
rearRightITDPitchOffset =
|
|
itd_pitch_offset_constant *
|
|
(spatialization.rearRightDelay - currentRearRightDelay) /
|
|
(Scalar)itd_delta_time;
|
|
currentRearRightDelay = spatialization.rearRightDelay;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
Tell(
|
|
"Quadrant " << spatialization.quadrant <<
|
|
" FL " << frontLeftITDPitchOffset <<
|
|
" FR " << frontRightITDPitchOffset <<
|
|
" RL " << rearLeftITDPitchOffset <<
|
|
" RR " << rearRightITDPitchOffset <<
|
|
"\n"
|
|
);
|
|
#endif
|
|
|
|
//
|
|
//---------------------------------------------------------------
|
|
// Check for source "between ears"
|
|
//---------------------------------------------------------------
|
|
//
|
|
const Scalar ear_radius =
|
|
audio_head->GetDistanceBetweenEars() * 0.5;
|
|
Scalar distance_to_source_listener_plane =
|
|
GetDistanceToSourceListenerPlane();
|
|
|
|
if (distance_to_source_listener_plane < ear_radius)
|
|
{
|
|
Verify(!Small_Enough(ear_radius));
|
|
|
|
const Scalar proportion =
|
|
0.5f *
|
|
(ear_radius - distance_to_source_listener_plane) /
|
|
ear_radius;
|
|
|
|
Scalar powerA, powerB;
|
|
|
|
#if DEBUG_LEVEL>0
|
|
if (!(proportion >= 0.0f && proportion <= 1.0f))
|
|
{
|
|
Dump(ear_radius);
|
|
Dump(distance_to_source_listener_plane);
|
|
Dump(proportion);
|
|
}
|
|
Verify(proportion >= 0.0f && proportion <= 1.0f);
|
|
#endif
|
|
|
|
powerA = Sqrt(1.0f - proportion);
|
|
powerB = Sqrt(proportion);
|
|
Verify(powerA >= 0.0f && powerA <= 1.0f);
|
|
Verify(powerB >= 0.0f && powerB <= 1.0f);
|
|
|
|
switch (spatialization.quadrant)
|
|
{
|
|
case L4AudioSpatialization::Quadrant1:
|
|
spatialization.rearLeftScale = spatialization.frontLeftScale * powerB;
|
|
spatialization.rearRightScale = spatialization.frontRightScale * powerB;
|
|
|
|
spatialization.frontLeftScale *= powerA;
|
|
spatialization.frontRightScale *= powerA;
|
|
break;
|
|
|
|
case L4AudioSpatialization::Quadrant2:
|
|
spatialization.rearRightScale = spatialization.rearLeftScale * powerB;
|
|
spatialization.frontRightScale = spatialization.frontLeftScale * powerB;
|
|
|
|
spatialization.rearLeftScale *= powerA;
|
|
spatialization.frontLeftScale *= powerA;
|
|
break;
|
|
|
|
case L4AudioSpatialization::Quadrant3:
|
|
spatialization.frontRightScale = spatialization.rearRightScale * powerB;
|
|
spatialization.frontLeftScale = spatialization.rearLeftScale * powerB;
|
|
|
|
spatialization.rearRightScale *= powerA;
|
|
spatialization.rearLeftScale *= powerA;
|
|
break;
|
|
|
|
case L4AudioSpatialization::Quadrant4:
|
|
spatialization.frontLeftScale = spatialization.frontRightScale * powerB;
|
|
spatialization.rearLeftScale = spatialization.rearRightScale * powerB;
|
|
|
|
spatialization.frontRightScale *= powerA;
|
|
spatialization.rearRightScale *= powerA;
|
|
break;
|
|
}
|
|
|
|
#if 0
|
|
Tell(
|
|
"FL " << spatialization.frontLeftScale <<
|
|
" FR " << spatialization.frontRightScale <<
|
|
" RL " << spatialization.rearLeftScale <<
|
|
" RR " << spatialization.rearRightScale <<
|
|
"\n"
|
|
);
|
|
#endif
|
|
}
|
|
|
|
Verify(spatialization.frontLeftScale >= 0.0f && spatialization.frontLeftScale <= 1.0f);
|
|
Verify(spatialization.frontRightScale >= 0.0f && spatialization.frontRightScale <= 1.0f);
|
|
Verify(spatialization.rearLeftScale >= 0.0f && spatialization.rearLeftScale <= 1.0f);
|
|
Verify(spatialization.rearRightScale >= 0.0f && spatialization.rearRightScale <= 1.0f);
|
|
}
|
|
|
|
//#############################################################################
|
|
//######################### AudioChannelSet #############################
|
|
//#############################################################################
|
|
|
|
//AudioChannelSet AudioChannelSet::Null;
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
/*AudioChannelSet::AudioChannelSet()
|
|
{
|
|
for (int i = 0; i < AudioChannelSetSize; i++)
|
|
{
|
|
channels[i] = NULL;
|
|
enables[i] = False;
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
Logical
|
|
AudioChannelSet::TestInstance() const
|
|
{
|
|
for (int i = 0; i < AudioChannelSetSize; i++)
|
|
{
|
|
if (channels[i] != NULL)
|
|
{
|
|
Verify(enables[i] == True);
|
|
Check(channels[i]);
|
|
}
|
|
}
|
|
return True;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
AudioChannelSet::EnableAll()
|
|
{
|
|
//
|
|
// Must set all channels to null and all enables to True
|
|
//
|
|
for (int i = 0; i < AudioChannelSetSize; i++)
|
|
{
|
|
channels[i] = NULL;
|
|
enables[i] = True;
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
AudioChannelSet::ReleaseAll()
|
|
{
|
|
//
|
|
// Must release all channels without changing enable values
|
|
//
|
|
for (int i = 0; i < AudioChannelSetSize; i++)
|
|
{
|
|
if (channels[i] != NULL)
|
|
{
|
|
Check(channels[i]);
|
|
channels[i]->Release();
|
|
channels[i] = NULL;
|
|
}
|
|
}
|
|
}*/
|
|
|
|
//#############################################################################
|
|
//########################## L4AudioSource ##############################
|
|
//#############################################################################
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
L4AudioSource::L4AudioSource(
|
|
PlugStream *stream,
|
|
Entity *entity
|
|
):
|
|
AudioSource(stream, entity)
|
|
{
|
|
channelSet.count = GetAudioVoiceCount();
|
|
L4AudioSourceX();
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
L4AudioSource::BuildFromPage(
|
|
PlugStream *stream,
|
|
NameList *name_list,
|
|
ClassID class_ID,
|
|
ObjectID object_ID
|
|
)
|
|
{
|
|
AudioSource::BuildFromPage(stream, name_list, class_ID, object_ID);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
L4AudioSource::L4AudioSourceX()
|
|
{
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
L4AudioSource::~L4AudioSource()
|
|
{
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
Logical
|
|
L4AudioSource::TestInstance() const
|
|
{
|
|
AudioSource::TestInstance();
|
|
Check(&channelSet);
|
|
return True;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
L4AudioSource::StopMessageImplementation()
|
|
{
|
|
Check(this);
|
|
|
|
AudioSource::StopMessageImplementation();
|
|
|
|
//
|
|
// Request stop from renderer
|
|
//
|
|
Check(application);
|
|
Cast_Object(L4AudioRenderer*, application->GetAudioRenderer())->
|
|
StopRequest(this);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
L4AudioSource::SetAudioChannelSet(const SourceSet &audio_channel_set)
|
|
{
|
|
Check(this);
|
|
channelSet = audio_channel_set;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
SourceSet*
|
|
L4AudioSource::GetAudioChannelSet()
|
|
{
|
|
Check(this);
|
|
return &channelSet;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
L4AudioSource::ReleaseChannels()
|
|
{
|
|
Check(this);
|
|
//How do I release the sources, man?
|
|
application->GetAudioRenderer()->ReleaseSourceSet(channelSet);
|
|
|
|
for (int i=0; i < channelSet.count; i++)
|
|
{
|
|
channelSet.sources[i] = 0;
|
|
}
|
|
//channelSet.ReleaseAll();
|
|
}
|
|
|
|
//#############################################################################
|
|
//######################## DirectPatchSource ############################
|
|
//#############################################################################
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
DirectPatchSource::DirectPatchSource(
|
|
PlugStream *stream,
|
|
Entity *entity
|
|
):
|
|
L4AudioSource(stream, entity)
|
|
{
|
|
MemoryStream_Read(stream, &audioPosition);
|
|
// channel = NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
DirectPatchSource::BuildFromPage(
|
|
PlugStream *stream,
|
|
NameList *name_list,
|
|
ClassID class_ID,
|
|
ObjectID object_ID
|
|
)
|
|
{
|
|
L4AudioSource::BuildFromPage(stream, name_list, class_ID, object_ID);
|
|
MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, position);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
DirectPatchSource::~DirectPatchSource()
|
|
{
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
Logical
|
|
DirectPatchSource::TestInstance() const
|
|
{
|
|
L4AudioSource::TestInstance();
|
|
/* if (channel != NULL)
|
|
{
|
|
Check(channel);
|
|
}*/
|
|
return True;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
DirectPatchSource::StartMessageImplementation()
|
|
{
|
|
Check(this);
|
|
|
|
L4AudioSource::StartMessageImplementation();
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Init channel set to requested channels
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
/* channelSet = AudioChannelSet::Null;
|
|
switch (audioPosition)
|
|
{
|
|
case FrontDirectPatchPosition:
|
|
case FrontLeftDirectPatchPosition:
|
|
case FrontRightDirectPatchPosition:
|
|
channelSet.EnableFrontLeft(True);
|
|
break;
|
|
|
|
case RearDirectPatchPosition:
|
|
case RearLeftDirectPatchPosition:
|
|
case RearRightDirectPatchPosition:
|
|
channelSet.EnableRearLeft(True);
|
|
break;
|
|
}*/
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Request start from renderer
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
Check(application);
|
|
Cast_Object(L4AudioRenderer*, application->GetAudioRenderer())->
|
|
StartRequest(this);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
DirectPatchSource::StartImplementation()
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Call inherited method
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
L4AudioSource::StartImplementation();
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Remember the channel
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
/* Verify(channel == NULL);
|
|
switch (audioPosition)
|
|
{
|
|
case FrontDirectPatchPosition:
|
|
case FrontLeftDirectPatchPosition:
|
|
case FrontRightDirectPatchPosition:
|
|
channel = channelSet.GetFrontLeft();
|
|
break;
|
|
|
|
case RearDirectPatchPosition:
|
|
case RearLeftDirectPatchPosition:
|
|
case RearRightDirectPatchPosition:
|
|
channel = channelSet.GetRearLeft();
|
|
break;
|
|
}
|
|
Check(channel);*/
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Setup the channel
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
ExecuteWatchers();
|
|
|
|
//
|
|
// Turn the volume down while setting up the channel
|
|
//
|
|
// channel->SendController(MIDI_VOLUME_CONTROL, MIDI_MIN_CONTROL_VALUE);
|
|
|
|
//
|
|
// Set the channel to the bank and program
|
|
//
|
|
PatchResource *patch_resource;
|
|
|
|
patch_resource = Cast_Object(PatchResource*, GetAudioResource());
|
|
Check(patch_resource);
|
|
patch_resource->SetDistance(GetDistanceToSource());
|
|
patch_resource->SetupPatch(channelSet);
|
|
|
|
//
|
|
// Set the channel to default control values
|
|
//
|
|
// channel->SendController(MIDI_REVERB_CONTROL, MIDI_MIN_CONTROL_VALUE);
|
|
// channel->SendController(MIDI_CHORUS_CONTROL, MIDI_MIN_CONTROL_VALUE);
|
|
|
|
/* switch (audioPosition)
|
|
{
|
|
case FrontDirectPatchPosition:
|
|
case RearDirectPatchPosition:
|
|
channel->SendController(MIDI_PAN_CONTROL, MIDI_CENTER_PAN_VALUE);
|
|
break;
|
|
case FrontLeftDirectPatchPosition:
|
|
case RearLeftDirectPatchPosition:
|
|
channel->SendController(MIDI_PAN_CONTROL, MIDI_LEFT_PAN_VALUE);
|
|
break;
|
|
case FrontRightDirectPatchPosition:
|
|
case RearRightDirectPatchPosition:
|
|
channel->SendController(MIDI_PAN_CONTROL, MIDI_RIGHT_PAN_VALUE);
|
|
break;
|
|
}*/
|
|
|
|
//
|
|
// Set midi history to default control values
|
|
//
|
|
lastMIDIVolume = MIDI_MIN_CONTROL_VALUE;
|
|
lastMIDIPitchBend = 0; // Set by force update
|
|
lastMIDIFilterCutoff = MIDI_MAX_CONTROL_VALUE; // Set by patch load
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Calculate attack time, velocity, and execute model
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
MIDIValue midi_velocity =
|
|
CalculateSourceAttackVolumeScale() *
|
|
(Scalar)MIDI_MAX_CONTROL_VALUE + 0.5f;
|
|
|
|
if (UseSourceAttackTime())
|
|
{
|
|
MIDINRPNValue midi_attack_time =
|
|
CalculateSourceAttackTime() *
|
|
(Scalar)AWE_VOL_ATTACK_TIME_RANGE + 0.5f;
|
|
|
|
// channel->SendNRPN(AWE_VOL_ATTACK_TIME_NRPN, midi_attack_time);
|
|
}
|
|
|
|
ExecuteModel(True);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Start note
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
//TODO: Start OpenAL source playing
|
|
// channel->SendNoteOn(GetCurrentNoteValue(), midi_velocity);
|
|
patch_resource->PlayNote(channelSet);
|
|
|
|
#if 0
|
|
Tell("On " << (int)GetCurrentNoteValue() << "\n");
|
|
#endif
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
DirectPatchSource::StopImplementation()
|
|
{
|
|
Check(this);
|
|
|
|
//TODO: Stop OpenAL source playing
|
|
PatchResource *patch_resource;
|
|
|
|
patch_resource = Cast_Object(PatchResource*, GetAudioResource());
|
|
Check(patch_resource);
|
|
patch_resource->StopNote(channelSet);
|
|
|
|
//
|
|
// Stop note
|
|
//
|
|
// Check(channel);
|
|
// channel->SendNoteOff(GetCurrentNoteValue(), MIDI_MIN_CONTROL_VALUE);
|
|
// channel = NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
DirectPatchSource::ExecuteModel(Logical force_update)
|
|
{
|
|
Check(this);
|
|
|
|
//TODO: Probably don't have to do anything in this function- maybe watch
|
|
//to mess with looping appropriately.
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Apply pitch offset
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
const MIDIPitchBend pitch_resolution = 12; // HACK - should come from audio.ini
|
|
AudioPitchCents pitch_offset;
|
|
|
|
pitch_offset = CalculateSourcePitchOffset();
|
|
double relativePitch = pow(2.0,pitch_offset/1200.0);
|
|
Clamp(relativePitch,0.5,2.0);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Apply filter scale
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
if (UseSourceBrightnessScale())
|
|
{
|
|
const MIDINRPNValue filter_resolution = 2;// HACK - should come from audio.ini
|
|
Scalar filter_scale;
|
|
PatchResource *patch_resource;
|
|
MIDINRPNValue max_midi_filter_cutoff;
|
|
MIDINRPNValue midi_filter_cutoff;
|
|
MIDINRPNValue filter_difference;
|
|
|
|
filter_scale = CalculateSourceBrightnessScale();
|
|
patch_resource = Cast_Object(PatchResource*, GetAudioResource());
|
|
max_midi_filter_cutoff = patch_resource->GetMaxMIDIFilterCutoff();
|
|
midi_filter_cutoff = filter_scale * (Scalar)max_midi_filter_cutoff + 0.5f;
|
|
filter_difference = lastMIDIFilterCutoff - midi_filter_cutoff;
|
|
|
|
if (Abs(filter_difference) >= filter_resolution)
|
|
{
|
|
lastMIDIFilterCutoff = midi_filter_cutoff;
|
|
}
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Apply volume scale
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
Scalar volume_scale;
|
|
const MIDIValue volume_resolution = 2; // HACK - should come from audio.ini
|
|
|
|
volume_scale = CalculateSourceVolumeScale();
|
|
L4AudioLocation *audio_location = Cast_Object(L4AudioLocation*, GetAudioLocation());
|
|
Check(application);
|
|
L4AudioRenderer *audio_renderer =
|
|
Cast_Object(L4AudioRenderer*, application->GetAudioRenderer());
|
|
Check(audio_renderer);
|
|
AudioHead *audio_head = audio_renderer->GetAudioHead();
|
|
Check(audio_head);
|
|
for (int i=0; i < channelSet.count; i++)
|
|
{
|
|
alSourcef(channelSet.sources[i],AL_MAX_DISTANCE,audio_location->getMaxDistance(audio_head));
|
|
alSourcef(channelSet.sources[i], AL_GAIN, volume_scale);
|
|
}
|
|
}
|
|
|
|
//#############################################################################
|
|
//###################### Dynamic3DPatchSource ###########################
|
|
//#############################################################################
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
Dynamic3DPatchSource::Dynamic3DPatchSource(
|
|
PlugStream *stream,
|
|
Entity *entity
|
|
):
|
|
L4AudioSource(stream, entity)
|
|
{
|
|
}
|
|
|
|
Logical
|
|
Dynamic3DPatchSource::IsAudioSourceClipped(AudioHead *audio_head)
|
|
{
|
|
if (AudioSource::IsAudioSourceClipped(audio_head) || l4_application->GetMissionPlayer()->GetPlayerVehicle()->GetSimulationState() == VTV::BurningState)
|
|
{
|
|
return true;
|
|
} else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
Dynamic3DPatchSource::~Dynamic3DPatchSource()
|
|
{
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
Logical
|
|
Dynamic3DPatchSource::TestInstance() const
|
|
{
|
|
L4AudioSource::TestInstance();
|
|
return True;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Dynamic3DPatchSource::StartMessageImplementation()
|
|
{
|
|
Check(this);
|
|
|
|
L4AudioSource::StartMessageImplementation();
|
|
|
|
//
|
|
// Init channel set to requested channels
|
|
//
|
|
// channelSet.EnableAll();
|
|
|
|
//
|
|
// Request start from renderer
|
|
//
|
|
Check(application);
|
|
Cast_Object(L4AudioRenderer*, application->GetAudioRenderer())->
|
|
StartRequest(this);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Dynamic3DPatchSource::StartImplementation()
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Call inherited method
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
L4AudioSource::StartImplementation();
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Get application, renderer and head pointers
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
L4AudioRenderer *audio_renderer;
|
|
AudioHead *audio_head;
|
|
|
|
Check(application);
|
|
audio_renderer =
|
|
Cast_Object(L4AudioRenderer*, application->GetAudioRenderer());
|
|
Check(audio_renderer);
|
|
audio_head = audio_renderer->GetAudioHead();
|
|
Check(audio_head);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Setup the channel
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
ExecuteWatchers();
|
|
|
|
//
|
|
// Turn the volume down while setting up the channels
|
|
//
|
|
|
|
//
|
|
// Set the channels to the bank and program
|
|
//
|
|
PatchResource *patch_resource;
|
|
|
|
patch_resource = Cast_Object(PatchResource*, GetAudioResource());
|
|
Check(patch_resource);
|
|
patch_resource->SetDistance(GetDistanceToSource());
|
|
patch_resource->SetupPatch(channelSet);
|
|
|
|
/*patch_resource->SetDistance(GetDistanceToSource());
|
|
for (i = 0; i < AudioChannelSetSize; i++)
|
|
{
|
|
channel = channelSet.GetNth(i);
|
|
patch_resource->SetupPatch(channel);
|
|
}*/
|
|
|
|
//
|
|
// Set the channels to default control values
|
|
//
|
|
//MIDIValue midi_reverb_level =
|
|
// audio_head->GetGlobalReverbScale() *
|
|
// (Scalar)MIDI_MAX_CONTROL_VALUE + 0.5f;
|
|
|
|
/* for (i = 0; i < AudioChannelSetSize; i++)
|
|
{
|
|
channel = channelSet.GetNth(i);
|
|
Check(channel);
|
|
channel->SendController(MIDI_REVERB_CONTROL, midi_reverb_level);
|
|
channel->SendController(MIDI_CHORUS_CONTROL, MIDI_MIN_CONTROL_VALUE);
|
|
}*/
|
|
|
|
//
|
|
// Set the channels to correct pan
|
|
//
|
|
/* channel = channelSet.GetFrontLeft();
|
|
Check(channel);
|
|
channel->SendController(MIDI_PAN_CONTROL, MIDI_LEFT_PAN_VALUE);
|
|
|
|
channel = channelSet.GetFrontRight();
|
|
Check(channel);
|
|
channel->SendController(MIDI_PAN_CONTROL, MIDI_RIGHT_PAN_VALUE);
|
|
|
|
channel = channelSet.GetRearLeft();
|
|
Check(channel);
|
|
channel->SendController(MIDI_PAN_CONTROL, MIDI_LEFT_PAN_VALUE);
|
|
|
|
channel = channelSet.GetRearRight();
|
|
Check(channel);
|
|
channel->SendController(MIDI_PAN_CONTROL, MIDI_RIGHT_PAN_VALUE);*/
|
|
|
|
//
|
|
// Set midi history to default control values
|
|
//
|
|
/*lastFrontLeftMIDIVolume = MIDI_MIN_CONTROL_VALUE;
|
|
lastFrontRightMIDIVolume = MIDI_MIN_CONTROL_VALUE;
|
|
lastRearLeftMIDIVolume = MIDI_MIN_CONTROL_VALUE;
|
|
lastRearRightMIDIVolume = MIDI_MIN_CONTROL_VALUE;
|
|
lastFrontLeftMIDIPitchBend = 0; // Set by force update
|
|
lastFrontRightMIDIPitchBend = 0; // Set by force update
|
|
lastRearLeftMIDIPitchBend = 0; // Set by force update
|
|
lastRearRightMIDIPitchBend = 0; // Set by force update
|
|
lastMIDIFilterCutoff = MIDI_MAX_CONTROL_VALUE; // Set by patch
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Calculate attack time, velocity, and execute model
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
MIDIValue midi_velocity =
|
|
CalculateSourceAttackVolumeScale() *
|
|
(Scalar)MIDI_MAX_CONTROL_VALUE + 0.5f;
|
|
|
|
if (UseSourceAttackTime())
|
|
{
|
|
MIDINRPNValue midi_attack_time =
|
|
CalculateSourceAttackTime() *
|
|
(Scalar)AWE_VOL_ATTACK_TIME_RANGE + 0.5f;
|
|
|
|
for (i = 0; i < AudioChannelSetSize; i++)
|
|
{
|
|
channel = channelSet.GetNth(i);
|
|
Check(channel);
|
|
channel->SendNRPN(AWE_VOL_ATTACK_TIME_NRPN, midi_attack_time);
|
|
}
|
|
}*/
|
|
|
|
ExecuteModel(True);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Start note
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
|
|
//TODO: Start OpenAL source
|
|
|
|
/* for (i = 0; i < AudioChannelSetSize; i++)
|
|
{
|
|
channel = channelSet.GetNth(i);
|
|
Check(channel);
|
|
channel->SendNoteOn(GetCurrentNoteValue(), midi_velocity);
|
|
}*/
|
|
patch_resource->PlayNote(channelSet);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Dynamic3DPatchSource::StopImplementation()
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
// Stop note
|
|
//
|
|
PatchResource *patch_resource;
|
|
|
|
patch_resource = Cast_Object(PatchResource*, GetAudioResource());
|
|
Check(patch_resource);
|
|
patch_resource->StopNote(channelSet);
|
|
|
|
/* AudioChannel *channel;
|
|
for (int i = 0; i < AudioChannelSetSize; i++)
|
|
{
|
|
channel = channelSet.GetNth(i);
|
|
Check(channel);
|
|
channel->SendNoteOff(GetCurrentNoteValue(), MIDI_MIN_CONTROL_VALUE);
|
|
}*/
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Dynamic3DPatchSource::ExecuteModel(Logical force_update)
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Call inherited method
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
L4AudioSource::Execute();
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Get audio resource
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
PatchResource *patch_resource;
|
|
|
|
patch_resource = Cast_Object(PatchResource*, GetAudioResource());
|
|
Check(patch_resource);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Get audio location
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
L4AudioLocation *audio_location;
|
|
L4AudioRenderer *audio_renderer;
|
|
AudioHead *audio_head;
|
|
|
|
audio_location = Cast_Object(L4AudioLocation*, GetAudioLocation());
|
|
Check(audio_location);
|
|
|
|
Check(application);
|
|
audio_renderer =
|
|
Cast_Object(L4AudioRenderer*, application->GetAudioRenderer());
|
|
Check(audio_renderer);
|
|
audio_head = audio_renderer->GetAudioHead();
|
|
Check(audio_head);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Render spatial model
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
|
|
//TODO: Sync location info to OpenAL sources
|
|
Vector3D pos;
|
|
|
|
Vector3D locationPosition = audio_location->GetLinkedEntity()->localOrigin.linearPosition;
|
|
Vector3D headPosition = audio_head->GetHeadEntity()->localOrigin.linearPosition;
|
|
|
|
pos.Subtract(locationPosition, headPosition);
|
|
|
|
float posMag = pos.Length();
|
|
|
|
pos.MultiplyByInverse(pos, audio_head->GetHeadEntity()->localToWorld);
|
|
|
|
Vector3D relative_velocity;
|
|
relative_velocity.MultiplyByInverse(
|
|
audio_location->GetLinkedEntity()->GetWorldLinearVelocity(),
|
|
audio_head->GetHeadEntity()->localToWorld
|
|
);
|
|
Check(&relative_velocity);
|
|
|
|
Scalar volume_scale = CalculateSourceVolumeScale();
|
|
|
|
Scalar pitch_offset;
|
|
|
|
pitch_offset = CalculateSourcePitchOffset();
|
|
|
|
double relativePitch = pow(2.0,pitch_offset/1200.0);
|
|
Clamp(relativePitch,0.5,2.0);
|
|
|
|
for (int i=0; i < channelSet.count; i++)
|
|
{
|
|
alSource3f(channelSet.sources[i],AL_POSITION,pos.x,pos.y,pos.z);
|
|
alSourcef(channelSet.sources[i], AL_GAIN, volume_scale);
|
|
alSource3f(channelSet.sources[i],AL_VELOCITY,-relative_velocity.x,-relative_velocity.y,-relative_velocity.z);
|
|
alSourcef(channelSet.sources[i],AL_MAX_DISTANCE,audio_location->getMaxDistance(audio_head));
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
AudioControlValue
|
|
Dynamic3DPatchSource::CalculateSourceVolumeScale()
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
// Call inherited method to calculate volume scale
|
|
//
|
|
Scalar
|
|
volume_scale = L4AudioSource::CalculateSourceVolumeScale();
|
|
return volume_scale;
|
|
|
|
//
|
|
// Update the spatial model that will result in the value
|
|
// for distance related volume attenuation
|
|
//
|
|
/*Check(application);
|
|
Check(application->GetAudioRenderer());
|
|
UpdateSpatialModel(application->GetAudioRenderer()->GetAudioHead());
|
|
|
|
//
|
|
// Apply distance attenuation to the volume scale
|
|
//
|
|
Check(GetAudioLocation());
|
|
volume_scale *= GetAudioLocation()->GetDistanceVolumeScale();
|
|
return volume_scale;*/
|
|
}
|
|
|
|
//#############################################################################
|
|
//####################### Static3DPatchSource ###########################
|
|
//#############################################################################
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
Static3DPatchSource::Static3DPatchSource(
|
|
PlugStream *stream,
|
|
Entity *entity
|
|
):
|
|
L4AudioSource(stream, entity),
|
|
position(0.0f, 0.0f, 0.0f)
|
|
{
|
|
MemoryStream_Read(stream, &useInternalSpatialization);
|
|
}
|
|
|
|
Logical Static3DPatchSource::IsAudioSourceClipped(AudioHead *audio_head)
|
|
{
|
|
if (AudioSource::IsAudioSourceClipped(audio_head) || l4_application->GetMissionPlayer()->GetPlayerVehicle()->GetSimulationState() == VTV::BurningState)
|
|
{
|
|
return true;
|
|
} else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
Static3DPatchSource::~Static3DPatchSource()
|
|
{
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Static3DPatchSource::BuildFromPage(
|
|
PlugStream *stream,
|
|
NameList *name_list,
|
|
ClassID class_ID,
|
|
ObjectID object_ID
|
|
)
|
|
{
|
|
L4AudioSource::BuildFromPage(stream, name_list, class_ID, object_ID);
|
|
|
|
if (name_list->FindData("use_internal") != NULL)
|
|
{
|
|
MEM_STRM_WRITE_ENTRY(*stream, name_list, Logical, use_internal);
|
|
}
|
|
else
|
|
{
|
|
Logical use_internal = True;
|
|
MemoryStream_Write(stream, &use_internal);
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
Logical
|
|
Static3DPatchSource::TestInstance() const
|
|
{
|
|
L4AudioSource::TestInstance();
|
|
if (useInternalSpatialization)
|
|
{
|
|
Check(&internalSpatialization);
|
|
}
|
|
return True;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Static3DPatchSource::SetPosition(const Vector3D &vector3D)
|
|
{
|
|
position = vector3D;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Static3DPatchSource::StartMessageImplementation()
|
|
{
|
|
Check(this);
|
|
|
|
L4AudioSource::StartMessageImplementation();
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Get audio renderer
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
L4AudioRenderer *audio_renderer;
|
|
|
|
Check(application);
|
|
audio_renderer =
|
|
Cast_Object(L4AudioRenderer*, application->GetAudioRenderer());
|
|
Check(audio_renderer);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Update spatial parameters
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
if (useInternalSpatialization)
|
|
{
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Calculate azimuth of position
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
Radian azimuth_of_source;
|
|
|
|
if (Small_Enough(position.x) && Small_Enough(position.z))
|
|
{
|
|
azimuth_of_source = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
Verify(!(Small_Enough(position.x) && Small_Enough(position.z)));
|
|
azimuth_of_source = Arctan(position.x, position.z);
|
|
}
|
|
Verify(azimuth_of_source <= PI && azimuth_of_source >= -PI);
|
|
|
|
internalSpatialization.CalculateSpatialization(azimuth_of_source);
|
|
}
|
|
else
|
|
{
|
|
UpdateSpatialModel(audio_renderer->GetAudioHead());
|
|
Cast_Object(L4AudioLocation*, GetAudioLocation())->GetSpatialization(
|
|
&internalSpatialization
|
|
);
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Init channel set to required channels
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
/* channelSet.EnableFrontLeft(False);
|
|
channelSet.EnableFrontRight(False);
|
|
channelSet.EnableRearLeft(False);
|
|
channelSet.EnableRearRight(False);
|
|
|
|
switch (GetQuadrant())
|
|
{
|
|
case L4AudioSpatialization::Quadrant1:
|
|
channelSet.EnableFrontLeft(True);
|
|
break;
|
|
|
|
case L4AudioSpatialization::Quadrant2:
|
|
channelSet.EnableFrontLeft(True);
|
|
channelSet.EnableRearLeft(True);
|
|
break;
|
|
|
|
case L4AudioSpatialization::Quadrant3:
|
|
channelSet.EnableRearLeft(True);
|
|
break;
|
|
|
|
case L4AudioSpatialization::Quadrant4:
|
|
channelSet.EnableFrontRight(True);
|
|
channelSet.EnableRearRight(True);
|
|
break;
|
|
}*/
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Request start from renderer
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
//audio_renderer->StartRequest(this);
|
|
(static_cast<L4AudioRenderer*>(application->GetAudioRenderer()))->StartRequest(this);
|
|
// Cast_Object(L4AudioRenderer*, application->GetAudioRenderer())->
|
|
// StartRequest(this);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Static3DPatchSource::StartImplementation()
|
|
{
|
|
Check(this);
|
|
|
|
L4AudioSource::StartImplementation();
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Get audio head constants
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
L4AudioRenderer *audio_renderer;
|
|
AudioHead *audio_head;
|
|
|
|
Check(application);
|
|
audio_renderer =
|
|
Cast_Object(L4AudioRenderer*, application->GetAudioRenderer());
|
|
Check(audio_renderer);
|
|
audio_head = audio_renderer->GetAudioHead();
|
|
Check(audio_head);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Setup the channel
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
ExecuteWatchers();
|
|
|
|
//
|
|
// Turn the volume down while setting up the channels
|
|
//
|
|
int i;
|
|
/* AudioChannel *channel;
|
|
|
|
for (i = 0; i < AudioChannelSetSize; i++)
|
|
{
|
|
if ((channel = channelSet.GetNth(i)) != NULL)
|
|
{
|
|
Check(channel);
|
|
channel->SendController(MIDI_VOLUME_CONTROL, MIDI_MIN_CONTROL_VALUE);
|
|
}
|
|
}*/
|
|
|
|
//
|
|
// Set the channels to the bank and program
|
|
//
|
|
PatchResource *patch_resource;
|
|
|
|
patch_resource = Cast_Object(PatchResource*, GetAudioResource());
|
|
Check(patch_resource);
|
|
patch_resource->SetDistance(GetDistanceToSource());
|
|
patch_resource->SetupPatch(channelSet);
|
|
/*for (i = 0; i < AudioChannelSetSize; i++)
|
|
{
|
|
if ((channel = channelSet.GetNth(i)) != NULL)
|
|
{
|
|
patch_resource->SetupPatch(channel);
|
|
}
|
|
}*/
|
|
|
|
//
|
|
// Set the channels to default control values
|
|
//
|
|
/*MIDIValue midi_reverb_level =
|
|
audio_head->GetGlobalReverbScale() *
|
|
(Scalar)MIDI_MAX_CONTROL_VALUE + 0.5f;*/
|
|
|
|
/*for (i = 0; i < AudioChannelSetSize; i++)
|
|
{
|
|
if ((channel = channelSet.GetNth(i)) != NULL)
|
|
{
|
|
Check(channel);
|
|
channel->SendController(MIDI_REVERB_CONTROL, midi_reverb_level);
|
|
channel->SendController(MIDI_CHORUS_CONTROL, MIDI_MIN_CONTROL_VALUE);
|
|
}
|
|
}*/
|
|
|
|
//
|
|
// Set the channels to correct pan
|
|
//
|
|
|
|
/*
|
|
switch (GetQuadrant())
|
|
{
|
|
case L4AudioSpatialization::Quadrant1:
|
|
{
|
|
const Radian azimuth_max =
|
|
45.0*RAD_PER_DEG; // HACK - should come from head
|
|
const Scalar slope =
|
|
-(Scalar)MIDI_MAX_CONTROL_VALUE / (2.0f * azimuth_max);
|
|
const Scalar intercept =
|
|
(MIDI_MAX_CONTROL_VALUE * 0.5f);
|
|
MIDIValue
|
|
midi_pan;
|
|
|
|
midi_pan = slope * GetAzimuthOfSource() + intercept;
|
|
Check(channelSet.GetFrontLeft());
|
|
channelSet.GetFrontLeft()->SendController(
|
|
MIDI_PAN_CONTROL,
|
|
midi_pan
|
|
);
|
|
}
|
|
break;
|
|
|
|
case L4AudioSpatialization::Quadrant2:
|
|
{
|
|
Check(channelSet.GetFrontLeft());
|
|
Check(channelSet.GetRearLeft());
|
|
channelSet.GetFrontLeft()->SendController(
|
|
MIDI_PAN_CONTROL,
|
|
MIDI_MIN_CONTROL_VALUE
|
|
);
|
|
channelSet.GetRearLeft()->SendController(
|
|
MIDI_PAN_CONTROL,
|
|
MIDI_MIN_CONTROL_VALUE
|
|
);
|
|
}
|
|
break;
|
|
|
|
case L4AudioSpatialization::Quadrant3:
|
|
{
|
|
const Radian azimuth_max =
|
|
45.0*RAD_PER_DEG; // HACK - should come from head
|
|
const Scalar slope =
|
|
(Scalar)MIDI_MAX_CONTROL_VALUE / (2.0f * azimuth_max);
|
|
const Scalar intercept =
|
|
(MIDI_MAX_CONTROL_VALUE * 0.5f);
|
|
MIDIValue
|
|
midi_pan;
|
|
|
|
midi_pan = slope * GetAzimuthOfSource() + intercept;
|
|
Check(channelSet.GetRearLeft());
|
|
channelSet.GetRearLeft()->SendController(
|
|
MIDI_PAN_CONTROL,
|
|
midi_pan
|
|
);
|
|
}
|
|
break;
|
|
|
|
case L4AudioSpatialization::Quadrant4:
|
|
{
|
|
Check(channelSet.GetFrontRight());
|
|
Check(channelSet.GetRearRight());
|
|
channelSet.GetFrontRight()->SendController(
|
|
MIDI_PAN_CONTROL,
|
|
MIDI_MAX_CONTROL_VALUE
|
|
);
|
|
channelSet.GetRearRight()->SendController(
|
|
MIDI_PAN_CONTROL,
|
|
MIDI_MAX_CONTROL_VALUE
|
|
);
|
|
}
|
|
break;
|
|
}*/
|
|
|
|
//
|
|
// Set midi history to default control values
|
|
//
|
|
/*lastFrontLeftMIDIVolume = MIDI_MIN_CONTROL_VALUE;
|
|
lastFrontRightMIDIVolume = MIDI_MIN_CONTROL_VALUE;
|
|
lastRearLeftMIDIVolume = MIDI_MIN_CONTROL_VALUE;
|
|
lastRearRightMIDIVolume = MIDI_MIN_CONTROL_VALUE;
|
|
lastMIDIPitchBend = 0; // Set by force update
|
|
lastMIDIFilterCutoff = MIDI_MAX_CONTROL_VALUE; // Set by patch
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Calculate attack time, velocity, and execute model
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
MIDIValue midi_velocity =
|
|
CalculateSourceAttackVolumeScale() *
|
|
(Scalar)MIDI_MAX_CONTROL_VALUE + 0.5f;
|
|
|
|
if (UseSourceAttackTime())
|
|
{
|
|
MIDINRPNValue midi_attack_time =
|
|
CalculateSourceAttackTime() *
|
|
(Scalar)AWE_VOL_ATTACK_TIME_RANGE + 0.5f;
|
|
|
|
for (i = 0; i < AudioChannelSetSize; i++)
|
|
{
|
|
if ((channel = channelSet.GetNth(i)) != NULL)
|
|
{
|
|
Check(channel);
|
|
channel->SendNRPN(AWE_VOL_ATTACK_TIME_NRPN, midi_attack_time);
|
|
}
|
|
}
|
|
}*/
|
|
|
|
ExecuteModel(True);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Start note
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
|
|
//TODO: Start OpenAL source playing
|
|
|
|
/*for (i = 0; i < AudioChannelSetSize; i++)
|
|
{
|
|
if ((channel = channelSet.GetNth(i)) != NULL)
|
|
{
|
|
Check(channel);
|
|
channel->SendNoteOn(GetCurrentNoteValue(), midi_velocity);
|
|
}
|
|
}*/
|
|
patch_resource->PlayNote(channelSet);
|
|
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Static3DPatchSource::StopImplementation()
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
//------------------------------------------------------------
|
|
// Stop note
|
|
//------------------------------------------------------------
|
|
//
|
|
|
|
//TODO: Stop OpenAL source playing
|
|
PatchResource *patch_resource;
|
|
|
|
patch_resource = Cast_Object(PatchResource*, GetAudioResource());
|
|
Check(patch_resource);
|
|
patch_resource->StopNote(channelSet);
|
|
|
|
/*AudioChannel *channel;
|
|
|
|
for (int i = 0; i < AudioChannelSetSize; i++)
|
|
{
|
|
if ((channel = channelSet.GetNth(i)) != NULL)
|
|
{
|
|
Check(channel);
|
|
channel->SendNoteOff(GetCurrentNoteValue(), MIDI_MIN_CONTROL_VALUE);
|
|
}
|
|
}*/
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Static3DPatchSource::ExecuteModel(Logical force_update)
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Get audio resource
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
PatchResource *patch_resource;
|
|
|
|
patch_resource = Cast_Object(PatchResource*, GetAudioResource());
|
|
Check(patch_resource);
|
|
|
|
Scalar volume_scale = CalculateSourceVolumeScale();
|
|
L4AudioLocation *audio_location = Cast_Object(L4AudioLocation*, GetAudioLocation());
|
|
Check(application);
|
|
L4AudioRenderer *audio_renderer =
|
|
Cast_Object(L4AudioRenderer*, application->GetAudioRenderer());
|
|
Check(audio_renderer);
|
|
AudioHead *audio_head = audio_renderer->GetAudioHead();
|
|
Check(audio_head);
|
|
|
|
Scalar pitch_offset;
|
|
|
|
pitch_offset = CalculateSourcePitchOffset();
|
|
double relativePitch = pow(2.0,pitch_offset/1200.0);
|
|
Clamp(relativePitch,0.5,2.0);
|
|
|
|
Vector3D relative_position;
|
|
Vector3D relative_velocity;
|
|
|
|
if (useInternalSpatialization)
|
|
{
|
|
relative_position = position;
|
|
} else
|
|
{
|
|
relative_position = audio_location->GetVectorToSource();
|
|
}
|
|
|
|
//Static models have their position freely available as relative positions and stand still
|
|
for (int i=0; i < channelSet.count; i++)
|
|
{
|
|
alSourcef(channelSet.sources[i], AL_GAIN, volume_scale);
|
|
alSource3f(channelSet.sources[i],AL_POSITION,relative_position.x,relative_position.y,relative_position.z);
|
|
alSourcef(channelSet.sources[i],AL_MAX_DISTANCE,audio_location->getMaxDistance(audio_head));
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Render spatial model
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
/*AudioChannel *front_left_channel = channelSet.GetFrontLeft();
|
|
AudioChannel *front_right_channel = channelSet.GetFrontRight();
|
|
AudioChannel *rear_left_channel = channelSet.GetRearLeft();
|
|
AudioChannel *rear_right_channel = channelSet.GetRearRight();*/
|
|
|
|
//TODO: Update spatial stuff?
|
|
|
|
//
|
|
// Apply volume scale offset
|
|
//
|
|
//Scalar volume_scale = CalculateSourceVolumeScale();
|
|
|
|
//
|
|
// Apply pitch offset and calculate MIDI pitch bend
|
|
//
|
|
/*Scalar pitch_offset;
|
|
MIDIPitchBend midi_pitch_bend;
|
|
|
|
pitch_offset = CalculateSourcePitchOffset();
|
|
midi_pitch_bend = pitch_offset * MIDI_PITCH_PER_CENTS + 0.5f;
|
|
Clamp(midi_pitch_bend, -MIDI_PITCH_BEND_MAX, MIDI_PITCH_BEND_MAX);
|
|
|
|
//
|
|
// Apply high frequency scale and calculate NRPN filter cutoff
|
|
//
|
|
Scalar filter_scale;
|
|
MIDINRPNValue max_midi_filter_cutoff;
|
|
MIDINRPNValue midi_filter_cutoff;
|
|
|
|
filter_scale = CalculateSourceBrightnessScale();
|
|
max_midi_filter_cutoff = patch_resource->GetMaxMIDIFilterCutoff();
|
|
midi_filter_cutoff = filter_scale * (Scalar)max_midi_filter_cutoff + 0.5f;
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Send pitch bend
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
const MIDIPitchBend pitch_resolution = 2;
|
|
MIDIPitchBend pitch_difference = midi_pitch_bend - lastMIDIPitchBend;
|
|
|
|
if (Abs(pitch_difference) >= pitch_resolution || force_update)
|
|
{
|
|
lastMIDIPitchBend = midi_pitch_bend;
|
|
|
|
switch (GetQuadrant())
|
|
{
|
|
case L4AudioSpatialization::Quadrant1:
|
|
Check(front_left_channel);
|
|
front_left_channel->SendPitchBend(midi_pitch_bend);
|
|
break;
|
|
|
|
case L4AudioSpatialization::Quadrant2:
|
|
Check(front_left_channel);
|
|
front_left_channel->SendPitchBend(midi_pitch_bend);
|
|
Check(rear_left_channel);
|
|
rear_left_channel->SendPitchBend(midi_pitch_bend);
|
|
break;
|
|
|
|
case L4AudioSpatialization::Quadrant3:
|
|
Check(rear_left_channel);
|
|
rear_left_channel->SendPitchBend(midi_pitch_bend);
|
|
break;
|
|
|
|
case L4AudioSpatialization::Quadrant4:
|
|
Check(front_right_channel);
|
|
front_right_channel->SendPitchBend(midi_pitch_bend);
|
|
Check(rear_right_channel);
|
|
rear_right_channel->SendPitchBend(midi_pitch_bend);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Send NRPN filter cutoff
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
if (UseSourceBrightnessScale())
|
|
{
|
|
const MIDIValue filter_resolution = 2;
|
|
MIDINRPNValue filter_difference;
|
|
|
|
filter_difference = midi_filter_cutoff - lastMIDIFilterCutoff;
|
|
|
|
if (Abs(filter_difference) >= filter_resolution)
|
|
{
|
|
lastMIDIFilterCutoff = midi_filter_cutoff;
|
|
|
|
switch (GetQuadrant())
|
|
{
|
|
case L4AudioSpatialization::Quadrant1:
|
|
Check(front_left_channel);
|
|
front_left_channel->SendNRPN(
|
|
AWE_FILTER_CUTOFF_NRPN,
|
|
midi_filter_cutoff
|
|
);
|
|
break;
|
|
|
|
case L4AudioSpatialization::Quadrant2:
|
|
Check(front_left_channel);
|
|
front_left_channel->SendNRPN(
|
|
AWE_FILTER_CUTOFF_NRPN,
|
|
midi_filter_cutoff
|
|
);
|
|
Check(rear_left_channel);
|
|
rear_left_channel->SendNRPN(
|
|
AWE_FILTER_CUTOFF_NRPN,
|
|
midi_filter_cutoff
|
|
);
|
|
break;
|
|
|
|
case L4AudioSpatialization::Quadrant3:
|
|
Check(rear_left_channel);
|
|
rear_left_channel->SendNRPN(
|
|
AWE_FILTER_CUTOFF_NRPN,
|
|
midi_filter_cutoff
|
|
);
|
|
break;
|
|
|
|
case L4AudioSpatialization::Quadrant4:
|
|
Check(front_right_channel);
|
|
front_right_channel->SendNRPN(
|
|
AWE_FILTER_CUTOFF_NRPN,
|
|
midi_filter_cutoff
|
|
);
|
|
Check(rear_right_channel);
|
|
rear_right_channel->SendNRPN(
|
|
AWE_FILTER_CUTOFF_NRPN,
|
|
midi_filter_cutoff
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Send MIDI volume
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
switch (GetQuadrant())
|
|
{
|
|
case L4AudioSpatialization::Quadrant1:
|
|
{
|
|
MIDIValue front_left_midi_volume =
|
|
volume_scale *
|
|
(Scalar)MIDI_MAX_CONTROL_VALUE + 0.5f;
|
|
|
|
if (front_left_midi_volume != lastFrontLeftMIDIVolume)
|
|
{
|
|
lastFrontLeftMIDIVolume = front_left_midi_volume;
|
|
Check(front_left_channel);
|
|
front_left_channel->SendController(
|
|
MIDI_VOLUME_CONTROL,
|
|
front_left_midi_volume
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case L4AudioSpatialization::Quadrant2:
|
|
{
|
|
MIDIValue front_left_midi_volume =
|
|
volume_scale * GetFrontLeftScale() *
|
|
(Scalar)MIDI_MAX_CONTROL_VALUE + 0.5f;
|
|
|
|
MIDIValue rear_left_midi_volume =
|
|
volume_scale * GetRearLeftScale() *
|
|
(Scalar)MIDI_MAX_CONTROL_VALUE + 0.5f;
|
|
|
|
if (front_left_midi_volume != lastFrontLeftMIDIVolume)
|
|
{
|
|
lastFrontLeftMIDIVolume = front_left_midi_volume;
|
|
Check(front_left_channel);
|
|
front_left_channel->SendController(
|
|
MIDI_VOLUME_CONTROL,
|
|
front_left_midi_volume
|
|
);
|
|
}
|
|
if (rear_left_midi_volume != lastRearLeftMIDIVolume)
|
|
{
|
|
lastRearLeftMIDIVolume = rear_left_midi_volume;
|
|
Check(rear_left_channel);
|
|
rear_left_channel->SendController(
|
|
MIDI_VOLUME_CONTROL,
|
|
rear_left_midi_volume
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case L4AudioSpatialization::Quadrant3:
|
|
{
|
|
MIDIValue rear_left_midi_volume =
|
|
volume_scale *
|
|
(Scalar)MIDI_MAX_CONTROL_VALUE + 0.5f;
|
|
|
|
if (rear_left_midi_volume != lastRearLeftMIDIVolume)
|
|
{
|
|
lastRearLeftMIDIVolume = rear_left_midi_volume;
|
|
Check(rear_left_channel);
|
|
rear_left_channel->SendController(
|
|
MIDI_VOLUME_CONTROL,
|
|
rear_left_midi_volume
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case L4AudioSpatialization::Quadrant4:
|
|
{
|
|
MIDIValue front_right_midi_volume =
|
|
volume_scale * GetFrontRightScale() *
|
|
(Scalar)MIDI_MAX_CONTROL_VALUE + 0.5f;
|
|
|
|
MIDIValue rear_right_midi_volume =
|
|
volume_scale * GetRearRightScale() *
|
|
(Scalar)MIDI_MAX_CONTROL_VALUE + 0.5f;
|
|
|
|
if (front_right_midi_volume != lastFrontRightMIDIVolume)
|
|
{
|
|
lastFrontRightMIDIVolume = front_right_midi_volume;
|
|
Check(front_right_channel);
|
|
front_right_channel->SendController(
|
|
MIDI_VOLUME_CONTROL,
|
|
front_right_midi_volume
|
|
);
|
|
}
|
|
if (rear_right_midi_volume != lastRearRightMIDIVolume)
|
|
{
|
|
lastRearRightMIDIVolume = rear_right_midi_volume;
|
|
Check(rear_right_channel);
|
|
rear_right_channel->SendController(
|
|
MIDI_VOLUME_CONTROL,
|
|
rear_right_midi_volume
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
}*/
|
|
}
|