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, OnVoiceError(void* pBufferContext, HRESULT Error)) {}
|
||||
STDMETHOD_(void, OnVoiceError(void* pBufferContext, HRESULT Error))
|
||||
{
|
||||
KGE_ERRORF("Voice error with HRESULT of %08X", Error);
|
||||
}
|
||||
};
|
||||
|
||||
AudioModule::AudioModule()
|
||||
|
|
|
|||
|
|
@ -139,9 +139,7 @@ bool Sound::Load(TranscoderPtr transcoder)
|
|||
}
|
||||
|
||||
// reset volume
|
||||
const float old_volume = volume_;
|
||||
volume_ = 0.f;
|
||||
SetVolume(old_volume);
|
||||
ResetVolume();
|
||||
|
||||
coder_ = transcoder;
|
||||
opened_ = true;
|
||||
|
|
@ -297,6 +295,14 @@ void Sound::SetVolume(float volume)
|
|||
voice->SetVolume(actual_volume);
|
||||
}
|
||||
|
||||
void Sound::ResetVolume()
|
||||
{
|
||||
const float old_volume = volume_;
|
||||
|
||||
volume_ += 1.f;
|
||||
SetVolume(old_volume);
|
||||
}
|
||||
|
||||
SoundCallbackPtr Sound::GetCallbackChain()
|
||||
{
|
||||
class SoundCallbackChain : public SoundCallback
|
||||
|
|
@ -313,6 +319,7 @@ SoundCallbackPtr Sound::GetCallbackChain()
|
|||
cb->OnStart(sound);
|
||||
}
|
||||
}
|
||||
RemoveUsedCallbacks();
|
||||
}
|
||||
|
||||
void OnLoopEnd(Sound*) override
|
||||
|
|
@ -324,6 +331,7 @@ SoundCallbackPtr Sound::GetCallbackChain()
|
|||
cb->OnLoopEnd(sound);
|
||||
}
|
||||
}
|
||||
RemoveUsedCallbacks();
|
||||
}
|
||||
|
||||
void OnEnd(Sound*) override
|
||||
|
|
@ -335,6 +343,7 @@ SoundCallbackPtr Sound::GetCallbackChain()
|
|||
cb->OnEnd(sound);
|
||||
}
|
||||
}
|
||||
RemoveUsedCallbacks();
|
||||
}
|
||||
|
||||
float OnVolumeChanged(Sound*, float volume) override
|
||||
|
|
@ -349,6 +358,23 @@ SoundCallbackPtr Sound::GetCallbackChain()
|
|||
}
|
||||
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_)
|
||||
|
|
|
|||
|
|
@ -178,6 +178,8 @@ protected:
|
|||
|
||||
SoundCallbackPtr GetCallbackChain();
|
||||
|
||||
void ResetVolume();
|
||||
|
||||
private:
|
||||
bool opened_;
|
||||
bool playing_;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#include <kiwano-audio/SoundPlayer.h>
|
||||
#include <kiwano/platform/Application.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
|
@ -32,81 +33,31 @@ 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);
|
||||
}
|
||||
|
||||
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))
|
||||
if (sound)
|
||||
{
|
||||
sound->SetVolume(volume_);
|
||||
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))
|
||||
SetCallback(sound.Get());
|
||||
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))
|
||||
sound->Pause();
|
||||
SoundPtr sound = Sound::Preload(file_path, callbacks);
|
||||
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))
|
||||
sound->Resume();
|
||||
}
|
||||
|
||||
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;
|
||||
SoundPtr sound = Sound::Preload(res, callbacks);
|
||||
Play(sound, loop_count);
|
||||
return sound;
|
||||
}
|
||||
|
||||
float SoundPlayer::GetVolume() const
|
||||
|
|
@ -116,53 +67,81 @@ float SoundPlayer::GetVolume() const
|
|||
|
||||
void SoundPlayer::SetVolume(float volume)
|
||||
{
|
||||
volume_ = std::min(std::max(volume, -224.f), 224.f);
|
||||
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();
|
||||
volume_ = volume;
|
||||
}
|
||||
|
||||
void SoundPlayer::PauseAll()
|
||||
{
|
||||
for (auto& pair : sound_cache_)
|
||||
for (auto& sound : sound_list_)
|
||||
{
|
||||
pair.second->Pause();
|
||||
sound->Pause();
|
||||
}
|
||||
}
|
||||
|
||||
void SoundPlayer::ResumeAll()
|
||||
{
|
||||
for (auto& pair : sound_cache_)
|
||||
for (auto& sound : sound_list_)
|
||||
{
|
||||
pair.second->Resume();
|
||||
sound->Resume();
|
||||
}
|
||||
}
|
||||
|
||||
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 kiwano
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
#pragma once
|
||||
#include <kiwano-audio/Sound.h>
|
||||
#include <kiwano/base/ObjectBase.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
|
@ -37,78 +36,34 @@ KGE_DECLARE_SMART_PTR(SoundPlayer);
|
|||
* \~chinese
|
||||
* @brief 音频播放器
|
||||
*/
|
||||
class KGE_API SoundPlayer : public ObjectBase
|
||||
class KGE_API SoundPlayer : public SoundCallback
|
||||
{
|
||||
public:
|
||||
using SoundMap = Map<size_t, SoundPtr>;
|
||||
using SoundList = List<SoundPtr>;
|
||||
|
||||
SoundPlayer();
|
||||
|
||||
~SoundPlayer();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 加载本地音频文件
|
||||
/// @param file_path 本地音频文件路径
|
||||
/// @return 音频标识符
|
||||
size_t Load(const String& file_path);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 加载音频资源
|
||||
/// @param res 音频资源
|
||||
/// @return 音频标识符
|
||||
size_t Load(const Resource& res);
|
||||
/// @brief 播放音频
|
||||
/// @param sound 音频
|
||||
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
||||
void Play(SoundPtr sound, int loop_count = 0);
|
||||
|
||||
/// \~chinese
|
||||
/// @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 本地音频文件路径
|
||||
/// @return 音频标识符
|
||||
size_t GetId(const String& file_path) const;
|
||||
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
||||
/// @param callbacks 注册回调
|
||||
SoundPtr Play(const String& file_path, int loop_count = 0, std::initializer_list<SoundCallbackPtr> callbacks = {});
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取音频资源id
|
||||
/// @brief 播放音频
|
||||
/// @param res 音频资源
|
||||
/// @return 音频标识符
|
||||
size_t GetId(const Resource& res) const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取音乐对象
|
||||
/// @param id 音频标识符
|
||||
SoundPtr GetSound(size_t id) const;
|
||||
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
||||
/// @param callbacks 注册回调
|
||||
SoundPtr Play(const Resource& res, int loop_count = 0, std::initializer_list<SoundCallbackPtr> callbacks = {});
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 暂停所有音频
|
||||
|
|
@ -123,29 +78,41 @@ public:
|
|||
void StopAll();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 释放音乐对象缓存
|
||||
/// @param id 音频标识符
|
||||
void ReleaseSound(size_t id);
|
||||
/// @brief 获取正在播放的音频列表
|
||||
const SoundList& GetPlayingList() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取缓存
|
||||
const SoundMap& GetCache() const;
|
||||
/// @brief 获取音量
|
||||
float GetVolume() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 清除缓存
|
||||
void ClearCache();
|
||||
/// @brief 设置音量
|
||||
/// @param volume 音量大小,1.0 为原始音量, 大于 1 为放大音量, 0 为最小音量
|
||||
void SetVolume(float volume);
|
||||
|
||||
private:
|
||||
float volume_;
|
||||
public:
|
||||
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
|
||||
|
|
|
|||
Loading…
Reference in New Issue