Add support of N163 demultiplexed output

so, there's to way for reduce N163 noises: reduce channel limit and demultiplex
* channel limit is runtime changeable and it makes some usable effects with disable demultiplex
* demultiplex is used for "non-ear destroyable" emulators, but less hardware accurate. (when LPF and RF filter is not considered)
Furnace support both after this, You can choose output behavior via configuration flag.
This commit is contained in:
cam900 2022-04-10 20:22:49 +09:00
parent e23dcd6e1b
commit e6d74766ca
5 changed files with 39 additions and 3 deletions

View file

@ -156,7 +156,7 @@ const char* DivPlatformN163::getEffectName(unsigned char effect) {
void DivPlatformN163::acquire(short* bufL, short* bufR, size_t start, size_t len) {
for (size_t i=start; i<start+len; i++) {
n163.tick();
int out=(n163.out()<<6)*2; // scale to 16 bit
int out=((n163.out()<<6)*2); // scale to 16 bit
if (out>32767) out=32767;
if (out<-32768) out=-32768;
bufL[i]=bufR[i]=out;
@ -607,6 +607,7 @@ void DivPlatformN163::reset() {
memset(regPool,0,128);
n163.set_disable(false);
n163.set_multiplex(multiplex);
chanMax=initChanMax;
loadWave=-1;
loadPos=0;
@ -636,8 +637,10 @@ void DivPlatformN163::setFlags(unsigned int flags) {
break;
}
initChanMax=chanMax=(flags>>4)&7;
multiplex=((flags>>7)&1)?false:true; // not accurate in real hardware
chipClock=rate;
rate/=15;
n163.set_multiplex(multiplex);
rWrite(0x7f,initChanMax<<4);
}

View file

@ -75,6 +75,7 @@ class DivPlatformN163: public DivDispatch {
unsigned char chanMax;
short loadWave, loadPos, loadLen;
unsigned char loadMode;
bool multiplex;
n163_core n163;
unsigned char regPool[128];

View file

@ -58,16 +58,27 @@
Frequency formula:
Frequency: Pitch input * ((Input clock * 15 * Number of activated voices) / 65536)
There's to way for reduce N163 noises: reduce channel limit and demultiplex
- Channel limit is runtime changeable and it makes some usable effects.
- Demultiplex is used for "non-ear destroyable" emulators, but less hardware accurate. (when LPF and RF filter is not considered)
This core is support both, You can choose output behavior
*/
#include "n163.hpp"
void n163_core::tick()
{
m_out = 0;
if (m_multiplex)
m_out = 0;
// 0xe000-0xe7ff Disable sound bits (bit 6, bit 0 to 5 are CPU ROM Bank 0x8000-0x9fff select.)
if (m_disable)
{
if (!m_multiplex)
m_out = 0;
return;
}
// tick per each clock
const u32 freq = m_ram[m_voice_cycle + 0] | (u32(m_ram[m_voice_cycle + 2]) << 8) | (bitfield<u32>(m_ram[m_voice_cycle + 4], 0, 2) << 16); // 18 bit frequency
@ -88,22 +99,34 @@ void n163_core::tick()
m_ram[m_voice_cycle + 5] = bitfield(accum, 16, 8);
// update voice cycle
bool flush = m_multiplex ? true : false;
m_voice_cycle -= 0x8;
if (m_voice_cycle < (0x78 - (bitfield(m_ram[0x7f], 4, 3) << 3)))
{
if (!m_multiplex)
flush = true;
m_voice_cycle = 0x78;
}
// output 4 bit waveform and volume, multiplexed
m_out = wave * volume;
m_acc += wave * volume;
if (flush)
{
m_out = m_acc / (m_multiplex ? 1 : (bitfield(m_ram[0x7f], 4, 3) + 1));
m_acc = 0;
}
}
void n163_core::reset()
{
// reset this chip
m_disable = false;
m_multiplex = true;
std::fill(std::begin(m_ram), std::end(m_ram), 0);
m_voice_cycle = 0x78;
m_addr_latch.reset();
m_out = 0;
m_acc = 0;
}
// accessor

View file

@ -48,6 +48,7 @@ public:
// register pool
u8 reg(u8 addr) { return m_ram[addr & 0x7f]; }
void set_multiplex(bool multiplex = true) { m_multiplex = multiplex; }
private:
// Address latch
@ -73,6 +74,9 @@ private:
u8 m_voice_cycle = 0x78; // Voice cycle for processing
addr_latch_t m_addr_latch; // address latch
s16 m_out = 0; // output
// demultiplex related
bool m_multiplex = true; // multiplex flag, but less noisy = inaccurate!
s16 m_acc = 0; // accumulated output
};
#endif

View file

@ -372,6 +372,11 @@ void FurnaceGUI::drawSysConf(int i) {
e->setSysFlags(i,(flags & ~(7 << 4)) | (((initialChannelLimit-1) & 7) << 4),restart);
updateWindowTitle();
} rightClickable
bool n163Multiplex=flags&128;
if (ImGui::Checkbox("Disable Multiplexed Output",&n163Multiplex)) {
e->setSysFlags(i,(flags&(~128))|(n163Multiplex<<7),restart);
updateWindowTitle();
}
break;
}
case DIV_SYSTEM_GB: