2026-03-01 12:16:08 +08:00
# include "stdafx.h"
# include "..\..\..\Minecraft.World\net.minecraft.world.entity.h"
# include "..\..\..\Minecraft.World\Mth.h"
# include "..\..\..\Minecraft.World\Random.h"
# include "..\..\..\Minecraft.World\LevelData.h"
# include "..\..\Minecraft.h"
# include "..\..\MultiplayerLocalPlayer.h"
# include "SoundEngine.h"
# include "..\..\TexturePackRepository.h"
# include "..\..\TexturePack.h"
# include "..\..\Common\DLC\DLCAudioFile.h"
# include "..\..\DLCTexturePack.h"
IXAudio2 * g_pXAudio2 = NULL ; // pointer to XAudio2 instance used by QNet and XACT
IXAudio2MasteringVoice * g_pXAudio2MasteringVoice = NULL ; // pointer to XAudio2 mastering voice
IXACT3Engine * SoundEngine : : m_pXACT3Engine = NULL ;
IXACT3WaveBank * SoundEngine : : m_pWaveBank = NULL ;
IXACT3WaveBank * SoundEngine : : m_pWaveBank2 = NULL ;
IXACT3WaveBank * SoundEngine : : m_pStreamedWaveBank = NULL ;
IXACT3WaveBank * SoundEngine : : m_pStreamedWaveBankAdditional = NULL ;
IXACT3SoundBank * SoundEngine : : m_pSoundBank = NULL ;
IXACT3SoundBank * SoundEngine : : m_pSoundBank2 = NULL ;
CRITICAL_SECTION SoundEngine : : m_CS ;
X3DAUDIO_HANDLE SoundEngine : : m_xact3dInstance ;
vector < SoundEngine : : soundInfo * > SoundEngine : : currentSounds ;
X3DAUDIO_DSP_SETTINGS SoundEngine : : m_DSPSettings ;
X3DAUDIO_EMITTER SoundEngine : : m_emitter ;
X3DAUDIO_LISTENER SoundEngine : : m_listeners [ 4 ] ;
int SoundEngine : : m_validListenerCount = 0 ;
X3DAUDIO_DISTANCE_CURVE_POINT SoundEngine : : m_VolumeCurvePoints [ 2 ] = {
{ 0.0f , 1.0f } ,
{ 1.0f , 0.0f } ,
} ;
X3DAUDIO_DISTANCE_CURVE_POINT SoundEngine : : m_DragonVolumeCurvePoints [ 2 ] = {
{ 0.0f , 1.0f } ,
{ 1.0f , 0.5f } ,
} ;
X3DAUDIO_DISTANCE_CURVE_POINT SoundEngine : : m_VolumeCurvePointsNoDecay [ 2 ] = {
{ 0.0f , 1.0f } ,
{ 1.0f , 1.0f } ,
} ;
X3DAUDIO_DISTANCE_CURVE SoundEngine : : m_VolumeCurve ;
X3DAUDIO_DISTANCE_CURVE SoundEngine : : m_DragonVolumeCurve ;
X3DAUDIO_DISTANCE_CURVE SoundEngine : : m_VolumeCurveNoDecay ;
void SoundEngine : : setXACTEngine ( IXACT3Engine * pXACT3Engine )
{
m_pXACT3Engine = pXACT3Engine ;
}
void SoundEngine : : destroy ( )
{
}
SoundEngine : : SoundEngine ( )
{
random = new Random ( ) ;
noMusicDelay = random - > nextInt ( 20 * 60 * 10 ) ;
ZeroMemory ( & m_MusicInfo , sizeof ( soundInfo ) ) ;
//bIsPlayingStreamingCDMusic=false;
//m_bIsPlayingStreamingGameMusic=false;
SetIsPlayingEndMusic ( false ) ;
SetIsPlayingNetherMusic ( false ) ;
m_VolumeCurve . PointCount = 2 ;
m_VolumeCurve . pPoints = m_VolumeCurvePoints ;
m_DragonVolumeCurve . PointCount = 2 ;
m_DragonVolumeCurve . pPoints = m_DragonVolumeCurvePoints ;
m_VolumeCurveNoDecay . PointCount = 2 ;
m_VolumeCurveNoDecay . pPoints = m_VolumeCurvePointsNoDecay ;
m_bStreamingMusicReady = false ;
m_bStreamingWaveBank1Ready = false ;
m_bStreamingWaveBank2Ready = false ;
}
void SoundEngine : : init ( Options * pOptions )
{
InitializeCriticalSection ( & m_CS ) ;
// Iniatialise XACT itself
HRESULT hr ;
if ( FAILED ( hr = XACT3CreateEngine ( 0 , & m_pXACT3Engine ) ) )
{
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
// Load global settings file
// 4J-PB - move this to the title update, since we've corrected it to allow sounds to be pitch varied when they weren't before
HANDLE file ;
# ifdef _TU_BUILD
file = CreateFile ( " UPDATE: \\ res \\ audio \\ Minecraft.xgs " , GENERIC_READ , 0 , NULL , OPEN_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
# else
file = CreateFile ( " GAME: \\ res \\ TitleUpdate \\ audio \\ Minecraft.xgs " , GENERIC_READ , 0 , NULL , OPEN_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
# endif
if ( file = = INVALID_HANDLE_VALUE )
{
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
DWORD dwFileSize = GetFileSize ( file , NULL ) ;
DWORD bytesRead = 0 ;
DWORD memFlags = MAKE_XALLOC_ATTRIBUTES ( 0 , FALSE , TRUE , FALSE , 0 , XALLOC_PHYSICAL_ALIGNMENT_DEFAULT , XALLOC_MEMPROTECT_READWRITE , FALSE , XALLOC_MEMTYPE_PHYSICAL ) ;
void * pvGlobalSettings = XMemAlloc ( dwFileSize , memFlags ) ;
ReadFile ( file , pvGlobalSettings , dwFileSize , & bytesRead , NULL ) ;
CloseHandle ( file ) ;
XACT_RUNTIME_PARAMETERS EngineParameters = { 0 } ;
EngineParameters . lookAheadTime = XACT_ENGINE_LOOKAHEAD_DEFAULT ;
EngineParameters . fnNotificationCallback = & this - > XACTNotificationCallback ;
EngineParameters . pGlobalSettingsBuffer = pvGlobalSettings ;
EngineParameters . globalSettingsBufferSize = dwFileSize ;
EngineParameters . globalSettingsFlags = XACT_FLAG_GLOBAL_SETTINGS_MANAGEDATA ;
EngineParameters . pXAudio2 = g_pXAudio2 ;
EngineParameters . pMasteringVoice = g_pXAudio2MasteringVoice ;
if ( FAILED ( hr = m_pXACT3Engine - > Initialize ( & EngineParameters ) ) )
{
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
// printf("XACT initialisation complete\n");
// Initialise X3D
XACT3DInitialize ( m_pXACT3Engine , m_xact3dInstance ) ;
// Set up common structures that can be re-used between sounds & just have required bits updated
memset ( & m_DSPSettings , 0 , sizeof ( X3DAUDIO_DSP_SETTINGS ) ) ;
WAVEFORMATEXTENSIBLE format ;
m_pXACT3Engine - > GetFinalMixFormat ( & format ) ;
m_DSPSettings . SrcChannelCount = 1 ;
m_DSPSettings . DstChannelCount = format . Format . nChannels ;
// printf("%d channels\n", format.Format.nChannels);
m_DSPSettings . pMatrixCoefficients = new FLOAT32 [ m_DSPSettings . SrcChannelCount * m_DSPSettings . DstChannelCount ] ;
for ( int i = 0 ; i < 4 ; i + + )
{
memset ( & m_listeners [ i ] , 0 , sizeof ( X3DAUDIO_LISTENER ) ) ;
m_listeners [ i ] . OrientFront . z = 1.0f ;
m_listeners [ i ] . OrientTop . y = 1.0f ;
}
m_validListenerCount = 1 ;
memset ( & m_emitter , 0 , sizeof ( X3DAUDIO_EMITTER ) ) ;
m_emitter . ChannelCount = 1 ;
m_emitter . pVolumeCurve = & m_VolumeCurve ;
m_emitter . pLFECurve = & m_VolumeCurve ;
m_emitter . CurveDistanceScaler = 16.0f ;
m_emitter . OrientFront . z = 1.0f ;
m_emitter . OrientTop . y = 1.0f ;
// Create resident wave bank - leave memory for this managed by xact so it can free it
file = CreateFile ( " GAME: \\ res \\ audio \\ resident.xwb " , GENERIC_READ , 0 , NULL , OPEN_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
if ( file = = INVALID_HANDLE_VALUE )
{
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
dwFileSize = GetFileSize ( file , NULL ) ;
void * pvWaveBank = XMemAlloc ( dwFileSize , memFlags ) ;
ReadFile ( file , pvWaveBank , dwFileSize , & bytesRead , NULL ) ;
CloseHandle ( file ) ;
if ( FAILED ( hr = m_pXACT3Engine - > CreateInMemoryWaveBank ( pvWaveBank , dwFileSize , XACT_FLAG_ENGINE_CREATE_MANAGEDATA , memFlags , & m_pWaveBank ) ) )
{
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
// 4J-PB - add new sounds wavebank
# ifdef _TU_BUILD
file = CreateFile ( " UPDATE: \\ res \\ audio \\ additional.xwb " , GENERIC_READ , 0 , NULL , OPEN_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
# else
file = CreateFile ( " GAME: \\ res \\ TitleUpdate \\ audio \\ additional.xwb " , GENERIC_READ , 0 , NULL , OPEN_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
# endif
if ( file = = INVALID_HANDLE_VALUE )
{
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
dwFileSize = GetFileSize ( file , NULL ) ;
void * pvWaveBank2 = XMemAlloc ( dwFileSize , memFlags ) ;
ReadFile ( file , pvWaveBank2 , dwFileSize , & bytesRead , NULL ) ;
CloseHandle ( file ) ;
if ( FAILED ( hr = m_pXACT3Engine - > CreateInMemoryWaveBank ( pvWaveBank2 , dwFileSize , XACT_FLAG_ENGINE_CREATE_MANAGEDATA , memFlags , & m_pWaveBank2 ) ) )
{
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
// Create streamed sound bank
file = CreateFile ( " GAME: \\ res \\ audio \\ streamed.xwb " , GENERIC_READ , 0 , NULL , OPEN_ALWAYS , FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING , NULL ) ;
if ( file = = INVALID_HANDLE_VALUE )
{
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
XACT_WAVEBANK_STREAMING_PARAMETERS streamParams ;
streamParams . file = file ;
streamParams . offset = 0 ;
streamParams . flags = 0 ;
streamParams . packetSize = 16 ; // Not sure what to pick for this - suggests a "multiple of 16" for DVD playback
if ( FAILED ( hr = m_pXACT3Engine - > CreateStreamingWaveBank ( & streamParams , & m_pStreamedWaveBank ) ) )
{
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
// Create streamed sound bank
//file = CreateFile("GAME:\\res\\audio\\AdditionalMusic.xwb", GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL);
# ifdef _TU_BUILD
file = CreateFile ( " UPDATE: \\ res \\ audio \\ AdditionalMusic.xwb " , GENERIC_READ , 0 , NULL , OPEN_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
# else
file = CreateFile ( " GAME: \\ res \\ TitleUpdate \\ audio \\ AdditionalMusic.xwb " , GENERIC_READ , 0 , NULL , OPEN_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
# endif
if ( file = = INVALID_HANDLE_VALUE )
{
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
streamParams . file = file ;
streamParams . offset = 0 ;
streamParams . flags = 0 ;
streamParams . packetSize = 16 ; // Not sure what to pick for this - suggests a "multiple of 16" for DVD playback
if ( FAILED ( hr = m_pXACT3Engine - > CreateStreamingWaveBank ( & streamParams , & m_pStreamedWaveBankAdditional ) ) )
{
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
// Create sound bank - leave memory for this managed by xact so it can free it
// 4J-PB - updated for the TU
//file = CreateFile("GAME:\\res\\audio\\minecraft.xsb", GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
# ifdef _TU_BUILD
file = CreateFile ( " UPDATE: \\ res \\ audio \\ minecraft.xsb " , GENERIC_READ , 0 , NULL , OPEN_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
# else
file = CreateFile ( " GAME: \\ res \\ TitleUpdate \\ audio \\ minecraft.xsb " , GENERIC_READ , 0 , NULL , OPEN_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
# endif
if ( file = = INVALID_HANDLE_VALUE )
{
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
dwFileSize = GetFileSize ( file , NULL ) ;
void * pvSoundBank = XMemAlloc ( dwFileSize , memFlags ) ;
ReadFile ( file , pvSoundBank , dwFileSize , & bytesRead , NULL ) ;
CloseHandle ( file ) ;
if ( FAILED ( hr = m_pXACT3Engine - > CreateSoundBank ( pvSoundBank , dwFileSize , XACT_FLAG_ENGINE_CREATE_MANAGEDATA , memFlags , & m_pSoundBank ) ) )
{
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
// Create sound bank2 - leave memory for this managed by xact so it can free it
# ifdef _TU_BUILD
file = CreateFile ( " UPDATE: \\ res \\ audio \\ additional.xsb " , GENERIC_READ , 0 , NULL , OPEN_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
# else
file = CreateFile ( " GAME: \\ res \\ TitleUpdate \\ audio \\ additional.xsb " , GENERIC_READ , 0 , NULL , OPEN_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
# endif
if ( file = = INVALID_HANDLE_VALUE )
{
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
dwFileSize = GetFileSize ( file , NULL ) ;
void * pvSoundBank2 = XMemAlloc ( dwFileSize , memFlags ) ;
ReadFile ( file , pvSoundBank2 , dwFileSize , & bytesRead , NULL ) ;
CloseHandle ( file ) ;
if ( FAILED ( hr = m_pXACT3Engine - > CreateSoundBank ( pvSoundBank2 , dwFileSize , XACT_FLAG_ENGINE_CREATE_MANAGEDATA , memFlags , & m_pSoundBank2 ) ) )
{
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
XACT_NOTIFICATION_DESCRIPTION desc = { 0 } ;
desc . flags = XACT_FLAG_NOTIFICATION_PERSIST ;
desc . type = XACTNOTIFICATIONTYPE_WAVEBANKPREPARED ;
desc . pvContext = this ;
m_pXACT3Engine - > RegisterNotification ( & desc ) ;
// get the category to manage the sfx (Default)
m_xactSFX = m_pXACT3Engine - > GetCategory ( " Default " ) ;
m_xactMusic = m_pXACT3Engine - > GetCategory ( " Music " ) ;
}
void SoundEngine : : CreateStreamingWavebank ( const char * pchName , IXACT3WaveBank * * ppStreamedWaveBank )
{
// Create streamed sound bank
HRESULT hr ;
HANDLE file = CreateFile ( pchName , GENERIC_READ , 0 , NULL , OPEN_ALWAYS , FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING , NULL ) ;
if ( file = = INVALID_HANDLE_VALUE )
2026-03-02 17:37:16 +07:00
{
2026-03-01 12:16:08 +08:00
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
XACT_WAVEBANK_STREAMING_PARAMETERS streamParams ;
streamParams . file = file ;
streamParams . offset = 0 ;
streamParams . flags = 0 ;
streamParams . packetSize = 16 ; // Not sure what to pick for this - suggests a "multiple of 16" for DVD playback
if ( FAILED ( hr = m_pXACT3Engine - > CreateStreamingWaveBank ( & streamParams , ppStreamedWaveBank ) ) )
{
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
}
void SoundEngine : : CreateSoundbank ( const char * pchName , IXACT3SoundBank * * ppSoundBank )
{
HRESULT hr ;
HANDLE file = CreateFile ( pchName , GENERIC_READ , 0 , NULL , OPEN_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
if ( file = = INVALID_HANDLE_VALUE )
{
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
DWORD dwFileSize = GetFileSize ( file , NULL ) ;
DWORD bytesRead = 0 ;
DWORD memFlags = MAKE_XALLOC_ATTRIBUTES ( 0 , FALSE , TRUE , FALSE , 0 , XALLOC_PHYSICAL_ALIGNMENT_DEFAULT , XALLOC_MEMPROTECT_READWRITE , FALSE , XALLOC_MEMTYPE_PHYSICAL ) ;
void * pvSoundBank = XMemAlloc ( dwFileSize , memFlags ) ;
ReadFile ( file , pvSoundBank , dwFileSize , & bytesRead , NULL ) ;
CloseHandle ( file ) ;
if ( FAILED ( hr = m_pXACT3Engine - > CreateSoundBank ( pvSoundBank , dwFileSize , XACT_FLAG_ENGINE_CREATE_MANAGEDATA , memFlags , ppSoundBank ) ) )
{
app . FatalLoadError ( ) ;
assert ( false ) ;
return ;
}
}
bool SoundEngine : : isStreamingWavebankReady ( )
{
if ( m_bStreamingMusicReady = = false )
{
DWORD dwState ;
m_pSoundBank - > GetState ( & dwState ) ;
if ( dwState & XACT_WAVEBANKSTATE_PREPARED )
{
m_bStreamingWaveBank1Ready = true ;
}
m_pSoundBank2 - > GetState ( & dwState ) ;
if ( dwState & XACT_WAVEBANKSTATE_PREPARED )
{
m_bStreamingWaveBank2Ready = true ;
}
if ( m_bStreamingWaveBank1Ready & & m_bStreamingWaveBank2Ready )
{
m_bStreamingMusicReady = true ;
}
}
return m_bStreamingMusicReady ;
}
# ifdef _XBOX
bool SoundEngine : : isStreamingWavebankReady ( IXACT3WaveBank * pWaveBank )
{
DWORD dwState ;
pWaveBank - > GetState ( & dwState ) ;
if ( dwState & XACT_WAVEBANKSTATE_PREPARED )
{
return true ;
}
else
{
return false ;
}
}
# endif
void SoundEngine : : XACTNotificationCallback ( const XACT_NOTIFICATION * pNotification )
{
if ( pNotification - > pvContext ! = NULL )
{
if ( pNotification - > type = = XACTNOTIFICATIONTYPE_WAVEBANKPREPARED )
{
SoundEngine * pSoundEngine = ( SoundEngine * ) pNotification - > pvContext ;
if ( pNotification - > waveBank . pWaveBank = = pSoundEngine - > m_pStreamedWaveBank )
{
pSoundEngine - > m_bStreamingWaveBank1Ready = true ;
}
if ( pNotification - > waveBank . pWaveBank = = pSoundEngine - > m_pStreamedWaveBankAdditional )
{
pSoundEngine - > m_bStreamingWaveBank2Ready = true ;
}
if ( pSoundEngine - > m_bStreamingWaveBank1Ready & & pSoundEngine - > m_bStreamingWaveBank2Ready )
{
pSoundEngine - > m_bStreamingMusicReady = true ;
}
}
}
}
char * SoundEngine : : ConvertSoundPathToName ( const wstring & name , bool bConvertSpaces )
{
static char buf [ 256 ] ;
assert ( name . length ( ) < 256 ) ;
for ( unsigned int i = 0 ; i < name . length ( ) ; i + + )
{
wchar_t c = name [ i ] ;
if ( c = = ' . ' ) c = ' _ ' ;
buf [ i ] = ( char ) c ;
}
buf [ name . length ( ) ] = 0 ;
return buf ;
}
void SoundEngine : : play ( int iSound , float x , float y , float z , float volume , float pitch )
{
if ( iSound = = - 1 )
{
app . DebugPrintf ( 6 , " PlaySound with sound of -1 !!!!!!!!!!!!!!! \n " ) ;
return ;
}
bool bSoundbank1 = ( iSound < = eSoundType_STEP_SAND ) ;
if ( ( m_pSoundBank = = NULL ) | | ( m_pSoundBank2 = = NULL ) ) return ;
if ( currentSounds . size ( ) > MAX_POLYPHONY )
{
return ;
}
wstring name = wchSoundNames [ iSound ] ;
//const unsigned char *name=ucSoundNames[iSound];
char * xboxName = ConvertSoundPathToName ( name ) ;
XACTINDEX idx ;
if ( bSoundbank1 )
{
idx = m_pSoundBank - > GetCueIndex ( xboxName ) ;
}
else
{
idx = m_pSoundBank2 - > GetCueIndex ( xboxName ) ;
}
if ( idx = = XACTINDEX_INVALID )
{
# ifndef _CONTENT_PACKAGE
# ifdef _DEBUG
__debugbreak ( ) ;
# endif
//wprintf(L"WARNING: Sound cue not found - %ls\n", name.c_str() );
app . DebugPrintf ( " Not found: %s \n " , xboxName ) ;
# endif
return ;
}
// 4J-PB - check how many of this cue are already playing and ignore if there are loads
int iSameSoundC = 0 ;
for ( unsigned int i = 0 ; i < currentSounds . size ( ) ; i + + )
{
SoundEngine : : soundInfo * info = currentSounds [ i ] ;
if ( ( info - > idx = = idx ) & & ( info - > iSoundBank = = ( bSoundbank1 ? 0 : 1 ) ) )
{
iSameSoundC + + ;
}
}
if ( iSameSoundC > MAX_SAME_SOUNDS_PLAYING )
{
return ;
}
IXACT3Cue * cueInstance ;
HRESULT hr ;
MemSect ( 31 ) ;
if ( bSoundbank1 )
{
if ( FAILED ( hr = m_pSoundBank - > Prepare ( idx , 0 , 0 , & cueInstance ) ) )
{
MemSect ( 0 ) ;
// printf("Sound prep failed\n");
return ;
}
}
else
{
if ( FAILED ( hr = m_pSoundBank2 - > Prepare ( idx , 0 , 0 , & cueInstance ) ) )
{
MemSect ( 0 ) ;
// printf("Sound prep failed\n");
return ;
}
}
MemSect ( 0 ) ;
// Register to receive callbacks for cues stopping so we can keep a track of active sounds
soundInfo * info = new soundInfo ( ) ;
info - > idx = idx ;
info - > eSoundID = ( eSOUND_TYPE ) iSound ;
info - > iSoundBank = bSoundbank1 ? 0 : 1 ;
info - > x = x ;
info - > y = y ;
info - > z = z ;
info - > volume = volume ; //*m_fSoundEffectsVolume;
info - > pitch = pitch ;
info - > pCue = cueInstance ;
info - > updatePos = true ;
EnterCriticalSection ( & m_CS ) ;
currentSounds . push_back ( info ) ;
LeaveCriticalSection ( & m_CS ) ;
XACTVARIABLEINDEX vidx = cueInstance - > GetVariableIndex ( " Pitch " ) ;
if ( vidx ! = XACTVARIABLEINDEX_INVALID )
{
// Convert pitch multiplier to semitones
float semiTones = ( log ( pitch ) / log ( 2.0f ) ) * 12.0f ;
cueInstance - > SetVariable ( vidx , semiTones ) ;
}
update3DPosition ( info ) ;
cueInstance - > Play ( ) ;
}
void SoundEngine : : playUI ( int iSound , float , float )
{
bool bSoundBank1 = ( iSound < = eSoundType_STEP_SAND ) ;
if ( ( m_pSoundBank = = NULL ) | | ( m_pSoundBank2 = = NULL ) ) return ;
if ( currentSounds . size ( ) > MAX_POLYPHONY )
{
return ;
}
wstring name = wchSoundNames [ iSound ] ;
char * xboxName = ( char * ) ConvertSoundPathToName ( name ) ;
XACTINDEX idx = m_pSoundBank - > GetCueIndex ( xboxName ) ;
if ( idx = = XACTINDEX_INVALID )
{
// check soundbank 2
idx = m_pSoundBank2 - > GetCueIndex ( xboxName ) ;
if ( idx = = XACTINDEX_INVALID )
{
# ifndef _CONTENT_PACKAGE
printf ( " Not found UI: %s \n " , xboxName ) ;
# endif
return ;
}
bSoundBank1 = false ;
}
IXACT3Cue * cueInstance ;
HRESULT hr ;
if ( bSoundBank1 )
{
if ( FAILED ( hr = m_pSoundBank - > Prepare ( idx , 0 , 0 , & cueInstance ) ) )
{
// printf("Sound prep failed\n");
return ;
}
}
else
{
if ( FAILED ( hr = m_pSoundBank2 - > Prepare ( idx , 0 , 0 , & cueInstance ) ) )
{
// printf("Sound prep failed\n");
return ;
}
}
// Add sound info just so we can detect end of this sound
soundInfo * info = new soundInfo ( ) ;
info - > eSoundID = ( eSOUND_TYPE ) 0 ;
info - > iSoundBank = bSoundBank1 ? 0 : 1 ;
info - > idx = idx ;
info - > x = 0.0f ;
info - > y = 0.0f ;
info - > z = 0.0f ;
info - > volume = 0.0f ;
info - > pitch = 0.0f ;
info - > pCue = cueInstance ;
info - > updatePos = false ;
EnterCriticalSection ( & m_CS ) ;
currentSounds . push_back ( info ) ;
LeaveCriticalSection ( & m_CS ) ;
cueInstance - > Play ( ) ;
}
void SoundEngine : : playStreaming ( const wstring & name , float x , float y , float z , float vol , float pitch , bool bMusicDelay )
{
IXACT3SoundBank * pSoundBank = NULL ;
2026-03-02 17:37:16 +07:00
2026-03-01 12:16:08 +08:00
bool bSoundBank2 = false ;
MemSect ( 34 ) ;
if ( m_MusicInfo . pCue ! = NULL )
{
m_MusicInfo . pCue - > Stop ( 0 ) ;
m_MusicInfo . pCue - > Destroy ( ) ;
m_MusicInfo . pCue = NULL ;
}
m_MusicInfo . volume = 1.0f ; //m_fMusicVolume;
m_MusicInfo . pitch = 1.0f ;
SetIsPlayingEndMusic ( false ) ;
SetIsPlayingNetherMusic ( false ) ;
if ( name . empty ( ) )
{
SetIsPlayingStreamingCDMusic ( false ) ;
SetIsPlayingStreamingGameMusic ( false ) ; // will be set to true when the sound is started in the tick
if ( bMusicDelay )
{
noMusicDelay = random - > nextInt ( 20 * 60 * 10 ) + 20 * 60 * 10 ;
}
else
{
noMusicDelay = 0 ;
}
// Check if we have a local player in The Nether or in The End, and play that music if they are
Minecraft * pMinecraft = Minecraft : : GetInstance ( ) ;
bool playerInEnd = false ;
bool playerInNether = false ;
for ( unsigned int i = 0 ; i < XUSER_MAX_COUNT ; i + + )
{
if ( pMinecraft - > localplayers [ i ] ! = NULL )
{
if ( pMinecraft - > localplayers [ i ] - > dimension = = LevelData : : DIMENSION_END )
{
playerInEnd = true ;
}
else if ( pMinecraft - > localplayers [ i ] - > dimension = = LevelData : : DIMENSION_NETHER )
{
playerInNether = true ;
}
}
}
TexturePack * pTexPack = Minecraft : : GetInstance ( ) - > skins - > getSelected ( ) ;
if ( Minecraft : : GetInstance ( ) - > skins - > isUsingDefaultSkin ( ) | | pTexPack - > hasAudio ( ) = = false )
{
if ( playerInEnd | | playerInNether )
{
pSoundBank = m_pSoundBank2 ;
}
else
{
pSoundBank = m_pSoundBank ;
}
}
else
{
// get the dlc texture pack
DLCTexturePack * pDLCTexPack = ( DLCTexturePack * ) pTexPack ;
pSoundBank = pDLCTexPack - > m_pSoundBank ;
// check we can play the sound
if ( isStreamingWavebankReady ( pDLCTexPack - > m_pStreamedWaveBank ) = = false )
{
return ;
}
}
if ( playerInEnd )
{
m_musicIDX = pSoundBank - > GetCueIndex ( " the_end_dragon " ) ;
SetIsPlayingEndMusic ( true ) ;
bSoundBank2 = true ;
}
else if ( playerInNether )
{
m_musicIDX = pSoundBank - > GetCueIndex ( " nether " ) ;
SetIsPlayingNetherMusic ( true ) ;
bSoundBank2 = true ;
}
else
{
m_musicIDX = pSoundBank - > GetCueIndex ( " music " ) ;
}
}
else
{
pSoundBank = m_pSoundBank ;
SetIsPlayingStreamingCDMusic ( true ) ;
SetIsPlayingStreamingGameMusic ( false ) ;
m_musicIDX = pSoundBank - > GetCueIndex ( ConvertSoundPathToName ( name ) ) ;
}
HRESULT hr ;
if ( FAILED ( hr = pSoundBank - > Prepare ( m_musicIDX , 0 , 0 , & m_MusicInfo . pCue ) ) )
{
// printf("Sound prep failed\n");
m_musicIDX = XACTINDEX_INVALID ; // don't do anything in the tick
m_MusicInfo . pCue = NULL ;
MemSect ( 0 ) ;
return ;
}
2026-03-02 17:37:16 +07:00
2026-03-01 12:16:08 +08:00
if ( GetIsPlayingStreamingCDMusic ( ) )
{
m_MusicInfo . x = x ;
m_MusicInfo . y = y ;
m_MusicInfo . z = z ;
m_MusicInfo . updatePos = true ;
update3DPosition ( & m_MusicInfo , false ) ;
m_MusicInfo . pCue - > Play ( ) ;
}
else
{
// don't play the game music - it will start playing in the tick when noMusicDelay is 0
m_MusicInfo . x = 0.0f ; // will be overridden by the bPlaceEmitterAtListener
m_MusicInfo . y = 0.0f ; // will be overridden by the bPlaceEmitterAtListener
m_MusicInfo . z = 0.0f ; // will be overridden by the bPlaceEmitterAtListener
m_MusicInfo . updatePos = false ;
update3DPosition ( & m_MusicInfo , true ) ;
}
MemSect ( 0 ) ;
}
void SoundEngine : : playMusicTick ( )
{
if ( ( m_pSoundBank = = NULL ) | | ( m_pSoundBank2 = = NULL ) ) return ;
if ( m_musicIDX = = XACTINDEX_INVALID )
{
// printf("Not found music\n");
return ;
}
// check to see if the sound has stopped playing
DWORD state ;
HRESULT hr ;
if ( m_MusicInfo . pCue ! = NULL )
{
if ( FAILED ( hr = m_MusicInfo . pCue - > GetState ( & state ) ) )
{
assert ( false ) ;
}
else
{
if ( state = = XACT_CUESTATE_STOPPED )
{
// remove the sound and reset the music
playStreaming ( L " " , 0 , 0 , 0 , 0 , 0 ) ;
return ;
}
}
}
if ( GetIsPlayingStreamingGameMusic ( ) )
{
if ( m_MusicInfo . pCue ! = NULL )
{
bool playerInEnd = false ;
bool playerInNether = false ;
Minecraft * pMinecraft = Minecraft : : GetInstance ( ) ;
for ( unsigned int i = 0 ; i < XUSER_MAX_COUNT ; + + i )
{
if ( pMinecraft - > localplayers [ i ] ! = NULL )
{
if ( pMinecraft - > localplayers [ i ] - > dimension = = LevelData : : DIMENSION_END )
{
playerInEnd = true ;
}
else if ( pMinecraft - > localplayers [ i ] - > dimension = = LevelData : : DIMENSION_NETHER )
{
playerInNether = true ;
}
}
}
if ( ( playerInEnd & & ! GetIsPlayingEndMusic ( ) ) | | ( ! playerInEnd & & GetIsPlayingEndMusic ( ) ) )
{
// remove the sound and reset the music
playStreaming ( L " " , 0 , 0 , 0 , 0 , 0 ) ;
}
else if ( ( playerInNether & & ! GetIsPlayingNetherMusic ( ) ) | | ( ! playerInNether & & GetIsPlayingNetherMusic ( ) ) )
{
// remove the sound and reset the music
playStreaming ( L " " , 0 , 0 , 0 , 0 , 0 ) ;
}
}
// not positional so doesn't need ticked
return ;
}
// is this cd music? If so, we need to tick it
if ( GetIsPlayingStreamingCDMusic ( ) )
{
update3DPosition ( & m_MusicInfo , false , true ) ;
}
else
{
if ( noMusicDelay > 0 )
{
noMusicDelay - - ;
return ;
}
if ( m_MusicInfo . pCue ! = NULL )
{
update3DPosition ( & m_MusicInfo , true ) ;
SetIsPlayingStreamingGameMusic ( true ) ;
// and play the game music here
m_MusicInfo . pCue - > Play ( ) ;
}
}
}
void SoundEngine : : updateMusicVolume ( float fVal )
{
XACTVOLUME xactVol = fVal ;
HRESULT hr = m_pXACT3Engine - > SetVolume ( m_xactMusic , fVal ) ;
}
void SoundEngine : : updateSystemMusicPlaying ( bool isPlaying )
{
}
void SoundEngine : : updateSoundEffectVolume ( float fVal )
{
XACTVOLUME xactVol = fVal ;
HRESULT hr = m_pXACT3Engine - > SetVolume ( m_xactSFX , fVal ) ;
}
void SoundEngine : : update3DPosition ( SoundEngine : : soundInfo * pInfo , bool bPlaceEmitterAtListener , bool bIsCDMusic )
{
X3DAUDIO_LISTENER * listener = & m_listeners [ 0 ] ; // Default case for single listener
if ( ( m_validListenerCount > 1 ) & & ! bPlaceEmitterAtListener )
{
// More than one listener. Find out which one is closest
float nearDistSq = ( listener - > Position . x - pInfo - > x ) * ( listener - > Position . x - pInfo - > x ) +
( listener - > Position . y - pInfo - > y ) * ( listener - > Position . y - pInfo - > y ) +
( listener - > Position . z + pInfo - > z ) * ( listener - > Position . z + pInfo - > z ) ;
for ( int i = 1 ; i < m_validListenerCount ; i + + )
{
float distSq = ( m_listeners [ i ] . Position . x - pInfo - > x ) * ( m_listeners [ i ] . Position . x - pInfo - > x ) +
( m_listeners [ i ] . Position . y - pInfo - > y ) * ( m_listeners [ i ] . Position . y - pInfo - > y ) +
( m_listeners [ i ] . Position . z + pInfo - > z ) * ( m_listeners [ i ] . Position . z + pInfo - > z ) ;
if ( distSq < nearDistSq )
{
listener = & m_listeners [ i ] ;
nearDistSq = distSq ;
}
}
// More than one listener, don't do directional sounds - point our listener towards the sound
float xzDist = sqrtf ( ( listener - > Position . x - pInfo - > x ) * ( listener - > Position . x - pInfo - > x ) +
( listener - > Position . z + pInfo - > z ) * ( listener - > Position . z + pInfo - > z ) ) ;
// Don't orientate if its too near to work out a distance
if ( xzDist > 0.001f )
{
listener - > OrientFront . x = ( pInfo - > x - listener - > Position . x ) / xzDist ;
listener - > OrientFront . y = 0.0f ;
listener - > OrientFront . z = ( - pInfo - > z - listener - > Position . z ) / xzDist ;
}
}
if ( bPlaceEmitterAtListener )
{
m_emitter . Position . x = listener - > Position . x ;
m_emitter . Position . y = listener - > Position . y ;
m_emitter . Position . z = listener - > Position . z ;
}
else
{
// Update the position of the emitter - we aren't dynamically changing anything else
m_emitter . Position . x = pInfo - > x ;
m_emitter . Position . y = pInfo - > y ;
m_emitter . Position . z = - pInfo - > z ; // Flipped sign of z as x3daudio is expecting left handed coord system
}
// If this is the CD music, then make the distance scaler 4 x normal
if ( bIsCDMusic )
{
m_emitter . CurveDistanceScaler = 64.0f ;
}
else
{
switch ( pInfo - > eSoundID )
{
// Is this the Dragon?
case eSoundType_MOB_ENDERDRAGON_GROWL :
case eSoundType_MOB_ENDERDRAGON_MOVE :
case eSoundType_MOB_ENDERDRAGON_END :
case eSoundType_MOB_ENDERDRAGON_HIT :
m_emitter . CurveDistanceScaler = 100.0f ;
break ;
case eSoundType_MOB_GHAST_MOAN :
case eSoundType_MOB_GHAST_SCREAM :
case eSoundType_MOB_GHAST_DEATH :
case eSoundType_MOB_GHAST_CHARGE :
case eSoundType_MOB_GHAST_FIREBALL :
m_emitter . CurveDistanceScaler = 30.0f ;
break ;
}
}
// 10000.0f is passed as the volume for thunder... treat this as a special case, and use a volume curve that doesn't decay with distance
// rather than just trying to guess at making something really really loud...
if ( pInfo - > volume = = 10000.0f )
{
m_emitter . pVolumeCurve = & m_VolumeCurveNoDecay ;
}
else
{
m_emitter . pVolumeCurve = & m_VolumeCurve ;
}
// Calculate all the 3D things
XACT3DCalculate ( m_xact3dInstance , listener , & m_emitter , & m_DSPSettings ) ;
// Put volume curve back to default in case something else is depending on this
m_emitter . pVolumeCurve = & m_VolumeCurve ;
//m_emitter.pLFECurve = &m_VolumeCurve;
m_emitter . CurveDistanceScaler = 16.0f ;
// Apply our general volume too by scaling the calculated coefficients - so long as this isn't our special case of 10000.0f (see comment above)
if ( pInfo - > volume ! = 10000.0f )
{
for ( unsigned int i = 0 ; i < m_DSPSettings . DstChannelCount ; i + + )
{
m_DSPSettings . pMatrixCoefficients [ i ] * = pInfo - > volume ;
}
}
// Finally apply to the cue
XACT3DApply ( & m_DSPSettings , pInfo - > pCue ) ;
}
2026-03-02 17:37:16 +07:00
void SoundEngine : : tick ( shared_ptr < Mob > * players , float a )
2026-03-01 12:16:08 +08:00
{
if ( m_pXACT3Engine = = NULL ) return ;
// Creater listener array from the local players
int listenerCount = 0 ;
bool doPosUpdate = true ;
if ( players )
{
for ( int i = 0 ; i < 4 ; i + + )
{
if ( players [ i ] ! = NULL )
{
float yRot = players [ i ] - > yRotO + ( players [ i ] - > yRot - players [ i ] - > yRotO ) * a ;
m_listeners [ listenerCount ] . Position . x = ( float ) ( players [ i ] - > xo + ( players [ i ] - > x - players [ i ] - > xo ) * a ) ;
m_listeners [ listenerCount ] . Position . y = ( float ) ( players [ i ] - > yo + ( players [ i ] - > y - players [ i ] - > yo ) * a ) ;
m_listeners [ listenerCount ] . Position . z = - ( float ) ( players [ i ] - > zo + ( players [ i ] - > z - players [ i ] - > zo ) * a ) ; // Flipped sign of z as x3daudio is expecting left handed coord system
float yCos = ( float ) cos ( - yRot * Mth : : RAD_TO_GRAD - PI ) ;
float ySin = ( float ) sin ( - yRot * Mth : : RAD_TO_GRAD - PI ) ;
m_listeners [ listenerCount ] . OrientFront . x = - ySin ;
m_listeners [ listenerCount ] . OrientFront . y = 0 ;
m_listeners [ listenerCount ] . OrientFront . z = yCos ; // Flipped sign of z as x3daudio is expecting left handed coord system
listenerCount + + ;
}
}
}
// If there were no valid players set, make up a default listener
if ( listenerCount = = 0 )
{
doPosUpdate = false ; // Don't bother updating positions of sounds already placed
m_listeners [ listenerCount ] . Position . x = 0 ;
m_listeners [ listenerCount ] . Position . y = 0 ;
m_listeners [ listenerCount ] . Position . z = 0 ;
m_listeners [ listenerCount ] . OrientFront . x = 0 ;
m_listeners [ listenerCount ] . OrientFront . y = 0 ;
m_listeners [ listenerCount ] . OrientFront . z = 1.0f ;
listenerCount + + ;
}
m_validListenerCount = listenerCount ;
EnterCriticalSection ( & m_CS ) ;
for ( unsigned int i = 0 ; i < currentSounds . size ( ) ; i + + )
{
SoundEngine : : soundInfo * info = currentSounds [ i ] ;
DWORD state ;
HRESULT hr ;
if ( FAILED ( hr = info - > pCue - > GetState ( & state ) ) )
{
assert ( false ) ;
}
else
{
if ( state = = XACT_CUESTATE_STOPPED )
{
info - > pCue - > Destroy ( ) ;
delete currentSounds [ i ] ;
currentSounds [ i ] = currentSounds . back ( ) ;
currentSounds . pop_back ( ) ;
}
else
{
if ( info - > updatePos )
{
if ( doPosUpdate )
{
update3DPosition ( info ) ;
}
}
}
}
}
LeaveCriticalSection ( & m_CS ) ;
m_pXACT3Engine - > DoWork ( ) ;
}
void SoundEngine : : add ( const wstring & name , File * file )
{
}
void SoundEngine : : addMusic ( const wstring & name , File * file )
{
}
void SoundEngine : : addStreaming ( const wstring & name , File * file )
{
}