Merge pull request #4 from amun3808/new-audio-system
New sound system & removed miles
This commit is contained in:
8421
extern/include/MSS.H
vendored
8421
extern/include/MSS.H
vendored
File diff suppressed because it is too large
Load Diff
2
extern/include/miniaudio.c
vendored
Normal file
2
extern/include/miniaudio.c
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
#define MINIAUDIO_IMPLEMENTATION
|
||||
#include "miniaudio.h"
|
||||
93468
extern/include/miniaudio.h
vendored
Normal file
93468
extern/include/miniaudio.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
extern/library/CMakeLists.txt
vendored
1
extern/library/CMakeLists.txt
vendored
@@ -1,6 +1,5 @@
|
||||
add_subdirectory(DirectX)
|
||||
add_subdirectory(Granny)
|
||||
add_subdirectory(MilesSoundSystem)
|
||||
add_subdirectory(Python)
|
||||
add_subdirectory(SpeedTree)
|
||||
add_subdirectory(WebView)
|
||||
@@ -1,6 +0,0 @@
|
||||
add_library(MilesSoundSystem STATIC IMPORTED GLOBAL)
|
||||
|
||||
set_target_properties(MilesSoundSystem PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/extern/include"
|
||||
IMPORTED_LOCATION "${CMAKE_CURRENT_LIST_DIR}/mss64.lib"
|
||||
)
|
||||
BIN
extern/library/MilesSoundSystem/mss64.lib
vendored
BIN
extern/library/MilesSoundSystem/mss64.lib
vendored
Binary file not shown.
9
src/AudioLib/CMakeLists.txt
Normal file
9
src/AudioLib/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
file(GLOB_RECURSE FILE_SOURCES "*.h" "*.c" "*.cpp")
|
||||
|
||||
add_library(AudioLib STATIC ${FILE_SOURCES})
|
||||
|
||||
target_link_libraries(AudioLib
|
||||
lzo2
|
||||
)
|
||||
|
||||
GroupSourcesByFolder(AudioLib)
|
||||
175
src/AudioLib/MaSoundInstance.cpp
Normal file
175
src/AudioLib/MaSoundInstance.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
#include "stdafx.h"
|
||||
#include "MaSoundInstance.h"
|
||||
|
||||
#include <miniaudio.c>
|
||||
|
||||
bool MaSoundInstance::InitFromBuffer(ma_engine& engine, const std::vector<uint8_t>& buffer, const std::string& identity)
|
||||
{
|
||||
if (!m_Initialized)
|
||||
{
|
||||
ma_decoder_config decoderConfig = ma_decoder_config_init_default();
|
||||
ma_result result = ma_decoder_init_memory(buffer.data(), buffer.size(),
|
||||
&decoderConfig, &m_Decoder);
|
||||
if (!MD_ASSERT(result == MA_SUCCESS))
|
||||
{
|
||||
TraceError("Failed to initialize decoder memory.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ma_sound_config soundConfig = ma_sound_config_init();
|
||||
soundConfig.pDataSource = &m_Decoder;
|
||||
|
||||
result = ma_sound_init_ex(&engine, &soundConfig, &m_Sound);
|
||||
if (!MD_ASSERT(result == MA_SUCCESS))
|
||||
{
|
||||
TraceError("Failed to initialize sound.");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Identity = identity;
|
||||
m_Initialized = true;
|
||||
}
|
||||
return m_Initialized;
|
||||
}
|
||||
|
||||
// Basically c&p
|
||||
bool MaSoundInstance::InitFromFile(ma_engine& engine, const std::string& filePathOnDisk)
|
||||
{
|
||||
if (!m_Initialized)
|
||||
{
|
||||
ma_decoder_config decoderConfig = ma_decoder_config_init_default();
|
||||
ma_result result = ma_decoder_init_file(filePathOnDisk.c_str(), &decoderConfig, &m_Decoder);
|
||||
if (!MD_ASSERT(result == MA_SUCCESS))
|
||||
{
|
||||
TraceError("Failed to initialize sound file decoder.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ma_sound_config soundConfig = ma_sound_config_init();
|
||||
soundConfig.pDataSource = &m_Decoder;
|
||||
|
||||
result = ma_sound_init_ex(&engine, &soundConfig, &m_Sound);
|
||||
if (!MD_ASSERT(result == MA_SUCCESS))
|
||||
{
|
||||
TraceError("Failed to initialize sound.");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Identity = filePathOnDisk;
|
||||
m_Initialized = true;
|
||||
}
|
||||
return m_Initialized;
|
||||
}
|
||||
|
||||
void MaSoundInstance::Destroy()
|
||||
{
|
||||
if (m_Initialized)
|
||||
{
|
||||
ma_sound_uninit(&m_Sound);
|
||||
ma_decoder_uninit(&m_Decoder);
|
||||
}
|
||||
m_Initialized = false;
|
||||
m_Identity = "";
|
||||
m_FadeTargetVolume = 0;
|
||||
m_FadeRatePerFrame = 0;
|
||||
}
|
||||
|
||||
bool MaSoundInstance::IsInitialized() const
|
||||
{
|
||||
return m_Initialized;
|
||||
}
|
||||
|
||||
bool MaSoundInstance::IsPlaying() const
|
||||
{
|
||||
return ma_sound_is_playing(&m_Sound) == MA_TRUE;
|
||||
}
|
||||
|
||||
bool MaSoundInstance::Play()
|
||||
{
|
||||
return m_Initialized && ma_sound_seek_to_pcm_frame(&m_Sound, 0) == MA_SUCCESS && ma_sound_start(&m_Sound) == MA_SUCCESS;
|
||||
}
|
||||
|
||||
bool MaSoundInstance::Resume()
|
||||
{
|
||||
return m_Initialized && ma_sound_start(&m_Sound) == MA_SUCCESS;
|
||||
}
|
||||
|
||||
bool MaSoundInstance::Stop()
|
||||
{
|
||||
return m_Initialized && ma_sound_stop(&m_Sound) == MA_SUCCESS;
|
||||
}
|
||||
|
||||
void MaSoundInstance::Loop()
|
||||
{
|
||||
ma_sound_set_looping(&m_Sound, MA_TRUE);
|
||||
}
|
||||
|
||||
float MaSoundInstance::GetVolume() const
|
||||
{
|
||||
return ma_sound_get_volume(&m_Sound);
|
||||
}
|
||||
|
||||
void MaSoundInstance::SetVolume(float volume)
|
||||
{
|
||||
ma_sound_set_volume(&m_Sound, volume);
|
||||
}
|
||||
|
||||
void MaSoundInstance::SetPitch(float pitch)
|
||||
{
|
||||
ma_sound_set_pitch(&m_Sound, pitch);
|
||||
}
|
||||
|
||||
void MaSoundInstance::SetPosition(float x, float y, float z)
|
||||
{
|
||||
ma_sound_set_position(&m_Sound, x, y, z);
|
||||
}
|
||||
|
||||
const std::string& MaSoundInstance::GetIdentity() const
|
||||
{
|
||||
return m_Identity;
|
||||
}
|
||||
|
||||
void MaSoundInstance::Config3D(bool toggle, float minDist, float maxDist, float rolloff)
|
||||
{
|
||||
ma_sound_set_spatialization_enabled(&m_Sound, toggle);
|
||||
ma_sound_set_rolloff(&m_Sound, 1.0f);
|
||||
ma_sound_set_min_distance(&m_Sound, minDist);
|
||||
ma_sound_set_max_distance(&m_Sound, maxDist);
|
||||
ma_sound_set_attenuation_model(&m_Sound, ma_attenuation_model_linear);
|
||||
}
|
||||
|
||||
void MaSoundInstance::Fade(float toVolume, float secDurationFromMinMax)
|
||||
{
|
||||
toVolume = std::clamp<float>(toVolume, 0.0f, 1.0f);
|
||||
m_FadeTargetVolume = toVolume;
|
||||
|
||||
float rate = 1.0f / 61.0f / secDurationFromMinMax;
|
||||
m_FadeRatePerFrame = GetVolume() > toVolume ? -rate : rate;
|
||||
}
|
||||
|
||||
void MaSoundInstance::StopFading()
|
||||
{
|
||||
m_FadeRatePerFrame = 0;
|
||||
}
|
||||
|
||||
bool MaSoundInstance::IsFading() const
|
||||
{
|
||||
return m_FadeRatePerFrame != 0;
|
||||
}
|
||||
|
||||
void MaSoundInstance::Update(float volumeFactor) // volume factor is the user's volume
|
||||
{
|
||||
if (m_FadeRatePerFrame != 0)
|
||||
{
|
||||
float targetVolume = std::clamp<float>(m_FadeTargetVolume * volumeFactor, 0.0f, 1.0f);
|
||||
float volume = std::clamp<float>(GetVolume() + (m_FadeRatePerFrame * volumeFactor), 0.0f, 1.0f);
|
||||
if ((m_FadeRatePerFrame > 0 && volume >= targetVolume) || (m_FadeRatePerFrame < 0 && volume <= targetVolume))
|
||||
{
|
||||
volume = m_FadeTargetVolume * volumeFactor;
|
||||
m_FadeRatePerFrame = 0.0f;
|
||||
if (volume <= 0.0f)
|
||||
ma_sound_stop(&m_Sound);
|
||||
}
|
||||
ma_sound_set_volume(&m_Sound, volume);
|
||||
}
|
||||
}
|
||||
54
src/AudioLib/MaSoundInstance.h
Normal file
54
src/AudioLib/MaSoundInstance.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
#include <miniaudio.h>
|
||||
|
||||
inline constexpr float CS_CLIENT_FPS = 61.0f;
|
||||
|
||||
class MaSoundInstance
|
||||
{
|
||||
public:
|
||||
bool InitFromBuffer(ma_engine& engine, const std::vector<uint8_t>& buffer, const std::string& identity);
|
||||
|
||||
bool InitFromFile(ma_engine& engine, const std::string& filePathOnDisk);
|
||||
|
||||
void Destroy();
|
||||
|
||||
bool IsInitialized() const;
|
||||
|
||||
bool IsPlaying() const;
|
||||
|
||||
bool Play();
|
||||
|
||||
bool Resume();
|
||||
|
||||
bool Stop();
|
||||
|
||||
void Loop();
|
||||
|
||||
float GetVolume() const;
|
||||
|
||||
void SetVolume(float volume);
|
||||
|
||||
void SetPitch(float pitch);
|
||||
|
||||
void SetPosition(float x, float y, float z);
|
||||
|
||||
const std::string& GetIdentity() const;
|
||||
|
||||
void Config3D(bool toggle, float minDist = 100.0f/*1m*/, float maxDist = 4000.0f/*40m*/, float rolloff = 1.0f);
|
||||
|
||||
void Fade(float toVolume, float secDurationFromMinMax);
|
||||
|
||||
void StopFading();
|
||||
|
||||
bool IsFading() const;
|
||||
|
||||
void Update(float volumeFactor = 1.0f);
|
||||
|
||||
private:
|
||||
std::string m_Identity;
|
||||
ma_sound m_Sound{};
|
||||
ma_decoder m_Decoder{};
|
||||
bool m_Initialized{};
|
||||
float m_FadeTargetVolume{};
|
||||
float m_FadeRatePerFrame{};
|
||||
};
|
||||
268
src/AudioLib/SoundEngine.cpp
Normal file
268
src/AudioLib/SoundEngine.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
#include "stdafx.h"
|
||||
#include "SoundEngine.h"
|
||||
|
||||
#include "EterBase/Random.h"
|
||||
#include "EterBase/Timer.h"
|
||||
#include "Eterpack/EterPackManager.h"
|
||||
|
||||
SoundEngine::SoundEngine()
|
||||
{
|
||||
}
|
||||
|
||||
SoundEngine::~SoundEngine()
|
||||
{
|
||||
for (auto& [name, instance] : m_Sounds2D)
|
||||
instance.Destroy();
|
||||
|
||||
for (auto& instance : m_Sounds3D)
|
||||
instance.Destroy();
|
||||
|
||||
ma_engine_uninit(&m_Engine);
|
||||
m_Files.clear();
|
||||
m_Sounds2D.clear();
|
||||
}
|
||||
|
||||
bool SoundEngine::Initialize()
|
||||
{
|
||||
if (!MD_ASSERT(ma_engine_init(NULL, &m_Engine) == MA_SUCCESS))
|
||||
{
|
||||
TraceError("SoundEngine::Initialize: Failed to initialize engine.");
|
||||
return false;
|
||||
}
|
||||
|
||||
SetListenerPosition(0.0f, 0.0f, 0.0f);
|
||||
SetListenerOrientation(0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SoundEngine::SetSoundVolume(float volume)
|
||||
{
|
||||
m_SoundVolume = std::clamp<float>(volume, 0.0, 1.0);
|
||||
}
|
||||
|
||||
bool SoundEngine::PlaySound2D(const std::string& name)
|
||||
{
|
||||
if (!Internal_LoadSoundFromPack(name))
|
||||
return false;
|
||||
|
||||
auto& instance = m_Sounds2D[name]; // 2d sounds are persistent, no need to destroy
|
||||
instance.InitFromBuffer(m_Engine, m_Files[name], name);
|
||||
instance.Config3D(false);
|
||||
instance.SetVolume(m_SoundVolume);
|
||||
return instance.Play();
|
||||
}
|
||||
|
||||
MaSoundInstance* SoundEngine::PlaySound3D(const std::string& name, float fx, float fy, float fz)
|
||||
{
|
||||
if (auto instance = Internal_GetInstance3D(name))
|
||||
{
|
||||
constexpr float minDist = 100.0f; // 1m
|
||||
constexpr float maxDist = 4000.0f; // 40m
|
||||
|
||||
instance->SetPosition(fx, fy, fz);
|
||||
instance->Config3D(true, minDist, maxDist, 1.0f);
|
||||
instance->SetVolume(m_SoundVolume);
|
||||
instance->Play();
|
||||
return instance;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MaSoundInstance* SoundEngine::PlayAmbienceSound3D(float fx, float fy, float fz, const std::string& name, int loopCount)
|
||||
{
|
||||
auto vec3 = ma_engine_listener_get_position(&m_Engine, 0);
|
||||
float dx = fx - vec3.x;
|
||||
float dy = fy - vec3.y;
|
||||
float dz = fz - vec3.z;
|
||||
float distance = sqrtf(dx * dx + dy * dy + dz * dz);
|
||||
return PlaySound3D(name, fx, fy, fz);
|
||||
}
|
||||
|
||||
void SoundEngine::StopAllSound3D()
|
||||
{
|
||||
for (auto& instance : m_Sounds3D)
|
||||
instance.Stop();
|
||||
}
|
||||
|
||||
void SoundEngine::UpdateSoundInstance(float fx, float fy, float fz, uint32_t dwcurFrame, const NSound::TSoundInstanceVector* c_pSoundInstanceVector, bool checkFrequency, bool isMain)
|
||||
{
|
||||
for (uint32_t i = 0; i < c_pSoundInstanceVector->size(); ++i)
|
||||
{
|
||||
const NSound::TSoundInstance& c_rSoundInstance = c_pSoundInstanceVector->at(i);
|
||||
if (c_rSoundInstance.dwFrame == dwcurFrame)
|
||||
{
|
||||
if (checkFrequency)
|
||||
{
|
||||
float& lastPlay = m_PlaySoundHistoryMap[c_rSoundInstance.strSoundFileName];
|
||||
float diff = CTimer::Instance().GetCurrentSecond() - lastPlay;
|
||||
|
||||
if (CTimer::Instance().GetCurrentSecond() - lastPlay < 0.3f)
|
||||
return;
|
||||
|
||||
lastPlay = CTimer::Instance().GetCurrentSecond();
|
||||
}
|
||||
|
||||
if (isMain) // Sounds coming from main instance will always be played in 2d
|
||||
{
|
||||
// float volume = 0.9f + frandom(-0.1f, 0.1f);
|
||||
// instance->SetPitch(pitch); // Should we play around with pitch a bit?
|
||||
PlaySound2D(c_rSoundInstance.strSoundFileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// float volume = 0.9f + frandom(-0.1f, 0.1f);
|
||||
// instance->SetPitch(pitch); // Should we play around with pitch a bit?
|
||||
PlaySound3D(c_rSoundInstance.strSoundFileName, fx, fy, fz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SoundEngine::FadeInMusic(const std::string& path, float targetVolume /* 1.0f by default */, float fadeInDurationSecondsFromMin)
|
||||
{
|
||||
if (path.empty())
|
||||
return false;
|
||||
|
||||
auto& fadeOutMusic = m_Music[m_CurrentMusicIndex];
|
||||
if (fadeOutMusic.IsPlaying() && path == fadeOutMusic.GetIdentity())
|
||||
{
|
||||
fadeOutMusic.Fade(targetVolume, fadeInDurationSecondsFromMin);
|
||||
return fadeOutMusic.Resume();
|
||||
}
|
||||
|
||||
// We're basically just swapping
|
||||
FadeOutMusic(fadeOutMusic.GetIdentity());
|
||||
m_CurrentMusicIndex = int(!m_CurrentMusicIndex);
|
||||
|
||||
auto& music = m_Music[m_CurrentMusicIndex];
|
||||
music.Destroy();
|
||||
music.InitFromFile(m_Engine, path);
|
||||
music.Config3D(false);
|
||||
music.Loop();
|
||||
music.SetVolume(0.0f);
|
||||
music.Fade(targetVolume, fadeInDurationSecondsFromMin);
|
||||
return music.Play();
|
||||
}
|
||||
|
||||
void SoundEngine::FadeOutMusic(const std::string& name, float targetVolume, float fadeOutDurationSecondsFromMax)
|
||||
{
|
||||
for (auto& music : m_Music)
|
||||
{
|
||||
if (music.GetIdentity() == name)
|
||||
music.Fade(targetVolume, fadeOutDurationSecondsFromMax);
|
||||
}
|
||||
}
|
||||
|
||||
void SoundEngine::FadeOutAllMusic()
|
||||
{
|
||||
for (auto& music : m_Music)
|
||||
FadeOutMusic(music.GetIdentity());
|
||||
}
|
||||
|
||||
void SoundEngine::SetMusicVolume(float volume)
|
||||
{
|
||||
m_MusicVolume = std::clamp<float>(volume, 0.0f, 1.0f);
|
||||
for (auto& music : m_Music)
|
||||
{
|
||||
if (music.IsInitialized() && !music.IsFading()) // fading music will update itself
|
||||
music.SetVolume(m_MusicVolume);
|
||||
}
|
||||
}
|
||||
|
||||
void SoundEngine::SaveVolume(bool isMinimized)
|
||||
{
|
||||
constexpr float ratePerSecond = 1.0f / CS_CLIENT_FPS;
|
||||
// 1.0 to 0 in 1s if minimized, 3s if just out of focus
|
||||
const float durationOnFullVolume = isMinimized ? 1.0 : 3.0f;
|
||||
|
||||
float outOfFocusVolume = 0.35f;
|
||||
if (m_MasterVolume <= outOfFocusVolume)
|
||||
outOfFocusVolume = m_MasterVolume;
|
||||
|
||||
m_MasterVolumeFadeTarget = isMinimized ? 0 : outOfFocusVolume;
|
||||
m_MasterVolumeFadeRatePerFrame = -ratePerSecond / durationOnFullVolume;
|
||||
}
|
||||
|
||||
void SoundEngine::RestoreVolume()
|
||||
{
|
||||
constexpr float ratePerSecond = 1.0f / CS_CLIENT_FPS;
|
||||
constexpr float durationToFullVolume = 4.0f; // 0 to 1.0 in 4s
|
||||
m_MasterVolumeFadeTarget = m_MasterVolume;
|
||||
m_MasterVolumeFadeRatePerFrame = ratePerSecond / durationToFullVolume;
|
||||
}
|
||||
|
||||
void SoundEngine::SetMasterVolume(float volume)
|
||||
{
|
||||
m_MasterVolume = volume;
|
||||
ma_engine_set_volume(&m_Engine, volume);
|
||||
}
|
||||
|
||||
void SoundEngine::SetListenerPosition(float x, float y, float z)
|
||||
{
|
||||
ma_engine_listener_set_position(&m_Engine, 0, x, y, z);
|
||||
}
|
||||
|
||||
void SoundEngine::SetListenerOrientation(float forwardX, float forwardY, float forwardZ,
|
||||
float upX, float upY, float upZ)
|
||||
{
|
||||
ma_engine_listener_set_direction(&m_Engine, 0, forwardX, forwardY, forwardZ);
|
||||
ma_engine_listener_set_world_up(&m_Engine, 0, upX, upY, upZ);
|
||||
}
|
||||
|
||||
void SoundEngine::SetListenerVelocity(float x, float y, float z)
|
||||
{
|
||||
ma_engine_listener_set_velocity(&m_Engine, 0, x, y, z);
|
||||
}
|
||||
|
||||
void SoundEngine::Update()
|
||||
{
|
||||
for (auto& music : m_Music)
|
||||
music.Update(m_MusicVolume);
|
||||
|
||||
if (m_MasterVolumeFadeRatePerFrame)
|
||||
{
|
||||
float volume = ma_engine_get_volume(&m_Engine) + m_MasterVolumeFadeRatePerFrame;
|
||||
if ((m_MasterVolumeFadeRatePerFrame > 0 && volume >= m_MasterVolumeFadeTarget) || (m_MasterVolumeFadeRatePerFrame < 0 && volume <= m_MasterVolumeFadeTarget))
|
||||
{
|
||||
volume = m_MasterVolumeFadeTarget;
|
||||
m_MasterVolumeFadeRatePerFrame = 0.0f;
|
||||
}
|
||||
ma_engine_set_volume(&m_Engine, volume);
|
||||
}
|
||||
}
|
||||
|
||||
MaSoundInstance* SoundEngine::Internal_GetInstance3D(const std::string& name)
|
||||
{
|
||||
if (Internal_LoadSoundFromPack(name))
|
||||
{
|
||||
for (auto& instance : m_Sounds3D)
|
||||
{
|
||||
if (!instance.IsPlaying())
|
||||
{
|
||||
instance.Destroy();
|
||||
instance.InitFromBuffer(m_Engine, m_Files[name], name);
|
||||
return &instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool SoundEngine::Internal_LoadSoundFromPack(const std::string& name)
|
||||
{
|
||||
if (m_Files.find(name) == m_Files.end())
|
||||
{
|
||||
LPCVOID soundData;
|
||||
CMappedFile soundFile;
|
||||
if (!CEterPackManager::Instance().Get(soundFile, name.c_str(), &soundData))
|
||||
{
|
||||
TraceError("Internal_LoadSoundFromPack: SoundEngine: Failed to register file '%s' - not found.", name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& buffer = m_Files[name];
|
||||
buffer.resize(soundFile.Size());
|
||||
memcpy(buffer.data(), soundData, soundFile.Size());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
96
src/AudioLib/SoundEngine.h
Normal file
96
src/AudioLib/SoundEngine.h
Normal file
@@ -0,0 +1,96 @@
|
||||
#pragma once
|
||||
#include "../eterBase/Singleton.h"
|
||||
#include "Type.h"
|
||||
#include "MaSoundInstance.h"
|
||||
|
||||
//#include <miniaudio.h>
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
|
||||
struct SoundFile
|
||||
{
|
||||
std::string name;
|
||||
std::vector<std::byte> buffer; // raw file data.
|
||||
};
|
||||
|
||||
class SoundEngine : public CSingleton<SoundEngine>
|
||||
{
|
||||
public:
|
||||
enum ESoundConfig
|
||||
{
|
||||
SOUND_INSTANCE_3D_MAX_NUM = 32,
|
||||
};
|
||||
// enum ESoundType
|
||||
// {
|
||||
// SOUND_TYPE_INTERFACE, // Interface sounds. Loaded on game opening, unloaded when the game ends.
|
||||
// SOUND_TYPE_CHARACTER, // Character sounds(hit, damage, etc). Loaded on login, unloaded when the game ends.
|
||||
// SOUND_TYPE_MONSTER, // monster attacks, hits, etc. Loaded and unloaded on warp
|
||||
// SOUND_TYPE_AMBIENCE, // Wind, rain, birds, etc. Loaded and unloaded on warp
|
||||
// SOUND_TYPE_MUSIC, // Bg music played on demand
|
||||
// SOUND_TYPE_MAX_NUM,
|
||||
// };
|
||||
public:
|
||||
SoundEngine();
|
||||
|
||||
~SoundEngine();
|
||||
|
||||
bool Initialize();
|
||||
|
||||
void SetSoundVolume(float volume);
|
||||
|
||||
bool PlaySound2D(const std::string& name);
|
||||
|
||||
MaSoundInstance* PlaySound3D(const std::string& name, float fx, float fy, float fz);
|
||||
|
||||
MaSoundInstance* PlayAmbienceSound3D(float fx, float fy, float fz, const std::string& name, int loopCount = 1);
|
||||
|
||||
void StopAllSound3D();
|
||||
|
||||
void UpdateSoundInstance(float fx, float fy, float fz, uint32_t dwcurFrame, const NSound::TSoundInstanceVector* c_pSoundInstanceVector, bool checkFrequency = false, bool isMain = false);
|
||||
|
||||
bool FadeInMusic(const std::string& path, float targetVolume = 1.0f, float fadeInDurationSecondsFromMin = 1.5f);
|
||||
|
||||
void FadeOutMusic(const std::string& name, float targetVolume = 0.0f, float fadeOutDurationSecondsFromMax = 1.5f);
|
||||
|
||||
void FadeOutAllMusic();
|
||||
|
||||
void SetMusicVolume(float volume);
|
||||
|
||||
void SaveVolume(bool isMinimized);
|
||||
|
||||
void RestoreVolume();
|
||||
|
||||
void SetMasterVolume(float volume);
|
||||
|
||||
void SetListenerPosition(float x, float y, float z);
|
||||
|
||||
void SetListenerOrientation(float forwardX, float forwardY, float forwardZ,
|
||||
float upX, float upY, float upZ);
|
||||
|
||||
void SetListenerVelocity(float x, float y, float z);
|
||||
|
||||
void Update();
|
||||
|
||||
|
||||
private:
|
||||
MaSoundInstance* Internal_GetInstance3D(const std::string& name);
|
||||
|
||||
bool Internal_LoadSoundFromPack(const std::string& name);
|
||||
|
||||
private:
|
||||
ma_engine m_Engine{};
|
||||
std::unordered_map<std::string, std::vector<uint8_t>> m_Files;
|
||||
std::unordered_map<std::string, MaSoundInstance> m_Sounds2D;
|
||||
std::array<MaSoundInstance, SOUND_INSTANCE_3D_MAX_NUM> m_Sounds3D;
|
||||
std::unordered_map<std::string, float> m_PlaySoundHistoryMap;
|
||||
|
||||
// One song at a time, but holding both current and previous for graceful fading
|
||||
std::array<MaSoundInstance, 2> m_Music;
|
||||
int m_CurrentMusicIndex{};
|
||||
float m_MusicVolume{ 1.0 };
|
||||
float m_SoundVolume{ 1.0 };
|
||||
|
||||
float m_MasterVolume{ 1.0 };
|
||||
float m_MasterVolumeFadeTarget{};
|
||||
float m_MasterVolumeFadeRatePerFrame{};
|
||||
};
|
||||
9
src/AudioLib/Stdafx.h
Normal file
9
src/AudioLib/Stdafx.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
//#include <windows.h>
|
||||
|
||||
#include "../eterBase/CRC32.h"
|
||||
#include "../eterBase/Utils.h"
|
||||
#include "../eterBase/Debug.h"
|
||||
|
||||
#include <algorithm>
|
||||
138
src/AudioLib/Type.cpp
Normal file
138
src/AudioLib/Type.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
#include "StdAfx.h"
|
||||
#include "Type.h"
|
||||
#include "../EterLib/TextFileLoader.h"
|
||||
|
||||
std::string NSound::strResult;
|
||||
|
||||
const char* NSound::GetResultString()
|
||||
{
|
||||
return strResult.c_str();
|
||||
}
|
||||
|
||||
void NSound::SetResultString(const char* c_pszStr)
|
||||
{
|
||||
strResult.assign(c_pszStr);
|
||||
}
|
||||
|
||||
bool NSound::LoadSoundInformationPiece(const char* c_szFileName, NSound::TSoundDataVector& rSoundDataVector, const char* c_szPathHeader)
|
||||
{
|
||||
std::string strResult;
|
||||
strResult = c_szFileName;
|
||||
|
||||
CTextFileLoader* pkTextFileLoader = CTextFileLoader::Cache(c_szFileName);
|
||||
if (!pkTextFileLoader)
|
||||
return false;
|
||||
|
||||
CTextFileLoader& rkTextFileLoader = *pkTextFileLoader;
|
||||
if (rkTextFileLoader.IsEmpty())
|
||||
{
|
||||
SetResultString((strResult + " Can not open file for reading").c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
rkTextFileLoader.SetTop();
|
||||
|
||||
int iCount;
|
||||
if (!rkTextFileLoader.GetTokenInteger("sounddatacount", &iCount))
|
||||
{
|
||||
SetResultString((strResult + " File format error, SoundDataCount Unable to find.").c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
rSoundDataVector.clear();
|
||||
rSoundDataVector.resize(iCount);
|
||||
|
||||
char szSoundDataHeader[32 + 1];
|
||||
for (uint32_t i = 0; i < rSoundDataVector.size(); ++i)
|
||||
{
|
||||
_snprintf_s(szSoundDataHeader, sizeof(szSoundDataHeader), "sounddata%02d", i);
|
||||
CTokenVector* pTokenVector;
|
||||
if (!rkTextFileLoader.GetTokenVector(szSoundDataHeader, &pTokenVector))
|
||||
{
|
||||
SetResultString((strResult + " File format error: " + szSoundDataHeader + " Unable to find").c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (2 != pTokenVector->size())
|
||||
{
|
||||
SetResultString((strResult + " File format error: The size of the vector is not 2").c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
rSoundDataVector[i].fTime = (float)atof(pTokenVector->at(0).c_str());
|
||||
if (c_szPathHeader)
|
||||
{
|
||||
rSoundDataVector[i].strSoundFileName = c_szPathHeader;
|
||||
rSoundDataVector[i].strSoundFileName += pTokenVector->at(1).c_str();
|
||||
}
|
||||
else
|
||||
{
|
||||
rSoundDataVector[i].strSoundFileName = pTokenVector->at(1).c_str();
|
||||
}
|
||||
|
||||
//TraceError("LoadSoundInformation %s -- %f -- %s", c_szFileName, rSoundDataVector[i].fTime, rSoundDataVector[i].strSoundFileName.c_str());
|
||||
}
|
||||
|
||||
SetResultString((strResult + " Loaded").c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NSound::SaveSoundInformationPiece(const char* c_szFileName, NSound::TSoundDataVector& rSoundDataVector)
|
||||
{
|
||||
if (rSoundDataVector.empty()) // If no data is considered success
|
||||
{
|
||||
if (IsFile(c_szFileName)) // If the data is empty but there is a file
|
||||
{
|
||||
_unlink(c_szFileName); // erase.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string strResult;
|
||||
strResult = c_szFileName;
|
||||
|
||||
FILE* File = fopen(c_szFileName, "wt");
|
||||
|
||||
if (!File)
|
||||
{
|
||||
char szErrorText[256 + 1];
|
||||
_snprintf_s(szErrorText, sizeof(szErrorText), "Failed to save file (%s).\nPlease check if it is read-only or you have no space on the disk.\n", c_szFileName);
|
||||
LogBox(szErrorText, "Error");
|
||||
SetResultString((strResult + " Cannot open file for writing").c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(File, "ScriptType CharacterSoundInformation\n");
|
||||
fprintf(File, "\n");
|
||||
|
||||
fprintf(File, "SoundDataCount %llu\n", rSoundDataVector.size());
|
||||
|
||||
for (uint32_t i = 0; i < rSoundDataVector.size(); ++i)
|
||||
{
|
||||
NSound::TSoundData& rSoundData = rSoundDataVector[i];
|
||||
fprintf(File, "SoundData%02d %f \"%s\"\n", i, rSoundData.fTime, rSoundData.strSoundFileName.c_str());
|
||||
}
|
||||
|
||||
fclose(File);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NSound::DataToInstance(const TSoundDataVector& c_rSoundDataVector, TSoundInstanceVector* pSoundInstanceVector)
|
||||
{
|
||||
if (c_rSoundDataVector.empty())
|
||||
return;
|
||||
|
||||
uint32_t dwFPS = 60;
|
||||
const float c_fFrameTime = 1.0f / float(dwFPS);
|
||||
|
||||
pSoundInstanceVector->clear();
|
||||
pSoundInstanceVector->resize(c_rSoundDataVector.size());
|
||||
for (uint32_t i = 0; i < c_rSoundDataVector.size(); ++i)
|
||||
{
|
||||
const TSoundData& c_rSoundData = c_rSoundDataVector[i];
|
||||
TSoundInstance& rSoundInstance = pSoundInstanceVector->at(i);
|
||||
|
||||
rSoundInstance.dwFrame = (uint32_t)(c_rSoundData.fTime / c_fFrameTime);
|
||||
rSoundInstance.strSoundFileName = c_rSoundData.strSoundFileName;
|
||||
}
|
||||
}
|
||||
29
src/AudioLib/Type.h
Normal file
29
src/AudioLib/Type.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace NSound
|
||||
{
|
||||
extern std::string strResult;
|
||||
|
||||
typedef struct SSoundData
|
||||
{
|
||||
float fTime;
|
||||
std::string strSoundFileName;
|
||||
} TSoundData;
|
||||
typedef struct SSoundInstance
|
||||
{
|
||||
uint32_t dwFrame;
|
||||
std::string strSoundFileName;
|
||||
} TSoundInstance;
|
||||
typedef std::vector<TSoundData> TSoundDataVector;
|
||||
typedef std::vector<TSoundInstance> TSoundInstanceVector;
|
||||
|
||||
bool LoadSoundInformationPiece(const char* c_szFileName, TSoundDataVector& rSoundDataVector, const char* c_szPathHeader = NULL);
|
||||
bool SaveSoundInformationPiece(const char* c_szFileName, TSoundDataVector& rSoundDataVector);
|
||||
void DataToInstance(const TSoundDataVector& c_rSoundDataVector, TSoundInstanceVector* pSoundInstanceVector);
|
||||
|
||||
const char* GetResultString();
|
||||
void SetResultString(const char* c_pszStr);
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
add_subdirectory(AudioLib)
|
||||
add_subdirectory(Discord)
|
||||
add_subdirectory(EffectLib)
|
||||
add_subdirectory(EterBase)
|
||||
@@ -8,7 +9,6 @@ add_subdirectory(EterLocale)
|
||||
add_subdirectory(EterPack)
|
||||
add_subdirectory(EterPythonLib)
|
||||
add_subdirectory(GameLib)
|
||||
add_subdirectory(MilesLib)
|
||||
add_subdirectory(PRTerrainLib)
|
||||
add_subdirectory(ScriptLib)
|
||||
add_subdirectory(SpeedTreeLib)
|
||||
|
||||
@@ -96,7 +96,7 @@ bool CEffectData::LoadScript(const char * c_szFileName)
|
||||
|
||||
bool CEffectData::LoadSoundScriptData(const char * c_szFileName)
|
||||
{
|
||||
TSoundDataVector SoundDataVector;
|
||||
NSound::TSoundDataVector SoundDataVector;
|
||||
|
||||
if (LoadSoundInformationPiece(c_szFileName, SoundDataVector))
|
||||
{
|
||||
@@ -164,7 +164,7 @@ CEffectMeshScript * CEffectData::GetMeshPointer(DWORD dwPosition)
|
||||
return m_MeshVector[dwPosition];
|
||||
}
|
||||
|
||||
TSoundInstanceVector * CEffectData::GetSoundInstanceVector()
|
||||
NSound::TSoundInstanceVector * CEffectData::GetSoundInstanceVector()
|
||||
{
|
||||
return &m_SoundInstanceVector;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../milesLib/Type.h"
|
||||
#include "../AudioLib/Type.h"
|
||||
|
||||
#include "ParticleSystemData.h"
|
||||
#include "EffectMesh.h"
|
||||
@@ -30,7 +30,7 @@ class CEffectData
|
||||
DWORD GetLightCount();
|
||||
CLightData * GetLightPointer(DWORD dwPosition);
|
||||
|
||||
TSoundInstanceVector * GetSoundInstanceVector();
|
||||
NSound::TSoundInstanceVector * GetSoundInstanceVector();
|
||||
|
||||
float GetBoundingSphereRadius();
|
||||
D3DXVECTOR3 GetBoundingSpherePosition();
|
||||
@@ -52,7 +52,7 @@ class CEffectData
|
||||
TParticleVector m_ParticleVector;
|
||||
TMeshVector m_MeshVector;
|
||||
TLightVector m_LightVector;
|
||||
TSoundInstanceVector m_SoundInstanceVector;
|
||||
NSound::TSoundInstanceVector m_SoundInstanceVector;
|
||||
|
||||
float m_fBoundingSphereRadius;
|
||||
D3DXVECTOR3 m_v3BoundingSpherePosition;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include "../eterBase/Stl.h"
|
||||
#include "../eterLib/StateManager.h"
|
||||
#include "../MilesLib/SoundManager.h"
|
||||
#include "../AudioLib/SoundEngine.h"
|
||||
|
||||
CDynamicPool<CEffectInstance> CEffectInstance::ms_kPool;
|
||||
int CEffectInstance::ms_iRenderingEffectCount = 0;
|
||||
@@ -50,12 +50,12 @@ void CEffectInstance::UpdateSound()
|
||||
{
|
||||
if (m_pSoundInstanceVector)
|
||||
{
|
||||
UpdateSoundInstance(m_dwFrame,
|
||||
*m_pSoundInstanceVector,
|
||||
m_matGlobal._41,
|
||||
m_matGlobal._42,
|
||||
m_matGlobal._43,
|
||||
false);
|
||||
SoundEngine::Instance().UpdateSoundInstance(m_matGlobal._41,
|
||||
m_matGlobal._42,
|
||||
m_matGlobal._43,
|
||||
m_dwFrame,
|
||||
m_pSoundInstanceVector,
|
||||
false, false);
|
||||
// NOTE : 매트릭스에서 위치를 직접 얻어온다 - [levites]
|
||||
}
|
||||
++m_dwFrame;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "../eterlib/GrpObjectInstance.h"
|
||||
#include "../eterlib/Pool.h"
|
||||
#include "../mileslib/Type.h"
|
||||
#include "../AudioLib/Type.h"
|
||||
|
||||
#include "EffectElementBaseInstance.h"
|
||||
#include "EffectData.h"
|
||||
@@ -77,7 +77,7 @@ class CEffectInstance : public CGraphicObjectInstance
|
||||
std::vector<CEffectMeshInstance*> m_MeshInstanceVector;
|
||||
std::vector<CLightInstance*> m_LightInstanceVector;
|
||||
|
||||
TSoundInstanceVector * m_pSoundInstanceVector;
|
||||
NSound::TSoundInstanceVector * m_pSoundInstanceVector;
|
||||
|
||||
float m_fBoundingSphereRadius;
|
||||
D3DXVECTOR3 m_v3BoundingSpherePosition;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "../eterLib/StdAfx.h"
|
||||
#include "../eterLib/TextFileLoader.h"
|
||||
|
||||
#include "../milesLib/StdAfx.h"
|
||||
#include "../AudioLib/StdAfx.h"
|
||||
|
||||
/*
|
||||
#include "FrameController.h"
|
||||
|
||||
@@ -38,3 +38,9 @@ extern HWND g_PopupHwnd;
|
||||
} \
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(_DEBUG)
|
||||
#define MD_ASSERT(expr) ((expr) ? true : (TraceError("MD_ASSERT('%s') failed at (%s:%d)", #expr, __FILE__, __LINE__), throw "ffs", false))
|
||||
#else
|
||||
#define MD_ASSERT(expr) ((expr) ? true : (TraceError("MD_ASSERT('%s') failed at (%s:%d)", #expr, __FILE__, __LINE__), false))
|
||||
#endif
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
#ifndef __INC_ETERPACKLIB_ETERPACK_H__
|
||||
#define __INC_ETERPACKLIB_ETERPACK_H__
|
||||
|
||||
#ifndef MAKEFOURCC
|
||||
#include <mmsyscom.h>
|
||||
#endif
|
||||
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "EterBase/MappedFile.h"
|
||||
|
||||
|
||||
//#define CHECKSUM_CHECK_MD5
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
|
||||
namespace eterpack
|
||||
{
|
||||
const DWORD c_PackCC = MAKEFOURCC('E', 'P', 'K', 'D');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "StdAfx.h"
|
||||
#include "../effectLib/EffectManager.h"
|
||||
#include "../milesLib/SoundManager.h"
|
||||
#include "../AudioLib/SoundEngine.h"
|
||||
|
||||
#include "ActorInstance.h"
|
||||
#include "RaceData.h"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "StdAfx.h"
|
||||
#include "../EffectLib/EffectManager.h"
|
||||
#include "../milesLib/SoundManager.h"
|
||||
#include "../AudioLib/SoundEngine.h"
|
||||
|
||||
#include "ActorInstance.h"
|
||||
#include "FlyingObjectManager.h"
|
||||
@@ -29,9 +29,9 @@ void CActorInstance::SoundEventProcess(BOOL bCheckFrequency)
|
||||
if (!m_pkCurRaceMotionData)
|
||||
return;
|
||||
|
||||
const TSoundInstanceVector* c_pkVct_kSndInst = m_pkCurRaceMotionData->GetSoundInstanceVectorPointer();
|
||||
UpdateSoundInstance(m_kCurMotNode.dwcurFrame, *c_pkVct_kSndInst,
|
||||
m_x, m_y, m_z, bCheckFrequency);
|
||||
const NSound::TSoundInstanceVector* c_pkVct_kSndInst = m_pkCurRaceMotionData->GetSoundInstanceVectorPointer();
|
||||
SoundEngine::Instance().UpdateSoundInstance(m_x, m_y, m_z, m_kCurMotNode.dwcurFrame, c_pkVct_kSndInst,
|
||||
bCheckFrequency, m_isMain);
|
||||
}
|
||||
|
||||
void CActorInstance::MotionEventProcess(DWORD dwcurFrame, int iIndex, const CRaceMotionData::TMotionEventData * c_pData)
|
||||
@@ -247,7 +247,7 @@ void CActorInstance::ProcessMotionEventSound(const CRaceMotionData::TMotionEvent
|
||||
const CRaceMotionData::TMotionSoundEventData * c_pSoundData = (const CRaceMotionData::TMotionSoundEventData *)c_pData;
|
||||
|
||||
Tracenf("PLAY SOUND: %s", c_pSoundData->strSoundFileName.c_str());
|
||||
CSoundManager::Instance().PlaySound3D(m_x, m_y, m_z, c_pSoundData->strSoundFileName.c_str());
|
||||
SoundEngine::Instance().PlaySound3D(c_pSoundData->strSoundFileName.c_str(), m_x, m_y, m_z);
|
||||
}
|
||||
|
||||
void CActorInstance::ProcessMotionEventFly(const CRaceMotionData::TMotionEventData * c_pData)
|
||||
|
||||
@@ -1316,27 +1316,27 @@ void CArea::TAmbienceInstance::__Update(float fxCenter, float fyCenter, float fz
|
||||
void CArea::TAmbienceInstance::UpdateOnceSound(float fxCenter, float fyCenter, float fzCenter)
|
||||
{
|
||||
float fDistance = sqrtf((fx - fxCenter)*(fx - fxCenter) + (fy - fyCenter)*(fy - fyCenter) + (fz - fzCenter)*(fz - fzCenter));
|
||||
if (DWORD(fDistance) < dwRange)
|
||||
if (uint32_t(fDistance) < dwRange)
|
||||
{
|
||||
if (!pSample)
|
||||
if (!playSoundInstance)
|
||||
{
|
||||
if (AmbienceData.AmbienceSoundVector.empty())
|
||||
return;
|
||||
|
||||
const char * c_szFileName = AmbienceData.AmbienceSoundVector[0].c_str();
|
||||
pSample = CSoundManager::Instance().PlayAmbienceSound3D(fx, fy, fz, c_szFileName);
|
||||
// Tracef(" %d : OncePlay [%f] : %s\n", iPlaySoundIndex, fDistance, c_szFileName);
|
||||
const char* c_szFileName = AmbienceData.AmbienceSoundVector[0].c_str();
|
||||
playSoundInstance = SoundEngine::Instance().PlayAmbienceSound3D(fx, fy, fz, c_szFileName);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (playSoundInstance)
|
||||
{
|
||||
pSample.reset();
|
||||
playSoundInstance->Stop();
|
||||
playSoundInstance = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CArea::TAmbienceInstance::UpdateStepSound(float fxCenter, float fyCenter, float fzCenter)
|
||||
{
|
||||
float fDistance = sqrtf((fx - fxCenter)*(fx - fxCenter) + (fy - fyCenter)*(fy - fyCenter) + (fz - fzCenter)*(fz - fzCenter));
|
||||
float fDistance = sqrtf((fx - fxCenter) * (fx - fxCenter) + (fy - fyCenter) * (fy - fyCenter) + (fz - fzCenter) * (fz - fzCenter));
|
||||
if (DWORD(fDistance) < dwRange)
|
||||
{
|
||||
float fcurTime = CTimer::Instance().GetCurrentSecond();
|
||||
@@ -1346,9 +1346,8 @@ void CArea::TAmbienceInstance::UpdateStepSound(float fxCenter, float fyCenter, f
|
||||
if (AmbienceData.AmbienceSoundVector.empty())
|
||||
return;
|
||||
|
||||
const char * c_szFileName = AmbienceData.AmbienceSoundVector[0].c_str();
|
||||
pSample = CSoundManager::Instance().PlayAmbienceSound3D(fx, fy, fz, c_szFileName);
|
||||
// Tracef(" %d : StepPlay [%f] : %s\n", iPlaySoundIndex, fDistance, c_szFileName);
|
||||
const char* c_szFileName = AmbienceData.AmbienceSoundVector[0].c_str();
|
||||
playSoundInstance = SoundEngine::Instance().PlayAmbienceSound3D(fx, fy, fz, c_szFileName);
|
||||
|
||||
fNextPlayTime = CTimer::Instance().GetCurrentSecond();
|
||||
fNextPlayTime += AmbienceData.fPlayInterval + frandom(0.0f, AmbienceData.fPlayIntervalVariation);
|
||||
@@ -1356,7 +1355,7 @@ void CArea::TAmbienceInstance::UpdateStepSound(float fxCenter, float fyCenter, f
|
||||
}
|
||||
else
|
||||
{
|
||||
pSample.reset();
|
||||
playSoundInstance = nullptr;
|
||||
fNextPlayTime = 0.0f;
|
||||
}
|
||||
}
|
||||
@@ -1364,20 +1363,24 @@ void CArea::TAmbienceInstance::UpdateStepSound(float fxCenter, float fyCenter, f
|
||||
void CArea::TAmbienceInstance::UpdateLoopSound(float fxCenter, float fyCenter, float fzCenter)
|
||||
{
|
||||
float fDistance = sqrtf((fx - fxCenter) * (fx - fxCenter) + (fy - fyCenter) * (fy - fyCenter) + (fz - fzCenter) * (fz - fzCenter));
|
||||
if (DWORD(fDistance) < dwRange)
|
||||
if (uint32_t(fDistance) < dwRange)
|
||||
{
|
||||
if (!pSample)
|
||||
if (!playSoundInstance)
|
||||
{
|
||||
pSample = CSoundManager::Instance().PlayAmbienceSound3D(fx, fy, fz, AmbienceData.AmbienceSoundVector[0], 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
pSample->SetVolume(__GetVolumeFromDistance(fDistance));
|
||||
if (AmbienceData.AmbienceSoundVector.empty())
|
||||
return;
|
||||
|
||||
const char* c_szFileName = AmbienceData.AmbienceSoundVector[0].c_str();
|
||||
playSoundInstance = SoundEngine::Instance().PlayAmbienceSound3D(fx, fy, fz, c_szFileName, 0);
|
||||
}
|
||||
|
||||
if (playSoundInstance)
|
||||
playSoundInstance->SetVolume(__GetVolumeFromDistance(fDistance));
|
||||
}
|
||||
else
|
||||
else if (playSoundInstance)
|
||||
{
|
||||
pSample.reset();
|
||||
playSoundInstance->Stop();
|
||||
playSoundInstance = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class CArea
|
||||
float fx, fy, fz;
|
||||
DWORD dwRange;
|
||||
float fMaxVolumeAreaPercentage;
|
||||
std::unique_ptr<SoundSample> pSample;
|
||||
MaSoundInstance* playSoundInstance;
|
||||
float fNextPlayTime;
|
||||
prt::TPropertyAmbience AmbienceData;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class CProperty;
|
||||
|
||||
#include "../eterLib/SkyBox.h"
|
||||
#include "../mileslib/SoundManager.h"
|
||||
#include "../AudioLib/SoundEngine.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Property
|
||||
|
||||
@@ -295,7 +295,7 @@ float CRaceMotionData::GetEventStartTime(DWORD dwIndex) const
|
||||
return m_MotionEventDataVector[dwIndex]->fStartingTime;
|
||||
}
|
||||
|
||||
const TSoundInstanceVector * CRaceMotionData::GetSoundInstanceVectorPointer() const
|
||||
const NSound::TSoundInstanceVector * CRaceMotionData::GetSoundInstanceVectorPointer() const
|
||||
{
|
||||
return &m_SoundInstanceVector;
|
||||
}
|
||||
@@ -553,7 +553,7 @@ bool CRaceMotionData::SaveMotionData(const char * c_szFileName)
|
||||
#endif
|
||||
bool CRaceMotionData::LoadSoundScriptData(const char * c_szFileName)
|
||||
{
|
||||
TSoundDataVector SoundDataVector;
|
||||
NSound::TSoundDataVector SoundDataVector;
|
||||
if (!LoadSoundInformationPiece(c_szFileName, SoundDataVector))
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "MilesLib/Type.h"
|
||||
#include "AudioLib/Type.h"
|
||||
#include "RaceMotionDataEvent.h"
|
||||
|
||||
class CRaceMotionData
|
||||
@@ -253,7 +253,7 @@ class CRaceMotionData
|
||||
float GetEventStartTime(DWORD dwIndex) const;
|
||||
|
||||
// Sound Data
|
||||
const TSoundInstanceVector * GetSoundInstanceVectorPointer() const;
|
||||
const NSound::TSoundInstanceVector * GetSoundInstanceVectorPointer() const;
|
||||
|
||||
// File
|
||||
#ifdef WORLD_EDITOR
|
||||
@@ -291,7 +291,7 @@ class CRaceMotionData
|
||||
BOOL m_bCancelEnableSkill;
|
||||
|
||||
TMotionEventDataVector m_MotionEventDataVector;
|
||||
TSoundInstanceVector m_SoundInstanceVector;
|
||||
NSound::TSoundInstanceVector m_SoundInstanceVector;
|
||||
|
||||
private:
|
||||
BOOL m_hasSplashEvent;
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "../eterBase/Random.h"
|
||||
|
||||
#include "../eterLib/StdAfx.h"
|
||||
#include "../milesLib/StdAfx.h"
|
||||
#include "../AudioLib/StdAfx.h"
|
||||
#include "../effectLib/StdAfx.h"
|
||||
|
||||
#include "GameType.h"
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
file(GLOB_RECURSE FILE_SOURCES "*.h" "*.c" "*.cpp")
|
||||
|
||||
add_library(MilesLib STATIC ${FILE_SOURCES})
|
||||
|
||||
target_link_libraries(MilesLib
|
||||
lzo2
|
||||
)
|
||||
|
||||
GroupSourcesByFolder(MilesLib)
|
||||
@@ -1,135 +0,0 @@
|
||||
#include "Stdafx.h"
|
||||
#include "MSSFileAPI.hpp"
|
||||
|
||||
#include "EterBase/Timer.h"
|
||||
#include "EterBase/Utils.h"
|
||||
|
||||
#include "EterPack/StdAfx.h"
|
||||
#include "EterPack/EterPackManager.h"
|
||||
|
||||
#include <mss.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace
|
||||
{
|
||||
enum ESeekType
|
||||
{
|
||||
SEEK_TYPE_BEGIN,
|
||||
SEEK_TYPE_CURRENT,
|
||||
SEEK_TYPE_END
|
||||
};
|
||||
|
||||
struct CSeekPackFile
|
||||
{
|
||||
std::vector<uint8_t> packFile;
|
||||
|
||||
U32 seek_position;
|
||||
|
||||
~CSeekPackFile()
|
||||
{
|
||||
seek_position = 0;
|
||||
}
|
||||
|
||||
U32 Seek(S32 offset, U32 type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case SEEK_TYPE_BEGIN:
|
||||
if (offset > packFile.size())
|
||||
offset = packFile.size();
|
||||
|
||||
seek_position = offset;
|
||||
break;
|
||||
|
||||
case SEEK_TYPE_CURRENT:
|
||||
seek_position = MIN(seek_position + offset, packFile.size());
|
||||
break;
|
||||
|
||||
case SEEK_TYPE_END:
|
||||
seek_position = MAX(0, packFile.size() - offset);
|
||||
break;
|
||||
}
|
||||
|
||||
return seek_position;
|
||||
}
|
||||
|
||||
BOOL Read(void* dest, int bytes)
|
||||
{
|
||||
if (seek_position + bytes > packFile.size())
|
||||
return FALSE;
|
||||
|
||||
memcpy(dest, (const char*)packFile.data() + seek_position, bytes);
|
||||
seek_position += bytes;
|
||||
return TRUE;
|
||||
}
|
||||
};
|
||||
static std::unordered_map<U32, CSeekPackFile> gs_SoundFile;
|
||||
static std::vector<U32> gs_FreeIndexes;
|
||||
static U32 gs_SoundFileIndex = 0;
|
||||
static std::mutex gs_SoundFileMutex;
|
||||
|
||||
U32 AILCALLBACK open_callback(MSS_FILE const* filename, UINTa* file_handle)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(gs_SoundFileMutex);
|
||||
|
||||
U32 index = 0;
|
||||
if (!gs_FreeIndexes.empty())
|
||||
{
|
||||
index = gs_FreeIndexes.back();
|
||||
gs_FreeIndexes.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
index = ++gs_SoundFileIndex;
|
||||
}
|
||||
|
||||
LPCVOID pData;
|
||||
CMappedFile mappedFile;
|
||||
if (!CEterPackManager::instance().Get(mappedFile, filename, &pData))
|
||||
return 0;
|
||||
|
||||
gs_SoundFile[index].packFile.resize(mappedFile.Size());
|
||||
memcpy(gs_SoundFile[index].packFile.data(), pData, mappedFile.Size());
|
||||
|
||||
*file_handle = index;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void AILCALLBACK close_callback(UINTa file_handle)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(gs_SoundFileMutex);
|
||||
|
||||
gs_SoundFile.erase(file_handle);
|
||||
gs_FreeIndexes.push_back(file_handle);
|
||||
}
|
||||
|
||||
S32 AILCALLBACK seek_callback(UINTa file_handle, S32 offset, U32 type)
|
||||
{
|
||||
auto it = gs_SoundFile.find(file_handle);
|
||||
if (it == gs_SoundFile.end())
|
||||
return 0;
|
||||
|
||||
return it->second.Seek(offset, type);
|
||||
}
|
||||
|
||||
U32 AILCALLBACK read_callback(UINTa file_handle, void* buffer, U32 bytes)
|
||||
{
|
||||
auto it = gs_SoundFile.find(file_handle);
|
||||
if (it == gs_SoundFile.end())
|
||||
return 0;
|
||||
|
||||
DWORD dwRealSize = MIN(it->second.packFile.size(), bytes);
|
||||
it->second.Read(buffer, dwRealSize);
|
||||
return dwRealSize;
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterMilesFileAPI()
|
||||
{
|
||||
AIL_set_file_callbacks(open_callback, close_callback,
|
||||
seek_callback, read_callback);
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
void RegisterMilesFileAPI();
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
#include "Stdafx.h"
|
||||
#include "MusicInstance.hpp"
|
||||
|
||||
MusicInstance::MusicInstance(HSTREAM stream, std::string_view filename,
|
||||
float fVolume, float fVolumeSpeed)
|
||||
: MusicState(MUSIC_STATE_FADE_IN)
|
||||
, fVolume(fVolume)
|
||||
, fLimitVolume(0.0f)
|
||||
, fVolumeSpeed(fVolumeSpeed)
|
||||
, filename(filename)
|
||||
, stream(stream)
|
||||
{
|
||||
this->stream.SetVolume(fVolume);
|
||||
this->stream.Play(0);
|
||||
}
|
||||
|
||||
bool MusicInstance::Update(float musicVolume)
|
||||
{
|
||||
if (MUSIC_STATE_OFF == MusicState)
|
||||
return false;
|
||||
|
||||
switch (MusicState)
|
||||
{
|
||||
case MUSIC_STATE_FADE_IN:
|
||||
fVolume += fVolumeSpeed;
|
||||
|
||||
if (fVolume >= musicVolume)
|
||||
{
|
||||
fVolume = musicVolume;
|
||||
fVolumeSpeed = 0.0f;
|
||||
MusicState = MUSIC_STATE_PLAY;
|
||||
}
|
||||
|
||||
stream.SetVolume(fVolume);
|
||||
break;
|
||||
|
||||
case MUSIC_STATE_FADE_LIMIT_OUT:
|
||||
fVolume -= fVolumeSpeed;
|
||||
|
||||
if (fVolume <= fLimitVolume)
|
||||
{
|
||||
fVolume = fLimitVolume;
|
||||
fVolumeSpeed = 0.0f;
|
||||
MusicState = MUSIC_STATE_OFF;
|
||||
}
|
||||
|
||||
stream.SetVolume(fVolume);
|
||||
break;
|
||||
|
||||
case MUSIC_STATE_FADE_OUT:
|
||||
fVolume -= fVolumeSpeed;
|
||||
return fVolume > 0.0f;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
#include "SoundStream.hpp"
|
||||
#include <mss.h>
|
||||
|
||||
enum MusicState
|
||||
{
|
||||
MUSIC_STATE_OFF,
|
||||
MUSIC_STATE_PLAY,
|
||||
MUSIC_STATE_FADE_IN,
|
||||
MUSIC_STATE_FADE_OUT,
|
||||
MUSIC_STATE_FADE_LIMIT_OUT,
|
||||
};
|
||||
|
||||
// TODO(tim): make members private?
|
||||
struct MusicInstance
|
||||
{
|
||||
MusicInstance(HSTREAM stream, std::string_view filename,
|
||||
float fVolume, float fVolumeSpeed);
|
||||
|
||||
bool Update(float musicVolume);
|
||||
|
||||
MusicState MusicState;
|
||||
float fVolume;
|
||||
float fLimitVolume;
|
||||
float fVolumeSpeed;
|
||||
std::string filename;
|
||||
SoundStream stream;
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
#include "Stdafx.h"
|
||||
#include "SampleFile.hpp"
|
||||
|
||||
SampleFile::SampleFile(std::string_view filename, std::vector<uint8_t>&& data)
|
||||
: m_filename(filename), fileData(std::forward<std::vector<uint8_t>>(data))
|
||||
{
|
||||
}
|
||||
|
||||
const void *SampleFile::GetData() const
|
||||
{
|
||||
return fileData.data();
|
||||
}
|
||||
|
||||
uint32_t SampleFile::GetSize() const
|
||||
{
|
||||
return fileData.size();
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "EterBase/StdAfx.h"
|
||||
#include <string_view>
|
||||
|
||||
#include "EterPack/StdAfx.h"
|
||||
#include "EterPack/EterPackmanager.h"
|
||||
|
||||
class SampleFile
|
||||
{
|
||||
public:
|
||||
SampleFile(std::string_view filename, std::vector<uint8_t>&& data);
|
||||
|
||||
const std::string &GetFilename() const
|
||||
{
|
||||
return m_filename;
|
||||
}
|
||||
|
||||
const void *GetData() const;
|
||||
uint32_t GetSize() const;
|
||||
|
||||
private:
|
||||
std::string m_filename;
|
||||
std::vector<uint8_t> fileData;
|
||||
};
|
||||
|
||||
using SampleFilePtr = std::shared_ptr<SampleFile>;
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
#include "Stdafx.h"
|
||||
#include "SampleFileCache.hpp"
|
||||
#include "EterBase/Debug.h"
|
||||
#include "EterLib/ResourceManager.h"
|
||||
|
||||
#include "EterPack/StdAfx.h"
|
||||
#include "EterPack/EterPackManager.h"
|
||||
|
||||
SampleFilePtr SampleFileCache::Get(std::string_view filename)
|
||||
{
|
||||
const auto it = m_samples.find(filename);
|
||||
if (it != m_samples.end())
|
||||
return it->second;
|
||||
|
||||
LPCVOID pData;
|
||||
CMappedFile mappedFile;
|
||||
|
||||
if(!CEterPackManager::instance().Get(mappedFile, filename.data(), &pData))
|
||||
{
|
||||
TraceError("Failed to open %s", filename);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> fileData;
|
||||
fileData.resize(mappedFile.Size());
|
||||
memcpy(fileData.data(), pData, mappedFile.Size());
|
||||
|
||||
auto sample = std::make_shared<SampleFile>(filename, std::move(fileData));
|
||||
m_samples.emplace(sample->GetFilename(), sample);
|
||||
return sample;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "SampleFile.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
class SampleFileCache
|
||||
{
|
||||
public:
|
||||
SampleFilePtr Get(std::string_view filename);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string_view, SampleFilePtr> m_samples;
|
||||
};
|
||||
|
||||
@@ -1,393 +0,0 @@
|
||||
#include "StdAfx.h"
|
||||
#include "SoundManager.h"
|
||||
|
||||
#include "EterBase/Timer.h"
|
||||
#include "EterBase/Utils.h"
|
||||
#include "EterBase/Debug.h"
|
||||
#undef min
|
||||
#undef max
|
||||
#include <cmath>
|
||||
//#define IS_STATIC
|
||||
//#include <StepTimer.h>
|
||||
|
||||
#include "MSSFileAPI.hpp"
|
||||
#include <mss.h>
|
||||
|
||||
MilesLibrary::MilesLibrary()
|
||||
{
|
||||
Register_RIB(MP3Dec);
|
||||
//AIL_configure_logging("miles.log", nullptr, 2);
|
||||
|
||||
AIL_startup();
|
||||
|
||||
RegisterMilesFileAPI();
|
||||
}
|
||||
|
||||
MilesLibrary::~MilesLibrary()
|
||||
{
|
||||
AIL_shutdown();
|
||||
}
|
||||
|
||||
CSoundManager::CSoundManager()
|
||||
: m_isSoundDisable(false), m_max2dSoundsPlaying(8), m_max3dSoundsPlaying(64), m_maxMusicPlaying(4),
|
||||
m_fxPosition(0.0f), m_fyPosition(0.0f), m_fzPosition(0.0f), m_fSoundScale(200.0f), m_fAmbienceSoundScale(1000.0f),
|
||||
m_fSoundVolume(1.0f), m_fMusicVolume(1.0f), m_fBackupMusicVolume(0.0f), m_fBackupSoundVolume(0.0f),
|
||||
m_driver(nullptr)
|
||||
{
|
||||
// ctor
|
||||
}
|
||||
|
||||
bool CSoundManager::Create()
|
||||
{
|
||||
m_driver = AIL_open_digital_driver(44100, 16, MSS_MC_USE_SYSTEM_CONFIG , 0);
|
||||
if (!m_driver)
|
||||
{
|
||||
Tracenf("AIL_open_digital_driver(): %s", AIL_last_error());
|
||||
return false;
|
||||
}
|
||||
AIL_set_3D_distance_factor(m_driver, 0.001f);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSoundManager::SetPosition(float fx, float fy, float fz)
|
||||
{
|
||||
m_fxPosition = fx;
|
||||
m_fyPosition = fy;
|
||||
m_fzPosition = fz;
|
||||
}
|
||||
|
||||
void CSoundManager::SetDirection(float fxDir, float fyDir, float fzDir, float fxUp, float fyUp, float fzUp)
|
||||
{
|
||||
if (!m_driver)
|
||||
return;
|
||||
|
||||
AIL_set_listener_3D_orientation(m_driver, fxDir, fyDir, -fzDir, fxUp, fyUp, -fzUp);
|
||||
}
|
||||
|
||||
void CSoundManager::Update()
|
||||
{
|
||||
for (auto it = m_sounds2d.begin(); it != m_sounds2d.end();)
|
||||
{
|
||||
if (it->IsDone())
|
||||
it = m_sounds2d.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
for (auto it = m_sounds3d.begin(); it != m_sounds3d.end();)
|
||||
{
|
||||
if (it->IsDone())
|
||||
it = m_sounds3d.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
for (auto it = m_music.begin(); it != m_music.end();)
|
||||
{
|
||||
// If Update() returns false, the song has finished playing.
|
||||
if (it->second.Update(m_fMusicVolume))
|
||||
++it;
|
||||
else
|
||||
it = m_music.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
float CSoundManager::GetSoundScale()
|
||||
{
|
||||
return m_fSoundScale;
|
||||
}
|
||||
|
||||
void CSoundManager::SetSoundScale(float fScale)
|
||||
{
|
||||
m_fSoundScale = fScale;
|
||||
}
|
||||
|
||||
void CSoundManager::SetAmbienceSoundScale(float fScale)
|
||||
{
|
||||
m_fAmbienceSoundScale = fScale;
|
||||
}
|
||||
|
||||
void CSoundManager::SetSoundVolume(float fVolume)
|
||||
{
|
||||
if (m_isSoundDisable)
|
||||
{
|
||||
m_fBackupSoundVolume = fVolume;
|
||||
return;
|
||||
}
|
||||
|
||||
fVolume = std::max(std::min(fVolume, 1.0f), 0.0f);
|
||||
m_fSoundVolume = fVolume;
|
||||
m_fBackupSoundVolume = fVolume;
|
||||
}
|
||||
|
||||
void CSoundManager::SetMusicVolume(float fVolume)
|
||||
{
|
||||
if (m_isSoundDisable)
|
||||
{
|
||||
m_fBackupMusicVolume = fVolume;
|
||||
return;
|
||||
}
|
||||
|
||||
fVolume = std::max(std::min(fVolume, 1.0f), 0.0f);
|
||||
m_fMusicVolume = fVolume;
|
||||
m_fBackupMusicVolume = fVolume;
|
||||
|
||||
for (auto &p : m_music)
|
||||
{
|
||||
if (MUSIC_STATE_OFF == p.second.MusicState)
|
||||
continue;
|
||||
if (MUSIC_STATE_FADE_OUT == p.second.MusicState)
|
||||
continue;
|
||||
|
||||
p.second.fVolume = fVolume;
|
||||
p.second.stream.SetVolume(fVolume);
|
||||
}
|
||||
}
|
||||
|
||||
void CSoundManager::SaveVolume()
|
||||
{
|
||||
// NOTE : 두번 이상 Save를 시도할때는 그냥 Return
|
||||
if (m_isSoundDisable)
|
||||
return;
|
||||
|
||||
float fBackupMusicVolume = m_fMusicVolume;
|
||||
float fBackupSoundVolume = m_fSoundVolume;
|
||||
SetMusicVolume(0.0f);
|
||||
SetSoundVolume(0.0f);
|
||||
m_fBackupMusicVolume = fBackupMusicVolume;
|
||||
m_fBackupSoundVolume = fBackupSoundVolume;
|
||||
m_isSoundDisable = true;
|
||||
}
|
||||
|
||||
void CSoundManager::RestoreVolume()
|
||||
{
|
||||
m_isSoundDisable = false;
|
||||
SetMusicVolume(m_fBackupMusicVolume);
|
||||
SetSoundVolume(m_fBackupSoundVolume);
|
||||
}
|
||||
|
||||
float CSoundManager::GetSoundVolume()
|
||||
{
|
||||
return m_fSoundVolume;
|
||||
}
|
||||
|
||||
float CSoundManager::GetMusicVolume()
|
||||
{
|
||||
return m_fMusicVolume;
|
||||
}
|
||||
|
||||
void CSoundManager::PlaySound2D(std::string_view filename)
|
||||
{
|
||||
if (0.0f == GetSoundVolume())
|
||||
return;
|
||||
|
||||
if (m_sounds2d.size() >= m_max2dSoundsPlaying)
|
||||
return;
|
||||
|
||||
const auto file = m_cache.Get(filename);
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
if (!m_driver)
|
||||
return;
|
||||
|
||||
const auto sample = AIL_allocate_sample_handle(m_driver);
|
||||
if (!sample)
|
||||
{
|
||||
Tracenf("AIL_allocate_sample_handle(): %s for %s", AIL_last_error(), filename.data());
|
||||
return;
|
||||
}
|
||||
|
||||
m_sounds2d.emplace_back(sample);
|
||||
m_sounds2d.back().SetFile(file);
|
||||
m_sounds2d.back().SetVolume(GetSoundVolume());
|
||||
m_sounds2d.back().Play(1);
|
||||
}
|
||||
|
||||
float CSoundManager::__GetVolumeFromDistance(float fDistance)
|
||||
{
|
||||
return GetSoundVolume() - (fDistance / 2500);
|
||||
}
|
||||
// return 1.0f / (1.0f + (1.0f * (fDistance - 1.0f)));
|
||||
|
||||
|
||||
void CSoundManager::PlaySound3D(float fx, float fy, float fz, std::string_view filename, int iPlayCount)
|
||||
{
|
||||
if (0.0f == GetSoundVolume())
|
||||
return;
|
||||
|
||||
if (m_sounds3d.size() >= m_max3dSoundsPlaying)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const auto file = m_cache.Get(filename);
|
||||
if (!file)
|
||||
{
|
||||
Tracenf("Not playing %s file not found", filename.data());
|
||||
return;
|
||||
}
|
||||
|
||||
const auto sample = AIL_allocate_sample_handle(m_driver);
|
||||
if (!sample)
|
||||
{
|
||||
Tracenf("AIL_allocate_sample_handle(): %s for %s", AIL_last_error(), filename.data());
|
||||
return;
|
||||
}
|
||||
|
||||
float fDistance = sqrtf((fx - m_fxPosition) * (fx - m_fxPosition) + (fy - m_fyPosition) * (fy - m_fyPosition) +
|
||||
(fz - m_fzPosition) * (fz - m_fzPosition));
|
||||
Tracenf("SampSet distance {} {}", fDistance ,__GetVolumeFromDistance(fDistance));
|
||||
|
||||
|
||||
m_sounds3d.emplace_back(sample);
|
||||
m_sounds3d.back().SetFile(file);
|
||||
m_sounds3d.back().SetPosition((fx - m_fxPosition) / m_fSoundScale,
|
||||
(fy - m_fyPosition) / m_fSoundScale,
|
||||
(fz - m_fzPosition) / m_fSoundScale);
|
||||
m_sounds3d.back().SetVolume(__GetVolumeFromDistance(fDistance));
|
||||
m_sounds3d.back().Play(iPlayCount);
|
||||
}
|
||||
|
||||
std::unique_ptr<SoundSample> CSoundManager::PlayAmbienceSound3D(float fx, float fy, float fz, std::string_view filename,
|
||||
int iPlayCount)
|
||||
{
|
||||
if (0.0f == GetSoundVolume())
|
||||
return nullptr;
|
||||
|
||||
if (m_sounds3d.size() >= m_max3dSoundsPlaying)
|
||||
return nullptr;
|
||||
|
||||
const auto file = m_cache.Get(filename);
|
||||
if (!file)
|
||||
return nullptr;
|
||||
|
||||
if (!m_driver)
|
||||
return nullptr;
|
||||
|
||||
const auto sample = AIL_allocate_sample_handle(m_driver);
|
||||
if (!sample)
|
||||
{
|
||||
Tracenf("AIL_allocate_sample_handle(): %s for %s", AIL_last_error(), filename.data());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto sound = std::make_unique<SoundSample>(sample);
|
||||
sound->SetFile(file);
|
||||
sound->SetPosition((fx - m_fxPosition) / m_fSoundScale,
|
||||
(fy - m_fyPosition) / m_fSoundScale,
|
||||
(fz - m_fzPosition) / m_fSoundScale);
|
||||
sound->SetVolume(GetSoundVolume());
|
||||
sound->Play(iPlayCount);
|
||||
|
||||
return sound;
|
||||
}
|
||||
|
||||
void CSoundManager::PlayCharacterSound3D(float fx, float fy, float fz, const std::string &filename,
|
||||
bool bCheckFrequency)
|
||||
{
|
||||
if (0.0f == GetSoundVolume())
|
||||
return;
|
||||
|
||||
// 어느 정도의 최적화가 필요할 수도 있다 - [levites]
|
||||
if (bCheckFrequency)
|
||||
{
|
||||
static float s_fLimitDistance = 5000 * 5000;
|
||||
float fdx = (fx - m_fxPosition) * (fx - m_fxPosition);
|
||||
float fdy = (fy - m_fyPosition) * (fy - m_fyPosition);
|
||||
|
||||
if (fdx + fdy > s_fLimitDistance)
|
||||
return;
|
||||
|
||||
const auto itor = m_playSoundHistoryMap.find(filename);
|
||||
if (m_playSoundHistoryMap.end() != itor)
|
||||
{
|
||||
float fTime = itor->second;
|
||||
if (CTimer::instance().GetCurrentSecond() - fTime < 0.3f)
|
||||
//if (DX::StepTimer::instance().GetTotalSeconds() - fTime < 0.3f)
|
||||
{
|
||||
// Tracef("똑같은 소리가 0.3초 내에 다시 플레이 %s\n", filename);
|
||||
return;
|
||||
}
|
||||
m_playSoundHistoryMap.erase(itor);
|
||||
}
|
||||
|
||||
m_playSoundHistoryMap.emplace(filename, CTimer::instance().GetCurrentSecond());
|
||||
//m_playSoundHistoryMap.emplace(filename, DX::StepTimer::instance().GetTotalSeconds());
|
||||
}
|
||||
|
||||
Tracenf("Playing sound %s", filename.data());
|
||||
PlaySound3D(fx, fy, fz, filename, 1);
|
||||
}
|
||||
|
||||
void CSoundManager::StopAllSound3D()
|
||||
{
|
||||
m_sounds3d.clear();
|
||||
}
|
||||
|
||||
void CSoundManager::FadeInMusic(const std::string &filename, float fVolumeSpeed)
|
||||
{
|
||||
const auto it = m_music.find(filename);
|
||||
if (it != m_music.end())
|
||||
{
|
||||
it->second.MusicState = MUSIC_STATE_FADE_IN;
|
||||
it->second.fVolumeSpeed = fVolumeSpeed;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_music.size() >= m_maxMusicPlaying)
|
||||
return;
|
||||
|
||||
FadeOutAllMusic();
|
||||
|
||||
if (!m_driver)
|
||||
return;
|
||||
|
||||
const auto stream = AIL_open_stream(m_driver, filename.c_str(), 0);
|
||||
if (!stream)
|
||||
{
|
||||
Tracenf("AIL_open_stream(%s): %s", filename.c_str(), AIL_last_error());
|
||||
return;
|
||||
}
|
||||
|
||||
m_music.emplace(std::piecewise_construct, std::forward_as_tuple(filename),
|
||||
std::forward_as_tuple(stream, filename, 0.0f, fVolumeSpeed));
|
||||
}
|
||||
|
||||
void CSoundManager::FadeLimitOutMusic(const std::string &filename, float fLimitVolume, float fVolumeSpeed)
|
||||
{
|
||||
const auto it = m_music.find(filename);
|
||||
if (it == m_music.end())
|
||||
{
|
||||
Tracenf("FadeLimitOutMusic: %s is not being played", filename.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
it->second.MusicState = MUSIC_STATE_FADE_LIMIT_OUT;
|
||||
it->second.fVolumeSpeed = fVolumeSpeed;
|
||||
it->second.fLimitVolume = fLimitVolume;
|
||||
}
|
||||
|
||||
void CSoundManager::FadeOutMusic(const std::string &filename, float fVolumeSpeed)
|
||||
{
|
||||
const auto it = m_music.find(filename);
|
||||
if (it == m_music.end())
|
||||
{
|
||||
Tracenf("FadeOutMusic: %s is not being played", filename.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
it->second.MusicState = MUSIC_STATE_FADE_OUT;
|
||||
it->second.fVolumeSpeed = fVolumeSpeed;
|
||||
}
|
||||
|
||||
void CSoundManager::FadeOutAllMusic()
|
||||
{
|
||||
for (auto &p : m_music)
|
||||
{
|
||||
if (MUSIC_STATE_OFF == p.second.MusicState)
|
||||
continue;
|
||||
|
||||
p.second.MusicState = MUSIC_STATE_FADE_OUT;
|
||||
p.second.fVolumeSpeed = 0.01f;
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
#pragma once
|
||||
#include "EterBase/Singleton.h"
|
||||
#include "SampleFileCache.hpp"
|
||||
#include "MusicInstance.hpp"
|
||||
#include "SoundSample.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
struct MilesLibrary
|
||||
{
|
||||
MilesLibrary();
|
||||
~MilesLibrary();
|
||||
};
|
||||
|
||||
class CSoundManager : public CSingleton<CSoundManager>
|
||||
{
|
||||
public:
|
||||
CSoundManager();
|
||||
|
||||
bool Create();
|
||||
|
||||
void SetPosition(float fx, float fy, float fz);
|
||||
void SetDirection(float fxDir, float fyDir, float fzDir, float fxUp, float fyUp, float fzUp);
|
||||
void Update();
|
||||
|
||||
float GetSoundScale();
|
||||
void SetSoundScale(float fScale);
|
||||
void SetAmbienceSoundScale(float fScale);
|
||||
|
||||
void SetSoundVolume(float fVolume);
|
||||
void SetMusicVolume(float fVolume);
|
||||
|
||||
void SaveVolume();
|
||||
void RestoreVolume();
|
||||
|
||||
float GetSoundVolume();
|
||||
float GetMusicVolume();
|
||||
|
||||
// Sound
|
||||
void PlaySound2D(std::string_view filename);
|
||||
float __GetVolumeFromDistance(float fDistance);
|
||||
void PlaySound3D(float fx, float fy, float fz,
|
||||
std::string_view filename,
|
||||
int iPlayCount = 1);
|
||||
std::unique_ptr<SoundSample> PlayAmbienceSound3D(float fx, float fy, float fz,
|
||||
std::string_view filename,
|
||||
int iPlayCount = 1);
|
||||
void PlayCharacterSound3D(float fx, float fy, float fz,
|
||||
const std::string &filename,
|
||||
bool bCheckFrequency = false);
|
||||
void StopAllSound3D();
|
||||
|
||||
// Music
|
||||
void FadeInMusic(const std::string &filename,
|
||||
float fVolumeSpeed = 0.016f);
|
||||
void FadeOutMusic(const std::string &filename,
|
||||
float fVolumeSpeed = 0.016f);
|
||||
void FadeLimitOutMusic(const std::string &filename,
|
||||
float fLimitVolume, float fVolumeSpeed = 0.016f);
|
||||
void FadeOutAllMusic();
|
||||
|
||||
protected:
|
||||
MilesLibrary m_miles;
|
||||
bool m_isSoundDisable;
|
||||
|
||||
uint32_t m_max2dSoundsPlaying;
|
||||
uint32_t m_max3dSoundsPlaying;
|
||||
uint32_t m_maxMusicPlaying;
|
||||
|
||||
float m_fxPosition;
|
||||
float m_fyPosition;
|
||||
float m_fzPosition;
|
||||
|
||||
float m_fSoundScale;
|
||||
float m_fAmbienceSoundScale;
|
||||
float m_fSoundVolume;
|
||||
float m_fMusicVolume;
|
||||
|
||||
float m_fBackupMusicVolume;
|
||||
float m_fBackupSoundVolume;
|
||||
|
||||
HDIGDRIVER m_driver;
|
||||
|
||||
SampleFileCache m_cache;
|
||||
std::unordered_map<std::string, MusicInstance> m_music;
|
||||
std::vector<SoundSample> m_sounds2d;
|
||||
std::vector<SoundSample> m_sounds3d;
|
||||
std::unordered_map<std::string, float> m_playSoundHistoryMap;
|
||||
};
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
#include "Stdafx.h"
|
||||
#include "SoundSample.hpp"
|
||||
|
||||
#include "../EterBase/Debug.h"
|
||||
#include "../EterBase/Timer.h"
|
||||
#include "../EterBase/Utils.h"
|
||||
|
||||
SoundSample::SoundSample(HSAMPLE sample) : m_sample(sample)
|
||||
{
|
||||
}
|
||||
|
||||
SoundSample::SoundSample(SoundSample &&other) : m_sample(other.m_sample), m_sampleFile(std::move(other.m_sampleFile))
|
||||
{
|
||||
other.m_sample = nullptr;
|
||||
other.m_sampleFile.reset();
|
||||
}
|
||||
|
||||
SoundSample::~SoundSample()
|
||||
{
|
||||
if (m_sample)
|
||||
{
|
||||
AIL_release_sample_handle(m_sample);
|
||||
m_sample = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
SoundSample &SoundSample::operator=(SoundSample &&other)
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
if (m_sample)
|
||||
AIL_release_sample_handle(m_sample);
|
||||
|
||||
m_sample = other.m_sample;
|
||||
other.m_sample = nullptr;
|
||||
|
||||
m_sampleFile = std::move(other.m_sampleFile);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool SoundSample::SetFile(SampleFilePtr sample)
|
||||
{
|
||||
if (!AIL_set_named_sample_file(m_sample, sample->GetFilename().c_str(), sample->GetData(), sample->GetSize(), 0))
|
||||
{
|
||||
Tracenf("%s: %s", sample->GetFilename().c_str(), AIL_last_error());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_sampleFile = std::move(sample);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoundSample::IsDone() const
|
||||
{
|
||||
return AIL_sample_status(m_sample) == SMP_DONE;
|
||||
}
|
||||
|
||||
void SoundSample::Play(int loopCount) const
|
||||
{
|
||||
//AIL_set_sample_3D_distances(m_sample, 5000.0f, -1.0f, 0);
|
||||
AIL_set_sample_loop_count(m_sample, loopCount);
|
||||
AIL_start_sample(m_sample);
|
||||
}
|
||||
|
||||
void SoundSample::Pause() const
|
||||
{
|
||||
AIL_stop_sample(m_sample);
|
||||
}
|
||||
|
||||
void SoundSample::Resume() const
|
||||
{
|
||||
AIL_resume_sample(m_sample);
|
||||
}
|
||||
|
||||
void SoundSample::Stop() const
|
||||
{
|
||||
AIL_end_sample(m_sample);
|
||||
}
|
||||
|
||||
float SoundSample::GetVolume() const
|
||||
{
|
||||
float volume;
|
||||
AIL_sample_volume_pan(m_sample, &volume, nullptr);
|
||||
return volume;
|
||||
}
|
||||
|
||||
void SoundSample::SetVolume(float volume) const
|
||||
{
|
||||
volume = std::max<float>(0.0f, std::min<float>(1.0f, volume));
|
||||
AIL_set_sample_volume_pan(m_sample, volume, 0.5f);
|
||||
}
|
||||
|
||||
void SoundSample::SetPosition(float x, float y, float z) const
|
||||
{
|
||||
//AIL_set_sample_3D_position(m_sample, x, y, -z);
|
||||
// AIL_set_sample_is_3D(m_sample, FALSE);
|
||||
}
|
||||
|
||||
void SoundSample::SetVelocity(float fDistanceX, float fDistanceY, float fDistanceZ, float fNagnitude) const
|
||||
{
|
||||
AIL_set_sample_3D_velocity(m_sample, fDistanceX, fDistanceY, fDistanceZ, fNagnitude);
|
||||
}
|
||||
|
||||
void SoundSample::UpdatePosition(float fElapsedTime)
|
||||
{
|
||||
AIL_update_sample_3D_position(m_sample, fElapsedTime);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
#pragma once
|
||||
#include "SampleFile.hpp"
|
||||
#include <mss.h>
|
||||
|
||||
class SoundSample
|
||||
{
|
||||
public:
|
||||
SoundSample(HSAMPLE sample);
|
||||
SoundSample(SoundSample &&other);
|
||||
SoundSample(const SoundSample &other) = delete;
|
||||
~SoundSample();
|
||||
|
||||
SoundSample &operator=(SoundSample &&other);
|
||||
SoundSample &operator=(const SoundSample &other) = delete;
|
||||
|
||||
bool SetFile(SampleFilePtr sample);
|
||||
|
||||
void Play(int loopCount = 1) const;
|
||||
void Pause() const;
|
||||
void Resume() const;
|
||||
void Stop() const;
|
||||
float GetVolume() const;
|
||||
void SetVolume(float volume) const;
|
||||
bool IsDone() const;
|
||||
|
||||
void SetPosition(float x, float y, float z) const;
|
||||
void SetVelocity(float fx, float fy, float fz, float fMagnitude) const;
|
||||
|
||||
void UpdatePosition(float fElapsedTime);
|
||||
|
||||
private:
|
||||
HSAMPLE m_sample;
|
||||
SampleFilePtr m_sampleFile;
|
||||
};
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
#include "Stdafx.h"
|
||||
#include "SoundStream.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
SoundStream::SoundStream(HSTREAM stream)
|
||||
: m_stream(stream)
|
||||
{
|
||||
}
|
||||
|
||||
SoundStream::~SoundStream()
|
||||
{
|
||||
if (m_stream)
|
||||
{
|
||||
AIL_close_stream(m_stream);
|
||||
m_stream = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool SoundStream::IsDone() const
|
||||
{
|
||||
return AIL_stream_status(m_stream) == -1;
|
||||
}
|
||||
|
||||
void SoundStream::Play(int loopCount) const
|
||||
{
|
||||
AIL_set_stream_loop_count(m_stream, loopCount);
|
||||
AIL_start_stream(m_stream);
|
||||
}
|
||||
|
||||
void SoundStream::Pause() const
|
||||
{
|
||||
AIL_pause_stream(m_stream, 1);
|
||||
}
|
||||
|
||||
void SoundStream::Resume() const
|
||||
{
|
||||
AIL_pause_stream(m_stream, 0);
|
||||
}
|
||||
|
||||
void SoundStream::Stop()
|
||||
{
|
||||
AIL_close_stream(m_stream);
|
||||
m_stream = NULL;
|
||||
}
|
||||
|
||||
float SoundStream::GetVolume() const
|
||||
{
|
||||
const auto sample = AIL_stream_sample_handle(m_stream);
|
||||
if (!sample)
|
||||
return 0.0f;
|
||||
|
||||
F32 volume;
|
||||
AIL_sample_volume_pan(sample, &volume, nullptr);
|
||||
return volume;
|
||||
}
|
||||
|
||||
void SoundStream::SetVolume(float volume) const
|
||||
{
|
||||
const auto sample = AIL_stream_sample_handle(m_stream);
|
||||
if (!sample)
|
||||
return;
|
||||
|
||||
volume = std::max<float>(0.0f, std::min<float>(1.0f, volume));
|
||||
AIL_set_sample_volume_pan(sample, volume, 0.5f);
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <mss.h>
|
||||
|
||||
class SoundStream
|
||||
{
|
||||
public:
|
||||
SoundStream(HSTREAM stream);
|
||||
~SoundStream();
|
||||
|
||||
SoundStream(const SoundStream&) = delete;
|
||||
void operator=(const SoundStream&) = delete;
|
||||
|
||||
void Play(int loopCount = 1) const;
|
||||
void Pause() const;
|
||||
void Resume() const;
|
||||
void Stop();
|
||||
float GetVolume() const;
|
||||
void SetVolume(float volume) const;
|
||||
bool IsDone() const;
|
||||
|
||||
private:
|
||||
HSTREAM m_stream;
|
||||
};
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "EterBase/StdAfx.h"
|
||||
|
||||
#include <mss.h>
|
||||
@@ -1,150 +0,0 @@
|
||||
#include "Stdafx.h"
|
||||
#include "Type.h"
|
||||
#include "SoundManager.h"
|
||||
|
||||
#include "../EterBase/Debug.h"
|
||||
#include "../EterLib/TextFileLoader.h"
|
||||
#include "../EterLib/Util.h"
|
||||
|
||||
bool LoadSoundInformationPiece(const char *c_szFileName,
|
||||
TSoundDataVector &rSoundDataVector,
|
||||
const char *c_szPathHeader)
|
||||
{
|
||||
CTextFileLoader *pkTextFileLoader = CTextFileLoader::Cache(c_szFileName);
|
||||
if (!pkTextFileLoader)
|
||||
return false;
|
||||
|
||||
CTextFileLoader &rkTextFileLoader = *pkTextFileLoader;
|
||||
if (rkTextFileLoader.IsEmpty())
|
||||
return false;
|
||||
|
||||
rkTextFileLoader.SetTop();
|
||||
|
||||
int iCount;
|
||||
if (!rkTextFileLoader.GetTokenInteger("sounddatacount", &iCount))
|
||||
{
|
||||
Tracenf("%s: no SoundDataCount", c_szFileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
rSoundDataVector.clear();
|
||||
rSoundDataVector.resize(iCount);
|
||||
|
||||
char szSoundDataHeader[32 + 1];
|
||||
for (uint32_t i = 0; i < rSoundDataVector.size(); ++i)
|
||||
{
|
||||
_snprintf(szSoundDataHeader, sizeof(szSoundDataHeader), "sounddata%02d", i);
|
||||
CTokenVector *pTokenVector;
|
||||
if (!rkTextFileLoader.GetTokenVector(szSoundDataHeader, &pTokenVector))
|
||||
{
|
||||
Tracenf("%s: no %s", c_szFileName, szSoundDataHeader);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (2 != pTokenVector->size())
|
||||
{
|
||||
Tracenf("%s: %s has wrong size %u", c_szFileName,
|
||||
szSoundDataHeader, pTokenVector->size());
|
||||
return false;
|
||||
}
|
||||
|
||||
rSoundDataVector[i].fTime = (float)atof(pTokenVector->at(0).c_str());
|
||||
if (c_szPathHeader)
|
||||
{
|
||||
rSoundDataVector[i].strSoundFileName = c_szPathHeader;
|
||||
rSoundDataVector[i].strSoundFileName += pTokenVector->at(1).c_str();
|
||||
}
|
||||
else
|
||||
{
|
||||
rSoundDataVector[i].strSoundFileName = pTokenVector->at(1).c_str();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveSoundInformationPiece(const char *c_szFileName, TSoundDataVector &rSoundDataVector)
|
||||
{
|
||||
/*storm::String realFilename;
|
||||
GetVfs().GetPathTranslator().Translate(c_szFileName, realFilename);
|
||||
|
||||
if (rSoundDataVector.empty()) // 데이터가 없으면 성공으로 간주
|
||||
{
|
||||
::DeleteFileA(realFilename.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
storm::File File;
|
||||
|
||||
bsys::error_code ec;
|
||||
File.Open(realFilename, ec,
|
||||
storm::AccessMode::kWrite,
|
||||
storm::CreationDisposition::kCreateAlways,
|
||||
storm::ShareMode::kNone,
|
||||
storm::UsageHint::kSequential);
|
||||
|
||||
if (ec) {
|
||||
SPDLOG_ERROR("Failed to open {0} for writing with {1}",
|
||||
realFilename, ec);
|
||||
return false;
|
||||
}
|
||||
|
||||
PrintfTabs(File, 0, "ScriptType CharacterSoundInformation\n");
|
||||
PrintfTabs(File, 0, "\n");
|
||||
|
||||
PrintfTabs(File, 0, "SoundDataCount %d\n", rSoundDataVector.size());
|
||||
|
||||
for (uint32_t i = 0; i < rSoundDataVector.size(); ++i)
|
||||
{
|
||||
const auto & rSoundData = rSoundDataVector[i];
|
||||
PrintfTabs(File, 0, "SoundData%02d %f \"%s\"\n",
|
||||
i, rSoundData.fTime,
|
||||
rSoundData.strSoundFileName.c_str());
|
||||
}
|
||||
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
void DataToInstance(const TSoundDataVector &c_rSoundDataVector, TSoundInstanceVector *pSoundInstanceVector)
|
||||
{
|
||||
if (c_rSoundDataVector.empty())
|
||||
return;
|
||||
|
||||
const float c_fFrameTime = 1.0f / 60.0f;
|
||||
|
||||
pSoundInstanceVector->clear();
|
||||
pSoundInstanceVector->resize(c_rSoundDataVector.size());
|
||||
for (uint32_t i = 0; i < c_rSoundDataVector.size(); ++i)
|
||||
{
|
||||
const TSoundData &c_rSoundData = c_rSoundDataVector[i];
|
||||
TSoundInstance &rSoundInstance = pSoundInstanceVector->at(i);
|
||||
|
||||
rSoundInstance.dwFrame = (uint32_t)(c_rSoundData.fTime / c_fFrameTime);
|
||||
rSoundInstance.strSoundFileName = c_rSoundData.strSoundFileName;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateSoundInstance(uint32_t frame, const TSoundInstanceVector &sounds,
|
||||
float fx, float fy, float fz, bool bCheckFrequency)
|
||||
{
|
||||
auto &snd = CSoundManager::Instance();
|
||||
for (const auto &instance : sounds)
|
||||
{
|
||||
if (instance.dwFrame != frame)
|
||||
continue;
|
||||
|
||||
snd.PlayCharacterSound3D(fx, fy, fz,
|
||||
instance.strSoundFileName,
|
||||
bCheckFrequency);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateSoundInstance(uint32_t frame, const TSoundInstanceVector &sounds)
|
||||
{
|
||||
for (const auto &instance : sounds)
|
||||
{
|
||||
if (instance.dwFrame == frame)
|
||||
CSoundManager::Instance().PlaySound2D(instance.strSoundFileName);
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
#ifndef METIN2_CLIENT_MILESLIB_TYPE_HPP
|
||||
#define METIN2_CLIENT_MILESLIB_TYPE_HPP
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
typedef struct SSoundData
|
||||
{
|
||||
float fTime;
|
||||
std::string strSoundFileName;
|
||||
} TSoundData;
|
||||
|
||||
typedef struct SSoundInstance
|
||||
{
|
||||
uint32_t dwFrame;
|
||||
std::string strSoundFileName;
|
||||
} TSoundInstance;
|
||||
|
||||
typedef std::vector<TSoundData> TSoundDataVector;
|
||||
typedef std::vector<TSoundInstance> TSoundInstanceVector;
|
||||
|
||||
bool LoadSoundInformationPiece(const char *c_szFileName,
|
||||
TSoundDataVector &rSoundDataVector,
|
||||
const char *c_szPathHeader = NULL);
|
||||
bool SaveSoundInformationPiece(const char *c_szFileName,
|
||||
TSoundDataVector &rSoundDataVector);
|
||||
|
||||
void DataToInstance(const TSoundDataVector &c_rSoundDataVector,
|
||||
TSoundInstanceVector *pSoundInstanceVector);
|
||||
|
||||
void UpdateSoundInstance(uint32_t frame, const TSoundInstanceVector &sounds,
|
||||
float fx, float fy, float fz, bool bCheckFrequency);
|
||||
|
||||
void UpdateSoundInstance(uint32_t frame, const TSoundInstanceVector &sounds);
|
||||
|
||||
#endif
|
||||
@@ -9,6 +9,7 @@ set_target_properties(UserInterface PROPERTIES LINK_FLAGS "/level='requireAdmini
|
||||
)
|
||||
|
||||
target_link_libraries(UserInterface
|
||||
AudioLib
|
||||
Discord
|
||||
EffectLib
|
||||
EterBase
|
||||
@@ -19,7 +20,6 @@ target_link_libraries(UserInterface
|
||||
EterPack
|
||||
EterPythonLib
|
||||
GameLib
|
||||
MilesLib
|
||||
PRTerrainLib
|
||||
ScriptLib
|
||||
SpeedTreeLib
|
||||
@@ -31,7 +31,6 @@ target_link_libraries(UserInterface
|
||||
DirectX
|
||||
Granny
|
||||
SpeedTree
|
||||
MilesSoundSystem
|
||||
Python
|
||||
WebView
|
||||
|
||||
|
||||
@@ -1051,10 +1051,10 @@ bool CPythonApplication::Create(PyObject * poSelf, const char * c_szName, int wi
|
||||
if (!m_pySystem.IsNoSoundCard())
|
||||
{
|
||||
// Sound
|
||||
if (!m_SoundManager.Create())
|
||||
if (!m_SoundEngine.Initialize())
|
||||
{
|
||||
// NOTE : Áß±¹ÃøÀÇ ¿äûÀ¸·Î »ý·«
|
||||
// LogBox(ApplicationStringTable_GetStringz(IDS_WARN_NO_SOUND_DEVICE));
|
||||
TraceError("Failed to initialize sound manager!");
|
||||
return false; // Is this important enough to stop the client?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "gamelib/ItemManager.h"
|
||||
#include "gamelib/FlyingObjectManager.h"
|
||||
#include "gamelib/GameEventManager.h"
|
||||
#include "milesLib/SoundManager.h"
|
||||
#include "AudioLib/SoundEngine.h"
|
||||
|
||||
#include "PythonEventManager.h"
|
||||
#include "PythonPlayer.h"
|
||||
@@ -310,7 +310,7 @@ class CPythonApplication : public CMSApplication, public CInputKeyboard, public
|
||||
CTimer m_timer;
|
||||
|
||||
CLightManager m_LightManager;
|
||||
CSoundManager m_SoundManager;
|
||||
SoundEngine m_SoundEngine;
|
||||
CFlyingManager m_FlyingManager;
|
||||
CRaceManager m_RaceManager;
|
||||
CGameEventManager m_GameEventManager;
|
||||
|
||||
@@ -91,9 +91,9 @@ void CPythonApplication::__UpdateCamera()
|
||||
// Sound Setting
|
||||
const D3DXVECTOR3 & c_rv3CameraDirection = pMainCamera->GetView();
|
||||
const D3DXVECTOR3 & c_rv3CameraUp = pMainCamera->GetUp();
|
||||
m_SoundManager.SetPosition(m_v3CenterPosition.x, m_v3CenterPosition.y, m_v3CenterPosition.z); // Listener - 캐릭터 위치
|
||||
m_SoundManager.SetDirection(c_rv3CameraDirection.x, c_rv3CameraDirection.y, c_rv3CameraDirection.z, c_rv3CameraUp.x, c_rv3CameraUp.y, c_rv3CameraUp.z);
|
||||
m_SoundManager.Update();
|
||||
m_SoundEngine.SetListenerPosition(m_v3CenterPosition.x, m_v3CenterPosition.y, m_v3CenterPosition.z); // Listener - 캐릭터 위치
|
||||
m_SoundEngine.SetListenerOrientation(c_rv3CameraDirection.x, c_rv3CameraDirection.y, c_rv3CameraDirection.z, c_rv3CameraUp.x, c_rv3CameraUp.y, c_rv3CameraUp.z);
|
||||
m_SoundEngine.Update();
|
||||
//////////////////////
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ LRESULT CPythonApplication::WindowProcedure(HWND hWnd, UINT uiMsg, WPARAM wParam
|
||||
|
||||
if (m_isActivateWnd)
|
||||
{
|
||||
m_SoundManager.RestoreVolume();
|
||||
m_SoundEngine.RestoreVolume();
|
||||
|
||||
//////////////////
|
||||
|
||||
@@ -71,7 +71,7 @@ LRESULT CPythonApplication::WindowProcedure(HWND hWnd, UINT uiMsg, WPARAM wParam
|
||||
}
|
||||
else
|
||||
{
|
||||
m_SoundManager.SaveVolume();
|
||||
m_SoundEngine.SaveVolume(m_isMinimizedWnd);
|
||||
|
||||
//////////////////
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ void CPythonItem::TGroundItemInstance::__PlayDropSound(DWORD eItemType, const D3
|
||||
if (eItemType>=DROPSOUND_NUM)
|
||||
return;
|
||||
|
||||
CSoundManager::Instance().PlaySound3D(c_rv3Pos.x, c_rv3Pos.y, c_rv3Pos.z, ms_astDropSoundFileName[eItemType].c_str());
|
||||
SoundEngine::Instance().PlaySound3D(ms_astDropSoundFileName[eItemType].c_str(), c_rv3Pos.x, c_rv3Pos.y, c_rv3Pos.z);
|
||||
}
|
||||
|
||||
bool CPythonItem::TGroundItemInstance::Update()
|
||||
@@ -165,7 +165,7 @@ void CPythonItem::PlayUseSound(DWORD dwItemID)
|
||||
if (eItemType>=USESOUND_NUM)
|
||||
return;
|
||||
|
||||
CSoundManager::Instance().PlaySound2D(m_astUseSoundFileName[eItemType].c_str());
|
||||
SoundEngine::Instance().PlaySound2D(m_astUseSoundFileName[eItemType].c_str());
|
||||
}
|
||||
|
||||
|
||||
@@ -181,12 +181,12 @@ void CPythonItem::PlayDropSound(DWORD dwItemID)
|
||||
if (eItemType>=DROPSOUND_NUM)
|
||||
return;
|
||||
|
||||
CSoundManager::Instance().PlaySound2D(SGroundItemInstance::ms_astDropSoundFileName[eItemType].c_str());
|
||||
SoundEngine::Instance().PlaySound2D(SGroundItemInstance::ms_astDropSoundFileName[eItemType].c_str());
|
||||
}
|
||||
|
||||
void CPythonItem::PlayUsePotionSound()
|
||||
{
|
||||
CSoundManager::Instance().PlaySound2D(m_astUseSoundFileName[USESOUND_POTION].c_str());
|
||||
SoundEngine::Instance().PlaySound2D(m_astUseSoundFileName[USESOUND_POTION].c_str());
|
||||
}
|
||||
|
||||
DWORD CPythonItem::__GetDropSoundType(const CItemData& c_rkItemData)
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
#include "StdAfx.h"
|
||||
#include "PythonApplication.h"
|
||||
|
||||
PyObject * sndPlaySound(PyObject * poSelf, PyObject * poArgs)
|
||||
PyObject* sndPlaySound2D(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
char * szFileName;
|
||||
char* szFileName;
|
||||
if (!PyTuple_GetString(poArgs, 0, &szFileName))
|
||||
return Py_BuildException();
|
||||
|
||||
CSoundManager& rkSndMgr=CSoundManager::Instance();
|
||||
rkSndMgr.PlaySound2D(szFileName);
|
||||
SoundEngine::Instance().PlaySound2D(szFileName);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject * sndPlaySound3D(PyObject * poSelf, PyObject * poArgs)
|
||||
PyObject* sndPlaySound3D(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
float fx;
|
||||
if (!PyTuple_GetFloat(poArgs, 0, &fx))
|
||||
@@ -23,58 +22,43 @@ PyObject * sndPlaySound3D(PyObject * poSelf, PyObject * poArgs)
|
||||
float fz;
|
||||
if (!PyTuple_GetFloat(poArgs, 2, &fz))
|
||||
return Py_BuildException();
|
||||
char * szFileName;
|
||||
char* szFileName;
|
||||
if (!PyTuple_GetString(poArgs, 3, &szFileName))
|
||||
return Py_BuildException();
|
||||
|
||||
CSoundManager& rkSndMgr=CSoundManager::Instance();
|
||||
rkSndMgr.PlaySound3D(fx, fy, fz, szFileName);
|
||||
SoundEngine::Instance().PlaySound3D(szFileName, fx, fy, fz);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject * sndPlayMusic(PyObject * poSelf, PyObject * poArgs)
|
||||
PyObject* sndFadeInMusic(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
char * szFileName;
|
||||
char* szFileName;
|
||||
if (!PyTuple_GetString(poArgs, 0, &szFileName))
|
||||
return Py_BuildException();
|
||||
|
||||
CSoundManager& rkSndMgr=CSoundManager::Instance();
|
||||
rkSndMgr.PlaySound2D(szFileName);
|
||||
SoundEngine::Instance().FadeInMusic(szFileName);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject * sndFadeInMusic(PyObject * poSelf, PyObject * poArgs)
|
||||
PyObject* sndFadeOutMusic(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
char * szFileName;
|
||||
char* szFileName;
|
||||
if (!PyTuple_GetString(poArgs, 0, &szFileName))
|
||||
return Py_BuildException();
|
||||
|
||||
CSoundManager& rkSndMgr=CSoundManager::Instance();
|
||||
rkSndMgr.FadeInMusic(szFileName);
|
||||
SoundEngine::Instance().FadeOutMusic(szFileName);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject * sndFadeOutMusic(PyObject * poSelf, PyObject * poArgs)
|
||||
PyObject* sndFadeOutAllMusic(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
char * szFileName;
|
||||
if (!PyTuple_GetString(poArgs, 0, &szFileName))
|
||||
return Py_BuildException();
|
||||
|
||||
CSoundManager& rkSndMgr=CSoundManager::Instance();
|
||||
rkSndMgr.FadeOutMusic(szFileName);
|
||||
SoundEngine::Instance().FadeOutAllMusic();
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject * sndFadeOutAllMusic(PyObject * poSelf, PyObject * poArgs)
|
||||
PyObject* sndFadeLimitOutMusic(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
CSoundManager& rkSndMgr=CSoundManager::Instance();
|
||||
rkSndMgr.FadeOutAllMusic();
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject * sndFadeLimitOutMusic(PyObject * poSelf, PyObject * poArgs)
|
||||
{
|
||||
char * szFileName;
|
||||
char* szFileName;
|
||||
if (!PyTuple_GetString(poArgs, 0, &szFileName))
|
||||
return Py_BuildException();
|
||||
|
||||
@@ -82,95 +66,74 @@ PyObject * sndFadeLimitOutMusic(PyObject * poSelf, PyObject * poArgs)
|
||||
if (!PyTuple_GetFloat(poArgs, 1, &fLimitVolume))
|
||||
return Py_BuildException();
|
||||
|
||||
CSoundManager& rkSndMgr=CSoundManager::Instance();
|
||||
rkSndMgr.FadeLimitOutMusic(szFileName, fLimitVolume);
|
||||
SoundEngine::Instance().FadeOutMusic(szFileName, fLimitVolume);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject * sndStopAllSound(PyObject * poSelf, PyObject * poArgs)
|
||||
PyObject* sndStopAllSound(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
CSoundManager& rkSndMgr=CSoundManager::Instance();
|
||||
rkSndMgr.StopAllSound3D();
|
||||
SoundEngine::Instance().StopAllSound3D();
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject * sndSetMusicVolume(PyObject * poSelf, PyObject * poArgs)
|
||||
PyObject* sndSetMasterVolume(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
float fVolume;
|
||||
if (!PyTuple_GetFloat(poArgs, 0, &fVolume))
|
||||
return Py_BuildException();
|
||||
|
||||
CSoundManager& rkSndMgr=CSoundManager::Instance();
|
||||
rkSndMgr.SetMusicVolume(fVolume);
|
||||
SoundEngine::Instance().SetMasterVolume(fVolume);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject * sndSetSoundVolumef(PyObject * poSelf, PyObject * poArgs)
|
||||
PyObject* sndSetMusicVolume(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
float fVolume;
|
||||
if (!PyTuple_GetFloat(poArgs, 0, &fVolume))
|
||||
return Py_BuildException();
|
||||
|
||||
CSoundManager& rkSndMgr=CSoundManager::Instance();
|
||||
rkSndMgr.SetSoundVolume(fVolume);
|
||||
SoundEngine::Instance().SetMusicVolume(fVolume);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
|
||||
PyObject * sndSetSoundVolume(PyObject * poSelf, PyObject * poArgs)
|
||||
PyObject* sndSetSoundVolumef(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
int iVolume;
|
||||
if (!PyTuple_GetInteger(poArgs, 0, &iVolume))
|
||||
float fVolume;
|
||||
if (!PyTuple_GetFloat(poArgs, 0, &fVolume))
|
||||
return Py_BuildException();
|
||||
|
||||
CSoundManager& rkSndMgr=CSoundManager::Instance();
|
||||
rkSndMgr.SetSoundVolume(iVolume);
|
||||
SoundEngine::Instance().SetSoundVolume(fVolume);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject * sndSetSoundScale(PyObject * poSelf, PyObject * poArgs)
|
||||
PyObject* sndSetSoundVolume(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
float fScale;
|
||||
if (!PyTuple_GetFloat(poArgs, 0, &fScale))
|
||||
float volume;
|
||||
if (!PyTuple_GetFloat(poArgs, 0, &volume))
|
||||
return Py_BuildException();
|
||||
|
||||
CSoundManager& rkSndMgr=CSoundManager::Instance();
|
||||
rkSndMgr.SetSoundScale(fScale);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject * sndSetAmbienceSoundScale(PyObject * poSelf, PyObject * poArgs)
|
||||
{
|
||||
float fScale;
|
||||
if (!PyTuple_GetFloat(poArgs, 0, &fScale))
|
||||
return Py_BuildException();
|
||||
|
||||
CSoundManager& rkSndMgr=CSoundManager::Instance();
|
||||
rkSndMgr.SetAmbienceSoundScale(fScale);
|
||||
SoundEngine::Instance().SetSoundVolume(volume / 100.0f);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
void initsnd()
|
||||
{
|
||||
static PyMethodDef s_methods[] =
|
||||
static PyMethodDef s_methods[] =
|
||||
{
|
||||
{ "PlaySound", sndPlaySound, METH_VARARGS },
|
||||
{ "PlaySound", sndPlaySound2D, METH_VARARGS },
|
||||
{ "PlaySound3D", sndPlaySound3D, METH_VARARGS },
|
||||
{ "PlayMusic", sndPlayMusic, METH_VARARGS },
|
||||
{ "FadeInMusic", sndFadeInMusic, METH_VARARGS },
|
||||
{ "FadeOutMusic", sndFadeOutMusic, METH_VARARGS },
|
||||
{ "FadeOutAllMusic", sndFadeOutAllMusic, METH_VARARGS },
|
||||
{ "FadeLimitOutMusic", sndFadeLimitOutMusic, METH_VARARGS },
|
||||
{ "StopAllSound", sndStopAllSound, METH_VARARGS },
|
||||
|
||||
{ "SetMusicVolumef", sndSetMusicVolume, METH_VARARGS },
|
||||
{ "SetMasterVolume", sndSetMasterVolume, METH_VARARGS },
|
||||
{ "SetMusicVolume", sndSetMusicVolume, METH_VARARGS },
|
||||
{ "SetSoundVolumef", sndSetSoundVolumef, METH_VARARGS },
|
||||
{ "SetSoundVolume", sndSetSoundVolume, METH_VARARGS },
|
||||
{ "SetSoundScale", sndSetSoundScale, METH_VARARGS },
|
||||
{ "SetAmbienceSoundScale", sndSetAmbienceSoundScale, METH_VARARGS },
|
||||
{ NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
Py_InitModule("snd", s_methods);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -632,7 +632,7 @@ void CPythonSystem::ChangeSystem()
|
||||
else
|
||||
CScreen::SetShadowFlag(false);
|
||||
*/
|
||||
CSoundManager& rkSndMgr = CSoundManager::Instance();
|
||||
SoundEngine& rkSndMgr = SoundEngine::Instance();
|
||||
/*
|
||||
float fMusicVolume;
|
||||
if (0 == m_Config.music_volume)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "eterPythonLib/StdAfx.h"
|
||||
#include "gameLib/StdAfx.h"
|
||||
#include "scriptLib/StdAfx.h"
|
||||
#include "milesLib/StdAfx.h"
|
||||
#include "AudioLib/StdAfx.h"
|
||||
#include "EffectLib/StdAfx.h"
|
||||
#include "PRTerrainLib/StdAfx.h"
|
||||
#include "SpeedTreeLib/StdAfx.h"
|
||||
|
||||
Reference in New Issue
Block a user