Prevents blocking at music loading.
This commit is contained in:
parent
859a988391
commit
e50625fd1b
@ -161,6 +161,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="src\HiraganaMatcher.h" />
|
<ClInclude Include="src\HiraganaMatcher.h" />
|
||||||
<ClInclude Include="src\iAudioDevice.h" />
|
<ClInclude Include="src\iAudioDevice.h" />
|
||||||
|
<ClInclude Include="src\iAudioEffect.h" />
|
||||||
<ClInclude Include="src\iInputMatcher.h" />
|
<ClInclude Include="src\iInputMatcher.h" />
|
||||||
<ClInclude Include="src\common.h" />
|
<ClInclude Include="src\common.h" />
|
||||||
<ClInclude Include="src\ElementStore.h" />
|
<ClInclude Include="src\ElementStore.h" />
|
||||||
@ -178,6 +179,7 @@
|
|||||||
<ClInclude Include="src\iWritable.h" />
|
<ClInclude Include="src\iWritable.h" />
|
||||||
<ClInclude Include="src\Logger.h" />
|
<ClInclude Include="src\Logger.h" />
|
||||||
<ClInclude Include="src\Lua.h" />
|
<ClInclude Include="src\Lua.h" />
|
||||||
|
<ClInclude Include="src\Music.h" />
|
||||||
<ClInclude Include="src\MusicElement.h" />
|
<ClInclude Include="src\MusicElement.h" />
|
||||||
<ClInclude Include="src\AudioDevice.h" />
|
<ClInclude Include="src\AudioDevice.h" />
|
||||||
<ClInclude Include="src\MusicElementFactory.h" />
|
<ClInclude Include="src\MusicElementFactory.h" />
|
||||||
|
@ -209,6 +209,12 @@
|
|||||||
<ClInclude Include="src\GlitchPosteffect.h">
|
<ClInclude Include="src\GlitchPosteffect.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\iAudioEffect.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Music.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Library Include="thirdparty\lua5.1.lib" />
|
<Library Include="thirdparty\lua5.1.lib" />
|
||||||
|
@ -21,63 +21,14 @@ gj::AudioDevice::AudioDevice() {
|
|||||||
gj::AudioDevice::~AudioDevice() {
|
gj::AudioDevice::~AudioDevice() {
|
||||||
ma_device_stop(&ma_);
|
ma_device_stop(&ma_);
|
||||||
ma_device_uninit(&ma_);
|
ma_device_uninit(&ma_);
|
||||||
|
|
||||||
/* the worker thread has been exited so no lock is necessary anymore */
|
|
||||||
|
|
||||||
if (playing_) {
|
|
||||||
ma_decoder_uninit(&dec_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void gj::AudioDevice::PlayMusic(const std::string& path, double offset) {
|
|
||||||
std::lock_guard _(mtx_);
|
|
||||||
|
|
||||||
if (playing_) {
|
|
||||||
ma_decoder_uninit(&dec_);
|
|
||||||
}
|
|
||||||
ma_decoder_config config = ma_decoder_config_init(kFormat, kChannel, kSampleRate);
|
|
||||||
if (ma_decoder_init_file(path.c_str(), &config, &dec_) != MA_SUCCESS) {
|
|
||||||
Abort("AudioDevice decoder error: "+path);
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint64_t offset_frame = static_cast<uint64_t>(kSampleRate * offset);
|
|
||||||
if (ma_decoder_seek_to_pcm_frame(&dec_, offset_frame) != MA_SUCCESS) {
|
|
||||||
Abort("decoder seek failure");
|
|
||||||
}
|
|
||||||
playing_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gj::AudioDevice::StopMusic() {
|
|
||||||
std::lock_guard _(mtx_);
|
|
||||||
if (!playing_) return;
|
|
||||||
|
|
||||||
ma_decoder_uninit(&dec_);
|
|
||||||
playing_ = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gj::AudioDevice::Callback_(ma_device* ma, void* out, const void* in, ma_uint32 framecnt) {
|
void gj::AudioDevice::Callback_(ma_device* ma, void* out, const void* in, ma_uint32 framecnt) {
|
||||||
AudioDevice* dev = reinterpret_cast<AudioDevice*>(ma->pUserData);
|
AudioDevice* dev = reinterpret_cast<AudioDevice*>(ma->pUserData);
|
||||||
std::lock_guard _(dev->mtx_);
|
std::lock_guard _(dev->mtx_);
|
||||||
|
|
||||||
const double amp = dev->amp_.load();
|
for (auto fx : dev->effects_) {
|
||||||
const double lpf = dev->lpf_coe_.load();
|
fx->Apply(reinterpret_cast<float*>(out), framecnt);
|
||||||
|
|
||||||
float* dst = reinterpret_cast<float*>(out);
|
|
||||||
|
|
||||||
size_t wrote = 0;
|
|
||||||
if (dev->playing_) {
|
|
||||||
const ma_uint64 n = ma_decoder_read_pcm_frames(&dev->dec_, dst, framecnt);
|
|
||||||
if (n < framecnt) {
|
|
||||||
dev->playing_ = false;
|
|
||||||
ma_decoder_uninit(&dev->dec_);
|
|
||||||
}
|
|
||||||
wrote += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < static_cast<size_t>(framecnt)*kChannel; ++i) {
|
|
||||||
dst[i] = static_cast<float>(dst[i]*amp);
|
|
||||||
dst[i] = static_cast<float>(dev->lpf_prev_*lpf + dst[i]*(1-lpf));
|
|
||||||
dev->lpf_prev_ = dst[i];
|
|
||||||
}
|
}
|
||||||
dev->time_.fetch_add(framecnt);
|
dev->time_.fetch_add(framecnt);
|
||||||
}
|
}
|
@ -5,6 +5,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#define NOMINMAX /* miniaudio includes windows.h */
|
#define NOMINMAX /* miniaudio includes windows.h */
|
||||||
#include "thirdparty/miniaudio.h"
|
#include "thirdparty/miniaudio.h"
|
||||||
@ -32,14 +33,23 @@ class AudioDevice : public iAudioDevice, public iClock {
|
|||||||
AudioDevice();
|
AudioDevice();
|
||||||
~AudioDevice();
|
~AudioDevice();
|
||||||
|
|
||||||
void PlayMusic(const std::string& path, double offset) override;
|
void AddEffect(iAudioEffect* fx) override {
|
||||||
void StopMusic() override;
|
std::lock_guard _(mtx_);
|
||||||
|
effects_.push_back(fx);
|
||||||
void SetVolume(double amp) override {
|
|
||||||
amp_.store(amp);
|
|
||||||
}
|
}
|
||||||
void SetLpfIntensity(double v) override {
|
void RemoveEffect(iAudioEffect* fx) override {
|
||||||
lpf_coe_.store(v);
|
std::lock_guard _(mtx_);
|
||||||
|
|
||||||
|
auto itr = std::find(effects_.begin(), effects_.end(), fx);
|
||||||
|
if (itr == effects_.end()) return;
|
||||||
|
effects_.erase(itr);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ch() const override {
|
||||||
|
return kChannel;
|
||||||
|
}
|
||||||
|
uint32_t sampleRate() const override {
|
||||||
|
return kSampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t now() const override {
|
uint64_t now() const override {
|
||||||
@ -51,16 +61,10 @@ class AudioDevice : public iAudioDevice, public iClock {
|
|||||||
|
|
||||||
ma_device ma_{0};
|
ma_device ma_{0};
|
||||||
|
|
||||||
bool playing_ = false;
|
|
||||||
ma_decoder dec_{0};
|
|
||||||
|
|
||||||
std::atomic<double> amp_ = 1;
|
|
||||||
|
|
||||||
std::atomic<double> lpf_coe_ = 0;
|
|
||||||
float lpf_prev_ = 0;
|
|
||||||
|
|
||||||
std::atomic<uint64_t> time_;
|
std::atomic<uint64_t> time_;
|
||||||
|
|
||||||
|
std::vector<iAudioEffect*> effects_;
|
||||||
|
|
||||||
static void Callback_(ma_device* ma, void* out, const void* in, ma_uint32 framecnt);
|
static void Callback_(ma_device* ma, void* out, const void* in, ma_uint32 framecnt);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -67,10 +67,21 @@ class ElementStore {
|
|||||||
performing_.end());
|
performing_.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsEmpty() {
|
bool IsEmpty() const {
|
||||||
return pending_.empty() && performing_.empty();
|
return pending_.empty() && performing_.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t CountPreparings() const {
|
||||||
|
size_t n = 0;
|
||||||
|
for (const auto& e : pending_) {
|
||||||
|
if (!e->HasPrepared()) ++n;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
size_t size() const {
|
||||||
|
return pending_.size() + performing_.size();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const iClock* clock_;
|
const iClock* clock_;
|
||||||
|
|
||||||
|
@ -75,6 +75,10 @@ class InputWindowElement : public iElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HasPrepared() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UniqPtr<iInputMatcher> matcher_;
|
UniqPtr<iInputMatcher> matcher_;
|
||||||
UniqPtr<iElementDriver> drv_;
|
UniqPtr<iElementDriver> drv_;
|
||||||
|
116
src/Music.h
Normal file
116
src/Music.h
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#define NOMINMAX
|
||||||
|
#include "thirdparty/miniaudio.h"
|
||||||
|
#undef NOMINMAX
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "iAudioEffect.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace gj {
|
||||||
|
|
||||||
|
|
||||||
|
class Music : public iAudioEffect {
|
||||||
|
public:
|
||||||
|
static constexpr auto kVolumeLpf = .9f;
|
||||||
|
|
||||||
|
Music() = delete;
|
||||||
|
Music(Music&&) = delete;
|
||||||
|
Music(const Music&) = delete;
|
||||||
|
|
||||||
|
Music& operator=(Music&&) = delete;
|
||||||
|
Music& operator=(const Music&) = delete;
|
||||||
|
|
||||||
|
Music(const std::string& path, uint8_t ch, uint32_t srate) :
|
||||||
|
ch_(ch), srate_(srate), lpf_prev_(ch) {
|
||||||
|
const auto config = ma_decoder_config_init(ma_format_f32, ch, srate);
|
||||||
|
|
||||||
|
if (ma_decoder_init_file(path.c_str(), &config, &dec_)) {
|
||||||
|
Abort("decoder error: "+path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~Music() {
|
||||||
|
if (seeker_.joinable()) {
|
||||||
|
seeker_.join();
|
||||||
|
}
|
||||||
|
ma_decoder_uninit(&dec_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Play() {
|
||||||
|
playing_.store(true);
|
||||||
|
}
|
||||||
|
void Stop() {
|
||||||
|
playing_.store(false);
|
||||||
|
}
|
||||||
|
void Seek(double sec) {
|
||||||
|
if (seeker_.joinable()) {
|
||||||
|
seeker_.join();
|
||||||
|
}
|
||||||
|
seeking_.store(true);
|
||||||
|
|
||||||
|
const size_t frame = static_cast<size_t>(srate_*sec);
|
||||||
|
seeker_ = std::thread([this, frame]() {
|
||||||
|
if (ma_decoder_seek_to_pcm_frame(&dec_, frame) != MA_SUCCESS) {
|
||||||
|
Abort("decoder seek failure");
|
||||||
|
}
|
||||||
|
seeking_.store(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetVolume(float f) {
|
||||||
|
volume_.store(f);
|
||||||
|
}
|
||||||
|
void SetLpf(float f) {
|
||||||
|
lpf_.store(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsBusy() const {
|
||||||
|
return seeking_.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Apply(float* ptr, size_t frames) override {
|
||||||
|
if (seeking_.load() || !playing_.load()) return;
|
||||||
|
|
||||||
|
frames = ma_decoder_read_pcm_frames(&dec_, ptr, frames);
|
||||||
|
|
||||||
|
const float lpf = lpf_.load();
|
||||||
|
const float lpfinv = 1-lpf;
|
||||||
|
|
||||||
|
const float volume = volume_.load();
|
||||||
|
|
||||||
|
const size_t n = frames * ch_;
|
||||||
|
for (size_t i = 0; i < frames; ++i) {
|
||||||
|
volume_actual_ = volume_actual_*kVolumeLpf + volume*(1-kVolumeLpf);
|
||||||
|
|
||||||
|
float* sample = &ptr[i*ch_];
|
||||||
|
for (uint8_t j = 0; j < ch_; ++j) {
|
||||||
|
sample[j] = lpf_prev_[j]*lpf + sample[j]*volume_actual_*lpfinv;
|
||||||
|
lpf_prev_[j] = sample[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t ch_;
|
||||||
|
uint32_t srate_;
|
||||||
|
|
||||||
|
std::thread seeker_;
|
||||||
|
|
||||||
|
ma_decoder dec_{0};
|
||||||
|
|
||||||
|
std::atomic<bool> seeking_ = false;
|
||||||
|
std::atomic<bool> playing_ = false;
|
||||||
|
|
||||||
|
std::atomic<float> volume_ = 0;
|
||||||
|
std::atomic<float> lpf_ = 0;
|
||||||
|
|
||||||
|
float volume_actual_;
|
||||||
|
std::vector<float> lpf_prev_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -5,7 +5,7 @@
|
|||||||
#include "iAudioDevice.h"
|
#include "iAudioDevice.h"
|
||||||
#include "iElement.h"
|
#include "iElement.h"
|
||||||
#include "iElementDriver.h"
|
#include "iElementDriver.h"
|
||||||
#include "Texture.h"
|
#include "Music.h"
|
||||||
|
|
||||||
namespace gj {
|
namespace gj {
|
||||||
|
|
||||||
@ -31,8 +31,12 @@ public:
|
|||||||
MusicElement& operator=(const MusicElement&) = delete;
|
MusicElement& operator=(const MusicElement&) = delete;
|
||||||
|
|
||||||
MusicElement(Param&& p) :
|
MusicElement(Param&& p) :
|
||||||
iElement(p.period), audio_(p.audio), path_(p.path), offset_(p.offset),
|
iElement(p.period), audio_(p.audio),
|
||||||
|
music_(p.path, audio_->ch(), audio_->sampleRate()),
|
||||||
drv_(std::move(p.driver)) {
|
drv_(std::move(p.driver)) {
|
||||||
|
music_.Seek(p.offset);
|
||||||
|
audio_->AddEffect(&music_);
|
||||||
|
|
||||||
param_["volume"] = 0.;
|
param_["volume"] = 0.;
|
||||||
param_["lpf"] = 0.;
|
param_["lpf"] = 0.;
|
||||||
}
|
}
|
||||||
@ -43,29 +47,29 @@ public:
|
|||||||
const double volume = std::get<double>(param_["volume"]);
|
const double volume = std::get<double>(param_["volume"]);
|
||||||
const double lpf = std::get<double>(param_["lpf"]);
|
const double lpf = std::get<double>(param_["lpf"]);
|
||||||
|
|
||||||
audio_->SetVolume(volume);
|
music_.SetVolume(static_cast<float>(volume));
|
||||||
audio_->SetLpfIntensity(lpf);
|
music_.SetLpf(static_cast<float>(lpf));
|
||||||
|
|
||||||
if (first_) {
|
if (first_) {
|
||||||
audio_->PlayMusic(path_, offset_);
|
music_.Play();
|
||||||
first_ = false;
|
first_ = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Finalize() override {
|
void Finalize() override {
|
||||||
if (!first_) {
|
audio_->RemoveEffect(&music_);
|
||||||
audio_->StopMusic();
|
}
|
||||||
}
|
|
||||||
|
bool HasPrepared() const override {
|
||||||
|
return !music_.IsBusy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
iAudioDevice* audio_;
|
iAudioDevice* audio_;
|
||||||
std::string path_;
|
Music music_;
|
||||||
|
|
||||||
bool first_ = true;
|
bool first_ = true;
|
||||||
|
|
||||||
double offset_;
|
|
||||||
|
|
||||||
UniqPtr<iElementDriver> drv_;
|
UniqPtr<iElementDriver> drv_;
|
||||||
iElementDriver::Param param_;
|
iElementDriver::Param param_;
|
||||||
};
|
};
|
||||||
|
@ -68,6 +68,10 @@ public:
|
|||||||
void Finalize() override {
|
void Finalize() override {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HasPrepared() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Texture tex_;
|
Texture tex_;
|
||||||
UniqPtr<iElementDriver> drv_;
|
UniqPtr<iElementDriver> drv_;
|
||||||
|
@ -53,6 +53,7 @@ gj::TitleScene::TitleScene(const Param& p) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
gj::UniqPtr<gj::iScene> gj::TitleScene::Update(Frame& frame) {
|
gj::UniqPtr<gj::iScene> gj::TitleScene::Update(Frame& frame) {
|
||||||
|
/* input handling */
|
||||||
for (const auto c : frame.input) {
|
for (const auto c : frame.input) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
@ -62,11 +63,31 @@ gj::UniqPtr<gj::iScene> gj::TitleScene::Update(Frame& frame) {
|
|||||||
SelectScore_((select_index_+1)%list_.size());
|
SelectScore_((select_index_+1)%list_.size());
|
||||||
break;
|
break;
|
||||||
case ' ':
|
case ' ':
|
||||||
|
if (music_) param_.audio->RemoveEffect(music_.get());
|
||||||
return param_.alloc->MakeUniq<iScene, PlayScene>(
|
return param_.alloc->MakeUniq<iScene, PlayScene>(
|
||||||
param_, list_[select_index_].displayName, list_[select_index_].score);
|
param_, list_[select_index_].displayName, list_[select_index_].score);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* play music */
|
||||||
|
if (trying_play_ && !(music_ && music_->IsBusy())) {
|
||||||
|
if (music_) {
|
||||||
|
param_.audio->RemoveEffect(music_.get());
|
||||||
|
}
|
||||||
|
auto au = param_.audio;
|
||||||
|
|
||||||
|
const auto& s = list_[select_index_];
|
||||||
|
music_ = param_.alloc->MakeUniq<Music>(s.music, au->ch(), au->sampleRate());
|
||||||
|
music_->Seek(s.playOffset);
|
||||||
|
music_->SetVolume(.2f);
|
||||||
|
music_->SetLpf(.99f);
|
||||||
|
music_->Play();
|
||||||
|
|
||||||
|
au->AddEffect(music_.get());
|
||||||
|
trying_play_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* graphics calculation */
|
||||||
const uint64_t now = param_.clock->now();
|
const uint64_t now = param_.clock->now();
|
||||||
|
|
||||||
const int32_t w = static_cast<int32_t>(frame.w);
|
const int32_t w = static_cast<int32_t>(frame.w);
|
||||||
@ -112,7 +133,7 @@ gj::UniqPtr<gj::iScene> gj::TitleScene::Update(Frame& frame) {
|
|||||||
frame.Add(&guide_);
|
frame.Add(&guide_);
|
||||||
|
|
||||||
pe_.seed = XorShift(now/period1+10);
|
pe_.seed = XorShift(now/period1+10);
|
||||||
pe_.maxShift = (XorShift(now/period1+7)%100/100.*2 - 1)*.1;
|
pe_.maxShift = (XorShift(now/period1+7)%100/100.*2 - 1)*.03;
|
||||||
frame.Add(&pe_);
|
frame.Add(&pe_);
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -123,7 +144,5 @@ void gj::TitleScene::SelectScore_(size_t index) {
|
|||||||
score_ = Text(ConvertStrToWstr(s.displayName));
|
score_ = Text(ConvertStrToWstr(s.displayName));
|
||||||
select_index_ = index;
|
select_index_ = index;
|
||||||
|
|
||||||
param_.audio->SetVolume(.5);
|
trying_play_ = true;
|
||||||
param_.audio->SetLpfIntensity(.999);
|
|
||||||
param_.audio->PlayMusic(s.music, s.playOffset);
|
|
||||||
}
|
}
|
@ -3,6 +3,7 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "GlitchPosteffect.h"
|
#include "GlitchPosteffect.h"
|
||||||
#include "iScene.h"
|
#include "iScene.h"
|
||||||
|
#include "Music.h"
|
||||||
#include "Text.h"
|
#include "Text.h"
|
||||||
#include "Texture.h"
|
#include "Texture.h"
|
||||||
|
|
||||||
@ -29,7 +30,7 @@ class TitleScene : public iScene {
|
|||||||
std::string displayName;
|
std::string displayName;
|
||||||
std::string score;
|
std::string score;
|
||||||
std::string music;
|
std::string music;
|
||||||
double playOffset;
|
double playOffset = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Param param_;
|
Param param_;
|
||||||
@ -40,13 +41,17 @@ class TitleScene : public iScene {
|
|||||||
Text guide_;
|
Text guide_;
|
||||||
|
|
||||||
Texture logo_;
|
Texture logo_;
|
||||||
|
|
||||||
|
GlitchPosteffect pe_;
|
||||||
|
|
||||||
size_t select_index_;
|
size_t select_index_;
|
||||||
std::vector<Score> list_;
|
std::vector<Score> list_;
|
||||||
|
|
||||||
GlitchPosteffect pe_;
|
bool trying_play_ = false;
|
||||||
|
UniqPtr<Music> music_;
|
||||||
|
|
||||||
void SelectScore_(size_t index);
|
void SelectScore_(size_t index);
|
||||||
|
void TryPlayingMusic_();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,10 +48,15 @@ static inline uint64_t XorShift(uint64_t x) {
|
|||||||
|
|
||||||
|
|
||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
static inline void Abort(const std::string& msg) {
|
static inline void Abort(const std::wstring& msg) {
|
||||||
MessageBox(NULL, ConvertStrToWstr(msg).c_str(), L"PROGRAM ABORTED", MB_OK);
|
MessageBox(NULL, msg.c_str(), L"PROGRAM ABORTED", MB_OK);
|
||||||
std::exit(1);
|
std::exit(1);
|
||||||
}
|
}
|
||||||
|
[[noreturn]]
|
||||||
|
static inline void Abort(const std::string& msg) {
|
||||||
|
Abort(ConvertStrToWstr(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "iAudioEffect.h"
|
||||||
|
|
||||||
|
|
||||||
namespace gj {
|
namespace gj {
|
||||||
|
|
||||||
@ -18,11 +20,11 @@ public:
|
|||||||
|
|
||||||
virtual ~iAudioDevice() = default;
|
virtual ~iAudioDevice() = default;
|
||||||
|
|
||||||
virtual void PlayMusic(const std::string& path, double offset) = 0;
|
virtual void AddEffect(iAudioEffect* fx) = 0;
|
||||||
virtual void StopMusic() = 0;
|
virtual void RemoveEffect(iAudioEffect* fx) = 0;
|
||||||
|
|
||||||
virtual void SetVolume(double amp) = 0;
|
virtual uint8_t ch() const = 0;
|
||||||
virtual void SetLpfIntensity(double v) = 0;
|
virtual uint32_t sampleRate() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
26
src/iAudioEffect.h
Normal file
26
src/iAudioEffect.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace gj {
|
||||||
|
|
||||||
|
|
||||||
|
/* Users have a responsible to remove AudioEffect from all devices at its destruction. */
|
||||||
|
class iAudioEffect {
|
||||||
|
public:
|
||||||
|
iAudioEffect() = default;
|
||||||
|
iAudioEffect(iAudioEffect&&) = default;
|
||||||
|
iAudioEffect(const iAudioEffect&) = default;
|
||||||
|
|
||||||
|
iAudioEffect& operator=(iAudioEffect&&) = default;
|
||||||
|
iAudioEffect& operator=(const iAudioEffect&) = default;
|
||||||
|
|
||||||
|
virtual ~iAudioEffect() = default;
|
||||||
|
|
||||||
|
virtual void Apply(float* ptr, size_t frame) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -25,6 +25,8 @@ class iElement {
|
|||||||
|
|
||||||
virtual void Finalize() = 0;
|
virtual void Finalize() = 0;
|
||||||
|
|
||||||
|
virtual bool HasPrepared() const = 0;
|
||||||
|
|
||||||
/* Interfaces had better not have a variable but this is for optimization. */
|
/* Interfaces had better not have a variable but this is for optimization. */
|
||||||
const Period period;
|
const Period period;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user