From b691c43c44ff180d10e7d4a9afc83b98551ff586 Mon Sep 17 00:00:00 2001 From: daoge_cmd <3523206925@qq.com> Date: Sun, 1 Mar 2026 12:16:08 +0800 Subject: Initial commit --- .../Common/Audio/Consoles_SoundEngine.cpp | 38 + .../Common/Audio/Consoles_SoundEngine.h | 81 + Minecraft.Client/Common/Audio/SoundEngine.cpp | 1668 ++++++++++++++++++++ Minecraft.Client/Common/Audio/SoundEngine.h | 168 ++ Minecraft.Client/Common/Audio/SoundNames.cpp | 165 ++ 5 files changed, 2120 insertions(+) create mode 100644 Minecraft.Client/Common/Audio/Consoles_SoundEngine.cpp create mode 100644 Minecraft.Client/Common/Audio/Consoles_SoundEngine.h create mode 100644 Minecraft.Client/Common/Audio/SoundEngine.cpp create mode 100644 Minecraft.Client/Common/Audio/SoundEngine.h create mode 100644 Minecraft.Client/Common/Audio/SoundNames.cpp (limited to 'Minecraft.Client/Common/Audio') diff --git a/Minecraft.Client/Common/Audio/Consoles_SoundEngine.cpp b/Minecraft.Client/Common/Audio/Consoles_SoundEngine.cpp new file mode 100644 index 00000000..269b605b --- /dev/null +++ b/Minecraft.Client/Common/Audio/Consoles_SoundEngine.cpp @@ -0,0 +1,38 @@ +#include "stdafx.h" +#include "Consoles_SoundEngine.h" + + +bool ConsoleSoundEngine::GetIsPlayingStreamingCDMusic() +{ + return m_bIsPlayingStreamingCDMusic; +} +bool ConsoleSoundEngine::GetIsPlayingStreamingGameMusic() +{ + return m_bIsPlayingStreamingGameMusic; +} +void ConsoleSoundEngine::SetIsPlayingStreamingCDMusic(bool bVal) +{ + m_bIsPlayingStreamingCDMusic=bVal; +} +void ConsoleSoundEngine::SetIsPlayingStreamingGameMusic(bool bVal) +{ + m_bIsPlayingStreamingGameMusic=bVal; +} +bool ConsoleSoundEngine::GetIsPlayingEndMusic() +{ + return m_bIsPlayingEndMusic; +} +bool ConsoleSoundEngine::GetIsPlayingNetherMusic() +{ + return m_bIsPlayingNetherMusic; +} +void ConsoleSoundEngine::SetIsPlayingEndMusic(bool bVal) +{ + m_bIsPlayingEndMusic=bVal; +} +void ConsoleSoundEngine::SetIsPlayingNetherMusic(bool bVal) +{ + m_bIsPlayingNetherMusic=bVal; +} + + diff --git a/Minecraft.Client/Common/Audio/Consoles_SoundEngine.h b/Minecraft.Client/Common/Audio/Consoles_SoundEngine.h new file mode 100644 index 00000000..4ec76036 --- /dev/null +++ b/Minecraft.Client/Common/Audio/Consoles_SoundEngine.h @@ -0,0 +1,81 @@ +#pragma once + +#include "..\..\..\Minecraft.World\SoundTypes.h" + +#ifdef _XBOX + +#elif defined (__PS3__) +#undef __in +#undef __out +#include "..\..\PS3\Miles\include\mss.h" +#elif defined (__PSVITA__) +#include "..\..\PSVITA\Miles\include\mss.h" +#elif defined _DURANGO +// 4J Stu - Temp define to get Miles to link, can likely be removed when we get a new version of Miles +#define _SEKRIT +#include "..\..\Durango\Miles\include\mss.h" +#elif defined _WINDOWS64 +#include "..\..\windows64\Miles\include\mss.h" +#else // PS4 +// 4J Stu - Temp define to get Miles to link, can likely be removed when we get a new version of Miles +#define _SEKRIT2 +#include "..\..\Orbis\Miles\include\mss.h" +#endif + +typedef struct +{ + float x,y,z; +} +AUDIO_VECTOR; + +typedef struct +{ + bool bValid; + AUDIO_VECTOR vPosition; + AUDIO_VECTOR vOrientFront; +} +AUDIO_LISTENER; + +class Options; + +class ConsoleSoundEngine +{ +public: + + ConsoleSoundEngine() : m_bIsPlayingStreamingCDMusic(false),m_bIsPlayingStreamingGameMusic(false), m_bIsPlayingEndMusic(false),m_bIsPlayingNetherMusic(false){}; + virtual void tick(shared_ptr *players, float a) =0; + virtual void destroy()=0; + virtual void play(int iSound, float x, float y, float z, float volume, float pitch) =0; + virtual void playStreaming(const wstring& name, float x, float y , float z, float volume, float pitch, bool bMusicDelay=true) =0; + virtual void playUI(int iSound, float volume, float pitch) =0; + virtual void updateMusicVolume(float fVal) =0; + virtual void updateSystemMusicPlaying(bool isPlaying) = 0; + virtual void updateSoundEffectVolume(float fVal) =0; + virtual void init(Options *) =0 ; + virtual void add(const wstring& name, File *file) =0; + virtual void addMusic(const wstring& name, File *file) =0; + virtual void addStreaming(const wstring& name, File *file) =0; + virtual char *ConvertSoundPathToName(const wstring& name, bool bConvertSpaces) =0; + virtual void playMusicTick() =0; + + virtual bool GetIsPlayingStreamingCDMusic() ; + virtual bool GetIsPlayingStreamingGameMusic() ; + virtual void SetIsPlayingStreamingCDMusic(bool bVal) ; + virtual void SetIsPlayingStreamingGameMusic(bool bVal) ; + virtual bool GetIsPlayingEndMusic() ; + virtual bool GetIsPlayingNetherMusic() ; + virtual void SetIsPlayingEndMusic(bool bVal) ; + virtual void SetIsPlayingNetherMusic(bool bVal) ; + static const WCHAR *wchSoundNames[eSoundType_MAX]; + static const WCHAR *wchUISoundNames[eSFX_MAX]; + +private: + // platform specific functions + + virtual int initAudioHardware(int iMinSpeakers)=0; + + bool m_bIsPlayingStreamingCDMusic; + bool m_bIsPlayingStreamingGameMusic; + bool m_bIsPlayingEndMusic; + bool m_bIsPlayingNetherMusic; +}; diff --git a/Minecraft.Client/Common/Audio/SoundEngine.cpp b/Minecraft.Client/Common/Audio/SoundEngine.cpp new file mode 100644 index 00000000..4eaf7df7 --- /dev/null +++ b/Minecraft.Client/Common/Audio/SoundEngine.cpp @@ -0,0 +1,1668 @@ +#include "stdafx.h" + +#include "SoundEngine.h" +#include "..\Consoles_App.h" +#include "..\..\MultiplayerLocalPlayer.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" +#include "..\..\Minecraft.World\leveldata.h" +#include "..\..\Minecraft.World\mth.h" +#include "..\..\TexturePackRepository.h" +#include "..\..\DLCTexturePack.h" +#include "Common\DLC\DLCAudioFile.h" + +#ifdef __PSVITA__ +#include +#endif + +#ifdef _WINDOWS64 +#include "..\..\Minecraft.Client\Windows64\Windows64_App.h" +#include "..\..\Minecraft.Client\Windows64\Miles\include\imssapi.h" +#endif + +#ifdef __ORBIS__ +#include +//#define __DISABLE_MILES__ // MGH disabled for now as it crashes if we call sceNpMatching2Initialize +#endif + +// take out Orbis until they are done +#if defined _XBOX + +SoundEngine::SoundEngine() {} +void SoundEngine::init(Options *pOptions) +{ +} + +void SoundEngine::tick(shared_ptr *players, float a) +{ +} +void SoundEngine::destroy() {} +void SoundEngine::play(int iSound, float x, float y, float z, float volume, float pitch) +{ + app.DebugPrintf("PlaySound - %d\n",iSound); +} +void SoundEngine::playStreaming(const wstring& name, float x, float y , float z, float volume, float pitch, bool bMusicDelay) {} +void SoundEngine::playUI(int iSound, float volume, float pitch) {} + +void SoundEngine::updateMusicVolume(float fVal) {} +void SoundEngine::updateSoundEffectVolume(float fVal) {} + +void SoundEngine::add(const wstring& name, File *file) {} +void SoundEngine::addMusic(const wstring& name, File *file) {} +void SoundEngine::addStreaming(const wstring& name, File *file) {} +char *SoundEngine::ConvertSoundPathToName(const wstring& name, bool bConvertSpaces) { return NULL; } +bool SoundEngine::isStreamingWavebankReady() { return true; } +void SoundEngine::playMusicTick() {}; + +#else + +#ifdef _WINDOWS64 +char SoundEngine::m_szSoundPath[]={"Durango\\Sound\\"}; +char SoundEngine::m_szMusicPath[]={"music\\"}; +char SoundEngine::m_szRedistName[]={"redist64"}; +#elif defined _DURANGO +char SoundEngine::m_szSoundPath[]={"Sound\\"}; +char SoundEngine::m_szMusicPath[]={"music\\"}; +char SoundEngine::m_szRedistName[]={"redist64"}; +#elif defined __ORBIS__ + +#ifdef _CONTENT_PACKAGE +char SoundEngine::m_szSoundPath[]={"Sound/"}; +#elif defined _ART_BUILD +char SoundEngine::m_szSoundPath[]={"Sound/"}; +#else +// just use the host Durango folder for the sound. In the content package, we'll have moved this in the .gp4 file +char SoundEngine::m_szSoundPath[]={"Durango/Sound/"}; +#endif +char SoundEngine::m_szMusicPath[]={"music/"}; +char SoundEngine::m_szRedistName[]={"redist64"}; +#elif defined __PSVITA__ +char SoundEngine::m_szSoundPath[]={"PSVita/Sound/"}; +char SoundEngine::m_szMusicPath[]={"music/"}; +char SoundEngine::m_szRedistName[]={"redist"}; +#elif defined __PS3__ +//extern const char* getPS3HomePath(); +char SoundEngine::m_szSoundPath[]={"PS3/Sound/"}; +char SoundEngine::m_szMusicPath[]={"music/"}; +char SoundEngine::m_szRedistName[]={"redist"}; + +#define USE_SPURS + +#ifdef USE_SPURS +#include +#else +#include +#endif + +#endif + +F32 AILCALLBACK custom_falloff_function (HSAMPLE S, + F32 distance, + F32 rolloff_factor, + F32 min_dist, + F32 max_dist); + +char *SoundEngine::m_szStreamFileA[eStream_Max]= +{ + "calm1", + "calm2", + "calm3", + "hal1", + "hal2", + "hal3", + "hal4", + "nuance1", + "nuance2", +#ifndef _XBOX + // add the new music tracks + "creative1", + "creative2", + "creative3", + "creative4", + "creative5", + "creative6", + "menu1", + "menu2", + "menu3", + "menu4", +#endif + "piano1", + "piano2", + "piano3", + + // Nether + "nether1", + "nether2", + "nether3", + "nether4", + // The End + "the_end_dragon_alive", + "the_end_end", + // CDs + "11", + "13", + "blocks", + "cat", + "chirp", + "far", + "mall", + "mellohi", + "stal", + "strad", + "ward", + "where_are_we_now" +}; + +///////////////////////////////////////////// +// +// ErrorCallback +// +///////////////////////////////////////////// +void AILCALL ErrorCallback(S64 i_Id, char const* i_Details) +{ + char *pchLastError=AIL_last_error(); + + if(pchLastError[0]!=0) + { + app.DebugPrintf("\rErrorCallback Error Category: %s\n", pchLastError); + } + + if (i_Details) + { + app.DebugPrintf("ErrorCallback - Details: %s\n", i_Details); + } +} + +#ifdef __PSVITA__ +// AP - this is the callback when the driver is about to mix. At this point the mutex is locked by Miles so we can now call all Miles functions without +// the possibility of incurring a stall. +static bool SoundEngine_Change = false; // has tick been called? +static CRITICAL_SECTION SoundEngine_MixerMutex; + +void AILCALL MilesMixerCB(HDIGDRIVER dig) +{ + // has the tick function been called since the last callback + if( SoundEngine_Change ) + { + SoundEngine_Change = false; + + EnterCriticalSection(&SoundEngine_MixerMutex); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + pMinecraft->soundEngine->updateMiles(); + pMinecraft->soundEngine->playMusicUpdate(); + + LeaveCriticalSection(&SoundEngine_MixerMutex); + } +} +#endif + +///////////////////////////////////////////// +// +// init +// +///////////////////////////////////////////// +void SoundEngine::init(Options *pOptions) +{ + app.DebugPrintf("---SoundEngine::init\n"); +#ifdef __DISABLE_MILES__ + return; +#endif +#ifdef __ORBIS__ + C4JThread::PushAffinityAllCores(); +#endif +#if defined _DURANGO || defined __ORBIS__ || defined __PS3__ || defined __PSVITA__ + Register_RIB(BinkADec); +#endif + + char *redistpath; + +#if (defined _WINDOWS64 || defined __PSVITA__)// || defined _DURANGO || defined __ORBIS__ ) + redistpath=AIL_set_redist_directory(m_szRedistName); +#endif + + app.DebugPrintf("---SoundEngine::init - AIL_startup\n"); + S32 ret = AIL_startup(); + + int iNumberOfChannels=initAudioHardware(8); + + // Create a driver to render our audio - 44khz, 16 bit, +#ifdef __PS3__ + // On the Sony PS3, the driver is always opened in 48 kHz, 32-bit floating point. The only meaningful configurations are MSS_MC_STEREO, MSS_MC_51_DISCRETE, and MSS_MC_71_DISCRETE. + m_hDriver = AIL_open_digital_driver( 48000, 16, iNumberOfChannels, AIL_OPEN_DIGITAL_USE_SPU0 ); +#elif defined __PSVITA__ + + // maximum of 16 samples + AIL_set_preference(DIG_MIXER_CHANNELS, 16); + + m_hDriver = AIL_open_digital_driver( 48000, 16, MSS_MC_STEREO, 0 ); + + // AP - For some reason the submit thread defaults to a priority of zero (invalid). Make sure it has the highest priority to avoid audio breakup. + SceUID threadID; + AIL_platform_property( m_hDriver, PSP2_SUBMIT_THREAD, &threadID, 0, 0); + S32 g_DefaultCPU = sceKernelGetThreadCpuAffinityMask(threadID); + S32 Old = sceKernelChangeThreadPriority(threadID, 64); + + // AP - register a callback when the mixer starts + AILMIXERCB temp = AIL_register_mix_callback(m_hDriver, MilesMixerCB); + + InitializeCriticalSection(&SoundEngine_MixerMutex); + +#elif defined(__ORBIS__) + m_hDriver = AIL_open_digital_driver( 48000, 16, 2, 0 ); + app.DebugPrintf("---SoundEngine::init - AIL_open_digital_driver\n"); + +#else + m_hDriver = AIL_open_digital_driver(44100, 16, MSS_MC_USE_SYSTEM_CONFIG, 0); +#endif + if (m_hDriver == 0) + { + app.DebugPrintf("Couldn't open digital sound driver. (%s)\n", AIL_last_error()); + AIL_shutdown(); +#ifdef __ORBIS__ + C4JThread::PopAffinity(); +#endif + return; + } + app.DebugPrintf("---SoundEngine::init - driver opened\n"); + +#ifdef __PSVITA__ + + // set high falloff power for maximum spatial effect in software mode + AIL_set_speaker_configuration( m_hDriver, 0, 0, 4.0F ); + +#endif + + AIL_set_event_error_callback(ErrorCallback); + + AIL_set_3D_rolloff_factor(m_hDriver,1.0); + + // Create an event system tied to that driver - let Miles choose memory defaults. + //if (AIL_startup_event_system(m_hDriver, 0, 0, 0) == 0) + // 4J-PB - Durango complains that the default memory (64k)isn't enough + // Error: MilesEvent: Out of event system memory (pool passed to event system startup exhausted). + // AP - increased command buffer from the default 5K to 20K for Vita + + if (AIL_startup_event_system(m_hDriver, 1024*20, 0, 1024*128) == 0) + { + app.DebugPrintf("Couldn't init event system (%s).\n", AIL_last_error()); + AIL_close_digital_driver(m_hDriver); + AIL_shutdown(); +#ifdef __ORBIS__ + C4JThread::PopAffinity(); +#endif + app.DebugPrintf("---SoundEngine::init - AIL_startup_event_system failed\n"); + return; + } + char szBankName[255]; +#if defined __PS3__ + if(app.GetBootedFromDiscPatch()) + { + char szTempSoundFilename[255]; + sprintf(szTempSoundFilename,"%s%s",m_szSoundPath, "Minecraft.msscmp" ); + + app.DebugPrintf("SoundEngine::playMusicUpdate - (booted from disc patch) looking for %s\n",szTempSoundFilename); + sprintf(szBankName,"%s/%s",app.GetBDUsrDirPath(szTempSoundFilename), m_szSoundPath ); + app.DebugPrintf("SoundEngine::playMusicUpdate - (booted from disc patch) music path - %s\n",szBankName); + } + else + { + sprintf(szBankName,"%s/%s",getUsrDirPath(), m_szSoundPath ); + } + +#elif defined __PSVITA__ + sprintf(szBankName,"%s/%s",getUsrDirPath(), m_szSoundPath ); +#elif defined __ORBIS__ + sprintf(szBankName,"%s/%s",getUsrDirPath(), m_szSoundPath ); +#else + strcpy((char *)szBankName,m_szSoundPath); +#endif + + strcat((char *)szBankName,"Minecraft.msscmp"); + + m_hBank=AIL_add_soundbank(szBankName, 0); + + if(m_hBank == NULL) + { + char *Error=AIL_last_error(); + app.DebugPrintf("Couldn't open soundbank: %s (%s)\n", szBankName, Error); + AIL_close_digital_driver(m_hDriver); + AIL_shutdown(); +#ifdef __ORBIS__ + C4JThread::PopAffinity(); +#endif + return; + } + + //#ifdef _DEBUG + HMSSENUM token = MSS_FIRST; + char const* Events[1] = {0}; + S32 EventCount = 0; + while (AIL_enumerate_events(m_hBank, &token, 0, &Events[0])) + { + app.DebugPrintf(4,"%d - %s\n", EventCount, Events[0]); + + EventCount++; + } + //#endif + + U64 u64Result; + u64Result=AIL_enqueue_event_by_name("Minecraft/CacheSounds"); + + m_MasterMusicVolume=1.0f; + m_MasterEffectsVolume=1.0f; + + //AIL_set_variable_float(0,"UserEffectVol",1); + + m_bSystemMusicPlaying = false; + + m_openStreamThread = NULL; + +#ifdef __ORBIS__ + C4JThread::PopAffinity(); +#endif + +#ifdef __PSVITA__ + // AP - By default the mixer won't start up and nothing will process. Kick off a blank sample to force the mixer to start up. + HSAMPLE Sample = AIL_allocate_sample_handle(m_hDriver); + AIL_init_sample(Sample, DIG_F_STEREO_16); + static U64 silence = 0; + AIL_set_sample_address(Sample, &silence, sizeof(U64)); + AIL_start_sample(Sample); + + // wait for 1 mix... + AIL_release_sample_handle(Sample); +#endif +} + +#ifdef __ORBIS__ +// void SoundEngine::SetHandle(int32_t hAudio) +// { +// //m_hAudio=hAudio; +// } +#endif + +void SoundEngine::SetStreamingSounds(int iOverworldMin, int iOverWorldMax, int iNetherMin, int iNetherMax, int iEndMin, int iEndMax, int iCD1) +{ + m_iStream_Overworld_Min=iOverworldMin; + m_iStream_Overworld_Max=iOverWorldMax; + m_iStream_Nether_Min=iNetherMin; + m_iStream_Nether_Max=iNetherMax; + m_iStream_End_Min=iEndMin; + m_iStream_End_Max=iEndMax; + m_iStream_CD_1=iCD1; + + // array to monitor recently played tracks + if(m_bHeardTrackA) + { + delete [] m_bHeardTrackA; + } + m_bHeardTrackA = new bool[iEndMax+1]; + memset(m_bHeardTrackA,0,sizeof(bool)*iEndMax+1); +} + +// AP - moved to a separate function so it can be called from the mixer callback on Vita +void SoundEngine::updateMiles() +{ +#ifdef __PSVITA__ + //CD - We must check for Background Music [BGM] at any point + //If it's playing disable our audio, otherwise enable + int NoBGMPlaying = sceAudioOutGetAdopt(SCE_AUDIO_OUT_PORT_TYPE_BGM); + updateSystemMusicPlaying( !NoBGMPlaying ); +#elif defined __ORBIS__ + // is the system playing background music? + SceAudioOutPortState outPortState; + sceAudioOutGetPortState(m_hBGMAudio,&outPortState); + updateSystemMusicPlaying( outPortState.output==SCE_AUDIO_OUT_STATE_OUTPUT_UNKNOWN ); +#endif + + if( m_validListenerCount == 1 ) + { + for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) + { + // set the listener as the first player we find + if( m_ListenerA[i].bValid ) + { + AIL_set_listener_3D_position(m_hDriver,m_ListenerA[i].vPosition.x,m_ListenerA[i].vPosition.y,-m_ListenerA[i].vPosition.z); // Flipped sign of z as Miles is expecting left handed coord system + AIL_set_listener_3D_orientation(m_hDriver,-m_ListenerA[i].vOrientFront.x,m_ListenerA[i].vOrientFront.y,m_ListenerA[i].vOrientFront.z,0,1,0); // Flipped sign of z as Miles is expecting left handed coord system + break; + } + } + } + else + { + // 4J-PB - special case for splitscreen + // the shortest distance between any listener and a sound will be used to play a sound a set distance away down the z axis. + // The listener position will be set to 0,0,0, and the orientation will be facing down the z axis + + AIL_set_listener_3D_position(m_hDriver,0,0,0); + AIL_set_listener_3D_orientation(m_hDriver,0,0,1,0,1,0); + } + + AIL_begin_event_queue_processing(); + + // Iterate over the sounds + S32 StartedCount = 0, CompletedCount = 0, TotalCount = 0; + HMSSENUM token = MSS_FIRST; + MILESEVENTSOUNDINFO SoundInfo; + int Playing = 0; + while (AIL_enumerate_sound_instances(0, &token, 0, 0, 0, &SoundInfo)) + { + AUDIO_INFO* game_data= (AUDIO_INFO*)( SoundInfo.UserBuffer ); + + if( SoundInfo.Status == MILESEVENT_SOUND_STATUS_PLAYING ) + { + Playing += 1; + } + + if ( SoundInfo.Status != MILESEVENT_SOUND_STATUS_COMPLETE ) + { + // apply the master volume + // watch for the 'special' volume levels + bool isThunder = false; + if( game_data->volume == 10000.0f ) + { + isThunder = true; + } + if(game_data->volume>1) + { + game_data->volume=1; + } + AIL_set_sample_volume_levels( SoundInfo.Sample, game_data->volume*m_MasterEffectsVolume, game_data->volume*m_MasterEffectsVolume); + + float distanceScaler = 16.0f; + switch(SoundInfo.Status) + { + case MILESEVENT_SOUND_STATUS_PENDING: + // 4J-PB - causes the falloff to be calculated on the PPU instead of the SPU, and seems to resolve our distorted sound issue + AIL_register_falloff_function_callback(SoundInfo.Sample,&custom_falloff_function); + + if(game_data->bIs3D) + { + AIL_set_sample_is_3D( SoundInfo.Sample, 1 ); + + int iSound = game_data->iSound - eSFX_MAX; + switch(iSound) + { + // Is this the Dragon? + case eSoundType_MOB_ENDERDRAGON_GROWL: + case eSoundType_MOB_ENDERDRAGON_MOVE: + case eSoundType_MOB_ENDERDRAGON_END: + case eSoundType_MOB_ENDERDRAGON_HIT: + distanceScaler=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: + distanceScaler=30.0f; + break; + } + + // Set a special distance scaler for thunder, which we respond to by having no attenutation + if( isThunder ) + { + distanceScaler = 10000.0f; + } + } + else + { + AIL_set_sample_is_3D( SoundInfo.Sample, 0 ); + } + + AIL_set_sample_3D_distances(SoundInfo.Sample,distanceScaler,1,0); + // set the pitch + if(!game_data->bUseSoundsPitchVal) + { + AIL_set_sample_playback_rate_factor(SoundInfo.Sample,game_data->pitch); + } + + if(game_data->bIs3D) + { + if(m_validListenerCount>1) + { + float fClosest=10000.0f; + int iClosestListener=0; + float fClosestX=0.0f,fClosestY=0.0f,fClosestZ=0.0f,fDist; + // need to calculate the distance from the sound to the nearest listener - use Manhattan Distance as the decision + for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) + { + if( m_ListenerA[i].bValid ) + { + float x,y,z; + + x=fabs(m_ListenerA[i].vPosition.x-game_data->x); + y=fabs(m_ListenerA[i].vPosition.y-game_data->y); + z=fabs(m_ListenerA[i].vPosition.z-game_data->z); + fDist=x+y+z; + + if(fDistx, game_data->y, -game_data->z ); // Flipped sign of z as Miles is expecting left handed coord system + } + } + break; + + default: + if(game_data->bIs3D) + { + if(m_validListenerCount>1) + { + float fClosest=10000.0f; + int iClosestListener=0; + float fClosestX=0.0f,fClosestY=0.0f,fClosestZ=0.0f,fDist; + // need to calculate the distance from the sound to the nearest listener - use Manhattan Distance as the decision + for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) + { + if( m_ListenerA[i].bValid ) + { + float x,y,z; + + x=fabs(m_ListenerA[i].vPosition.x-game_data->x); + y=fabs(m_ListenerA[i].vPosition.y-game_data->y); + z=fabs(m_ListenerA[i].vPosition.z-game_data->z); + fDist=x+y+z; + + if(fDistx, game_data->y, -game_data->z ); // Flipped sign of z as Miles is expecting left handed coord system + } + } + break; + } + } + } + AIL_complete_event_queue_processing(); +} + +//#define DISTORTION_TEST +#ifdef DISTORTION_TEST +static float fVal=0.0f; +#endif +///////////////////////////////////////////// +// +// tick +// +///////////////////////////////////////////// + +#ifdef __PSVITA__ +static S32 running = AIL_ms_count(); +#endif + +void SoundEngine::tick(shared_ptr *players, float a) +{ +#ifdef __DISABLE_MILES__ + return; +#endif + +#ifdef __PSVITA__ + EnterCriticalSection(&SoundEngine_MixerMutex); +#endif + + // update the listener positions + int listenerCount = 0; +#ifdef DISTORTION_TEST + float fX,fY,fZ; +#endif + if( players ) + { + bool bListenerPostionSet=false; + for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) + { + if( players[i] != NULL ) + { + m_ListenerA[i].bValid=true; + F32 x,y,z; + x=players[i]->xo + (players[i]->x - players[i]->xo) * a; + y=players[i]->yo + (players[i]->y - players[i]->yo) * a; + z=players[i]->zo + (players[i]->z - players[i]->zo) * a; + + float yRot = players[i]->yRotO + (players[i]->yRot - players[i]->yRotO) * a; + float yCos = (float)cos(-yRot * Mth::RAD_TO_GRAD - PI); + float ySin = (float)sin(-yRot * Mth::RAD_TO_GRAD - PI); + + // store the listener positions for splitscreen + m_ListenerA[i].vPosition.x = x; + m_ListenerA[i].vPosition.y = y; + m_ListenerA[i].vPosition.z = z; + + m_ListenerA[i].vOrientFront.x = ySin; + m_ListenerA[i].vOrientFront.y = 0; + m_ListenerA[i].vOrientFront.z = yCos; + + listenerCount++; + } + else + { + m_ListenerA[i].bValid=false; + } + } + } + + + // If there were no valid players set, make up a default listener + if( listenerCount == 0 ) + { + m_ListenerA[0].vPosition.x = 0; + m_ListenerA[0].vPosition.y = 0; + m_ListenerA[0].vPosition.z = 0; + m_ListenerA[0].vOrientFront.x = 0; + m_ListenerA[0].vOrientFront.y = 0; + m_ListenerA[0].vOrientFront.z = 1.0f; + listenerCount++; + } + m_validListenerCount = listenerCount; + +#ifdef __PSVITA__ + // AP - Show that a change has occurred so we know to update the values at the next Mixer callback + SoundEngine_Change = true; + + LeaveCriticalSection(&SoundEngine_MixerMutex); +#else + updateMiles(); +#endif +} + +///////////////////////////////////////////// +// +// SoundEngine +// +///////////////////////////////////////////// +SoundEngine::SoundEngine() +{ + random = new Random(); + m_hStream=0; + m_StreamState=eMusicStreamState_Idle; + m_iMusicDelay=0; + m_validListenerCount=0; + + m_bHeardTrackA=NULL; + + // Start the streaming music playing some music from the overworld + SetStreamingSounds(eStream_Overworld_Calm1,eStream_Overworld_piano3, + eStream_Nether1,eStream_Nether4, + eStream_end_dragon,eStream_end_end, + eStream_CD_1); + + m_musicID=getMusicID(LevelData::DIMENSION_OVERWORLD); + + m_StreamingAudioInfo.bIs3D=false; + m_StreamingAudioInfo.x=0; + m_StreamingAudioInfo.y=0; + m_StreamingAudioInfo.z=0; + m_StreamingAudioInfo.volume=1; + m_StreamingAudioInfo.pitch=1; + + memset(CurrentSoundsPlaying,0,sizeof(int)*(eSoundType_MAX+eSFX_MAX)); + memset(m_ListenerA,0,sizeof(AUDIO_LISTENER)*XUSER_MAX_COUNT); + +#ifdef __ORBIS__ + m_hBGMAudio=GetAudioBGMHandle(); +#endif +} + +void SoundEngine::destroy() {} + +#ifdef _DEBUG +void SoundEngine::GetSoundName(char *szSoundName,int iSound) +{ + strcpy((char *)szSoundName,"Minecraft/"); + wstring name = wchSoundNames[iSound]; + char *SoundName = (char *)ConvertSoundPathToName(name); + strcat((char *)szSoundName,SoundName); +} +#endif + +///////////////////////////////////////////// +// +// play +// +///////////////////////////////////////////// +void SoundEngine::play(int iSound, float x, float y, float z, float volume, float pitch) +{ + U8 szSoundName[256]; + + if(iSound==-1) + { + app.DebugPrintf(6,"PlaySound with sound of -1 !!!!!!!!!!!!!!!\n"); + return; + } + + // AP removed old counting system. Now relying on Miles' Play Count Limit + /* // if we are already playing loads of this sounds ignore this one + if(CurrentSoundsPlaying[iSound+eSFX_MAX]>MAX_SAME_SOUNDS_PLAYING) + { + // wstring name = wchSoundNames[iSound]; + // char *SoundName = (char *)ConvertSoundPathToName(name); + // app.DebugPrintf("Too many %s sounds playing!\n",SoundName); + return; + }*/ + + //if (iSound != eSoundType_MOB_IRONGOLEM_WALK) return; + + // build the name + strcpy((char *)szSoundName,"Minecraft/"); + +#ifdef DISTORTION_TEST + wstring name = wchSoundNames[eSoundType_MOB_ENDERDRAGON_GROWL]; +#else + wstring name = wchSoundNames[iSound]; +#endif + + char *SoundName = (char *)ConvertSoundPathToName(name); + strcat((char *)szSoundName,SoundName); + +// app.DebugPrintf(6,"PlaySound - %d - %s - %s (%f %f %f, vol %f, pitch %f)\n",iSound, SoundName, szSoundName,x,y,z,volume,pitch); + + AUDIO_INFO AudioInfo; + AudioInfo.x=x; + AudioInfo.y=y; + AudioInfo.z=z; + AudioInfo.volume=volume; + AudioInfo.pitch=pitch; + AudioInfo.bIs3D=true; + AudioInfo.bUseSoundsPitchVal=false; + AudioInfo.iSound=iSound+eSFX_MAX; +#ifdef _DEBUG + strncpy(AudioInfo.chName,(char *)szSoundName,64); +#endif + + S32 token = AIL_enqueue_event_start(); + AIL_enqueue_event_buffer(&token, &AudioInfo, sizeof(AUDIO_INFO), 0); + AIL_enqueue_event_end_named(token, (char *)szSoundName); +} + +///////////////////////////////////////////// +// +// playUI +// +///////////////////////////////////////////// +void SoundEngine::playUI(int iSound, float volume, float pitch) +{ + U8 szSoundName[256]; + wstring name; + // we have some game sounds played as UI sounds... + // Not the best way to do this, but it seems to only be the portal sounds + + if(iSound>=eSFX_MAX) + { + // AP removed old counting system. Now relying on Miles' Play Count Limit + /* // if we are already playing loads of this sounds ignore this one + if(CurrentSoundsPlaying[iSound+eSFX_MAX]>MAX_SAME_SOUNDS_PLAYING) return;*/ + + // build the name + strcpy((char *)szSoundName,"Minecraft/"); + name = wchSoundNames[iSound]; + } + else + { + // AP removed old counting system. Now relying on Miles' Play Count Limit + /* // if we are already playing loads of this sounds ignore this one + if(CurrentSoundsPlaying[iSound]>MAX_SAME_SOUNDS_PLAYING) return;*/ + + // build the name + strcpy((char *)szSoundName,"Minecraft/UI/"); + name = wchUISoundNames[iSound]; + } + + char *SoundName = (char *)ConvertSoundPathToName(name); + strcat((char *)szSoundName,SoundName); +// app.DebugPrintf("UI: Playing %s, volume %f, pitch %f\n",SoundName,volume,pitch); + + //app.DebugPrintf("PlaySound - %d - %s\n",iSound, SoundName); + + AUDIO_INFO AudioInfo; + memset(&AudioInfo,0,sizeof(AUDIO_INFO)); + AudioInfo.volume=volume; // will be multiplied by the master volume + AudioInfo.pitch=pitch; + AudioInfo.bUseSoundsPitchVal=true; + if(iSound>=eSFX_MAX) + { + AudioInfo.iSound=iSound+eSFX_MAX; + } + else + { + AudioInfo.iSound=iSound; + } +#ifdef _DEBUG + strncpy(AudioInfo.chName,(char *)szSoundName,64); +#endif + + // 4J-PB - not going to stop UI events happening based on the number of currently playing sounds + S32 token = AIL_enqueue_event_start(); + AIL_enqueue_event_buffer(&token, &AudioInfo, sizeof(AUDIO_INFO), 0); + AIL_enqueue_event_end_named(token, (char *)szSoundName); +} + +///////////////////////////////////////////// +// +// playStreaming +// +///////////////////////////////////////////// +void SoundEngine::playStreaming(const wstring& name, float x, float y , float z, float volume, float pitch, bool bMusicDelay) +{ + // This function doesn't actually play a streaming sound, just sets states and an id for the music tick to play it + // Level audio will be played when a play with an empty name comes in + // CD audio will be played when a named stream comes in + + m_StreamingAudioInfo.x=x; + m_StreamingAudioInfo.y=y; + m_StreamingAudioInfo.z=z; + m_StreamingAudioInfo.volume=volume; + m_StreamingAudioInfo.pitch=pitch; + + if(m_StreamState==eMusicStreamState_Playing) + { + m_StreamState=eMusicStreamState_Stop; + } + else if(m_StreamState==eMusicStreamState_Opening) + { + m_StreamState=eMusicStreamState_OpeningCancel; + } + + if(name.empty()) + { + // music, or stop CD + m_StreamingAudioInfo.bIs3D=false; + + // we need a music id + // random delay of up to 3 minutes for music + m_iMusicDelay = random->nextInt(20 * 60 * 3);//random->nextInt(20 * 60 * 10) + 20 * 60 * 10; + +#ifdef _DEBUG + m_iMusicDelay=0; +#endif + Minecraft *pMinecraft=Minecraft::GetInstance(); + + bool playerInEnd=false; + bool playerInNether=false; + + for(unsigned int i=0;ilocalplayers[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) + { + m_musicID = getMusicID(LevelData::DIMENSION_END); + } + else if(playerInNether) + { + m_musicID = getMusicID(LevelData::DIMENSION_NETHER); + } + else + { + m_musicID = getMusicID(LevelData::DIMENSION_OVERWORLD); + } + } + else + { + // jukebox + m_StreamingAudioInfo.bIs3D=true; + m_musicID=getMusicID(name); + m_iMusicDelay=0; + } +} + + +int SoundEngine::GetRandomishTrack(int iStart,int iEnd) +{ + // 4J-PB - make it more likely that we'll get a track we've not heard for a while, although repeating tracks sometimes is fine + + // if all tracks have been heard, clear the flags + bool bAllTracksHeard=true; + int iVal=iStart; + for(int i=iStart;i<=iEnd;i++) + { + if(m_bHeardTrackA[i]==false) + { + bAllTracksHeard=false; + app.DebugPrintf("Not heard all tracks yet\n"); + break; + } + } + + if(bAllTracksHeard) + { + app.DebugPrintf("Heard all tracks - resetting the tracking array\n"); + + for(int i=iStart;i<=iEnd;i++) + { + m_bHeardTrackA[i]=false; + } + } + + // trying to get a track we haven't heard, but not too hard + for(int i=0;i<=((iEnd-iStart)/2);i++) + { + // random->nextInt(1) will always return 0 + iVal=random->nextInt((iEnd-iStart)+1)+iStart; + if(m_bHeardTrackA[iVal]==false) + { + // not heard this + app.DebugPrintf("(%d) Not heard track %d yet, so playing it now\n",i,iVal); + m_bHeardTrackA[iVal]=true; + break; + } + else + { + app.DebugPrintf("(%d) Skipping track %d already heard it recently\n",i,iVal); + } + } + + app.DebugPrintf("Select track %d\n",iVal); + return iVal; +} +///////////////////////////////////////////// +// +// getMusicID +// +///////////////////////////////////////////// +int SoundEngine::getMusicID(int iDomain) +{ + int iRandomVal=0; + Minecraft *pMinecraft=Minecraft::GetInstance(); + + // Before the game has started? + if(pMinecraft==NULL) + { + // any track from the overworld + return GetRandomishTrack(m_iStream_Overworld_Min,m_iStream_Overworld_Max); + } + + if(pMinecraft->skins->isUsingDefaultSkin()) + { + switch(iDomain) + { + case LevelData::DIMENSION_END: + // the end isn't random - it has different music depending on whether the dragon is alive or not, but we've not added the dead dragon music yet + return m_iStream_End_Min; + case LevelData::DIMENSION_NETHER: + return GetRandomishTrack(m_iStream_Nether_Min,m_iStream_Nether_Max); + //return m_iStream_Nether_Min + random->nextInt(m_iStream_Nether_Max-m_iStream_Nether_Min); + default: //overworld + //return m_iStream_Overworld_Min + random->nextInt(m_iStream_Overworld_Max-m_iStream_Overworld_Min); + return GetRandomishTrack(m_iStream_Overworld_Min,m_iStream_Overworld_Max); + } + } + else + { + // using a texture pack - may have multiple End music tracks + switch(iDomain) + { + case LevelData::DIMENSION_END: + return GetRandomishTrack(m_iStream_End_Min,m_iStream_End_Max); + case LevelData::DIMENSION_NETHER: + //return m_iStream_Nether_Min + random->nextInt(m_iStream_Nether_Max-m_iStream_Nether_Min); + return GetRandomishTrack(m_iStream_Nether_Min,m_iStream_Nether_Max); + default: //overworld + //return m_iStream_Overworld_Min + random->nextInt(m_iStream_Overworld_Max-m_iStream_Overworld_Min); + return GetRandomishTrack(m_iStream_Overworld_Min,m_iStream_Overworld_Max); + } + } +} + +///////////////////////////////////////////// +// +// getMusicID +// +///////////////////////////////////////////// +// check what the CD is +int SoundEngine::getMusicID(const wstring& name) +{ + int iCD=0; + char *SoundName = (char *)ConvertSoundPathToName(name,true); + + // 4J-PB - these will always be the game cds, so use the m_szStreamFileA for this + for(int i=0;i<12;i++) + { + if(strcmp(SoundName,m_szStreamFileA[i+eStream_CD_1])==0) + { + iCD=i; + break; + } + } + + // adjust for cd start position on normal or mash-up pack + return iCD+m_iStream_CD_1; +} + +///////////////////////////////////////////// +// +// getMasterMusicVolume +// +///////////////////////////////////////////// +float SoundEngine::getMasterMusicVolume() +{ + if( m_bSystemMusicPlaying ) + { + return 0.0f; + } + else + { + return m_MasterMusicVolume; + } +} + +///////////////////////////////////////////// +// +// updateMusicVolume +// +///////////////////////////////////////////// +void SoundEngine::updateMusicVolume(float fVal) +{ + m_MasterMusicVolume=fVal; +} + +///////////////////////////////////////////// +// +// updateSystemMusicPlaying +// +///////////////////////////////////////////// +void SoundEngine::updateSystemMusicPlaying(bool isPlaying) +{ + m_bSystemMusicPlaying = isPlaying; +} + +///////////////////////////////////////////// +// +// updateSoundEffectVolume +// +///////////////////////////////////////////// +void SoundEngine::updateSoundEffectVolume(float fVal) +{ + m_MasterEffectsVolume=fVal; + //AIL_set_variable_float(0,"UserEffectVol",fVal); +} + +void SoundEngine::add(const wstring& name, File *file) {} +void SoundEngine::addMusic(const wstring& name, File *file) {} +void SoundEngine::addStreaming(const wstring& name, File *file) {} +bool SoundEngine::isStreamingWavebankReady() { return true; } + +int SoundEngine::OpenStreamThreadProc( void* lpParameter ) +{ +#ifdef __DISABLE_MILES__ + return 0; +#endif + SoundEngine *soundEngine = (SoundEngine *)lpParameter; + soundEngine->m_hStream = AIL_open_stream(soundEngine->m_hDriver,soundEngine->m_szStreamName,0); + return 0; +} + +///////////////////////////////////////////// +// +// playMusicTick +// +///////////////////////////////////////////// +void SoundEngine::playMusicTick() +{ +// AP - vita will update the music during the mixer callback +#ifndef __PSVITA__ + playMusicUpdate(); +#endif +} + +// AP - moved to a separate function so it can be called from the mixer callback on Vita +void SoundEngine::playMusicUpdate() +{ + //return; + static bool firstCall = true; + static float fMusicVol = 0.0f; + if( firstCall ) + { + fMusicVol = getMasterMusicVolume(); + firstCall = false; + } + + switch(m_StreamState) + { + case eMusicStreamState_Idle: + + // start a stream playing + if (m_iMusicDelay > 0) + { + m_iMusicDelay--; + return; + } + + if(m_musicID!=-1) + { + // start playing it + + +#if ( defined __PS3__ || defined __PSVITA__ || defined __ORBIS__ ) + +#ifdef __PS3__ + // 4J-PB - Need to check if we are a patched BD build + if(app.GetBootedFromDiscPatch()) + { + sprintf(m_szStreamName,"%s/%s",app.GetBDUsrDirPath(m_szMusicPath), m_szMusicPath ); + app.DebugPrintf("SoundEngine::playMusicUpdate - (booted from disc patch) music path - %s",m_szStreamName); + } + else + { + sprintf(m_szStreamName,"%s/%s",getUsrDirPath(), m_szMusicPath ); + } +#else + sprintf(m_szStreamName,"%s/%s",getUsrDirPath(), m_szMusicPath ); +#endif + +#else + strcpy((char *)m_szStreamName,m_szMusicPath); +#endif + // are we using a mash-up pack? + //if(pMinecraft && !pMinecraft->skins->isUsingDefaultSkin() && pMinecraft->skins->getSelected()->hasAudio()) + if(Minecraft::GetInstance()->skins->getSelected()->hasAudio()) + { + // It's a mash-up - need to use the DLC path for the music + TexturePack *pTexPack=Minecraft::GetInstance()->skins->getSelected(); + DLCTexturePack *pDLCTexPack=(DLCTexturePack *)pTexPack; + DLCPack *pack = pDLCTexPack->getDLCInfoParentPack(); + DLCAudioFile *dlcAudioFile = (DLCAudioFile *) pack->getFile(DLCManager::e_DLCType_Audio, 0); + + app.DebugPrintf("Mashup pack \n"); + + // build the name + + // if the music ID is beyond the end of the texture pack music files, then it's a CD + if(m_musicIDGetSoundName(m_musicID); + wstring wstrFile=L"TPACK:\\Data\\" + wstrSoundName +L".binka"; + std::wstring mountedPath = StorageManager.GetMountedPath(wstrFile); + wcstombs(m_szStreamName,mountedPath.c_str(),255); +#else + wstring &wstrSoundName=dlcAudioFile->GetSoundName(m_musicID); + char szName[255]; + wcstombs(szName,wstrSoundName.c_str(),255); + + string strFile="TPACK:\\Data\\" + string(szName) + ".binka"; + std::string mountedPath = StorageManager.GetMountedPath(strFile); + strcpy(m_szStreamName,mountedPath.c_str()); +#endif + } + else + { + SetIsPlayingStreamingGameMusic(false); + SetIsPlayingStreamingCDMusic(true); + m_MusicType=eMusicType_CD; + m_StreamingAudioInfo.bIs3D=true; + + // Need to adjust to index into the cds in the game's m_szStreamFileA + strcat((char *)m_szStreamName,"cds/"); + strcat((char *)m_szStreamName,m_szStreamFileA[m_musicID-m_iStream_CD_1+eStream_CD_1]); + strcat((char *)m_szStreamName,".binka"); + } + } + else + { + // 4J-PB - if this is a PS3 disc patch, we have to check if the music file is in the patch data +#ifdef __PS3__ + if(app.GetBootedFromDiscPatch() && (m_musicIDRun(); + m_StreamState = eMusicStreamState_Opening; + } + break; + + case eMusicStreamState_Opening: + // If the open stream thread is complete, then we are ready to proceed to actually playing + if( !m_openStreamThread->isRunning() ) + { + delete m_openStreamThread; + m_openStreamThread = NULL; + + HSAMPLE hSample = AIL_stream_sample_handle( m_hStream); + + // 4J-PB - causes the falloff to be calculated on the PPU instead of the SPU, and seems to resolve our distorted sound issue + AIL_register_falloff_function_callback(hSample,&custom_falloff_function); + + if(m_StreamingAudioInfo.bIs3D) + { + AIL_set_sample_3D_distances(hSample,64.0f,1,0); // Larger distance scaler for music discs + if(m_validListenerCount>1) + { + float fClosest=10000.0f; + int iClosestListener=0; + float fClosestX=0.0f,fClosestY=0.0f,fClosestZ=0.0f,fDist; + // need to calculate the distance from the sound to the nearest listener - use Manhattan Distance as the decision + for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) + { + if( m_ListenerA[i].bValid ) + { + float x,y,z; + + x=fabs(m_ListenerA[i].vPosition.x-m_StreamingAudioInfo.x); + y=fabs(m_ListenerA[i].vPosition.y-m_StreamingAudioInfo.y); + z=fabs(m_ListenerA[i].vPosition.z-m_StreamingAudioInfo.z); + fDist=x+y+z; + + if(fDistisRunning() ) + { + delete m_openStreamThread; + m_openStreamThread = NULL; + m_StreamState = eMusicStreamState_Stop; + } + break; + case eMusicStreamState_Stop: + // should gradually take the volume down in steps + AIL_pause_stream(m_hStream,1); + AIL_close_stream(m_hStream); + m_hStream=0; + SetIsPlayingStreamingCDMusic(false); + SetIsPlayingStreamingGameMusic(false); + m_StreamState=eMusicStreamState_Idle; + break; + case eMusicStreamState_Stopping: + break; + case eMusicStreamState_Play: + break; + case eMusicStreamState_Playing: + if(GetIsPlayingStreamingGameMusic()) + { + //if(m_MusicInfo.pCue!=NULL) + { + bool playerInEnd = false; + bool playerInNether=false; + Minecraft *pMinecraft = Minecraft::GetInstance(); + for(unsigned int i = 0; i < MAX_LOCAL_PLAYERS; ++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()) + { + m_StreamState=eMusicStreamState_Stop; + + // Set the end track + m_musicID = getMusicID(LevelData::DIMENSION_END); + SetIsPlayingEndMusic(true); + SetIsPlayingNetherMusic(false); + } + else if(!playerInEnd && GetIsPlayingEndMusic()) + { + if(playerInNether) + { + m_StreamState=eMusicStreamState_Stop; + + // Set the end track + m_musicID = getMusicID(LevelData::DIMENSION_NETHER); + SetIsPlayingEndMusic(false); + SetIsPlayingNetherMusic(true); + } + else + { + m_StreamState=eMusicStreamState_Stop; + + // Set the end track + m_musicID = getMusicID(LevelData::DIMENSION_OVERWORLD); + SetIsPlayingEndMusic(false); + SetIsPlayingNetherMusic(false); + } + } + else if (playerInNether && !GetIsPlayingNetherMusic()) + { + m_StreamState=eMusicStreamState_Stop; + // set the Nether track + m_musicID = getMusicID(LevelData::DIMENSION_NETHER); + SetIsPlayingNetherMusic(true); + SetIsPlayingEndMusic(false); + } + else if(!playerInNether && GetIsPlayingNetherMusic()) + { + if(playerInEnd) + { + m_StreamState=eMusicStreamState_Stop; + // set the Nether track + m_musicID = getMusicID(LevelData::DIMENSION_END); + SetIsPlayingNetherMusic(false); + SetIsPlayingEndMusic(true); + } + else + { + m_StreamState=eMusicStreamState_Stop; + // set the Nether track + m_musicID = getMusicID(LevelData::DIMENSION_OVERWORLD); + SetIsPlayingNetherMusic(false); + SetIsPlayingEndMusic(false); + } + } + + // volume change required? + if(fMusicVol!=getMasterMusicVolume()) + { + fMusicVol=getMasterMusicVolume(); + HSAMPLE hSample = AIL_stream_sample_handle( m_hStream); + //AIL_set_sample_3D_position( hSample, m_StreamingAudioInfo.x, m_StreamingAudioInfo.y, m_StreamingAudioInfo.z ); + AIL_set_sample_volume_levels( hSample, fMusicVol, fMusicVol); + } + } + } + else + { + // Music disc playing - if it's a 3D stream, then set the position - we don't have any streaming audio in the world that moves, so this isn't + // required unless we have more than one listener, and are setting the listening position to the origin and setting a fake position + // for the sound down the z axis + if(m_StreamingAudioInfo.bIs3D) + { + if(m_validListenerCount>1) + { + float fClosest=10000.0f; + int iClosestListener=0; + float fClosestX=0.0f,fClosestY=0.0f,fClosestZ=0.0f,fDist; + + // need to calculate the distance from the sound to the nearest listener - use Manhattan Distance as the decision + for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) + { + if( m_ListenerA[i].bValid ) + { + float x,y,z; + + x=fabs(m_ListenerA[i].vPosition.x-m_StreamingAudioInfo.x); + y=fabs(m_ListenerA[i].vPosition.y-m_StreamingAudioInfo.y); + z=fabs(m_ListenerA[i].vPosition.z-m_StreamingAudioInfo.z); + fDist=x+y+z; + + if(fDistnextInt(20 * 60 * 3);//random->nextInt(20 * 60 * 10) + 20 * 60 * 10; + // 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;ilocalplayers[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) + { + m_musicID = getMusicID(LevelData::DIMENSION_END); + SetIsPlayingEndMusic(true); + SetIsPlayingNetherMusic(false); + } + else if(playerInNether) + { + m_musicID = getMusicID(LevelData::DIMENSION_NETHER); + SetIsPlayingNetherMusic(true); + SetIsPlayingEndMusic(false); + } + else + { + m_musicID = getMusicID(LevelData::DIMENSION_OVERWORLD); + SetIsPlayingNetherMusic(false); + SetIsPlayingEndMusic(false); + } + + m_StreamState=eMusicStreamState_Idle; + } + break; + } + + // check the status of the stream - this is for when a track completes rather than is stopped by the user action + + if(m_hStream!=0) + { + if(AIL_stream_status(m_hStream)==SMP_DONE ) // SMP_DONE + { + AIL_close_stream(m_hStream); + m_hStream=0; + SetIsPlayingStreamingCDMusic(false); + SetIsPlayingStreamingGameMusic(false); + + m_StreamState=eMusicStreamState_Completed; + } + } +} + + +///////////////////////////////////////////// +// +// ConvertSoundPathToName +// +///////////////////////////////////////////// +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='/'; + if(bConvertSpaces) + { + if(c==' ') c='_'; + } + buf[i] = (char)c; + } + buf[name.length()] = 0; + return buf; +} + +#endif + + +F32 AILCALLBACK custom_falloff_function (HSAMPLE S, + F32 distance, + F32 rolloff_factor, + F32 min_dist, + F32 max_dist) +{ + F32 result; + + // This is now emulating the linear fall-off function that we used on the Xbox 360. The parameter which is passed as "max_dist" is the only one actually used, + // and is generally used as CurveDistanceScaler is used on XACT on the Xbox. A special value of 10000.0f is passed for thunder, which has no attenuation + + if( max_dist == 10000.0f ) + { + return 1.0f; + } + + result = 1.0f - ( distance / max_dist ); + if( result < 0.0f ) result = 0.0f; + if( result > 1.0f ) result = 1.0f; + + return result; +} diff --git a/Minecraft.Client/Common/Audio/SoundEngine.h b/Minecraft.Client/Common/Audio/SoundEngine.h new file mode 100644 index 00000000..92c99d23 --- /dev/null +++ b/Minecraft.Client/Common/Audio/SoundEngine.h @@ -0,0 +1,168 @@ +#pragma once +class Mob; +class Options; +using namespace std; +#include "..\..\Minecraft.World\SoundTypes.h" + +enum eMUSICFILES +{ + eStream_Overworld_Calm1 = 0, + eStream_Overworld_Calm2, + eStream_Overworld_Calm3, + eStream_Overworld_hal1, + eStream_Overworld_hal2, + eStream_Overworld_hal3, + eStream_Overworld_hal4, + eStream_Overworld_nuance1, + eStream_Overworld_nuance2, +#ifndef _XBOX + // Add the new music tracks + eStream_Overworld_Creative1, + eStream_Overworld_Creative2, + eStream_Overworld_Creative3, + eStream_Overworld_Creative4, + eStream_Overworld_Creative5, + eStream_Overworld_Creative6, + eStream_Overworld_Menu1, + eStream_Overworld_Menu2, + eStream_Overworld_Menu3, + eStream_Overworld_Menu4, +#endif + eStream_Overworld_piano1, + eStream_Overworld_piano2, + eStream_Overworld_piano3, // <-- make piano3 the last overworld one + // Nether + eStream_Nether1, + eStream_Nether2, + eStream_Nether3, + eStream_Nether4, + // The End + eStream_end_dragon, + eStream_end_end, + eStream_CD_1, + eStream_CD_2, + eStream_CD_3, + eStream_CD_4, + eStream_CD_5, + eStream_CD_6, + eStream_CD_7, + eStream_CD_8, + eStream_CD_9, + eStream_CD_10, + eStream_CD_11, + eStream_CD_12, + eStream_Max, +}; + +enum eMUSICTYPE +{ + eMusicType_None, + eMusicType_Game, + eMusicType_CD, +}; + + +enum MUSIC_STREAMSTATE +{ + eMusicStreamState_Idle=0, + eMusicStreamState_Stop, + eMusicStreamState_Stopping, + eMusicStreamState_Opening, + eMusicStreamState_OpeningCancel, + eMusicStreamState_Play, + eMusicStreamState_Playing, + eMusicStreamState_Completed +}; + +typedef struct +{ + F32 x,y,z,volume,pitch; + int iSound; + bool bIs3D; + bool bUseSoundsPitchVal; +#ifdef _DEBUG + char chName[64]; +#endif +} +AUDIO_INFO; + +class SoundEngine : public ConsoleSoundEngine +{ + static const int MAX_SAME_SOUNDS_PLAYING = 8; // 4J added +public: + SoundEngine(); + virtual void destroy(); +#ifdef _DEBUG + void GetSoundName(char *szSoundName,int iSound); +#endif + virtual void play(int iSound, float x, float y, float z, float volume, float pitch); + virtual void playStreaming(const wstring& name, float x, float y , float z, float volume, float pitch, bool bMusicDelay=true); + virtual void playUI(int iSound, float volume, float pitch); + virtual void playMusicTick(); + virtual void updateMusicVolume(float fVal); + virtual void updateSystemMusicPlaying(bool isPlaying); + virtual void updateSoundEffectVolume(float fVal); + virtual void init(Options *); + virtual void tick(shared_ptr *players, float a); // 4J - updated to take array of local players rather than single one + virtual void add(const wstring& name, File *file); + virtual void addMusic(const wstring& name, File *file); + virtual void addStreaming(const wstring& name, File *file); + virtual char *ConvertSoundPathToName(const wstring& name, bool bConvertSpaces=false); + bool isStreamingWavebankReady(); // 4J Added + int getMusicID(int iDomain); + int getMusicID(const wstring& name); + void SetStreamingSounds(int iOverworldMin, int iOverWorldMax, int iNetherMin, int iNetherMax, int iEndMin, int iEndMax, int iCD1); + void updateMiles(); // AP added so Vita can update all the Miles functions during the mixer callback + void playMusicUpdate(); + +private: + float getMasterMusicVolume(); + // platform specific functions +#ifdef __PS3__ + int initAudioHardware(int iMinSpeakers); +#else + int initAudioHardware(int iMinSpeakers) { return iMinSpeakers;} +#endif + + int GetRandomishTrack(int iStart,int iEnd); + + HMSOUNDBANK m_hBank; + HDIGDRIVER m_hDriver; + HSTREAM m_hStream; + + static char m_szSoundPath[]; + static char m_szMusicPath[]; + static char m_szRedistName[]; + static char *m_szStreamFileA[eStream_Max]; + + AUDIO_LISTENER m_ListenerA[MAX_LOCAL_PLAYERS]; + int m_validListenerCount; + + + Random *random; + int m_musicID; + int m_iMusicDelay; + int m_StreamState; + int m_MusicType; + AUDIO_INFO m_StreamingAudioInfo; + wstring m_CDMusic; + BOOL m_bSystemMusicPlaying; + float m_MasterMusicVolume; + float m_MasterEffectsVolume; + + C4JThread *m_openStreamThread; + static int OpenStreamThreadProc( void* lpParameter ); + char m_szStreamName[255]; + int CurrentSoundsPlaying[eSoundType_MAX+eSFX_MAX]; + + // streaming music files - will be different for mash-up packs + int m_iStream_Overworld_Min,m_iStream_Overworld_Max; + int m_iStream_Nether_Min,m_iStream_Nether_Max; + int m_iStream_End_Min,m_iStream_End_Max; + int m_iStream_CD_1; + bool *m_bHeardTrackA; + +#ifdef __ORBIS__ + int32_t m_hBGMAudio; +#endif +}; diff --git a/Minecraft.Client/Common/Audio/SoundNames.cpp b/Minecraft.Client/Common/Audio/SoundNames.cpp new file mode 100644 index 00000000..170c87a0 --- /dev/null +++ b/Minecraft.Client/Common/Audio/SoundNames.cpp @@ -0,0 +1,165 @@ +#include "stdafx.h" + +#include "Consoles_SoundEngine.h" + + + +const WCHAR *ConsoleSoundEngine::wchSoundNames[eSoundType_MAX]= +{ + L"mob.chicken", // eSoundType_MOB_CHICKEN_AMBIENT + L"mob.chickenhurt", // eSoundType_MOB_CHICKEN_HURT + L"mob.chickenplop", // eSoundType_MOB_CHICKENPLOP + L"mob.cow", // eSoundType_MOB_COW_AMBIENT + L"mob.cowhurt", // eSoundType_MOB_COW_HURT + L"mob.pig", // eSoundType_MOB_PIG_AMBIENT + L"mob.pigdeath", // eSoundType_MOB_PIG_DEATH + L"mob.sheep", // eSoundType_MOB_SHEEP_AMBIENT + L"mob.wolf.growl", // eSoundType_MOB_WOLF_GROWL + L"mob.wolf.whine", // eSoundType_MOB_WOLF_WHINE + L"mob.wolf.panting", // eSoundType_MOB_WOLF_PANTING + L"mob.wolf.bark", // eSoundType_MOB_WOLF_BARK + L"mob.wolf.hurt", // eSoundType_MOB_WOLF_HURT + L"mob.wolf.death", // eSoundType_MOB_WOLF_DEATH + L"mob.wolf.shake", // eSoundType_MOB_WOLF_SHAKE + L"mob.blaze.breathe", // eSoundType_MOB_BLAZE_BREATHE + L"mob.blaze.hit", // eSoundType_MOB_BLAZE_HURT + L"mob.blaze.death", // eSoundType_MOB_BLAZE_DEATH + L"mob.ghast.moan", // eSoundType_MOB_GHAST_MOAN + L"mob.ghast.scream", // eSoundType_MOB_GHAST_SCREAM + L"mob.ghast.death", // eSoundType_MOB_GHAST_DEATH + L"mob.ghast.fireball", // eSoundType_MOB_GHAST_FIREBALL + L"mob.ghast.charge", // eSoundType_MOB_GHAST_CHARGE + L"mob.endermen.idle", // eSoundType_MOB_ENDERMEN_IDLE + L"mob.endermen.hit", // eSoundType_MOB_ENDERMEN_HIT + L"mob.endermen.death", // eSoundType_MOB_ENDERMEN_DEATH + L"mob.endermen.portal", // eSoundType_MOB_ENDERMEN_PORTAL + L"mob.zombiepig.zpig", // eSoundType_MOB_ZOMBIEPIG_AMBIENT + L"mob.zombiepig.zpighurt", // eSoundType_MOB_ZOMBIEPIG_HURT + L"mob.zombiepig.zpigdeath", // eSoundType_MOB_ZOMBIEPIG_DEATH + L"mob.zombiepig.zpigangry", // eSoundType_MOB_ZOMBIEPIG_ZPIGANGRY + L"mob.silverfish.say", // eSoundType_MOB_SILVERFISH_AMBIENT, + L"mob.silverfish.hit", // eSoundType_MOB_SILVERFISH_HURT + L"mob.silverfish.kill", // eSoundType_MOB_SILVERFISH_DEATH, + L"mob.silverfish.step", // eSoundType_MOB_SILVERFISH_STEP, + L"mob.skeleton", // eSoundType_MOB_SKELETON_AMBIENT, + L"mob.skeletonhurt", // eSoundType_MOB_SKELETON_HURT, + L"mob.spider", // eSoundType_MOB_SPIDER_AMBIENT, + L"mob.spiderdeath", // eSoundType_MOB_SPIDER_DEATH, + L"mob.slime", // eSoundType_MOB_SLIME, + L"mob.slimeattack", // eSoundType_MOB_SLIME_ATTACK, + L"mob.creeper", // eSoundType_MOB_CREEPER_HURT, + L"mob.creeperdeath", // eSoundType_MOB_CREEPER_DEATH, + L"mob.zombie", // eSoundType_MOB_ZOMBIE_AMBIENT, + L"mob.zombiehurt", // eSoundType_MOB_ZOMBIE_HURT, + L"mob.zombiedeath", // eSoundType_MOB_ZOMBIE_DEATH, + L"mob.zombie.wood", // eSoundType_MOB_ZOMBIE_WOOD, + L"mob.zombie.woodbreak", // eSoundType_MOB_ZOMBIE_WOOD_BREAK, + L"mob.zombie.metal", // eSoundType_MOB_ZOMBIE_METAL, + L"mob.magmacube.big", // eSoundType_MOB_MAGMACUBE_BIG, + L"mob.magmacube.small", // eSoundType_MOB_MAGMACUBE_SMALL, + L"mob.cat.purr", // eSoundType_MOB_CAT_PURR + L"mob.cat.purreow", // eSoundType_MOB_CAT_PURREOW + L"mob.cat.meow", // eSoundType_MOB_CAT_MEOW + // 4J-PB - correct the name of the event for hitting ocelots + L"mob.cat.hit", // eSoundType_MOB_CAT_HITT +// L"mob.irongolem.throw", // eSoundType_MOB_IRONGOLEM_THROW +// L"mob.irongolem.hit", // eSoundType_MOB_IRONGOLEM_HIT +// L"mob.irongolem.death", // eSoundType_MOB_IRONGOLEM_DEATH +// L"mob.irongolem.walk", // eSoundType_MOB_IRONGOLEM_WALK + L"random.bow", // eSoundType_RANDOM_BOW, + L"random.bowhit", // eSoundType_RANDOM_BOW_HIT, + L"random.explode", // eSoundType_RANDOM_EXPLODE, + L"random.fizz", // eSoundType_RANDOM_FIZZ, + L"random.pop", // eSoundType_RANDOM_POP, + L"random.fuse", // eSoundType_RANDOM_FUSE, + L"random.drink", // eSoundType_RANDOM_DRINK, + L"random.eat", // eSoundType_RANDOM_EAT, + L"random.burp", // eSoundType_RANDOM_BURP, + L"random.splash", // eSoundType_RANDOM_SPLASH, + L"random.click", // eSoundType_RANDOM_CLICK, + L"random.glass", // eSoundType_RANDOM_GLASS, + L"random.orb", // eSoundType_RANDOM_ORB, + L"random.break", // eSoundType_RANDOM_BREAK, + L"random.chestopen", // eSoundType_RANDOM_CHEST_OPEN, + L"random.chestclosed", // eSoundType_RANDOM_CHEST_CLOSE, + L"random.door_open", // eSoundType_RANDOM_DOOR_OPEN, + L"random.door_close", // eSoundType_RANDOM_DOOR_CLOSE, + L"ambient.weather.rain", // eSoundType_AMBIENT_WEATHER_RAIN, + L"ambient.weather.thunder", // eSoundType_AMBIENT_WEATHER_THUNDER, + L"ambient.cave.cave", // eSoundType_CAVE_CAVE, DON'T USE FOR XBOX 360!!! +#ifdef _XBOX + L"ambient.cave.cave2", // eSoundType_CAVE_CAVE2 - removed the two sounds that were at 192k in the first ambient cave event +#endif + L"portal.portal", // eSoundType_PORTAL_PORTAL, + // 4J-PB - added a couple that were still using wstring + L"portal.trigger", // eSoundType_PORTAL_TRIGGER + L"portal.travel", // eSoundType_PORTAL_TRAVEL + + L"fire.ignite", // eSoundType_FIRE_IGNITE, + L"fire.fire", // eSoundType_FIRE_FIRE, + L"damage.hurtflesh", // eSoundType_DAMAGE_HURT, + L"damage.fallsmall", // eSoundType_DAMAGE_FALL_SMALL, + L"damage.fallbig", // eSoundType_DAMAGE_FALL_BIG, + L"note.harp", // eSoundType_NOTE_HARP, + L"note.bd", // eSoundType_NOTE_BD, + L"note.snare", // eSoundType_NOTE_SNARE, + L"note.hat", // eSoundType_NOTE_HAT, + L"note.bassattack", // eSoundType_NOTE_BASSATTACK, + L"tile.piston.in", // eSoundType_TILE_PISTON_IN, + L"tile.piston.out", // eSoundType_TILE_PISTON_OUT, + L"liquid.water", // eSoundType_LIQUID_WATER, + L"liquid.lavapop", // eSoundType_LIQUID_LAVA_POP, + L"liquid.lava", // eSoundType_LIQUID_LAVA, + L"step.stone", // eSoundType_STEP_STONE, + L"step.wood", // eSoundType_STEP_WOOD, + L"step.gravel", // eSoundType_STEP_GRAVEL, + L"step.grass", // eSoundType_STEP_GRASS, + L"step.metal", // eSoundType_STEP_METAL, + L"step.cloth", // eSoundType_STEP_CLOTH, + L"step.sand", // eSoundType_STEP_SAND, + + // below this are the additional sounds from the second soundbank + L"mob.enderdragon.end", // eSoundType_MOB_ENDERDRAGON_END + L"mob.enderdragon.growl", // eSoundType_MOB_ENDERDRAGON_GROWL + L"mob.enderdragon.hit", // eSoundType_MOB_ENDERDRAGON_HIT + L"mob.enderdragon.wings", // eSoundType_MOB_ENDERDRAGON_MOVE + L"mob.irongolem.throw", // eSoundType_MOB_IRONGOLEM_THROW + L"mob.irongolem.hit", // eSoundType_MOB_IRONGOLEM_HIT + L"mob.irongolem.death", // eSoundType_MOB_IRONGOLEM_DEATH + L"mob.irongolem.walk", // eSoundType_MOB_IRONGOLEM_WALK + + // TU14 + L"damage.thorns", // eSoundType_DAMAGE_THORNS + L"random.anvil_break", // eSoundType_RANDOM_ANVIL_BREAK + L"random.anvil_land", // eSoundType_RANDOM_ANVIL_LAND + L"random.anvil_use", // eSoundType_RANDOM_ANVIL_USE + L"mob.villager.haggle", // eSoundType_MOB_VILLAGER_HAGGLE + L"mob.villager.idle", // eSoundType_MOB_VILLAGER_IDLE + L"mob.villager.hit", // eSoundType_MOB_VILLAGER_HIT + L"mob.villager.death", // eSoundType_MOB_VILLAGER_DEATH + L"mob.villager.yes", // eSoundType_MOB_VILLAGER_YES + L"mob.villager.no", // eSoundType_MOB_VILLAGER_NO + L"mob.zombie.infect", // eSoundType_MOB_ZOMBIE_INFECT + L"mob.zombie.unfect", // eSoundType_MOB_ZOMBIE_UNFECT + L"mob.zombie.remedy", // eSoundType_MOB_ZOMBIE_REMEDY + L"step.snow", // eSoundType_STEP_SNOW + L"step.ladder", // eSoundType_STEP_LADDER + L"dig.cloth", // eSoundType_DIG_CLOTH + L"dig.grass", // eSoundType_DIG_GRASS + L"dig.gravel", // eSoundType_DIG_GRAVEL + L"dig.sand", // eSoundType_DIG_SAND + L"dig.snow", // eSoundType_DIG_SNOW + L"dig.stone", // eSoundType_DIG_STONE + L"dig.wood", // eSoundType_DIG_WOOD +}; + + +const WCHAR *ConsoleSoundEngine::wchUISoundNames[eSFX_MAX]= +{ + L"back", + L"craft", + L"craftfail", + L"focus", + L"press", + L"scroll", +}; -- cgit v1.2.3