From e6d74766ca6af5ffc17e1f19030d468716b30f92 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 10 Apr 2022 20:22:49 +0900 Subject: [PATCH 1/2] 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. --- src/engine/platform/n163.cpp | 5 ++++- src/engine/platform/n163.h | 1 + src/engine/platform/sound/n163/n163.cpp | 27 +++++++++++++++++++++++-- src/engine/platform/sound/n163/n163.hpp | 4 ++++ src/gui/sysConf.cpp | 5 +++++ 5 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index 2800fad1..a61f95f8 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -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; i32767) 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); } diff --git a/src/engine/platform/n163.h b/src/engine/platform/n163.h index 4bc5cc63..70f842ad 100644 --- a/src/engine/platform/n163.h +++ b/src/engine/platform/n163.h @@ -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]; diff --git a/src/engine/platform/sound/n163/n163.cpp b/src/engine/platform/sound/n163/n163.cpp index 192189d9..b18f146b 100644 --- a/src/engine/platform/sound/n163/n163.cpp +++ b/src/engine/platform/sound/n163/n163.cpp @@ -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(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 diff --git a/src/engine/platform/sound/n163/n163.hpp b/src/engine/platform/sound/n163/n163.hpp index b97de9ae..a3182757 100644 --- a/src/engine/platform/sound/n163/n163.hpp +++ b/src/engine/platform/sound/n163/n163.hpp @@ -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 diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 8ecf7c07..5b2aa658 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -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: From 86b523a83ebccde32659bfc924ec18625d21ca5d Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 10 Apr 2022 20:24:31 +0900 Subject: [PATCH 2/2] Revert unnecessary changes --- src/engine/platform/n163.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index a61f95f8..25be01b1 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -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; i32767) out=32767; if (out<-32768) out=-32768; bufL[i]=bufR[i]=out;