feat: update sound player

This commit is contained in:
Nomango 2023-09-25 00:59:27 +08:00
parent 1e65028321
commit 7d969eddd8
5 changed files with 138 additions and 161 deletions

View File

@ -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()

View File

@ -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_)

View File

@ -178,6 +178,8 @@ protected:
SoundCallbackPtr GetCallbackChain();
void ResetVolume();
private:
bool opened_;
bool playing_;

View File

@ -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

View File

@ -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