parent
7b31f6a3e5
commit
cb7aa4aa05
|
@ -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;
|
||||
|
|
|
@ -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<next) { \
|
||||
dacAntiClick+=8; \
|
||||
rWrite(0x4011,dacAntiClick); \
|
||||
} else { \
|
||||
dacAntiClickOn=false; \
|
||||
rWrite(0x4011,next); \
|
||||
} \
|
||||
} \
|
||||
if (++dacPos>=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<start+len; i++) {
|
||||
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<next) {
|
||||
dacAntiClick+=8;
|
||||
rWrite(0x4011,dacAntiClick);
|
||||
} else {
|
||||
dacAntiClickOn=false;
|
||||
rWrite(0x4011,next);
|
||||
}
|
||||
}
|
||||
if (++dacPos>=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; i<start+len; i++) {
|
||||
doPCM;
|
||||
|
||||
nes1_NP->Tick(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<DivRegWrite>& 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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue