diff options
Diffstat (limited to 'Minecraft.Client/Xbox/Audio/SoundEngine.cpp')
| -rw-r--r-- | Minecraft.Client/Xbox/Audio/SoundEngine.cpp | 1078 |
1 files changed, 1078 insertions, 0 deletions
diff --git a/Minecraft.Client/Xbox/Audio/SoundEngine.cpp b/Minecraft.Client/Xbox/Audio/SoundEngine.cpp new file mode 100644 index 00000000..b088150c --- /dev/null +++ b/Minecraft.Client/Xbox/Audio/SoundEngine.cpp @@ -0,0 +1,1078 @@ +#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 ) + { + 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; + + 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; + } + + + 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); +} + +void SoundEngine::tick(shared_ptr<Mob> *players, float a) +{ + 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) +{ +} |
