feat: update sound player
This commit is contained in:
parent
1e65028321
commit
7d969eddd8
|
|
@ -62,7 +62,10 @@ public:
|
||||||
|
|
||||||
STDMETHOD_(void, OnVoiceProcessingPassStart(UINT32 SamplesRequired)) {}
|
STDMETHOD_(void, OnVoiceProcessingPassStart(UINT32 SamplesRequired)) {}
|
||||||
|
|
||||||
STDMETHOD_(void, OnVoiceError(void* pBufferContext, HRESULT Error)) {}
|
STDMETHOD_(void, OnVoiceError(void* pBufferContext, HRESULT Error))
|
||||||
|
{
|
||||||
|
KGE_ERRORF("Voice error with HRESULT of %08X", Error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AudioModule::AudioModule()
|
AudioModule::AudioModule()
|
||||||
|
|
|
||||||
|
|
@ -139,9 +139,7 @@ bool Sound::Load(TranscoderPtr transcoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset volume
|
// reset volume
|
||||||
const float old_volume = volume_;
|
ResetVolume();
|
||||||
volume_ = 0.f;
|
|
||||||
SetVolume(old_volume);
|
|
||||||
|
|
||||||
coder_ = transcoder;
|
coder_ = transcoder;
|
||||||
opened_ = true;
|
opened_ = true;
|
||||||
|
|
@ -297,6 +295,14 @@ void Sound::SetVolume(float volume)
|
||||||
voice->SetVolume(actual_volume);
|
voice->SetVolume(actual_volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sound::ResetVolume()
|
||||||
|
{
|
||||||
|
const float old_volume = volume_;
|
||||||
|
|
||||||
|
volume_ += 1.f;
|
||||||
|
SetVolume(old_volume);
|
||||||
|
}
|
||||||
|
|
||||||
SoundCallbackPtr Sound::GetCallbackChain()
|
SoundCallbackPtr Sound::GetCallbackChain()
|
||||||
{
|
{
|
||||||
class SoundCallbackChain : public SoundCallback
|
class SoundCallbackChain : public SoundCallback
|
||||||
|
|
@ -313,6 +319,7 @@ SoundCallbackPtr Sound::GetCallbackChain()
|
||||||
cb->OnStart(sound);
|
cb->OnStart(sound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RemoveUsedCallbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnLoopEnd(Sound*) override
|
void OnLoopEnd(Sound*) override
|
||||||
|
|
@ -324,6 +331,7 @@ SoundCallbackPtr Sound::GetCallbackChain()
|
||||||
cb->OnLoopEnd(sound);
|
cb->OnLoopEnd(sound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RemoveUsedCallbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnEnd(Sound*) override
|
void OnEnd(Sound*) override
|
||||||
|
|
@ -335,6 +343,7 @@ SoundCallbackPtr Sound::GetCallbackChain()
|
||||||
cb->OnEnd(sound);
|
cb->OnEnd(sound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RemoveUsedCallbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
float OnVolumeChanged(Sound*, float volume) override
|
float OnVolumeChanged(Sound*, float volume) override
|
||||||
|
|
@ -349,6 +358,23 @@ SoundCallbackPtr Sound::GetCallbackChain()
|
||||||
}
|
}
|
||||||
return actual_volume;
|
return actual_volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RemoveUsedCallbacks()
|
||||||
|
{
|
||||||
|
auto& cbs = sound->GetCallbacks();
|
||||||
|
auto iter = cbs.begin();
|
||||||
|
while (iter != cbs.end())
|
||||||
|
{
|
||||||
|
if (*iter == nullptr)
|
||||||
|
{
|
||||||
|
iter = cbs.erase(iter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!callback_chain_)
|
if (!callback_chain_)
|
||||||
|
|
|
||||||
|
|
@ -178,6 +178,8 @@ protected:
|
||||||
|
|
||||||
SoundCallbackPtr GetCallbackChain();
|
SoundCallbackPtr GetCallbackChain();
|
||||||
|
|
||||||
|
void ResetVolume();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool opened_;
|
bool opened_;
|
||||||
bool playing_;
|
bool playing_;
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#include <kiwano-audio/SoundPlayer.h>
|
#include <kiwano-audio/SoundPlayer.h>
|
||||||
|
#include <kiwano/platform/Application.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
|
|
@ -32,81 +33,31 @@ SoundPlayer::SoundPlayer()
|
||||||
|
|
||||||
SoundPlayer::~SoundPlayer()
|
SoundPlayer::~SoundPlayer()
|
||||||
{
|
{
|
||||||
ClearCache();
|
StopAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t SoundPlayer::GetId(const String& file_path) const
|
void SoundPlayer::Play(SoundPtr sound, int loop_count)
|
||||||
{
|
{
|
||||||
return std::hash<String>()(file_path);
|
if (sound)
|
||||||
}
|
|
||||||
|
|
||||||
size_t SoundPlayer::GetId(const Resource& res) const
|
|
||||||
{
|
|
||||||
return static_cast<size_t>(res.GetId());
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t SoundPlayer::Load(const String& file_path)
|
|
||||||
{
|
|
||||||
size_t id = GetId(file_path);
|
|
||||||
if (sound_cache_.end() != sound_cache_.find(id))
|
|
||||||
return id;
|
|
||||||
|
|
||||||
SoundPtr sound = MakePtr<Sound>();
|
|
||||||
if (sound && sound->Load(file_path))
|
|
||||||
{
|
{
|
||||||
sound->SetVolume(volume_);
|
SetCallback(sound.Get());
|
||||||
sound_cache_.insert(std::make_pair(id, sound));
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t SoundPlayer::Load(const Resource& res)
|
|
||||||
{
|
|
||||||
size_t id = GetId(res);
|
|
||||||
if (sound_cache_.end() != sound_cache_.find(id))
|
|
||||||
return id;
|
|
||||||
|
|
||||||
SoundPtr sound = MakePtr<Sound>();
|
|
||||||
|
|
||||||
if (sound && sound->Load(res))
|
|
||||||
{
|
|
||||||
sound->SetVolume(volume_);
|
|
||||||
sound_cache_.insert(std::make_pair(id, sound));
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundPlayer::Play(size_t id, int loop_count)
|
|
||||||
{
|
|
||||||
if (auto sound = GetSound(id))
|
|
||||||
sound->Play(loop_count);
|
sound->Play(loop_count);
|
||||||
|
sound_list_.push_back(sound);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundPlayer::Pause(size_t id)
|
SoundPtr SoundPlayer::Play(const String& file_path, int loop_count, std::initializer_list<SoundCallbackPtr> callbacks)
|
||||||
{
|
{
|
||||||
if (auto sound = GetSound(id))
|
SoundPtr sound = Sound::Preload(file_path, callbacks);
|
||||||
sound->Pause();
|
Play(sound, loop_count);
|
||||||
|
return sound;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundPlayer::Resume(size_t id)
|
SoundPtr SoundPlayer::Play(const Resource& res, int loop_count, std::initializer_list<SoundCallbackPtr> callbacks)
|
||||||
{
|
{
|
||||||
if (auto sound = GetSound(id))
|
SoundPtr sound = Sound::Preload(res, callbacks);
|
||||||
sound->Resume();
|
Play(sound, loop_count);
|
||||||
}
|
return sound;
|
||||||
|
|
||||||
void SoundPlayer::Stop(size_t id)
|
|
||||||
{
|
|
||||||
if (auto sound = GetSound(id))
|
|
||||||
sound->Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SoundPlayer::IsPlaying(size_t id)
|
|
||||||
{
|
|
||||||
if (auto sound = GetSound(id))
|
|
||||||
return sound->IsPlaying();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float SoundPlayer::GetVolume() const
|
float SoundPlayer::GetVolume() const
|
||||||
|
|
@ -116,53 +67,81 @@ float SoundPlayer::GetVolume() const
|
||||||
|
|
||||||
void SoundPlayer::SetVolume(float volume)
|
void SoundPlayer::SetVolume(float volume)
|
||||||
{
|
{
|
||||||
volume_ = std::min(std::max(volume, -224.f), 224.f);
|
volume_ = volume;
|
||||||
for (auto& pair : sound_cache_)
|
|
||||||
{
|
|
||||||
pair.second->SetVolume(volume_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SoundPtr SoundPlayer::GetSound(size_t id) const
|
|
||||||
{
|
|
||||||
auto iter = sound_cache_.find(id);
|
|
||||||
if (iter != sound_cache_.end())
|
|
||||||
return iter->second;
|
|
||||||
return SoundPtr();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundPlayer::PauseAll()
|
void SoundPlayer::PauseAll()
|
||||||
{
|
{
|
||||||
for (auto& pair : sound_cache_)
|
for (auto& sound : sound_list_)
|
||||||
{
|
{
|
||||||
pair.second->Pause();
|
sound->Pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundPlayer::ResumeAll()
|
void SoundPlayer::ResumeAll()
|
||||||
{
|
{
|
||||||
for (auto& pair : sound_cache_)
|
for (auto& sound : sound_list_)
|
||||||
{
|
{
|
||||||
pair.second->Resume();
|
sound->Resume();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundPlayer::StopAll()
|
void SoundPlayer::StopAll()
|
||||||
{
|
{
|
||||||
for (auto& pair : sound_cache_)
|
for (auto& sound : sound_list_)
|
||||||
{
|
{
|
||||||
pair.second->Stop();
|
sound->Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundPlayer::ReleaseSound(size_t id)
|
void SoundPlayer::OnEnd(Sound* sound)
|
||||||
{
|
{
|
||||||
sound_cache_.erase(id);
|
// remove callback
|
||||||
|
RemoveCallback(sound);
|
||||||
|
|
||||||
|
// remove sound after stopped
|
||||||
|
auto iter = std::find(sound_list_.begin(), sound_list_.end(), sound);
|
||||||
|
if (iter != sound_list_.end())
|
||||||
|
{
|
||||||
|
trash_.push_back(*iter);
|
||||||
|
sound_list_.erase(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear trash in main thread
|
||||||
|
Application::GetInstance().PerformInMainThread(std::bind(&SoundPlayer::ClearTrash, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundPlayer::ClearCache()
|
float SoundPlayer::OnVolumeChanged(Sound* sound, float volume)
|
||||||
{
|
{
|
||||||
sound_cache_.clear();
|
return volume * volume_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SoundPlayer::SetCallback(Sound* sound)
|
||||||
|
{
|
||||||
|
// add callback if not exists
|
||||||
|
auto& cbs = sound->GetCallbacks();
|
||||||
|
auto iter = std::find_if(cbs.begin(), cbs.end(), [this](const SoundCallbackPtr& ptr) { return ptr.Get() == this; });
|
||||||
|
if (iter == cbs.end())
|
||||||
|
{
|
||||||
|
sound->AddCallback(this);
|
||||||
|
}
|
||||||
|
sound->ResetVolume();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundPlayer::RemoveCallback(Sound* sound)
|
||||||
|
{
|
||||||
|
auto& cbs = sound->GetCallbacks();
|
||||||
|
auto iter = std::find_if(cbs.begin(), cbs.end(), [this](const SoundCallbackPtr& ptr) { return ptr.Get() == this; });
|
||||||
|
if (iter != cbs.end())
|
||||||
|
{
|
||||||
|
*iter = nullptr; // will be removed by sound
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundPlayer::ClearTrash()
|
||||||
|
{
|
||||||
|
trash_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace audio
|
} // namespace audio
|
||||||
} // namespace kiwano
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano-audio/Sound.h>
|
#include <kiwano-audio/Sound.h>
|
||||||
#include <kiwano/base/ObjectBase.h>
|
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
|
|
@ -37,78 +36,34 @@ KGE_DECLARE_SMART_PTR(SoundPlayer);
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 音频播放器
|
* @brief 音频播放器
|
||||||
*/
|
*/
|
||||||
class KGE_API SoundPlayer : public ObjectBase
|
class KGE_API SoundPlayer : public SoundCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using SoundMap = Map<size_t, SoundPtr>;
|
using SoundList = List<SoundPtr>;
|
||||||
|
|
||||||
SoundPlayer();
|
SoundPlayer();
|
||||||
|
|
||||||
~SoundPlayer();
|
~SoundPlayer();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 加载本地音频文件
|
/// @brief 播放音频
|
||||||
/// @param file_path 本地音频文件路径
|
/// @param sound 音频
|
||||||
/// @return 音频标识符
|
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
||||||
size_t Load(const String& file_path);
|
void Play(SoundPtr sound, int loop_count = 0);
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 加载音频资源
|
|
||||||
/// @param res 音频资源
|
|
||||||
/// @return 音频标识符
|
|
||||||
size_t Load(const Resource& res);
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 播放音频
|
/// @brief 播放音频
|
||||||
/// @param id 音频标识符
|
|
||||||
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
|
||||||
void Play(size_t id, int loop_count = 0);
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 暂停音频
|
|
||||||
/// @param id 音频标识符
|
|
||||||
void Pause(size_t id);
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 继续播放音频
|
|
||||||
/// @param id 音频标识符
|
|
||||||
void Resume(size_t id);
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 停止音频
|
|
||||||
/// @param id 音频标识符
|
|
||||||
void Stop(size_t id);
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 获取音频播放状态
|
|
||||||
/// @param id 音频标识符
|
|
||||||
bool IsPlaying(size_t id);
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 获取音量
|
|
||||||
float GetVolume() const;
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 设置音量
|
|
||||||
/// @param volume 音量大小,1.0 为原始音量, 大于 1 为放大音量, 0 为最小音量
|
|
||||||
void SetVolume(float volume);
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 获取本地音频文件id
|
|
||||||
/// @param file_path 本地音频文件路径
|
/// @param file_path 本地音频文件路径
|
||||||
/// @return 音频标识符
|
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
||||||
size_t GetId(const String& file_path) const;
|
/// @param callbacks 注册回调
|
||||||
|
SoundPtr Play(const String& file_path, int loop_count = 0, std::initializer_list<SoundCallbackPtr> callbacks = {});
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取音频资源id
|
/// @brief 播放音频
|
||||||
/// @param res 音频资源
|
/// @param res 音频资源
|
||||||
/// @return 音频标识符
|
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
||||||
size_t GetId(const Resource& res) const;
|
/// @param callbacks 注册回调
|
||||||
|
SoundPtr Play(const Resource& res, int loop_count = 0, std::initializer_list<SoundCallbackPtr> callbacks = {});
|
||||||
/// \~chinese
|
|
||||||
/// @brief 获取音乐对象
|
|
||||||
/// @param id 音频标识符
|
|
||||||
SoundPtr GetSound(size_t id) const;
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 暂停所有音频
|
/// @brief 暂停所有音频
|
||||||
|
|
@ -123,29 +78,41 @@ public:
|
||||||
void StopAll();
|
void StopAll();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 释放音乐对象缓存
|
/// @brief 获取正在播放的音频列表
|
||||||
/// @param id 音频标识符
|
const SoundList& GetPlayingList() const;
|
||||||
void ReleaseSound(size_t id);
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取缓存
|
/// @brief 获取音量
|
||||||
const SoundMap& GetCache() const;
|
float GetVolume() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 清除缓存
|
/// @brief 设置音量
|
||||||
void ClearCache();
|
/// @param volume 音量大小,1.0 为原始音量, 大于 1 为放大音量, 0 为最小音量
|
||||||
|
void SetVolume(float volume);
|
||||||
|
|
||||||
private:
|
public:
|
||||||
float volume_;
|
void OnEnd(Sound* sound) override;
|
||||||
|
|
||||||
SoundMap sound_cache_;
|
float OnVolumeChanged(Sound* sound, float volume) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void SetCallback(Sound* sound);
|
||||||
|
|
||||||
|
void RemoveCallback(Sound* sound);
|
||||||
|
|
||||||
|
void ClearTrash();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float volume_;
|
||||||
|
SoundList sound_list_;
|
||||||
|
SoundList trash_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
inline const SoundPlayer::SoundMap& SoundPlayer::GetCache() const
|
inline const SoundPlayer::SoundList& SoundPlayer::GetPlayingList() const
|
||||||
{
|
{
|
||||||
return sound_cache_;
|
return sound_list_;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace audio
|
} // namespace audio
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue