jak-project/game/sound/989snd/ame_handler.cpp

324 lines
7.3 KiB
C++
Raw Normal View History

2022-05-19 16:54:36 -04:00
// Copyright: 2021 - 2022, Ziemas
// SPDX-License-Identifier: ISC
#include "ame_handler.h"
#include "game/sound/989snd/blocksound_handler.h"
2022-05-19 16:54:36 -04:00
namespace snd {
// added!
u64 SoundFlavaHack = 0;
2022-05-19 16:54:36 -04:00
ame_handler::ame_handler(MultiMIDIBlockHeader* block,
voice_manager& vm,
MIDISound& sound,
s32 vol,
s32 pan,
locator& loc,
u32 bank)
: m_sound(sound),
m_bank(bank),
m_header(block),
m_locator(loc),
m_vm(vm),
m_repeats(sound.Repeats) {
if (vol == VOLUME_DONT_CHANGE) {
vol = 1024;
}
m_vol = (vol * m_sound.Vol) >> 10;
if (m_vol >= 128) {
m_vol = 127;
}
if (pan == PAN_DONT_CHANGE || pan == PAN_RESET) {
m_pan = m_sound.Pan;
} else {
m_pan = pan;
}
start_segment(0);
};
bool ame_handler::tick() {
for (auto it = m_midis.begin(); it != m_midis.end();) {
bool done = it->second->tick();
if (done) {
it = m_midis.erase(it);
} else {
it++;
}
}
return m_midis.empty();
};
void ame_handler::start_segment(u32 id) {
auto midiblock = (MIDIBlockHeader*)(m_header->BlockPtr[id] + (uintptr_t)m_header);
m_midis.emplace(id, std::make_unique<midi_handler>(midiblock, m_vm, m_sound, m_vol, m_pan,
m_locator, m_bank, this));
}
void ame_handler::stop() {
for (auto it = m_midis.begin(); it != m_midis.end();) {
it->second->stop();
it = m_midis.erase(it);
}
}
void ame_handler::stop_segment(u32 id) {
auto m = m_midis.find(id);
if (m == m_midis.end())
return;
m->second->stop();
m_midis.erase(id);
}
void ame_handler::pause() {
for (auto& m : m_midis) {
m.second->pause();
}
}
void ame_handler::unpause() {
for (auto& m : m_midis) {
m.second->unpause();
}
}
void ame_handler::set_vol_pan(s32 vol, s32 pan) {
if (vol >= 0) {
if (vol != VOLUME_DONT_CHANGE) {
m_vol = (m_sound.Vol * vol) >> 10;
}
} else {
m_vol = -vol;
}
if (m_vol >= 128) {
m_vol = 127;
}
if (pan == PAN_RESET) {
m_pan = m_sound.Pan;
} else if (pan != PAN_DONT_CHANGE) {
m_pan = pan;
}
for (auto& m : m_midis) {
m.second->set_vol_pan(vol, pan);
}
}
void ame_handler::set_pmod(s32 mod) {
// TODO
}
#define AME_BEGIN(op) \
if (skip) { \
if (skip == 1) { \
skip = 0; \
} \
} else \
do {
#define AME_END(x) \
} \
while (0) \
; \
stream += (x);
std::pair<bool, u8*> ame_handler::run_ame(midi_handler& midi, u8* stream) {
int skip = 0;
bool done = false;
bool cont = true;
while (!done) {
auto op = static_cast<u8>(*stream++);
switch (op) {
case 0x0: {
AME_BEGIN(op)
if (m_excite <= (stream[0] + 1)) {
skip = 1;
}
AME_END(1)
} break;
case 0x1: {
AME_BEGIN(op)
if (m_excite != (stream[0] + 1)) {
skip = 1;
}
AME_END(1)
} break;
case 0x2: {
AME_BEGIN(op)
if (m_excite > (stream[0] + 1)) {
skip = 1;
}
AME_END(1)
} break;
case 0x3: {
AME_BEGIN(op)
stop_segment(stream[0]);
AME_END(1)
} break;
case 0x4: {
// fmt::print("ame trace 4\n");
if (skip == 1) {
skip = 2;
}
} break;
case 0x5: {
// fmt::print("ame trace 5\n");
if (skip == 2) {
skip = 0;
}
} break;
case 0x6: {
AME_BEGIN(op)
if (m_register[stream[0]] > (stream[1] - 1)) {
skip = 1;
}
AME_END(2)
} break;
case 0x7: {
AME_BEGIN(op)
if (m_register[stream[0]] < (stream[1] + 1)) {
skip = 1;
}
AME_END(2)
} break;
case 0xB: {
// fmt::print("ame trace b\n");
m_macro[stream[0]] = &stream[1];
while (*stream != 0xf7) {
stream++;
}
stream++;
} break;
case 0xc: {
AME_BEGIN(op)
auto [sub_cont, ptr] = run_ame(midi, m_macro[stream[0]]);
if (!sub_cont) {
cont = false;
done = true;
}
AME_END(1)
} break;
case 0xd: {
AME_BEGIN(op)
cont = false;
done = true;
start_segment(m_register[stream[0] - 1]);
AME_END(1)
} break;
case 0xe: {
AME_BEGIN(op)
start_segment(m_register[stream[0] - 1]);
AME_END(1)
} break;
case 0xf: {
// fmt::print("ame trace f\n");
if (skip) {
while (*stream != 0x7f) {
stream++;
}
stream++;
if (skip == 1)
skip = 0;
} else {
auto group = *stream++;
m_groups[group].basis = *stream++;
u8 channel = 0;
while (*stream != 0xf7) {
m_groups[group].channel[channel] = *stream++;
m_groups[group].excite_min[channel] = *stream++;
m_groups[group].excite_max[channel] = *stream++;
channel++;
}
m_groups[group].num_channels = channel;
stream++;
}
} break;
case 0x10: {
AME_BEGIN(op)
u8 group = stream[0];
u8 comp = 0;
if (m_groups[group].basis == 0) {
comp = m_excite;
} else {
comp = m_register[m_groups[group].basis - 1];
}
// fmt::print("group: {} basis: {} excite: {}\n", group, m_groups[group].basis, comp);
2022-05-19 16:54:36 -04:00
for (int i = 0; i < m_groups[group].num_channels; i++) {
// auto xmin = m_groups[group].excite_min[i];
// auto xmax = m_groups[group].excite_max[i];
// fmt::print("chan {} excite: {}-{}\n", i, xmin, xmax);
// note : added hack here! :-)
if (!SoundFlavaHack &&
(comp < m_groups[group].excite_min[i] || comp > m_groups[group].excite_max[i])) {
2022-05-19 16:54:36 -04:00
midi.mute_channel(m_groups[group].channel[i]);
} else {
midi.unmute_channel(m_groups[group].channel[i]);
}
}
AME_END(1)
} break;
case 0x11: {
AME_BEGIN(op)
done = true;
cont = false;
start_segment(stream[0]);
AME_END(1)
} break;
case 0x12: {
AME_BEGIN(op)
start_segment(stream[0]);
AME_END(1)
} break;
case 0x13: {
AME_BEGIN(op)
m_register[stream[0]] = stream[1];
AME_END(2)
} break;
case 0x14: {
AME_BEGIN(op)
if (m_register[stream[0]] < 0x7f) {
m_register[stream[0]]++;
}
AME_END(1)
} break;
case 0x15: {
AME_BEGIN(op)
if (m_register[stream[0]] > 0) {
m_register[stream[0]]--;
}
AME_END(1)
} break;
case 0x16: {
AME_BEGIN(op)
if (m_register[stream[0]] != stream[1]) {
skip = 1;
}
AME_END(2)
} break;
default: {
throw ame_error(fmt::format("Unhandled AME event {:02x}", (u8)op));
} break;
}
if (*stream == 0xf7) {
// fmt::print("ame done\n");
stream++;
done = true;
}
}
return {cont, stream};
}
} // namespace snd
#undef AME_BEGIN
#undef AME_END