2022-05-19 16:54:36 -04:00
|
|
|
#include "blocksound_handler.h"
|
2022-06-22 23:37:46 -04:00
|
|
|
|
2022-05-19 16:54:36 -04:00
|
|
|
#include <random>
|
|
|
|
#include <stdexcept>
|
|
|
|
|
2022-06-22 23:37:46 -04:00
|
|
|
#include "util.h"
|
|
|
|
|
2022-12-02 18:08:44 -05:00
|
|
|
#include "common/log/log.h"
|
|
|
|
|
2022-05-19 16:54:36 -04:00
|
|
|
namespace snd {
|
2022-12-02 18:08:44 -05:00
|
|
|
std::array<s8, 32> g_block_reg{};
|
|
|
|
|
2023-12-07 20:22:54 -05:00
|
|
|
BlockSoundHandler::BlockSoundHandler(SoundBank& bank,
|
2023-12-09 18:11:24 -05:00
|
|
|
SFXBlock::SFX& sfx,
|
|
|
|
VoiceManager& vm,
|
|
|
|
s32 sfx_vol,
|
|
|
|
s32 sfx_pan,
|
|
|
|
SndPlayParams& params)
|
2023-12-07 20:22:54 -05:00
|
|
|
: m_group(sfx.VolGroup), m_sfx(sfx), m_vm(vm), m_bank(bank) {
|
|
|
|
s32 vol, pan, pitch_mod, pitch_bend;
|
|
|
|
if (sfx_vol == -1) {
|
|
|
|
sfx_vol = sfx.Vol;
|
|
|
|
}
|
|
|
|
if (sfx_pan == -1) {
|
|
|
|
sfx_pan = sfx.Pan;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (params.vol.has_value()) {
|
|
|
|
vol = params.vol.value();
|
|
|
|
} else {
|
|
|
|
vol = 1024;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (params.pan.has_value()) {
|
|
|
|
pan = params.pan.value();
|
|
|
|
} else {
|
|
|
|
pan = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (params.pitch_mod.has_value()) {
|
|
|
|
pitch_mod = params.pitch_mod.value();
|
|
|
|
} else {
|
|
|
|
pitch_mod = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (params.pitch_bend.has_value()) {
|
|
|
|
pitch_bend = params.pitch_bend.value();
|
|
|
|
} else {
|
|
|
|
pitch_bend = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vol == VOLUME_DONT_CHANGE) {
|
|
|
|
vol = 1024;
|
|
|
|
}
|
|
|
|
s32 play_vol = (sfx_vol * vol) >> 10;
|
|
|
|
if (play_vol >= 128) {
|
|
|
|
play_vol = 127;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pan == PAN_RESET || pan == PAN_DONT_CHANGE) {
|
|
|
|
pan = sfx_pan;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_orig_volume = sfx_vol;
|
|
|
|
m_orig_pan = sfx_pan;
|
|
|
|
|
|
|
|
m_cur_volume = play_vol;
|
|
|
|
m_cur_pan = pan;
|
|
|
|
m_cur_pb = pitch_bend;
|
|
|
|
m_cur_pm = pitch_mod;
|
|
|
|
|
|
|
|
m_app_volume = vol;
|
|
|
|
m_app_pan = pan;
|
|
|
|
m_app_pb = pitch_bend;
|
|
|
|
m_app_pm = pitch_mod;
|
|
|
|
|
|
|
|
m_lfo_volume = 0;
|
|
|
|
m_lfo_pan = 0;
|
|
|
|
m_lfo_pb = 0;
|
|
|
|
m_lfo_pm = 0;
|
|
|
|
|
|
|
|
if (params.registers.has_value()) {
|
|
|
|
m_registers = params.registers.value();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Figure this stuff out properly someday
|
|
|
|
// if (m_sfx.d.Flags & 2) {
|
|
|
|
// fmt::print("solo flag\n");
|
|
|
|
// m_done = true;
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
|
|
|
|
m_next_grain = 0;
|
|
|
|
m_countdown = m_sfx.Grains[0].Delay;
|
|
|
|
while (m_countdown <= 0 && !m_done) {
|
|
|
|
DoGrain();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BlockSoundHandler::~BlockSoundHandler() {
|
|
|
|
for (auto& p : m_voices) {
|
|
|
|
auto v = p.lock();
|
|
|
|
if (v != nullptr) {
|
|
|
|
v->Stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BlockSoundHandler::Tick() {
|
|
|
|
m_voices.remove_if([](std::weak_ptr<BlockSoundVoice>& p) { return p.expired(); });
|
2022-05-19 16:54:36 -04:00
|
|
|
|
2022-12-02 18:08:44 -05:00
|
|
|
for (auto& lfo : m_lfo) {
|
2023-12-07 20:22:54 -05:00
|
|
|
lfo.Tick();
|
2022-12-02 18:08:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
for (auto it = m_children.begin(); it != m_children.end();) {
|
2023-12-07 20:22:54 -05:00
|
|
|
bool done = it->get()->Tick();
|
2022-12-02 18:08:44 -05:00
|
|
|
if (done) {
|
|
|
|
it = m_children.erase(it);
|
|
|
|
} else {
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_done && m_children.empty()) {
|
2022-05-19 16:54:36 -04:00
|
|
|
if (m_voices.empty()) {
|
|
|
|
return m_done;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_paused)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
m_countdown--;
|
|
|
|
while (m_countdown <= 0 && !m_done) {
|
2023-12-07 20:22:54 -05:00
|
|
|
DoGrain();
|
2022-05-19 16:54:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2023-12-07 20:22:54 -05:00
|
|
|
void BlockSoundHandler::Pause() {
|
2022-05-19 16:54:36 -04:00
|
|
|
m_paused = true;
|
|
|
|
|
2023-06-12 19:48:09 -04:00
|
|
|
for (auto& c : m_children) {
|
2023-12-07 20:22:54 -05:00
|
|
|
c->Pause();
|
2023-06-12 19:48:09 -04:00
|
|
|
}
|
|
|
|
|
2022-05-19 16:54:36 -04:00
|
|
|
for (auto& p : m_voices) {
|
|
|
|
auto voice = p.lock();
|
|
|
|
if (voice == nullptr) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-12-07 20:22:54 -05:00
|
|
|
m_vm.Pause(voice);
|
2022-05-19 16:54:36 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-07 20:22:54 -05:00
|
|
|
void BlockSoundHandler::Unpause() {
|
2022-05-19 16:54:36 -04:00
|
|
|
m_paused = false;
|
|
|
|
|
2023-06-12 19:48:09 -04:00
|
|
|
for (auto& c : m_children) {
|
2023-12-07 20:22:54 -05:00
|
|
|
c->Unpause();
|
2023-06-12 19:48:09 -04:00
|
|
|
}
|
|
|
|
|
2022-05-19 16:54:36 -04:00
|
|
|
for (auto& p : m_voices) {
|
|
|
|
auto voice = p.lock();
|
|
|
|
if (voice == nullptr) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-12-07 20:22:54 -05:00
|
|
|
m_vm.Unpause(voice);
|
2022-05-19 16:54:36 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-07 20:22:54 -05:00
|
|
|
void BlockSoundHandler::Stop() {
|
2022-05-19 16:54:36 -04:00
|
|
|
m_done = true;
|
|
|
|
|
2023-06-12 19:48:09 -04:00
|
|
|
for (auto& c : m_children) {
|
2023-12-07 20:22:54 -05:00
|
|
|
c->Stop();
|
2023-06-12 19:48:09 -04:00
|
|
|
}
|
|
|
|
|
2022-05-19 16:54:36 -04:00
|
|
|
for (auto& p : m_voices) {
|
|
|
|
auto voice = p.lock();
|
|
|
|
if (voice == nullptr) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-12-07 20:22:54 -05:00
|
|
|
voice->KeyOff();
|
2022-05-19 16:54:36 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-07 20:22:54 -05:00
|
|
|
void BlockSoundHandler::SetVolPan(s32 vol, s32 pan) {
|
2022-05-19 16:54:36 -04:00
|
|
|
if (vol >= 0) {
|
|
|
|
if (vol != VOLUME_DONT_CHANGE) {
|
2022-12-02 18:08:44 -05:00
|
|
|
m_app_volume = vol;
|
2022-05-19 16:54:36 -04:00
|
|
|
}
|
|
|
|
} else {
|
2022-12-02 18:08:44 -05:00
|
|
|
m_app_volume = -1024 * vol / 127;
|
2022-05-19 16:54:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pan == PAN_RESET) {
|
2023-12-07 20:22:54 -05:00
|
|
|
m_app_pan = m_sfx.Pan;
|
2022-05-19 16:54:36 -04:00
|
|
|
} else if (pan != PAN_DONT_CHANGE) {
|
|
|
|
m_app_pan = pan;
|
|
|
|
}
|
|
|
|
|
2022-12-02 18:08:44 -05:00
|
|
|
s32 new_vol = ((m_app_volume * m_orig_volume) >> 10) + m_lfo_volume;
|
|
|
|
new_vol = std::clamp(new_vol, 0, 127);
|
2022-05-19 16:54:36 -04:00
|
|
|
|
2022-12-02 18:08:44 -05:00
|
|
|
s32 new_pan = m_app_pan + m_lfo_pan;
|
|
|
|
while (new_pan >= 360) {
|
|
|
|
new_pan -= 360;
|
2022-05-19 16:54:36 -04:00
|
|
|
}
|
2022-12-02 18:08:44 -05:00
|
|
|
while (new_pan < 0) {
|
|
|
|
new_pan += 360;
|
2022-05-19 16:54:36 -04:00
|
|
|
}
|
|
|
|
|
2022-12-02 18:08:44 -05:00
|
|
|
if (new_pan != m_cur_pan || new_vol != m_cur_volume) {
|
|
|
|
m_cur_volume = new_vol;
|
|
|
|
m_cur_pan = new_pan;
|
|
|
|
|
|
|
|
for (auto& c : m_children) {
|
2023-12-07 20:22:54 -05:00
|
|
|
c->SetVolPan(m_app_volume * m_orig_volume / 127, pan);
|
2022-12-02 18:08:44 -05:00
|
|
|
}
|
2022-05-19 16:54:36 -04:00
|
|
|
|
|
|
|
for (auto& p : m_voices) {
|
|
|
|
auto voice = p.lock();
|
|
|
|
if (voice == nullptr) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-12-07 20:22:54 -05:00
|
|
|
auto volume = m_vm.MakeVolume(127, 0, m_cur_volume, m_cur_pan, voice->g_vol, voice->g_pan);
|
|
|
|
auto left = m_vm.AdjustVolToGroup(volume.left, m_group);
|
|
|
|
auto right = m_vm.AdjustVolToGroup(volume.right, m_group);
|
2022-05-19 16:54:36 -04:00
|
|
|
|
2023-12-07 20:22:54 -05:00
|
|
|
voice->SetVolume(left >> 1, right >> 1);
|
2022-05-19 16:54:36 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-07 20:22:54 -05:00
|
|
|
void BlockSoundHandler::UpdatePitch() {
|
2022-12-02 18:08:44 -05:00
|
|
|
m_cur_pm = m_app_pm + m_lfo_pm;
|
|
|
|
m_cur_pb = std::clamp<s32>(m_app_pb + m_lfo_pb, INT16_MIN, INT16_MAX);
|
2022-05-19 16:54:36 -04:00
|
|
|
|
|
|
|
for (auto& p : m_voices) {
|
|
|
|
auto voice = p.lock();
|
|
|
|
if (voice == nullptr) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-12-07 20:22:54 -05:00
|
|
|
auto note = PitchBend(voice->tone, m_cur_pb, m_cur_pm, m_note, m_fine);
|
2022-05-19 16:54:36 -04:00
|
|
|
auto pitch =
|
|
|
|
PS1Note2Pitch(voice->tone.CenterNote, voice->tone.CenterFine, note.first, note.second);
|
2022-12-02 18:08:44 -05:00
|
|
|
|
2023-12-07 20:22:54 -05:00
|
|
|
voice->SetPitch(pitch);
|
2022-05-19 16:54:36 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-07 20:22:54 -05:00
|
|
|
void BlockSoundHandler::SetPMod(s32 mod) {
|
2022-12-05 23:43:14 -05:00
|
|
|
for (auto& c : m_children) {
|
2023-12-07 20:22:54 -05:00
|
|
|
c->SetPMod(mod);
|
2022-12-05 23:43:14 -05:00
|
|
|
}
|
2022-05-19 16:54:36 -04:00
|
|
|
m_app_pm = mod;
|
2023-12-07 20:22:54 -05:00
|
|
|
UpdatePitch();
|
2022-05-19 16:54:36 -04:00
|
|
|
}
|
|
|
|
|
2023-12-07 20:22:54 -05:00
|
|
|
void BlockSoundHandler::SetPBend(s32 bend) {
|
2022-12-05 23:43:14 -05:00
|
|
|
for (auto& c : m_children) {
|
2023-12-07 20:22:54 -05:00
|
|
|
c->SetPBend(bend);
|
2022-12-05 23:43:14 -05:00
|
|
|
}
|
2022-05-19 16:54:36 -04:00
|
|
|
m_app_pb = bend;
|
2023-12-07 20:22:54 -05:00
|
|
|
UpdatePitch();
|
2022-05-19 16:54:36 -04:00
|
|
|
}
|
|
|
|
|
2023-12-07 20:22:54 -05:00
|
|
|
void BlockSoundHandler::DoGrain() {
|
|
|
|
auto& grain = m_sfx.Grains[m_next_grain];
|
2022-05-19 16:54:36 -04:00
|
|
|
|
2023-12-07 20:22:54 -05:00
|
|
|
s32 ret = grain(*this);
|
2022-05-19 16:54:36 -04:00
|
|
|
|
|
|
|
if (m_skip_grains) {
|
|
|
|
m_grains_to_play--;
|
|
|
|
if (m_grains_to_play == 0) {
|
|
|
|
m_next_grain += m_grains_to_skip;
|
|
|
|
m_skip_grains = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_next_grain++;
|
2023-12-07 20:22:54 -05:00
|
|
|
if (m_next_grain >= m_sfx.Grains.size()) {
|
2022-05-19 16:54:36 -04:00
|
|
|
m_done = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-12-07 20:22:54 -05:00
|
|
|
m_countdown = m_sfx.Grains[m_next_grain].Delay + ret;
|
2022-05-19 16:54:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace snd
|