Magic_Game/src/kiwano-audio/Sound.cpp

228 lines
4.9 KiB
C++
Raw Normal View History

2019-07-30 10:46:01 +08:00
// Copyright (c) 2016-2018 Kiwano - Nomango
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
2019-11-13 14:33:15 +08:00
#include <kiwano/core/Logger.h>
#include <kiwano/platform/FileSystem.h>
2019-10-11 21:55:29 +08:00
#include <kiwano-audio/Sound.h>
#include <kiwano-audio/AudioEngine.h>
2019-07-30 10:46:01 +08:00
namespace kiwano
{
namespace audio
{
Sound::Sound()
: opened_(false)
, playing_(false)
, voice_(nullptr)
{
}
Sound::~Sound()
{
Close();
}
2019-08-18 17:49:13 +08:00
bool Sound::Load(String const& file_path)
2019-07-30 10:46:01 +08:00
{
2020-01-17 11:24:24 +08:00
if (!FileSystem::Instance().IsFileExists(file_path))
2019-08-18 17:49:13 +08:00
{
2019-12-17 20:47:55 +08:00
KGE_WARN(L"Media file '%s' not found", file_path.c_str());
2019-08-18 17:49:13 +08:00
return false;
}
2019-08-19 09:28:59 +08:00
if (opened_)
{
Close();
}
2019-08-18 17:49:13 +08:00
2020-01-17 11:24:24 +08:00
String full_path = FileSystem::Instance().GetFullPathForFile(file_path);
2019-10-11 21:12:29 +08:00
HRESULT hr = transcoder_.LoadMediaFile(full_path);
2019-08-18 17:49:13 +08:00
if (FAILED(hr))
2019-07-30 10:46:01 +08:00
{
2019-12-17 20:47:55 +08:00
KGE_ERROR(L"Load media file failed with HRESULT of %08X", hr);
2019-08-18 17:49:13 +08:00
return false;
}
2020-01-17 11:24:24 +08:00
if (!AudioEngine::Instance().CreateSound(*this, transcoder_.GetBuffer()))
2019-08-18 17:49:13 +08:00
{
2019-08-19 09:28:59 +08:00
Close();
2019-08-18 17:49:13 +08:00
return false;
2019-07-30 10:46:01 +08:00
}
2019-08-18 17:49:13 +08:00
opened_ = true;
return true;
}
bool Sound::Load(Resource const& res)
{
if (opened_)
2019-07-30 10:46:01 +08:00
{
2019-08-18 17:49:13 +08:00
Close();
2019-07-30 10:46:01 +08:00
}
2019-08-23 13:22:21 +08:00
HRESULT hr = transcoder_.LoadMediaResource(res);
2019-07-30 10:46:01 +08:00
if (FAILED(hr))
{
2019-12-17 20:47:55 +08:00
KGE_ERROR(L"Load media resource failed with HRESULT of %08X", hr);
2019-07-30 10:46:01 +08:00
return false;
}
2020-01-17 11:24:24 +08:00
if (!AudioEngine::Instance().CreateSound(*this, transcoder_.GetBuffer()))
2019-07-30 10:46:01 +08:00
{
2019-08-19 09:28:59 +08:00
Close();
2019-07-30 10:46:01 +08:00
return false;
}
opened_ = true;
return true;
}
2019-12-31 10:37:29 +08:00
bool Sound::IsValid() const
{
return voice_ != nullptr;
}
2019-09-29 22:23:13 +08:00
void Sound::Play(int loop_count)
2019-07-30 10:46:01 +08:00
{
if (!opened_)
{
2019-12-17 20:47:55 +08:00
KGE_ERROR(L"Sound must be opened first!");
2019-07-30 10:46:01 +08:00
return;
}
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
// if sound stream is not empty, stop() will clear it
XAUDIO2_VOICE_STATE state;
voice_->GetState(&state);
if (state.BuffersQueued)
Stop();
// clamp loop count
loop_count = (loop_count < 0) ? XAUDIO2_LOOP_INFINITE : std::min(loop_count, XAUDIO2_LOOP_INFINITE - 1);
2019-08-19 09:28:59 +08:00
auto wave_buffer = transcoder_.GetBuffer();
2019-07-30 10:46:01 +08:00
XAUDIO2_BUFFER buffer = { 0 };
2019-08-19 09:28:59 +08:00
buffer.pAudioData = wave_buffer.data;
2019-07-30 10:46:01 +08:00
buffer.Flags = XAUDIO2_END_OF_STREAM;
2019-08-19 09:28:59 +08:00
buffer.AudioBytes = wave_buffer.size;
2019-10-12 11:26:41 +08:00
buffer.LoopCount = static_cast<uint32_t>(loop_count);
2019-07-30 10:46:01 +08:00
HRESULT hr = voice_->SubmitSourceBuffer(&buffer);
if (SUCCEEDED(hr))
{
hr = voice_->Start();
}
if (FAILED(hr))
{
2019-12-17 20:47:55 +08:00
KGE_ERROR(L"Submitting source buffer failed with HRESULT of %08X", hr);
2019-07-30 10:46:01 +08:00
}
playing_ = SUCCEEDED(hr);
}
void Sound::Pause()
{
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
if (SUCCEEDED(voice_->Stop()))
playing_ = false;
}
void Sound::Resume()
{
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
if (SUCCEEDED(voice_->Start()))
playing_ = true;
}
void Sound::Stop()
{
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
HRESULT hr = voice_->Stop();
if (SUCCEEDED(hr))
hr = voice_->ExitLoop();
if (SUCCEEDED(hr))
hr = voice_->FlushSourceBuffers();
if (SUCCEEDED(hr))
playing_ = false;
}
void Sound::Close()
{
if (voice_)
{
voice_->Stop();
voice_->FlushSourceBuffers();
voice_->DestroyVoice();
voice_ = nullptr;
}
2019-08-19 09:28:59 +08:00
transcoder_.ClearBuffer();
2019-07-30 10:46:01 +08:00
opened_ = false;
playing_ = false;
}
bool Sound::IsPlaying() const
{
if (opened_)
{
if (!voice_)
return false;
XAUDIO2_VOICE_STATE state;
voice_->GetState(&state);
2019-10-12 11:26:41 +08:00
uint32_t buffers_queued = state.BuffersQueued;
2019-07-30 10:46:01 +08:00
if (buffers_queued && playing_)
return true;
}
return false;
}
2019-09-29 22:23:13 +08:00
float Sound::GetVolume() const
2019-07-30 10:46:01 +08:00
{
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
2019-09-29 22:23:13 +08:00
float volume = 0.0f;
2019-07-30 10:46:01 +08:00
voice_->GetVolume(&volume);
return volume;
}
2019-09-29 22:23:13 +08:00
void Sound::SetVolume(float volume)
2019-07-30 10:46:01 +08:00
{
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
volume = std::min(std::max(volume, -224.f), 224.f);
voice_->SetVolume(volume);
}
}
}