From ba75b39c3f9e83ab801b2fcd770d73e4385db007 Mon Sep 17 00:00:00 2001 From: Liriosha <57261793+Liriosha@users.noreply.github.com> Date: Thu, 19 Mar 2026 03:21:19 -0400 Subject: [PATCH] Rewrite, format, fix shiggy bug --- .../Common/Audio/Consoles_SoundEngine.cpp | 43 +- .../Common/Audio/Consoles_SoundEngine.h | 109 +- .../Platform/Common/Audio/SoundEngine.cpp | 3696 ++++++++++------- .../Platform/Common/Audio/SoundEngine.h | 3 + .../Platform/Common/Audio/SoundNames.cpp | 11 +- .../Common/Audio/miniaudio_libvorbis.c | 591 --- .../Common/Audio/miniaudio_libvorbis.h | 42 - .../Platform/Common/Audio/stb_vorbis.h | 3 +- subprojects/shiggy | 1 - 9 files changed, 2168 insertions(+), 2331 deletions(-) delete mode 100644 Minecraft.Client/Platform/Common/Audio/miniaudio_libvorbis.c delete mode 100644 Minecraft.Client/Platform/Common/Audio/miniaudio_libvorbis.h delete mode 160000 subprojects/shiggy diff --git a/Minecraft.Client/Platform/Common/Audio/Consoles_SoundEngine.cpp b/Minecraft.Client/Platform/Common/Audio/Consoles_SoundEngine.cpp index 5d096eabf..900ec6dc3 100644 --- a/Minecraft.Client/Platform/Common/Audio/Consoles_SoundEngine.cpp +++ b/Minecraft.Client/Platform/Common/Audio/Consoles_SoundEngine.cpp @@ -1,38 +1,25 @@ #include "../../Minecraft.World/Platform/stdafx.h" #include "Consoles_SoundEngine.h" - -bool ConsoleSoundEngine::GetIsPlayingStreamingCDMusic() -{ - return m_bIsPlayingStreamingCDMusic; +bool ConsoleSoundEngine::GetIsPlayingStreamingCDMusic() { + return m_bIsPlayingStreamingCDMusic; } -bool ConsoleSoundEngine::GetIsPlayingStreamingGameMusic() -{ - return m_bIsPlayingStreamingGameMusic; +bool ConsoleSoundEngine::GetIsPlayingStreamingGameMusic() { + return m_bIsPlayingStreamingGameMusic; } -void ConsoleSoundEngine::SetIsPlayingStreamingCDMusic(bool bVal) -{ - m_bIsPlayingStreamingCDMusic=bVal; +void ConsoleSoundEngine::SetIsPlayingStreamingCDMusic(bool bVal) { + m_bIsPlayingStreamingCDMusic = bVal; } -void ConsoleSoundEngine::SetIsPlayingStreamingGameMusic(bool bVal) -{ - m_bIsPlayingStreamingGameMusic=bVal; +void ConsoleSoundEngine::SetIsPlayingStreamingGameMusic(bool bVal) { + m_bIsPlayingStreamingGameMusic = bVal; } -bool ConsoleSoundEngine::GetIsPlayingEndMusic() -{ - return m_bIsPlayingEndMusic; +bool ConsoleSoundEngine::GetIsPlayingEndMusic() { return m_bIsPlayingEndMusic; } +bool ConsoleSoundEngine::GetIsPlayingNetherMusic() { + return m_bIsPlayingNetherMusic; } -bool ConsoleSoundEngine::GetIsPlayingNetherMusic() -{ - return m_bIsPlayingNetherMusic; +void ConsoleSoundEngine::SetIsPlayingEndMusic(bool bVal) { + m_bIsPlayingEndMusic = bVal; } -void ConsoleSoundEngine::SetIsPlayingEndMusic(bool bVal) -{ - m_bIsPlayingEndMusic=bVal; +void ConsoleSoundEngine::SetIsPlayingNetherMusic(bool bVal) { + m_bIsPlayingNetherMusic = bVal; } -void ConsoleSoundEngine::SetIsPlayingNetherMusic(bool bVal) -{ - m_bIsPlayingNetherMusic=bVal; -} - - diff --git a/Minecraft.Client/Platform/Common/Audio/Consoles_SoundEngine.h b/Minecraft.Client/Platform/Common/Audio/Consoles_SoundEngine.h index d8529e486..9b2dc5077 100644 --- a/Minecraft.Client/Platform/Common/Audio/Consoles_SoundEngine.h +++ b/Minecraft.Client/Platform/Common/Audio/Consoles_SoundEngine.h @@ -4,81 +4,86 @@ #ifdef _XBOX -#elif defined (__PS3__) +#elif defined(__PS3__) #undef __in #undef __out #include "../../Minecraft.Client/Platform/PS3/Miles/include/mss.h" -#elif defined (__PSVITA__) +#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 +// 4J Stu - Temp define to get Miles to link, can likely be removed when we get +// a new version of Miles #define _SEKRIT #include "../../Minecraft.Client/Platform/Durango/Miles/include/mss.h" #elif defined _WINDOWS64 #include "../../windows64/Miles/include/mss.h" #elif defined(__linux__) -// (DecalOverdose)HACK + TODO: Find native Linux headers and libs for this, but for now I'm using Win64 ones +// (DecalOverdose)HACK + TODO: Find native Linux headers and libs for this, but +// for now I'm using Win64 ones #include "../../Minecraft.Client/Platform/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 +#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 "../../Minecraft.Client/Platform/Orbis/Miles/include/mss.h" #endif -typedef struct -{ - float x,y,z; -} -AUDIO_VECTOR; +typedef struct { + float x, y, z; +} AUDIO_VECTOR; -typedef struct -{ - bool bValid; - AUDIO_VECTOR vPosition; - AUDIO_VECTOR vOrientFront; -} -AUDIO_LISTENER; +typedef struct { + bool bValid; + AUDIO_VECTOR vPosition; + AUDIO_VECTOR vOrientFront; +} AUDIO_LISTENER; class Options; -class ConsoleSoundEngine -{ +class ConsoleSoundEngine { public: + ConsoleSoundEngine() + : m_bIsPlayingStreamingCDMusic(false), + m_bIsPlayingStreamingGameMusic(false), + m_bIsPlayingEndMusic(false), + m_bIsPlayingNetherMusic(false) {}; + virtual void tick(std::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 std::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 std::wstring& name, File* file) = 0; + virtual void addMusic(const std::wstring& name, File* file) = 0; + virtual void addStreaming(const std::wstring& name, File* file) = 0; + virtual char* ConvertSoundPathToName(const std::wstring& name, + bool bConvertSpaces) = 0; + virtual void playMusicTick() = 0; - ConsoleSoundEngine() : m_bIsPlayingStreamingCDMusic(false),m_bIsPlayingStreamingGameMusic(false), m_bIsPlayingEndMusic(false),m_bIsPlayingNetherMusic(false){}; - virtual void tick(std::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 std::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 std::wstring& name, File *file) =0; - virtual void addMusic(const std::wstring& name, File *file) =0; - virtual void addStreaming(const std::wstring& name, File *file) =0; - virtual char *ConvertSoundPathToName(const std::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]; + 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 + // platform specific functions - virtual int initAudioHardware(int iMinSpeakers)=0; + virtual int initAudioHardware(int iMinSpeakers) = 0; - bool m_bIsPlayingStreamingCDMusic; - bool m_bIsPlayingStreamingGameMusic; - bool m_bIsPlayingEndMusic; - bool m_bIsPlayingNetherMusic; + bool m_bIsPlayingStreamingCDMusic; + bool m_bIsPlayingStreamingGameMusic; + bool m_bIsPlayingEndMusic; + bool m_bIsPlayingNetherMusic; }; diff --git a/Minecraft.Client/Platform/Common/Audio/SoundEngine.cpp b/Minecraft.Client/Platform/Common/Audio/SoundEngine.cpp index 570809cb1..c7a3069d3 100644 --- a/Minecraft.Client/Platform/Common/Audio/SoundEngine.cpp +++ b/Minecraft.Client/Platform/Common/Audio/SoundEngine.cpp @@ -26,11 +26,7 @@ #include "../../Minecraft.Client/Platform/Windows64/Miles/include/imssapi.h" #endif -#ifdef __ORBIS__ -#include -// #define __DISABLE_MILES__ // MGH disabled for now as it -// crashes if we call sceNpMatching2Initialize -#endif +// ASSETS const char* SoundEngine::m_szStreamFileA[eStream_Max] = {"calm1", "calm2", "calm3", @@ -71,13 +67,96 @@ const char* SoundEngine::m_szStreamFileA[eStream_Max] = {"calm1", "strad", "ward", "where_are_we_now"}; -// take out Orbis until they are done -#if defined _XBOX || defined(__linux__) +#ifdef __linux__ +char SoundEngine::m_szSoundPath[] = {"Sound/"}; +char SoundEngine::m_szMusicPath[] = {"music/"}; +char SoundEngine::m_szRedistName[] = {"redist64"}; +#endif -SoundEngine::SoundEngine() {} +#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 +// END ASSETS + +// Linux specific functions +#ifdef __linux__ +std::wstring stws(const char* utf8) +{ + size_t len = std::mbstowcs(nullptr, utf8, 0); + if (len == static_cast(-1)) return L""; + std::wstring result(len, L'\0'); + std::mbstowcs(&result[0], utf8, len); + return result; +} +SoundEngine::SoundEngine() { +} std::vector m_activeSounds; void SoundEngine::init(Options* pOptions) { app.DebugPrintf("---SoundEngine::init\n"); + random = new Random(); + memset(&m_engine, 0, sizeof(ma_engine)); + memset(&m_engineConfig, 0, sizeof(ma_engine_config)); + m_musicStreamActive = false; + m_StreamState=eMusicStreamState_Idle; + m_iMusicDelay=0; + m_validListenerCount=0; + + m_bHeardTrackA=nullptr; + + // 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) * (static_cast(eSoundType_MAX) + static_cast(eSFX_MAX))); + memset(m_ListenerA,0,sizeof(AUDIO_LISTENER)*XUSER_MAX_COUNT); m_engineConfig = ma_engine_config_init(); m_engineConfig.listenerCount = MAX_LOCAL_PLAYERS; @@ -95,10 +174,7 @@ void SoundEngine::init(Options* pOptions) { m_bSystemMusicPlaying = false; } - -void SoundEngine::tick(std::shared_ptr* players, float a) {} void SoundEngine::destroy() { ma_engine_uninit(&m_engine); } - void SoundEngine::play(int iSound, float x, float y, float z, float volume, float pitch) { char szSoundName[256] = "Sound/Minecraft/"; @@ -180,8 +256,7 @@ void SoundEngine::play(int iSound, float x, float y, float z, float volume, if (ma_sound_init_from_file(&m_engine, finalPath, MA_SOUND_FLAG_ASYNC, nullptr, nullptr, &s->sound) != MA_SUCCESS) { - app.DebugPrintf("Failed to initialize sound from file: %s\n", - finalPath); + app.DebugPrintf("Failed to load sound ID : %i from %S\n", iSound, wchSoundNames[iSound]); delete s; return; } @@ -262,6 +337,1998 @@ void SoundEngine::playUI(int iSound, float volume, float pitch) { m_activeSounds.push_back(s); } + +int SoundEngine::getMusicID(int iDomain) +{ + int iRandomVal=0; + Minecraft *pMinecraft=Minecraft::GetInstance(); + + // Protection from errors + if(pMinecraft==nullptr || pMinecraft->skins==nullptr) + { + // 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); + } + } +} + +int SoundEngine::getMusicID(const std::wstring& name) +{ + int iCD = 0; + for (size_t i = 0; i < 12; i++) + { + std::wstring fileNameW = stws(m_szStreamFileA[i + eStream_CD_1]); + + if (name == fileNameW) + { + iCD = static_cast(i); + break; + } + } + return iCD + m_iStream_CD_1; +} + +void SoundEngine::playStreaming(const wstring& name, float x, float y, float z, + float volume, float pitch, bool bMusicDelay) { + 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; + } + app.DebugPrintf("playStreaming %S", name.c_str()); + 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]!=nullptr) + { + 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::OpenStreamThreadProc(void* lpParameter) +{ + SoundEngine* soundEngine = (SoundEngine*)lpParameter; + + const char* ext = strrchr(soundEngine->m_szStreamName, '.'); + + if (soundEngine->m_musicStreamActive) + { + ma_sound_stop(&soundEngine->m_musicStream); + ma_sound_uninit(&soundEngine->m_musicStream); + soundEngine->m_musicStreamActive = false; + } + + ma_result result = ma_sound_init_from_file( + &soundEngine->m_engine, + soundEngine->m_szStreamName, + MA_SOUND_FLAG_STREAM, + nullptr, + nullptr, + &soundEngine->m_musicStream); + + if (result != MA_SUCCESS) + { + app.DebugPrintf("SoundEngine::OpenStreamThreadProc - Failed to open stream: %s\n", soundEngine->m_szStreamName); + return 0; + } + + ma_sound_set_spatialization_enabled(&soundEngine->m_musicStream, MA_FALSE); + ma_sound_set_looping(&soundEngine->m_musicStream, MA_FALSE); + + soundEngine->m_musicStreamActive = true; + + return 0; +} + + +void SoundEngine::playMusicTick() +{ + static float fMusicVol = 0.0f; + fMusicVol = getMasterMusicVolume(); + + switch(m_StreamState) + { + case eMusicStreamState_Idle: + + // start a stream playing + if (m_iMusicDelay > 0) + { + m_iMusicDelay--; + return; + } + + if (m_musicStreamActive) + { + app.DebugPrintf("WARNING: m_musicStreamActive already true in Idle state, resetting to Playing\n"); + m_StreamState = eMusicStreamState_Playing; + return; + } + + if(m_musicID!=-1) + { + // start playing it + + strcpy((char *)m_szStreamName, m_szMusicPath); + // 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); + + char szName[255]; + wcstombs(szName, wstrSoundName.c_str(), 255); + + string strFile = "TPACK:\\Data\\" + string(szName) + ".wav"; + + std::string mountedPath = StorageManager.GetMountedPath(strFile); + strcpy(m_szStreamName, mountedPath.c_str()); + } + 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,".wav"); + } + } + else + { + if(m_musicID(m_szStreamName), "rb"); + if (pFile) + { + fclose(pFile); + } + else + { + const char* extensions[] = { ".ogg", ".mp3", ".wav" }; + size_t extCount = sizeof(extensions) / sizeof(extensions[0]); + bool found = false; + + char* dotPos = strrchr(reinterpret_cast(m_szStreamName), '.'); + if (dotPos != nullptr && (dotPos - reinterpret_cast(m_szStreamName)) < 250) + { + for (size_t i = 0; i < extCount; i++) + { + strncpy(dotPos, extensions[i], 5 ); + app.DebugPrintf("Checking %s\n",m_szStreamName); + pFile = fopen(reinterpret_cast(m_szStreamName), "rb"); + if (pFile) + { + fclose(pFile); + found = true; + break; + } + } + } + + if (!found) + { + if (dotPos != nullptr) + { + strncpy(dotPos, ".wav", 5); + } + app.DebugPrintf("WARNING: No audio file found for music ID %d (tried .ogg, .mp3, .wav)\n", m_musicID); + return; + } + } + + app.DebugPrintf("Starting streaming - %s\n",m_szStreamName); + m_openStreamThread = new C4JThread(OpenStreamThreadProc, this, "OpenStreamThreadProc"); + m_openStreamThread->Run(); + m_StreamState = eMusicStreamState_Opening; + } + break; + + case eMusicStreamState_Opening: + if( !m_openStreamThread->isRunning() ) + { + delete m_openStreamThread; + m_openStreamThread = nullptr; + + app.DebugPrintf("OpenStreamThreadProc finished. m_musicStreamActive=%d\n", m_musicStreamActive); + + if (!m_musicStreamActive) + { + const char* currentExt = strrchr(reinterpret_cast(m_szStreamName), '.'); + if (currentExt && _stricmp(currentExt, ".wav") == 0) + { + const bool isCD = (m_musicID >= m_iStream_CD_1); + const char* folder = isCD ? "cds/" : "music/"; + + int n = sprintf_s(reinterpret_cast(m_szStreamName), 512, "%s%s%s.wav", m_szMusicPath, folder, m_szStreamFileA[m_musicID]); + + if (n > 0) + { + FILE* pFile = fopen(reinterpret_cast(m_szStreamName), "rb"); + if (pFile) + { + fclose(pFile); + + m_openStreamThread = new C4JThread(OpenStreamThreadProc, this, "OpenStreamThreadProc"); + m_openStreamThread->Run(); + break; + } + } + } + + m_StreamState = eMusicStreamState_Idle; + break; + } + + if (m_StreamingAudioInfo.bIs3D) + { + ma_sound_set_spatialization_enabled(&m_musicStream, MA_TRUE); + ma_sound_set_position(&m_musicStream, m_StreamingAudioInfo.x, m_StreamingAudioInfo.y, m_StreamingAudioInfo.z); + } + else + { + ma_sound_set_spatialization_enabled(&m_musicStream, MA_FALSE); + } + + ma_sound_set_pitch(&m_musicStream, m_StreamingAudioInfo.pitch); + + float finalVolume = m_StreamingAudioInfo.volume * getMasterMusicVolume(); + + ma_sound_set_volume(&m_musicStream, finalVolume); + ma_result startResult = ma_sound_start(&m_musicStream); + app.DebugPrintf("ma_sound_start result: %d\n", startResult); + + m_StreamState=eMusicStreamState_Playing; + } + break; + case eMusicStreamState_OpeningCancel: + if( !m_openStreamThread->isRunning() ) + { + delete m_openStreamThread; + m_openStreamThread = nullptr; + m_StreamState = eMusicStreamState_Stop; + } + break; + case eMusicStreamState_Stop: + if (m_musicStreamActive) + { + ma_sound_stop(&m_musicStream); + ma_sound_uninit(&m_musicStream); + m_musicStreamActive = false; + } + + SetIsPlayingStreamingCDMusic(false); + SetIsPlayingStreamingGameMusic(false); + + m_StreamState = eMusicStreamState_Idle; + break; + case eMusicStreamState_Stopping: + break; + case eMusicStreamState_Play: + break; + case eMusicStreamState_Playing: + { + static int frameCount = 0; + if (frameCount++ % 60 == 0) + { + if (m_musicStreamActive) + { + bool isPlaying = ma_sound_is_playing(&m_musicStream); + float vol = ma_sound_get_volume(&m_musicStream); + bool isAtEnd = ma_sound_at_end(&m_musicStream); + } + } + } + if(GetIsPlayingStreamingGameMusic()) + { + { + bool playerInEnd = false; + bool playerInNether=false; + Minecraft *pMinecraft = Minecraft::GetInstance(); + for(unsigned int i = 0; i < MAX_LOCAL_PLAYERS; ++i) + { + if(pMinecraft->localplayers[i]!=nullptr) + { + 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 (m_musicStreamActive) + { + float finalVolume = m_StreamingAudioInfo.volume * fMusicVol; + + ma_sound_set_volume(&m_musicStream, finalVolume); + } + } + } + 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 && m_validListenerCount > 1) + { + int iClosestListener = 0; + float fClosestDist = 1e6f; + + for (size_t i = 0; i < MAX_LOCAL_PLAYERS; i++) + { + if (m_ListenerA[i].bValid) + { + float dx = m_StreamingAudioInfo.x - m_ListenerA[i].vPosition.x; + float dy = m_StreamingAudioInfo.y - m_ListenerA[i].vPosition.y; + float dz = m_StreamingAudioInfo.z - m_ListenerA[i].vPosition.z; + float dist = sqrtf(dx*dx + dy*dy + dz*dz); + + if (dist < fClosestDist) + { + fClosestDist = dist; + iClosestListener = i; + } + } + } + + float relX = m_StreamingAudioInfo.x - m_ListenerA[iClosestListener].vPosition.x; + float relY = m_StreamingAudioInfo.y - m_ListenerA[iClosestListener].vPosition.y; + float relZ = m_StreamingAudioInfo.z - m_ListenerA[iClosestListener].vPosition.z; + + if (m_musicStreamActive) + { + ma_sound_set_position(&m_musicStream, relX, relY, relZ); + } + } + } + + break; + + case eMusicStreamState_Completed: + { + // random delay of up to 3 minutes for music + m_iMusicDelay = random->nextInt(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]!=nullptr) + { + 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_musicStreamActive) + { + if (!ma_sound_is_playing(&m_musicStream) && ma_sound_at_end(&m_musicStream)) + { + ma_sound_uninit(&m_musicStream); + m_musicStreamActive = false; + + SetIsPlayingStreamingCDMusic(false); + SetIsPlayingStreamingGameMusic(false); + + m_StreamState = eMusicStreamState_Completed; + } + } +} + + +void SoundEngine::updateMiniAudio() +{ + if (m_validListenerCount == 1) + { + for (size_t i = 0; i < MAX_LOCAL_PLAYERS; i++) + { + if (m_ListenerA[i].bValid) + { + ma_engine_listener_set_position( + &m_engine, + 0, + m_ListenerA[i].vPosition.x, + m_ListenerA[i].vPosition.y, + m_ListenerA[i].vPosition.z); + + ma_engine_listener_set_direction( + &m_engine, + 0, + m_ListenerA[i].vOrientFront.x, + m_ListenerA[i].vOrientFront.y, + m_ListenerA[i].vOrientFront.z); + + ma_engine_listener_set_world_up( + &m_engine, + 0, + 0.0f, 1.0f, 0.0f); + + break; + } + } + } + else + { + ma_engine_listener_set_position(&m_engine, 0, 0.0f, 0.0f, 0.0f); + ma_engine_listener_set_direction(&m_engine, 0, 0.0f, 0.0f, 1.0f); + ma_engine_listener_set_world_up(&m_engine, 0, 0.0f, 1.0f, 0.0f); + } + + for (auto it = m_activeSounds.begin(); it != m_activeSounds.end(); ) + { + MiniAudioSound* s = *it; + + if (!ma_sound_is_playing(&s->sound)) + { + ma_sound_uninit(&s->sound); + delete s; + it = m_activeSounds.erase(it); + continue; + } + + float finalVolume = s->info.volume * m_MasterEffectsVolume * SFX_VOLUME_MULTIPLIER; + if (finalVolume > SFX_MAX_GAIN) + finalVolume = SFX_MAX_GAIN; + + ma_sound_set_volume(&s->sound, finalVolume); + ma_sound_set_pitch(&s->sound, s->info.pitch); + + if (s->info.bIs3D) + { + if (m_validListenerCount > 1) + { + float fClosest=10000.0f; + int iClosestListener=0; + float fClosestX=0.0f,fClosestY=0.0f,fClosestZ=0.0f,fDist; + for( size_t i = 0; i < MAX_LOCAL_PLAYERS; i++ ) + { + if( m_ListenerA[i].bValid ) + { + float x,y,z; + + x=fabs(m_ListenerA[i].vPosition.x-s->info.x); + y=fabs(m_ListenerA[i].vPosition.y-s->info.y); + z=fabs(m_ListenerA[i].vPosition.z-s->info.z); + fDist=x+y+z; + + if(fDistsound, 0, 0, realDist); + } + else + { + ma_sound_set_position( + &s->sound, + s->info.x, + s->info.y, + s->info.z); + } + } + + ++it; + } +} + +void SoundEngine::tick(shared_ptr *players, float a) +{ + // update the listener positions + int listenerCount = 0; + if( players ) + { + bool bListenerPostionSet = false; + for( size_t i = 0; i < MAX_LOCAL_PLAYERS; i++ ) + { + if( players[i] != nullptr ) + { + 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); + float ySin = (float)sin(yRot * Mth::RAD_TO_GRAD); + + // 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; + updateMiniAudio(); +} +// Classic sound module +#else +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 +// 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(std::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() +{ + 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/"); + std::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) + { + // std::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 + std::wstring name = wchSoundNames[eSoundType_MOB_ENDERDRAGON_GROWL]; +#else + std::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]; + std::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 std::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::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); + std::wstring wstrFile=L"TPACK:\\Data\\" + wstrSoundName +L".binka"; + std::wstring mountedPath = StorageManager.GetMountedPath(wstrFile); + wcstombs(m_szStreamName,mountedPath.c_str(),255); +#else + std::wstring &wstrSoundName=dlcAudioFile->GetSoundName(m_musicID); + char szName[255]; + wcstombs(szName,wstrSoundName.c_str(),255); + + std::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; + } + } +} +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; +} +#endif + + +// Universal, these functions shouldn't need platform specific implementations void SoundEngine::updateMusicVolume(float fVal) { m_MasterMusicVolume = fVal; } void SoundEngine::updateSystemMusicPlaying(bool isPlaying) { m_bSystemMusicPlaying = isPlaying; @@ -269,15 +2336,6 @@ void SoundEngine::updateSystemMusicPlaying(bool isPlaying) { void SoundEngine::updateSoundEffectVolume(float fVal) { m_MasterEffectsVolume = fVal; } -void SoundEngine::add(const std::wstring& name, File* file) {} -void SoundEngine::addMusic(const std::wstring& name, File* file) {} -void SoundEngine::addStreaming(const std::wstring& name, File* file) {} -char* SoundEngine::ConvertSoundPathToName(const std::wstring& name, - bool bConvertSpaces) { - return NULL; -} -bool SoundEngine::isStreamingWavebankReady() { return true; } -void SoundEngine::playMusicTick() {}; void SoundEngine::SetStreamingSounds(int iOverworldMin, int iOverWorldMax, int iNetherMin, int iNetherMax, int iEndMin, int iEndMax, int iCD1) { @@ -296,9 +2354,6 @@ void SoundEngine::SetStreamingSounds(int iOverworldMin, int iOverWorldMax, m_bHeardTrackA = new bool[iEndMax + 1]; memset(m_bHeardTrackA, 0, sizeof(bool) * iEndMax + 1); } -// TODO : FIX STUB -void SoundEngine::playStreaming(const wstring& name, float x, float y, float z, - float volume, float pitch, bool bMusicDelay) {} 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 @@ -341,26 +2396,6 @@ int SoundEngine::GetRandomishTrack(int iStart, int iEnd) { app.DebugPrintf("Select track %d\n", iVal); return iVal; } -///////////////////////////////////////////// -// -// getMusicID -// -///////////////////////////////////////////// -int SoundEngine::getMusicID(int iDomain) { return 0; } - -///////////////////////////////////////////// -// -// getMusicID -// -///////////////////////////////////////////// -// check what the CD is -int SoundEngine::getMusicID(const wstring& name) { return 0; } - -///////////////////////////////////////////// -// -// getMasterMusicVolume -// -///////////////////////////////////////////// float SoundEngine::getMasterMusicVolume() { if (m_bSystemMusicPlaying) { return 0.0f; @@ -368,1575 +2403,14 @@ float SoundEngine::getMasterMusicVolume() { return m_MasterMusicVolume; } } - -#ifdef __linux__ -char SoundEngine::m_szSoundPath[] = {"Sound/"}; -char SoundEngine::m_szMusicPath[] = {"music/"}; -char SoundEngine::m_szRedistName[] = {"redist64"}; -#endif - -#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 - -#ifndef __linux__ - -F32 AILCALLBACK custom_falloff_function(HSAMPLE S, F32 distance, - F32 rolloff_factor, F32 min_dist, - F32 max_dist); - -///////////////////////////////////////////// -// -// 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 (fDist < fClosest) { - fClosest = fDist; - fClosestX = x; - fClosestY = y; - fClosestZ = z; - iClosestListener = i; - } - } - } - - // our distances in the world aren't very big, so - // floats rather than casts to doubles should be - // fine - fDist = sqrtf((fClosestX * fClosestX) + - (fClosestY * fClosestY) + - (fClosestZ * fClosestZ)); - AIL_set_sample_3D_position(SoundInfo.Sample, 0, 0, - fDist); - - // app.DebugPrintf("Playing sound %d %f from nearest - // listener - // [%d]\n",SoundInfo.EventID,fDist,iClosestListener); - } else { - AIL_set_sample_3D_position( - SoundInfo.Sample, game_data->x, 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 (fDist < fClosest) { - fClosest = fDist; - fClosestX = x; - fClosestY = y; - fClosestZ = z; - iClosestListener = i; - } - } - } - // our distances in the world aren't very big, so - // floats rather than casts to doubles should be - // fine - fDist = sqrtf((fClosestX * fClosestX) + - (fClosestY * fClosestY) + - (fClosestZ * fClosestZ)); - AIL_set_sample_3D_position(SoundInfo.Sample, 0, 0, - fDist); - - // app.DebugPrintf("Playing sound %d %f from nearest - // listener - // [%d]\n",SoundInfo.EventID,fDist,iClosestListener); - } else { - AIL_set_sample_3D_position( - SoundInfo.Sample, game_data->x, 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(std::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/"); - std::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) - { - // std::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 - std::wstring name = wchSoundNames[eSoundType_MOB_ENDERDRAGON_GROWL]; -#else - std::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]; - std::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 std::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; 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) { - 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 std::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 std::wstring& name, File* file) {} + void SoundEngine::addMusic(const std::wstring& name, File* file) {} void SoundEngine::addStreaming(const std::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_musicID < m_iStream_CD_1) { - SetIsPlayingStreamingGameMusic(true); - SetIsPlayingStreamingCDMusic(false); - m_MusicType = eMusicType_Game; - m_StreamingAudioInfo.bIs3D = false; - -#ifdef _XBOX_ONE - std::wstring& wstrSoundName = - dlcAudioFile->GetSoundName(m_musicID); - std::wstring wstrFile = - L"TPACK:\\Data\\" + wstrSoundName + L".binka"; - std::wstring mountedPath = - StorageManager.GetMountedPath(wstrFile); - wcstombs(m_szStreamName, mountedPath.c_str(), 255); -#else - std::wstring& wstrSoundName = - dlcAudioFile->GetSoundName(m_musicID); - char szName[255]; - wcstombs(szName, wstrSoundName.c_str(), 255); - - std::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_musicID < m_iStream_CD_1)) { - // rebuild the path for the music - strcpy((char*)m_szStreamName, m_szMusicPath); - strcat((char*)m_szStreamName, "music/"); - strcat((char*)m_szStreamName, - m_szStreamFileA[m_musicID]); - strcat((char*)m_szStreamName, ".binka"); - - // check if this is in the patch data - sprintf(m_szStreamName, "%s/%s", - app.GetBDUsrDirPath(m_szStreamName), - m_szMusicPath); - strcat((char*)m_szStreamName, "music/"); - strcat((char*)m_szStreamName, - m_szStreamFileA[m_musicID]); - strcat((char*)m_szStreamName, ".binka"); - - SetIsPlayingStreamingGameMusic(true); - SetIsPlayingStreamingCDMusic(false); - m_MusicType = eMusicType_Game; - m_StreamingAudioInfo.bIs3D = false; - } else if (m_musicID < m_iStream_CD_1) { - SetIsPlayingStreamingGameMusic(true); - SetIsPlayingStreamingCDMusic(false); - m_MusicType = eMusicType_Game; - m_StreamingAudioInfo.bIs3D = false; - // build the name - strcat((char*)m_szStreamName, "music/"); - strcat((char*)m_szStreamName, - m_szStreamFileA[m_musicID]); - strcat((char*)m_szStreamName, ".binka"); - } - - else { - SetIsPlayingStreamingGameMusic(false); - SetIsPlayingStreamingCDMusic(true); - m_MusicType = eMusicType_CD; - m_StreamingAudioInfo.bIs3D = true; - // build the name - strcat((char*)m_szStreamName, "cds/"); - strcat((char*)m_szStreamName, - m_szStreamFileA[m_musicID]); - strcat((char*)m_szStreamName, ".binka"); - } -#else - if (m_musicID < m_iStream_CD_1) { - SetIsPlayingStreamingGameMusic(true); - SetIsPlayingStreamingCDMusic(false); - m_MusicType = eMusicType_Game; - m_StreamingAudioInfo.bIs3D = false; - // build the name - strcat((char*)m_szStreamName, "music/"); - } else { - SetIsPlayingStreamingGameMusic(false); - SetIsPlayingStreamingCDMusic(true); - m_MusicType = eMusicType_CD; - m_StreamingAudioInfo.bIs3D = true; - // build the name - strcat((char*)m_szStreamName, "cds/"); - } - strcat((char*)m_szStreamName, m_szStreamFileA[m_musicID]); - strcat((char*)m_szStreamName, ".binka"); - -#endif - } - - // std::wstring name = - // m_szStreamFileA[m_musicID]; char *SoundName = (char - // *)ConvertSoundPathToName(name); strcat((char - // *)szStreamName,SoundName); - - app.DebugPrintf("Starting streaming - %s\n", m_szStreamName); - - // Don't actually open in this thread, as it can block for - // ~300ms. - m_openStreamThread = new C4JThread(OpenStreamThreadProc, this, - "OpenStreamThreadProc"); - m_openStreamThread->Run(); - 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 (fDist < fClosest) { - fClosest = fDist; - fClosestX = x; - fClosestY = y; - fClosestZ = z; - iClosestListener = i; - } - } - } - - // our distances in the world aren't very big, so floats - // rather than casts to doubles should be fine - fDist = sqrtf((fClosestX * fClosestX) + - (fClosestY * fClosestY) + - (fClosestZ * fClosestZ)); - AIL_set_sample_3D_position(hSample, 0, 0, fDist); - } else { - AIL_set_sample_3D_position( - hSample, m_StreamingAudioInfo.x, - m_StreamingAudioInfo.y, - -m_StreamingAudioInfo - .z); // Flipped sign of z as Miles is - // expecting left handed coord system - } - } else { - // clear the 3d flag on the stream after a jukebox finishes - // and streaming music starts - AIL_set_sample_is_3D(hSample, 0); - } - // set the pitch - app.DebugPrintf("Sample rate:%d\n", - AIL_sample_playback_rate(hSample)); - AIL_set_sample_playback_rate_factor(hSample, - m_StreamingAudioInfo.pitch); - // set the volume - AIL_set_sample_volume_levels( - hSample, - m_StreamingAudioInfo.volume * getMasterMusicVolume(), - m_StreamingAudioInfo.volume * getMasterMusicVolume()); - - AIL_start_stream(m_hStream); - - m_StreamState = eMusicStreamState_Playing; - } - break; - case eMusicStreamState_OpeningCancel: - if (!m_openStreamThread->isRunning()) { - 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 (fDist < fClosest) { - fClosest = fDist; - fClosestX = x; - fClosestY = y; - fClosestZ = z; - iClosestListener = i; - } - } - } - - // our distances in the world aren't very big, so floats - // rather than casts to doubles should be fine - HSAMPLE hSample = AIL_stream_sample_handle(m_hStream); - fDist = sqrtf((fClosestX * fClosestX) + - (fClosestY * fClosestY) + - (fClosestZ * fClosestZ)); - AIL_set_sample_3D_position(hSample, 0, 0, fDist); - } - } - } - - break; - - case eMusicStreamState_Completed: { - // random delay of up to 3 minutes for music - m_iMusicDelay = random->nextInt( - 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; 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) { - 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 -// -///////////////////////////////////////////// +// This is unused by the linux version, it'll need to be changed char* SoundEngine::ConvertSoundPathToName(const std::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; -} - -#endif + return NULL; +} \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/Audio/SoundEngine.h b/Minecraft.Client/Platform/Common/Audio/SoundEngine.h index f09edf3ed..29d8ea928 100644 --- a/Minecraft.Client/Platform/Common/Audio/SoundEngine.h +++ b/Minecraft.Client/Platform/Common/Audio/SoundEngine.h @@ -134,6 +134,9 @@ private: #else int initAudioHardware(int iMinSpeakers) { return iMinSpeakers; } #endif + #ifdef __linux__ + void updateMiniAudio(); + #endif int GetRandomishTrack(int iStart, int iEnd); diff --git a/Minecraft.Client/Platform/Common/Audio/SoundNames.cpp b/Minecraft.Client/Platform/Common/Audio/SoundNames.cpp index 30718d4d2..fcb63905b 100644 --- a/Minecraft.Client/Platform/Common/Audio/SoundNames.cpp +++ b/Minecraft.Client/Platform/Common/Audio/SoundNames.cpp @@ -8,7 +8,7 @@ const WCHAR* ConsoleSoundEngine::wchSoundNames[eSoundType_MAX] = { L"mob/chicken/chickenplop", // eSoundType_MOB_CHICKENPLOP L"mob/cow/say", // eSoundType_MOB_COW_AMBIENT L"mob/cow/hurt", // eSoundType_MOB_COW_HURT - L"mob/pig/say", // eSoundType_MOB_PIG_AMBIENT + L"mob/pig/pig", // eSoundType_MOB_PIG_AMBIENT L"mob/pig/pigdeath", // eSoundType_MOB_PIG_DEATH L"mob/sheep/sheep", // eSoundType_MOB_SHEEP_AMBIENT L"mob/wolf/growl", // eSoundType_MOB_WOLF_GROWL @@ -78,8 +78,8 @@ const WCHAR* ConsoleSoundEngine::wchSoundNames[eSoundType_MAX] = { 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"block/chest/open", // eSoundType_RANDOM_CHEST_OPEN, + L"block/chest/close", // 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, @@ -94,9 +94,10 @@ const WCHAR* ConsoleSoundEngine::wchSoundNames[eSoundType_MAX] = { L"portal/trigger", // eSoundType_PORTAL_TRIGGER L"portal/travel", // eSoundType_PORTAL_TRAVEL - L"fire/ignite", // eSoundType_FIRE_IGNITE, + L"fire/new_ignite", // eSoundType_FIRE_IGNITE, L"fire/fire", // eSoundType_FIRE_FIRE, - L"damage/hurtflesh", // eSoundType_DAMAGE_HURT, + // Renamed to damage/hit as the other file doesn't exist + L"damage/hit", // eSoundType_DAMAGE_HURT, L"damage/fallsmall", // eSoundType_DAMAGE_FALL_SMALL, L"damage/fallbig", // eSoundType_DAMAGE_FALL_BIG, L"note/harp", // eSoundType_NOTE_HARP, diff --git a/Minecraft.Client/Platform/Common/Audio/miniaudio_libvorbis.c b/Minecraft.Client/Platform/Common/Audio/miniaudio_libvorbis.c deleted file mode 100644 index 7ca537133..000000000 --- a/Minecraft.Client/Platform/Common/Audio/miniaudio_libvorbis.c +++ /dev/null @@ -1,591 +0,0 @@ -#ifndef miniaudio_libvorbis_c -#define miniaudio_libvorbis_c - -#include "miniaudio_libvorbis.h" - -#if !defined(MA_NO_LIBVORBIS) -#ifndef OV_EXCLUDE_STATIC_CALLBACKS -#define OV_EXCLUDE_STATIC_CALLBACKS -#endif -#include -#endif - -#include /* For memset(). */ -#include - -static ma_result ma_libvorbis_ds_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - return ma_libvorbis_read_pcm_frames((ma_libvorbis*)pDataSource, pFramesOut, frameCount, pFramesRead); -} - -static ma_result ma_libvorbis_ds_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) -{ - return ma_libvorbis_seek_to_pcm_frame((ma_libvorbis*)pDataSource, frameIndex); -} - -static ma_result ma_libvorbis_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) -{ - return ma_libvorbis_get_data_format((ma_libvorbis*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); -} - -static ma_result ma_libvorbis_ds_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) -{ - return ma_libvorbis_get_cursor_in_pcm_frames((ma_libvorbis*)pDataSource, pCursor); -} - -static ma_result ma_libvorbis_ds_get_length(ma_data_source* pDataSource, ma_uint64* pLength) -{ - return ma_libvorbis_get_length_in_pcm_frames((ma_libvorbis*)pDataSource, pLength); -} - -static ma_data_source_vtable g_ma_libvorbis_ds_vtable = -{ - ma_libvorbis_ds_read, - ma_libvorbis_ds_seek, - ma_libvorbis_ds_get_data_format, - ma_libvorbis_ds_get_cursor, - ma_libvorbis_ds_get_length, - NULL, /* onSetLooping */ - 0 /* flags */ -}; - - -#if !defined(MA_NO_LIBVORBIS) -static size_t ma_libvorbis_vf_callback__read(void* pBufferOut, size_t size, size_t count, void* pUserData) -{ - ma_libvorbis* pVorbis = (ma_libvorbis*)pUserData; - ma_result result; - size_t bytesToRead; - size_t bytesRead; - - /* For consistency with fread(). If `size` of `count` is 0, return 0 immediately without changing anything. */ - if (size == 0 || count == 0) { - return 0; - } - - bytesToRead = size * count; - result = pVorbis->onRead(pVorbis->pReadSeekTellUserData, pBufferOut, bytesToRead, &bytesRead); - if (result != MA_SUCCESS) { - /* Not entirely sure what to return here. What if an error occurs, but some data was read and bytesRead is > 0? */ - return 0; - } - - return bytesRead / size; -} - -static int ma_libvorbis_vf_callback__seek(void* pUserData, ogg_int64_t offset, int whence) -{ - ma_libvorbis* pVorbis = (ma_libvorbis*)pUserData; - ma_result result; - ma_seek_origin origin; - - if (whence == SEEK_SET) { - origin = ma_seek_origin_start; - } else if (whence == SEEK_END) { - origin = ma_seek_origin_end; - } else { - origin = ma_seek_origin_current; - } - - result = pVorbis->onSeek(pVorbis->pReadSeekTellUserData, offset, origin); - if (result != MA_SUCCESS) { - return -1; - } - - return 0; -} - -static long ma_libvorbis_vf_callback__tell(void* pUserData) -{ - ma_libvorbis* pVorbis = (ma_libvorbis*)pUserData; - ma_result result; - ma_int64 cursor; - - result = pVorbis->onTell(pVorbis->pReadSeekTellUserData, &cursor); - if (result != MA_SUCCESS) { - return -1; - } - - return (long)cursor; -} -#endif - -static ma_result ma_libvorbis_init_internal(const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_libvorbis* pVorbis) -{ - if (pVorbis == NULL) { - return MA_INVALID_ARGS; - } - - memset(pVorbis, 0, sizeof(*pVorbis)); - pVorbis->format = ma_format_f32; /* f32 by default. */ - - if (pConfig != NULL && (pConfig->preferredFormat == ma_format_f32 || pConfig->preferredFormat == ma_format_s16)) { - pVorbis->format = pConfig->preferredFormat; - } else { - /* Getting here means something other than f32 and s16 was specified. Just leave this unset to use the default format. */ - } - - #if !defined(MA_NO_LIBVORBIS) - { - ma_result result; - ma_data_source_config dataSourceConfig; - - dataSourceConfig = ma_data_source_config_init(); - dataSourceConfig.vtable = &g_ma_libvorbis_ds_vtable; - - result = ma_data_source_init(&dataSourceConfig, &pVorbis->ds); - if (result != MA_SUCCESS) { - return result; /* Failed to initialize the base data source. */ - } - - pVorbis->vf = (OggVorbis_File*)ma_malloc(sizeof(OggVorbis_File), pAllocationCallbacks); - if (pVorbis->vf == NULL) { - ma_data_source_uninit(&pVorbis->ds); - return MA_OUT_OF_MEMORY; - } - - return MA_SUCCESS; - } - #else - { - /* libvorbis is disabled. */ - (void)pAllocationCallbacks; - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_libvorbis_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_libvorbis* pVorbis) -{ - ma_result result; - - (void)pAllocationCallbacks; /* Can't seem to find a way to configure memory allocations in libvorbis. */ - - if (onRead == NULL || onSeek == NULL) { - return MA_INVALID_ARGS; /* onRead and onSeek are mandatory. */ - } - - result = ma_libvorbis_init_internal(pConfig, pAllocationCallbacks, pVorbis); - if (result != MA_SUCCESS) { - return result; - } - - pVorbis->onRead = onRead; - pVorbis->onSeek = onSeek; - pVorbis->onTell = onTell; - pVorbis->pReadSeekTellUserData = pReadSeekTellUserData; - - #if !defined(MA_NO_LIBVORBIS) - { - int libvorbisResult; - ov_callbacks libvorbisCallbacks; - - /* We can now initialize the vorbis decoder. This must be done after we've set up the callbacks. */ - libvorbisCallbacks.read_func = ma_libvorbis_vf_callback__read; - libvorbisCallbacks.seek_func = ma_libvorbis_vf_callback__seek; - libvorbisCallbacks.close_func = NULL; - libvorbisCallbacks.tell_func = ma_libvorbis_vf_callback__tell; - - libvorbisResult = ov_open_callbacks(pVorbis, (OggVorbis_File*)pVorbis->vf, NULL, 0, libvorbisCallbacks); - if (libvorbisResult < 0) { - ma_data_source_uninit(&pVorbis->ds); - ma_free(pVorbis->vf, pAllocationCallbacks); - return MA_INVALID_FILE; - } - - return MA_SUCCESS; - } - #else - { - /* libvorbis is disabled. */ - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_libvorbis_init_file(const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_libvorbis* pVorbis) -{ - ma_result result; - - (void)pAllocationCallbacks; /* Can't seem to find a way to configure memory allocations in libvorbis. */ - - result = ma_libvorbis_init_internal(pConfig, pAllocationCallbacks, pVorbis); - if (result != MA_SUCCESS) { - return result; - } - - #if !defined(MA_NO_LIBVORBIS) - { - int libvorbisResult; - - libvorbisResult = ov_fopen(pFilePath, (OggVorbis_File*)pVorbis->vf); - if (libvorbisResult < 0) { - ma_data_source_uninit(&pVorbis->ds); - ma_free(pVorbis->vf, pAllocationCallbacks); - return MA_INVALID_FILE; - } - - return MA_SUCCESS; - } - #else - { - /* libvorbis is disabled. */ - (void)pFilePath; - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API void ma_libvorbis_uninit(ma_libvorbis* pVorbis, const ma_allocation_callbacks* pAllocationCallbacks) -{ - if (pVorbis == NULL) { - return; - } - - (void)pAllocationCallbacks; - - #if !defined(MA_NO_LIBVORBIS) - { - ov_clear((OggVorbis_File*)pVorbis->vf); - } - #else - { - /* libvorbis is disabled. Should never hit this since initialization would have failed. */ - assert(MA_FALSE); - } - #endif - - ma_data_source_uninit(&pVorbis->ds); - ma_free(pVorbis->vf, pAllocationCallbacks); -} - -MA_API ma_result ma_libvorbis_read_pcm_frames(ma_libvorbis* pVorbis, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) -{ - if (pFramesRead != NULL) { - *pFramesRead = 0; - } - - if (frameCount == 0) { - return MA_INVALID_ARGS; - } - - if (pVorbis == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_LIBVORBIS) - { - /* We always use floating point format. */ - ma_result result = MA_SUCCESS; /* Must be initialized to MA_SUCCESS. */ - ma_uint64 totalFramesRead; - ma_format format; - ma_uint32 channels; - - ma_libvorbis_get_data_format(pVorbis, &format, &channels, NULL, NULL, 0); - - totalFramesRead = 0; - while (totalFramesRead < frameCount) { - long libvorbisResult; - ma_uint64 framesToRead; - ma_uint64 framesRemaining; - - framesRemaining = (frameCount - totalFramesRead); - framesToRead = 1024; - if (framesToRead > framesRemaining) { - framesToRead = framesRemaining; - } - - if (format == ma_format_f32) { - float** ppFramesF32; - - libvorbisResult = ov_read_float((OggVorbis_File*)pVorbis->vf, &ppFramesF32, (int)framesToRead, NULL); - if (libvorbisResult < 0) { - result = MA_ERROR; /* Error while decoding. */ - break; - } else { - /* Frames need to be interleaved. */ - ma_interleave_pcm_frames(format, channels, libvorbisResult, (const void**)ppFramesF32, ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, format, channels)); - totalFramesRead += libvorbisResult; - - if (libvorbisResult == 0) { - result = MA_AT_END; - break; - } - } - } else { - libvorbisResult = ov_read((OggVorbis_File*)pVorbis->vf, (char*)ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, format, channels), (int)(framesToRead * ma_get_bytes_per_frame(format, channels)), 0, 2, 1, NULL); - if (libvorbisResult < 0) { - result = MA_ERROR; /* Error while decoding. */ - break; - } else { - /* Conveniently, there's no need to interleaving when using ov_read(). I'm not sure why ov_read_float() is different in that regard... */ - totalFramesRead += libvorbisResult / ma_get_bytes_per_frame(format, channels); - - if (libvorbisResult == 0) { - result = MA_AT_END; - break; - } - } - } - } - - if (pFramesRead != NULL) { - *pFramesRead = totalFramesRead; - } - - if (result == MA_SUCCESS && totalFramesRead == 0) { - result = MA_AT_END; - } - - return result; - } - #else - { - /* libvorbis is disabled. Should never hit this since initialization would have failed. */ - assert(MA_FALSE); - - (void)pFramesOut; - (void)frameCount; - (void)pFramesRead; - - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_libvorbis_seek_to_pcm_frame(ma_libvorbis* pVorbis, ma_uint64 frameIndex) -{ - if (pVorbis == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_LIBVORBIS) - { - int libvorbisResult = ov_pcm_seek((OggVorbis_File*)pVorbis->vf, (ogg_int64_t)frameIndex); - if (libvorbisResult != 0) { - if (libvorbisResult == OV_ENOSEEK) { - return MA_INVALID_OPERATION; /* Not seekable. */ - } else if (libvorbisResult == OV_EINVAL) { - return MA_INVALID_ARGS; - } else { - return MA_ERROR; - } - } - - return MA_SUCCESS; - } - #else - { - /* libvorbis is disabled. Should never hit this since initialization would have failed. */ - assert(MA_FALSE); - - (void)frameIndex; - - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_libvorbis_get_data_format(ma_libvorbis* pVorbis, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) -{ - /* Defaults for safety. */ - if (pFormat != NULL) { - *pFormat = ma_format_unknown; - } - if (pChannels != NULL) { - *pChannels = 0; - } - if (pSampleRate != NULL) { - *pSampleRate = 0; - } - if (pChannelMap != NULL) { - memset(pChannelMap, 0, sizeof(*pChannelMap) * channelMapCap); - } - - if (pVorbis == NULL) { - return MA_INVALID_OPERATION; - } - - if (pFormat != NULL) { - *pFormat = pVorbis->format; - } - - #if !defined(MA_NO_LIBVORBIS) - { - vorbis_info* pInfo = ov_info((OggVorbis_File*)pVorbis->vf, 0); - if (pInfo == NULL) { - return MA_INVALID_OPERATION; - } - - if (pChannels != NULL) { - *pChannels = pInfo->channels; - } - - if (pSampleRate != NULL) { - *pSampleRate = pInfo->rate; - } - - if (pChannelMap != NULL) { - ma_channel_map_init_standard(ma_standard_channel_map_vorbis, pChannelMap, channelMapCap, pInfo->channels); - } - - return MA_SUCCESS; - } - #else - { - /* libvorbis is disabled. Should never hit this since initialization would have failed. */ - assert(MA_FALSE); - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_libvorbis_get_cursor_in_pcm_frames(ma_libvorbis* pVorbis, ma_uint64* pCursor) -{ - if (pCursor == NULL) { - return MA_INVALID_ARGS; - } - - *pCursor = 0; /* Safety. */ - - if (pVorbis == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_LIBVORBIS) - { - ogg_int64_t offset = ov_pcm_tell((OggVorbis_File*)pVorbis->vf); - if (offset < 0) { - return MA_INVALID_FILE; - } - - *pCursor = (ma_uint64)offset; - - return MA_SUCCESS; - } - #else - { - /* libvorbis is disabled. Should never hit this since initialization would have failed. */ - assert(MA_FALSE); - return MA_NOT_IMPLEMENTED; - } - #endif -} - -MA_API ma_result ma_libvorbis_get_length_in_pcm_frames(ma_libvorbis* pVorbis, ma_uint64* pLength) -{ - if (pLength == NULL) { - return MA_INVALID_ARGS; - } - - *pLength = 0; /* Safety. */ - - if (pVorbis == NULL) { - return MA_INVALID_ARGS; - } - - #if !defined(MA_NO_LIBVORBIS) - { - /* - Will work in the supermajority of cases where a file has a single logical bitstream. Concatenated streams - are much harder to determine the length of since they can have sample rate changes, but they should be - extremely rare outside of unseekable livestreams anyway. - */ - if (ov_streams((OggVorbis_File*)pVorbis->vf) == 1) { - ogg_int64_t length = ov_pcm_total((OggVorbis_File*)pVorbis->vf, 0); - if(length != OV_EINVAL) { - *pLength = (ma_uint64)length; - } else { - /* Unseekable. */ - } - } else { - /* Concatenated stream. */ - } - - return MA_SUCCESS; - } - #else - { - /* libvorbis is disabled. Should never hit this since initialization would have failed. */ - assert(MA_FALSE); - return MA_NOT_IMPLEMENTED; - } - #endif -} - - -/* -The code below defines the vtable that you'll plug into your `ma_decoder_config` object. -*/ -#if !defined(MA_NO_LIBVORBIS) -static ma_result ma_decoding_backend_init__libvorbis(void* pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_libvorbis* pVorbis; - - (void)pUserData; - - pVorbis = (ma_libvorbis*)ma_malloc(sizeof(*pVorbis), pAllocationCallbacks); - if (pVorbis == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_libvorbis_init(onRead, onSeek, onTell, pReadSeekTellUserData, pConfig, pAllocationCallbacks, pVorbis); - if (result != MA_SUCCESS) { - ma_free(pVorbis, pAllocationCallbacks); - return result; - } - - *ppBackend = pVorbis; - - return MA_SUCCESS; -} - -static ma_result ma_decoding_backend_init_file__libvorbis(void* pUserData, const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_libvorbis* pVorbis; - - (void)pUserData; - - pVorbis = (ma_libvorbis*)ma_malloc(sizeof(*pVorbis), pAllocationCallbacks); - if (pVorbis == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_libvorbis_init_file(pFilePath, pConfig, pAllocationCallbacks, pVorbis); - if (result != MA_SUCCESS) { - ma_free(pVorbis, pAllocationCallbacks); - return result; - } - - *ppBackend = pVorbis; - - return MA_SUCCESS; -} - -static void ma_decoding_backend_uninit__libvorbis(void* pUserData, ma_data_source* pBackend, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_libvorbis* pVorbis = (ma_libvorbis*)pBackend; - - (void)pUserData; - - ma_libvorbis_uninit(pVorbis, pAllocationCallbacks); - ma_free(pVorbis, pAllocationCallbacks); -} - - -static ma_decoding_backend_vtable ma_gDecodingBackendVTable_libvorbis = -{ - ma_decoding_backend_init__libvorbis, - ma_decoding_backend_init_file__libvorbis, - NULL, /* onInitFileW() */ - NULL, /* onInitMemory() */ - ma_decoding_backend_uninit__libvorbis -}; -ma_decoding_backend_vtable* ma_decoding_backend_libvorbis = &ma_gDecodingBackendVTable_libvorbis; -#else -ma_decoding_backend_vtable* ma_decoding_backend_libvorbis = NULL; -#endif - -#endif /* miniaudio_libvorbis_c */ \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/Audio/miniaudio_libvorbis.h b/Minecraft.Client/Platform/Common/Audio/miniaudio_libvorbis.h deleted file mode 100644 index c56f9f6c4..000000000 --- a/Minecraft.Client/Platform/Common/Audio/miniaudio_libvorbis.h +++ /dev/null @@ -1,42 +0,0 @@ -/* -This implements a data source that decodes Vorbis streams via libvorbis + libvorbisfile - -This object can be plugged into any `ma_data_source_*()` API and can also be used as a custom -decoding backend. See the custom_decoder example. -*/ -#ifndef miniaudio_libvorbis_h -#define miniaudio_libvorbis_h - -#ifdef __cplusplus -extern "C" { -#endif - -#include "../../../miniaudio.h" - -typedef struct -{ - ma_data_source_base ds; /* The libvorbis decoder can be used independently as a data source. */ - ma_read_proc onRead; - ma_seek_proc onSeek; - ma_tell_proc onTell; - void* pReadSeekTellUserData; - ma_format format; /* Will be either f32 or s16. */ - /*OggVorbis_File**/ void* vf; /* Typed as void* so we can avoid a dependency on opusfile in the header section. */ -} ma_libvorbis; - -MA_API ma_result ma_libvorbis_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_libvorbis* pVorbis); -MA_API ma_result ma_libvorbis_init_file(const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_libvorbis* pVorbis); -MA_API void ma_libvorbis_uninit(ma_libvorbis* pVorbis, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_result ma_libvorbis_read_pcm_frames(ma_libvorbis* pVorbis, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); -MA_API ma_result ma_libvorbis_seek_to_pcm_frame(ma_libvorbis* pVorbis, ma_uint64 frameIndex); -MA_API ma_result ma_libvorbis_get_data_format(ma_libvorbis* pVorbis, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); -MA_API ma_result ma_libvorbis_get_cursor_in_pcm_frames(ma_libvorbis* pVorbis, ma_uint64* pCursor); -MA_API ma_result ma_libvorbis_get_length_in_pcm_frames(ma_libvorbis* pVorbis, ma_uint64* pLength); - -/* Decoding backend vtable. This is what you'll plug into ma_decoder_config.pBackendVTables. No user data required. */ -extern ma_decoding_backend_vtable* ma_decoding_backend_libvorbis; - -#ifdef __cplusplus -} -#endif -#endif /* miniaudio_libvorbis_h */ \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/Audio/stb_vorbis.h b/Minecraft.Client/Platform/Common/Audio/stb_vorbis.h index ae8080410..53f292d21 100644 --- a/Minecraft.Client/Platform/Common/Audio/stb_vorbis.h +++ b/Minecraft.Client/Platform/Common/Audio/stb_vorbis.h @@ -956,7 +956,8 @@ static int set_file_offset(stb_vorbis *f, unsigned int loc) #endif f->eof = 0; if (USE_MEMORY(f)) { - if (f->stream_start + loc >= f->stream_end || f->stream_start + loc < f->stream_start) { + if ((size_t)(f->stream_start + loc) >= (size_t)f->stream_end || + (size_t)(f->stream_start + loc) < (size_t)f->stream_start) { f->stream = f->stream_end; f->eof = 1; return 0; diff --git a/subprojects/shiggy b/subprojects/shiggy deleted file mode 160000 index 7adc6c478..000000000 --- a/subprojects/shiggy +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7adc6c47882409c31e4f2d66fbfabdf4a3a98fd1