From cb7aa4aa058fdf423a2eb7094f1db26ed47df378 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 1 May 2022 23:20:20 -0500 Subject: [PATCH] NES: wire up NSFplay no muting supported for now see #27 --- src/engine/dispatchContainer.cpp | 1 + src/engine/platform/nes.cpp | 147 +++++++++++++----- src/engine/platform/nes.h | 10 ++ .../platform/sound/nes_nsfplay/nes_apu.h | 20 +-- .../platform/sound/nes_nsfplay/nes_dmc.h | 20 +-- .../platform/sound/nes_nsfplay/nes_fds.h | 20 +-- .../platform/sound/nes_nsfplay/nes_mmc5.h | 20 +-- .../platform/sound/nes_nsfplay/nes_n106.h | 20 +-- .../platform/sound/nes_nsfplay/nes_vrc6.h | 20 +-- src/gui/gui.h | 2 + src/gui/settings.cpp | 12 ++ 11 files changed, 193 insertions(+), 99 deletions(-) diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index e9f1a03e2..187523c72 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -189,6 +189,7 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do break; case DIV_SYSTEM_NES: dispatch=new DivPlatformNES; + ((DivPlatformNES*)dispatch)->setNSFPlay(eng->getConfInt("nesCore",0)==1); break; case DIV_SYSTEM_C64_6581: dispatch=new DivPlatformC64; diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index 7f35dc5bd..084c1123c 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -27,7 +27,7 @@ struct _nla_table nla_table; #define CHIP_DIVIDER 16 -#define rWrite(a,v) if (!skipRegisterWrites) {apu_wr_reg(nes,a,v); regPool[(a)&0x7f]=v; if (dumpWrites) {addWrite(a,v);} } +#define rWrite(a,v) if (!skipRegisterWrites) {doWrite(a,v); regPool[(a)&0x7f]=v; if (dumpWrites) {addWrite(a,v);} } const char* regCheatSheetNES[]={ "S0Volume", "4000", @@ -75,36 +75,48 @@ const char* DivPlatformNES::getEffectName(unsigned char effect) { return NULL; } -void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len) { +void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) { + if (useNP) { + nes1_NP->Write(addr,data); + nes2_NP->Write(addr,data); + } else { + apu_wr_reg(nes,addr,data); + } +} + +#define doPCM \ + if (dacSample!=-1) { \ + dacPeriod+=dacRate; \ + if (dacPeriod>=rate) { \ + DivSample* s=parent->getSample(dacSample); \ + if (s->samples>0) { \ + if (!isMuted[4]) { \ + unsigned char next=((unsigned char)s->data8[dacPos]+0x80)>>1; \ + if (dacAntiClickOn && dacAntiClick=s->samples) { \ + if (s->loopStart>=0 && s->loopStart<(int)s->samples) { \ + dacPos=s->loopStart; \ + } else { \ + dacSample=-1; \ + } \ + } \ + dacPeriod-=rate; \ + } else { \ + dacSample=-1; \ + } \ + } \ + } + +void DivPlatformNES::acquire_puNES(short* bufL, short* bufR, size_t start, size_t len) { for (size_t i=start; i=rate) { - DivSample* s=parent->getSample(dacSample); - if (s->samples>0) { - if (!isMuted[4]) { - unsigned char next=((unsigned char)s->data8[dacPos]+0x80)>>1; - if (dacAntiClickOn && dacAntiClick=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { - dacPos=s->loopStart; - } else { - dacSample=-1; - } - } - dacPeriod-=rate; - } else { - dacSample=-1; - } - } - } + doPCM; apu_tick(nes,NULL); nes->apu.odd_cycle=!nes->apu.odd_cycle; @@ -126,6 +138,32 @@ void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len) } } +void DivPlatformNES::acquire_NSFPlay(short* bufL, short* bufR, size_t start, size_t len) { + int out1[2]; + int out2[2]; + for (size_t i=start; iTick(1); + nes2_NP->Tick(1); + nes1_NP->Render(out1); + nes2_NP->Render(out2); + + int sample=out1[0]+out1[1]+out2[0]+out2[1]; + if (sample>32767) sample=32767; + if (sample<-32768) sample=-32768; + bufL[i]=sample; + } +} + +void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len) { + if (useNP) { + acquire_NSFPlay(bufL,bufR,start,len); + } else { + acquire_puNES(bufL,bufR,start,len); + } +} + static unsigned char noiseTable[253]={ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 4, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, @@ -466,7 +504,7 @@ int DivPlatformNES::dispatch(DivCommand c) { void DivPlatformNES::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - nes->muted[ch]=mute; + if (!useNP) nes->muted[ch]=mute; } void DivPlatformNES::forceIns() { @@ -513,10 +551,15 @@ void DivPlatformNES::reset() { dacSample=-1; sampleBank=0; - apu_turn_on(nes,apuType); + if (useNP) { + nes1_NP->Reset(); + nes2_NP->Reset(); + } else { + apu_turn_on(nes,apuType); + nes->apu.cpu_cycles=0; + nes->apu.cpu_opcode_cycle=0; + } memset(regPool,0,128); - nes->apu.cpu_cycles=0; - nes->apu.cpu_opcode_cycle=0; rWrite(0x4015,0x1f); rWrite(0x4001,chan[0].sweep); @@ -534,14 +577,20 @@ void DivPlatformNES::setFlags(unsigned int flags) { if (flags==2) { // Dendy rate=COLOR_PAL*2.0/5.0; apuType=2; - nes->apu.type=apuType; } else if (flags==1) { // PAL rate=COLOR_PAL*3.0/8.0; apuType=1; - nes->apu.type=apuType; } else { // NTSC rate=COLOR_NTSC/2.0; apuType=0; + } + if (useNP) { + nes1_NP->SetClock(rate); + nes1_NP->SetRate(rate); + nes2_NP->SetClock(rate); + nes2_NP->SetRate(rate); + nes2_NP->SetPal(apuType==1); + } else { nes->apu.type=apuType; } chipClock=rate; @@ -564,16 +613,31 @@ void DivPlatformNES::poke(std::vector& wlist) { for (DivRegWrite& i: wlist) rWrite(i.addr,i.val); } +void DivPlatformNES::setNSFPlay(bool use) { + useNP=use; +} + int DivPlatformNES::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { parent=p; apuType=flags; dumpWrites=false; skipRegisterWrites=false; - nes=new struct NESAPU; + if (useNP) { + nes1_NP=new xgm::NES_APU; + nes1_NP->SetOption(xgm::NES_APU::OPT_NONLINEAR_MIXER,1); + nes2_NP=new xgm::NES_DMC; + nes2_NP->SetOption(xgm::NES_DMC::OPT_NONLINEAR_MIXER,1); + nes2_NP->SetMemory([](unsigned short addr, unsigned int& data) { + data=0; + }); + nes2_NP->SetAPU(nes1_NP); + } else { + nes=new struct NESAPU; + } writeOscBuf=0; for (int i=0; i<5; i++) { isMuted[i]=false; - nes->muted[i]=false; + if (!useNP) nes->muted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; } setFlags(flags); @@ -587,7 +651,12 @@ void DivPlatformNES::quit() { for (int i=0; i<5; i++) { delete oscBuf[i]; } - delete nes; + if (useNP) { + delete nes1_NP; + delete nes2_NP; + } else { + delete nes; + } } DivPlatformNES::~DivPlatformNES() { diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index abd23da99..8b898c7fc 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -23,6 +23,8 @@ #include "../dispatch.h" #include "../macroInt.h" +#include "sound/nes_nsfplay/nes_apu.h" + class DivPlatformNES: public DivDispatch { struct Channel { int freq, baseFreq, pitch, pitch2, prevFreq, note, ins; @@ -66,11 +68,18 @@ class DivPlatformNES: public DivDispatch { unsigned char writeOscBuf; unsigned char apuType; bool dacAntiClickOn; + bool useNP; struct NESAPU* nes; + xgm::NES_APU* nes1_NP; + xgm::NES_DMC* nes2_NP; unsigned char regPool[128]; friend void putDispatchChan(void*,int,int); + void doWrite(unsigned short addr, unsigned char data); + void acquire_puNES(short* bufL, short* bufR, size_t start, size_t len); + void acquire_NSFPlay(short* bufL, short* bufR, size_t start, size_t len); + public: void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); @@ -84,6 +93,7 @@ class DivPlatformNES: public DivDispatch { void muteChannel(int ch, bool mute); bool keyOffAffectsArp(int ch); float getPostAmp(); + void setNSFPlay(bool use); void setFlags(unsigned int flags); void notifyInsDeletion(void* ins); void poke(unsigned int addr, unsigned short val); diff --git a/src/engine/platform/sound/nes_nsfplay/nes_apu.h b/src/engine/platform/sound/nes_nsfplay/nes_apu.h index 004c99974..b302dd02c 100644 --- a/src/engine/platform/sound/nes_nsfplay/nes_apu.h +++ b/src/engine/platform/sound/nes_nsfplay/nes_apu.h @@ -68,16 +68,16 @@ namespace xgm void FrameSequence(int s); - virtual void Reset (); - virtual void Tick (unsigned int clocks); - virtual unsigned int Render (int b[2]); - virtual bool Read (unsigned int adr, unsigned int & val, unsigned int id=0); - virtual bool Write (unsigned int adr, unsigned int val, unsigned int id=0); - virtual void SetRate (double rate); - virtual void SetClock (double clock); - virtual void SetOption (int id, int b); - virtual void SetMask(int m){ mask = m; } - virtual void SetStereoMix (int trk, short mixl, short mixr); + void Reset (); + void Tick (unsigned int clocks); + unsigned int Render (int b[2]); + bool Read (unsigned int adr, unsigned int & val, unsigned int id=0); + bool Write (unsigned int adr, unsigned int val, unsigned int id=0); + void SetRate (double rate); + void SetClock (double clock); + void SetOption (int id, int b); + void SetMask(int m){ mask = m; } + void SetStereoMix (int trk, short mixl, short mixr); }; } // namespace diff --git a/src/engine/platform/sound/nes_nsfplay/nes_dmc.h b/src/engine/platform/sound/nes_nsfplay/nes_dmc.h index 4d19617d8..b0aa2ef92 100644 --- a/src/engine/platform/sound/nes_nsfplay/nes_dmc.h +++ b/src/engine/platform/sound/nes_nsfplay/nes_dmc.h @@ -102,16 +102,16 @@ namespace xgm int GetDamp(){ return (damp<<1)|dac_lsb ; } void TickFrameSequence (unsigned int clocks); - virtual void Reset (); - virtual void Tick (unsigned int clocks); - virtual unsigned int Render (int b[2]); - virtual bool Write (unsigned int adr, unsigned int val, unsigned int id=0); - virtual bool Read (unsigned int adr, unsigned int & val, unsigned int id=0); - virtual void SetRate (double rate); - virtual void SetClock (double rate); - virtual void SetOption (int, int); - virtual void SetMask(int m){ mask = m; } - virtual void SetStereoMix (int trk, short mixl, short mixr); + void Reset (); + void Tick (unsigned int clocks); + unsigned int Render (int b[2]); + bool Write (unsigned int adr, unsigned int val, unsigned int id=0); + bool Read (unsigned int adr, unsigned int & val, unsigned int id=0); + void SetRate (double rate); + void SetClock (double rate); + void SetOption (int, int); + void SetMask(int m){ mask = m; } + void SetStereoMix (int trk, short mixl, short mixr); }; } diff --git a/src/engine/platform/sound/nes_nsfplay/nes_fds.h b/src/engine/platform/sound/nes_nsfplay/nes_fds.h index 180841dd8..9185e4da6 100644 --- a/src/engine/platform/sound/nes_nsfplay/nes_fds.h +++ b/src/engine/platform/sound/nes_nsfplay/nes_fds.h @@ -56,16 +56,16 @@ public: NES_FDS (); ~NES_FDS (); - virtual void Reset (); - virtual void Tick (unsigned int clocks); - virtual unsigned int Render (int b[2]); - virtual bool Write (unsigned int adr, unsigned int val, unsigned int id=0); - virtual bool Read (unsigned int adr, unsigned int & val, unsigned int id=0); - virtual void SetRate (double); - virtual void SetClock (double); - virtual void SetOption (int, int); - virtual void SetMask(int m){ mask = m&1; } - virtual void SetStereoMix (int trk, short mixl, short mixr); + void Reset (); + void Tick (unsigned int clocks); + unsigned int Render (int b[2]); + bool Write (unsigned int adr, unsigned int val, unsigned int id=0); + bool Read (unsigned int adr, unsigned int & val, unsigned int id=0); + void SetRate (double); + void SetClock (double); + void SetOption (int, int); + void SetMask(int m){ mask = m&1; } + void SetStereoMix (int trk, short mixl, short mixr); }; } // namespace xgm diff --git a/src/engine/platform/sound/nes_nsfplay/nes_mmc5.h b/src/engine/platform/sound/nes_nsfplay/nes_mmc5.h index d0ae8bd0c..19d5ab269 100644 --- a/src/engine/platform/sound/nes_nsfplay/nes_mmc5.h +++ b/src/engine/platform/sound/nes_nsfplay/nes_mmc5.h @@ -50,16 +50,16 @@ namespace xgm void FrameSequence (); void TickFrameSequence (unsigned int clocks); - virtual void Reset (); - virtual void Tick (unsigned int clocks); - virtual unsigned int Render (int b[2]); - virtual bool Write (unsigned int adr, unsigned int val, unsigned int id=0); - virtual bool Read (unsigned int adr, unsigned int & val, unsigned int id=0); - virtual void SetOption (int id, int b); - virtual void SetClock (double); - virtual void SetRate (double); - virtual void SetMask (int m){ mask = m; } - virtual void SetStereoMix (int trk, short mixl, short mixr); + void Reset (); + void Tick (unsigned int clocks); + unsigned int Render (int b[2]); + bool Write (unsigned int adr, unsigned int val, unsigned int id=0); + bool Read (unsigned int adr, unsigned int & val, unsigned int id=0); + void SetOption (int id, int b); + void SetClock (double); + void SetRate (double); + void SetMask (int m){ mask = m; } + void SetStereoMix (int trk, short mixl, short mixr); }; } diff --git a/src/engine/platform/sound/nes_nsfplay/nes_n106.h b/src/engine/platform/sound/nes_nsfplay/nes_n106.h index 5ce937e26..a59dd6687 100644 --- a/src/engine/platform/sound/nes_nsfplay/nes_n106.h +++ b/src/engine/platform/sound/nes_nsfplay/nes_n106.h @@ -47,16 +47,16 @@ public: NES_N106 (); ~NES_N106 (); - virtual void Reset (); - virtual void Tick (unsigned int clocks); - virtual unsigned int Render (int b[2]); - virtual bool Write (unsigned int adr, unsigned int val, unsigned int id=0); - virtual bool Read (unsigned int adr, unsigned int & val, unsigned int id=0); - virtual void SetRate (double); - virtual void SetClock (double); - virtual void SetOption (int, int); - virtual void SetMask (int m); - virtual void SetStereoMix (int trk, short mixl, short mixr); + void Reset (); + void Tick (unsigned int clocks); + unsigned int Render (int b[2]); + bool Write (unsigned int adr, unsigned int val, unsigned int id=0); + bool Read (unsigned int adr, unsigned int & val, unsigned int id=0); + void SetRate (double); + void SetClock (double); + void SetOption (int, int); + void SetMask (int m); + void SetStereoMix (int trk, short mixl, short mixr); }; } // namespace xgm diff --git a/src/engine/platform/sound/nes_nsfplay/nes_vrc6.h b/src/engine/platform/sound/nes_nsfplay/nes_vrc6.h index 85fed39c4..198a8bd66 100644 --- a/src/engine/platform/sound/nes_nsfplay/nes_vrc6.h +++ b/src/engine/platform/sound/nes_nsfplay/nes_vrc6.h @@ -36,16 +36,16 @@ namespace xgm NES_VRC6 (); ~NES_VRC6 (); - virtual void Reset (); - virtual void Tick (unsigned int clocks); - virtual unsigned int Render (int b[2]); - virtual bool Read (unsigned int adr, unsigned int & val, unsigned int id=0); - virtual bool Write (unsigned int adr, unsigned int val, unsigned int id=0); - virtual void SetClock (double); - virtual void SetRate (double); - virtual void SetOption (int, int); - virtual void SetMask (int m){ mask = m; } - virtual void SetStereoMix (int trk, short mixl, short mixr); + void Reset (); + void Tick (unsigned int clocks); + unsigned int Render (int b[2]); + bool Read (unsigned int adr, unsigned int & val, unsigned int id=0); + bool Write (unsigned int adr, unsigned int val, unsigned int id=0); + void SetClock (double); + void SetRate (double); + void SetOption (int, int); + void SetMask (int m){ mask = m; } + void SetStereoMix (int trk, short mixl, short mixr); }; } // namespace diff --git a/src/gui/gui.h b/src/gui/gui.h index 520abdc41..49e56f0c2 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -788,6 +788,7 @@ class FurnaceGUI { int arcadeCore; int ym2612Core; int saaCore; + int nesCore; int mainFont; int patFont; int audioRate; @@ -870,6 +871,7 @@ class FurnaceGUI { arcadeCore(0), ym2612Core(0), saaCore(1), + nesCore(0), mainFont(0), patFont(0), audioRate(44100), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 152f94b8c..383fa4202 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -84,6 +84,11 @@ const char* saaCores[]={ "SAASound" }; +const char* nesCores[]={ + "puNES", + "NSFplay" +}; + const char* valueInputStyles[]={ "Disabled/custom", "Two octaves (0 is C-4, F is D#5)", @@ -859,6 +864,10 @@ void FurnaceGUI::drawSettings() { ImGui::SameLine(); ImGui::Combo("##SAACore",&settings.saaCore,saaCores,2); + ImGui::Text("NES core"); + ImGui::SameLine(); + ImGui::Combo("##NESCore",&settings.nesCore,nesCores,2); + ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Appearance")) { @@ -1731,6 +1740,7 @@ void FurnaceGUI::syncSettings() { settings.arcadeCore=e->getConfInt("arcadeCore",0); settings.ym2612Core=e->getConfInt("ym2612Core",0); settings.saaCore=e->getConfInt("saaCore",1); + settings.nesCore=e->getConfInt("nesCore",0); settings.mainFont=e->getConfInt("mainFont",0); settings.patFont=e->getConfInt("patFont",0); settings.mainFontPath=e->getConfString("mainFontPath",""); @@ -1805,6 +1815,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.arcadeCore,0,1); clampSetting(settings.ym2612Core,0,1); clampSetting(settings.saaCore,0,1); + clampSetting(settings.nesCore,0,1); clampSetting(settings.mainFont,0,6); clampSetting(settings.patFont,0,6); clampSetting(settings.patRowsBase,0,1); @@ -1907,6 +1918,7 @@ void FurnaceGUI::commitSettings() { e->setConf("arcadeCore",settings.arcadeCore); e->setConf("ym2612Core",settings.ym2612Core); e->setConf("saaCore",settings.saaCore); + e->setConf("nesCore",settings.nesCore); e->setConf("mainFont",settings.mainFont); e->setConf("patFont",settings.patFont); e->setConf("mainFontPath",settings.mainFontPath);