Magic_Game/core/utils/Music.cpp

276 lines
5.1 KiB
C++

// Copyright (c) 2016-2018 Easy2D - 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.
#include "Music.h"
#include "Transcoder.h"
#include "File.h"
#include "../base/modules.h"
#include "../base/audio.h"
#include "../base/logs.h"
namespace easy2d
{
Music::Music()
: opened_(false)
, playing_(false)
, wave_data_(nullptr)
, size_(0)
, voice_(nullptr)
{
}
Music::Music(const String& file_path)
: opened_(false)
, playing_(false)
, wave_data_(nullptr)
, size_(0)
, voice_(nullptr)
{
Load(file_path);
}
Music::Music(Resource& res)
: opened_(false)
, playing_(false)
, wave_data_(nullptr)
, size_(0)
, voice_(nullptr)
{
Load(res);
}
Music::~Music()
{
Close();
}
bool Music::Load(const String & file_path)
{
if (opened_)
{
Close();
}
File music_file;
if (!music_file.Open(file_path))
{
E2D_WARNING("Media file not found.");
return false;
}
// 用户输入的路径不一定是完整路径,因为用户可能通过 File::AddSearchPath 添加
// 默认搜索路径,所以需要通过 File::GetPath 获取完整路径
String music_file_path = music_file.GetPath();
Transcoder transcoder;
if (!transcoder.LoadMediaFile(music_file_path.c_str(), &wave_data_, &size_))
{
return false;
}
HRESULT hr = audio::instance.CreateVoice(&voice_, transcoder.GetWaveFormatEx());
if (FAILED(hr))
{
if (wave_data_)
{
delete[] wave_data_;
wave_data_ = nullptr;
}
logs::Trace(L"Create source voice error", hr);
return false;
}
opened_ = true;
return true;
}
bool Music::Load(Resource& res)
{
if (opened_)
{
Close();
}
Transcoder transcoder;
if (!transcoder.LoadMediaResource(res, &wave_data_, &size_))
{
return false;
}
HRESULT hr = audio::instance.CreateVoice(&voice_, transcoder.GetWaveFormatEx());
if (FAILED(hr))
{
if (wave_data_)
{
delete[] wave_data_;
wave_data_ = nullptr;
}
logs::Trace(L"Create source voice error", hr);
return false;
}
opened_ = true;
return true;
}
bool Music::Play(int loop_count)
{
if (!opened_)
{
E2D_WARNING("Music must be opened first!");
return false;
}
if (voice_ == nullptr)
{
E2D_WARNING("IXAudio2SourceVoice Null pointer exception!");
return false;
}
XAUDIO2_VOICE_STATE state;
voice_->GetState(&state);
if (state.BuffersQueued)
{
Stop();
}
if (loop_count < 0)
{
loop_count = XAUDIO2_LOOP_INFINITE;
}
else
{
loop_count = std::min(loop_count, XAUDIO2_LOOP_INFINITE - 1);
}
// 提交 wave 样本数据
XAUDIO2_BUFFER buffer = { 0 };
buffer.pAudioData = wave_data_;
buffer.Flags = XAUDIO2_END_OF_STREAM;
buffer.AudioBytes = size_;
buffer.LoopCount = loop_count;
HRESULT hr;
if (FAILED(hr = voice_->SubmitSourceBuffer(&buffer)))
{
logs::Trace(L"Submitting source buffer error", hr);
return false;
}
hr = voice_->Start(0);
playing_ = SUCCEEDED(hr);
return playing_;
}
void Music::Pause()
{
if (voice_)
{
if (SUCCEEDED(voice_->Stop()))
{
playing_ = false;
}
}
}
void Music::Resume()
{
if (voice_)
{
if (SUCCEEDED(voice_->Start()))
{
playing_ = true;
}
}
}
void Music::Stop()
{
if (voice_)
{
if (SUCCEEDED(voice_->Stop()))
{
voice_->ExitLoop();
voice_->FlushSourceBuffers();
playing_ = false;
}
}
}
void Music::Close()
{
if (voice_)
{
voice_->Stop();
voice_->FlushSourceBuffers();
voice_->DestroyVoice();
voice_ = nullptr;
}
if (wave_data_)
{
delete[] wave_data_;
wave_data_ = nullptr;
}
opened_ = false;
playing_ = false;
}
bool Music::IsPlaying() const
{
if (opened_ && voice_)
{
XAUDIO2_VOICE_STATE state;
voice_->GetState(&state);
if (state.BuffersQueued && playing_)
return true;
}
return false;
}
float Music::GetVolume() const
{
if (voice_)
{
float volume = 0.f;
voice_->GetVolume(&volume);
return volume;
}
return 0.f;
}
bool Music::SetVolume(float volume)
{
if (voice_)
{
volume = std::min(std::max(volume, -224.f), 224.f);
return SUCCEEDED(voice_->SetVolume(volume));
}
return false;
}
IXAudio2SourceVoice * Music::GetSourceVoice() const
{
return voice_;
}
}