furnace/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es550x_alu.cpp
2022-09-17 00:16:20 +09:00

132 lines
2.5 KiB
C++

/*
License: Zlib
see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details
Copyright holder(s): cam900
Ensoniq ES5504/ES5505/ES5506 Shared Accumulator emulation core
*/
#include "es550x.hpp"
// Accumulator functions
void es550x_shared_core::es550x_voice_t::es550x_alu_t::reset()
{
m_cr.reset();
m_fc = 0;
m_start = 0;
m_end = 0;
m_accum = 0;
m_sample[0] = m_sample[1] = 0;
}
bool es550x_shared_core::es550x_voice_t::es550x_alu_t::busy() { return m_cr.stop() == 0; }
bool es550x_shared_core::es550x_voice_t::es550x_alu_t::tick()
{
if (m_cr.dir())
{
m_accum -= m_fc;
}
else
{
m_accum += m_fc;
}
m_accum &= m_accum_mask;
return ((!m_cr.lei()) &&
(((m_cr.dir()) && (m_accum < m_start)) || ((!m_cr.dir()) && (m_accum > m_end))))
? true
: false;
}
void es550x_shared_core::es550x_voice_t::es550x_alu_t::loop_exec()
{
if (m_cr.irqe())
{ // Set IRQ
m_cr.set_irq(true);
}
if (m_cr.dir()) // Reverse playback
{
if (m_cr.lpe()) // Loop enable
{
if (m_cr.ble()) // Bidirectional
{
m_cr.set_dir(false);
m_accum = m_start + (m_start - m_accum);
}
else
{ // Normal
m_accum = m_end - (m_start - m_accum);
}
}
else if (m_cr.ble() && m_transwave) // m_transwave
{
m_cr.set_loop(0);
m_cr.set_lei(true); // Loop end ignore
m_accum = m_end - (m_start - m_accum);
}
else
{ // Stop
m_cr.set_stop0(true);
}
}
else
{
if (m_cr.lpe()) // Loop enable
{
if (m_cr.ble()) // Bidirectional
{
m_cr.set_dir(true);
m_accum = m_end - (m_end - m_accum);
}
else
{ // Normal
m_accum = (m_accum - m_end) + m_start;
}
}
else if (m_cr.ble() && m_transwave) // m_transwave
{
m_cr.set_loop(0);
m_cr.set_lei(true); // Loop end ignore
m_accum = (m_accum - m_end) + m_start;
}
else
{ // Stop
m_cr.set_stop0(true);
}
}
}
s32 es550x_shared_core::es550x_voice_t::es550x_alu_t::interpolation()
{
// SF = S1 + ACCfr * (S2 - S1)
return m_sample[0] + ((bitfield<s32>(m_accum, std::max<s8>(0, m_fraction - 9), 9) *
(m_sample[1] - m_sample[0])) >>
9);
}
u32 es550x_shared_core::es550x_voice_t::es550x_alu_t::get_accum_integer()
{
return bitfield(m_accum, m_fraction, m_integer);
}
void es550x_shared_core::es550x_voice_t::es550x_alu_t::irq_exec(es550x_intf &intf,
es550x_irq_t &irqv,
u8 index)
{
const bool prev = irqv.irqb();
if (m_cr.irq())
{
if (irqv.irqb())
{
irqv.set(index);
m_cr.set_irq(false);
}
}
if (prev != irqv.irqb())
{
irq_update(intf, irqv);
}
}