mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-27 15:03:01 +00:00
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:
parent
e23dcd6e1b
commit
e6d74766ca
5 changed files with 39 additions and 3 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue