furnace/src/engine/platform/sound/scc/scc.hpp

140 lines
3.0 KiB
C++

/*
License: BSD-3-Clause
see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details
Copyright holder(s): cam900
Contributor(s): Natt Akuma, James Alan Nguyen, Laurens Holst
Modifiers and Contributors for Furnace: Natt Akuma, tildearrow, Grauw
Konami SCC emulation core
See scc.cpp for more info.
*/
#include <algorithm>
#include <memory>
#ifndef _VGSOUND_EMU_SCC_HPP
#define _VGSOUND_EMU_SCC_HPP
#pragma once
namespace scc
{
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned int u32;
typedef signed int s32;
// get bitfield, bitfield(input, position, len)
template<typename T> T bitfield(T in, u8 pos, u8 len = 1)
{
return (in >> pos) & (len ? (T(1 << len) - 1) : 1);
}
}
using namespace scc;
// shared for SCCs
class scc_core
{
public:
// constructor
scc_core()
: m_voice{*this,*this,*this,*this,*this}
{};
virtual ~scc_core(){};
// accessors
virtual u8 scc_r(bool is_sccplus, u8 address) = 0;
virtual void scc_w(bool is_sccplus, u8 address, u8 data) = 0;
// internal state
virtual void reset();
void tick();
// getters
s32 out() { return m_out; } // output to DA0...DA10 pin
s32 chan_out(u8 ch) { return m_voice[ch].out; }
u8 reg(u8 address) { return m_reg[address]; }
protected:
// voice structs
struct voice_t
{
// constructor
voice_t(scc_core &host) : m_host(host) {};
// internal state
void reset();
void tick();
// registers
scc_core &m_host;
s8 wave[32] = {0}; // internal waveform
bool enable = false; // output enable flag
u16 pitch = 0; // pitch
u8 volume = 0; // volume
u8 addr = 0; // waveform pointer
u16 counter = 0; // frequency counter
s32 out = 0; // current output
};
voice_t m_voice[5]; // 5 voices
// accessor
u8 wave_r(bool is_sccplus, u8 address);
void wave_w(bool is_sccplus, u8 address, u8 data);
void freq_vol_enable_w(u8 address, u8 data);
struct test_t
{
// constructor
test_t()
: freq_4bit(0)
, freq_8bit(0)
, resetpos(0)
, rotate(0)
, rotate4(0)
{ };
void reset()
{
freq_4bit = 0;
freq_8bit = 0;
resetpos = 0;
rotate = 0;
rotate4 = 0;
}
u8 freq_4bit : 1; // 4 bit frequency
u8 freq_8bit : 1; // 8 bit frequency
u8 resetpos : 1; // reset counter after pitch writes
u8 rotate : 1; // rotate and write protect waveform for all channels
u8 rotate4 : 1; // same as above but for channel 4 only
};
test_t m_test; // test register
s32 m_out = 0; // output to DA0...10
u8 m_reg[256] = {0}; // register pool
};
// SCC core
class k051649_scc_core : public scc_core
{
public:
// accessors
virtual u8 scc_r(bool is_sccplus, u8 address) override;
virtual void scc_w(bool is_sccplus, u8 address, u8 data) override;
};
class k052539_scc_core : public k051649_scc_core
{
public:
// accessors
virtual u8 scc_r(bool is_sccplus, u8 address) override;
virtual void scc_w(bool is_sccplus, u8 address, u8 data) override;
};
#endif