diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 81f005140..e5ed94073 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -95,6 +95,10 @@ class DivEngine; class DivDispatch { protected: DivEngine* parent; + /** + * please honor this variable if needed. + */ + bool skipRegisterWrites; public: /** * the rate the samples are provided. @@ -167,6 +171,16 @@ class DivDispatch { */ virtual void setPAL(bool pal); + /** + * set skip reg writes. + */ + void setSkipRegisterWrites(bool value); + + /** + * force-retrigger instruments. + */ + virtual void forceIns(); + /** * initialize this DivDispatch. * @param parent the parent DivEngine. diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 41c7d2946..25aff9899 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1419,15 +1419,30 @@ void DivEngine::setLoops(int loops) { remainingLoops=loops; } -void DivEngine::play() { - isBusy.lock(); +void DivEngine::playSub() { reset(); + int goal=curOrder; + curOrder=0; curRow=0; clockDrift=0; cycles=0; ticks=1; speedAB=false; playing=true; + dispatch->setSkipRegisterWrites(true); + while (curOrdersetSkipRegisterWrites(false); + dispatch->forceIns(); + clockDrift=0; + cycles=0; + ticks=1; +} + +void DivEngine::play() { + isBusy.lock(); + playSub(); isBusy.unlock(); } @@ -1667,12 +1682,7 @@ void DivEngine::setOrder(unsigned char order) { curOrder=order; if (order>=song.ordersLen) curOrder=0; if (playing) { - reset(); - curRow=0; - clockDrift=0; - cycles=0; - ticks=1; - speedAB=false; + playSub(); } isBusy.unlock(); } diff --git a/src/engine/engine.h b/src/engine/engine.h index 0f8584516..329968900 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -113,6 +113,7 @@ class DivEngine { bool perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal); void renderSamples(); void reset(); + void playSub(); public: DivSong song; diff --git a/src/engine/platform/abstract.cpp b/src/engine/platform/abstract.cpp index 7012cc5db..8f5ad455a 100644 --- a/src/engine/platform/abstract.cpp +++ b/src/engine/platform/abstract.cpp @@ -34,6 +34,14 @@ bool DivDispatch::keyOffAffectsArp(int ch) { void DivDispatch::setPAL(bool pal) { } +void DivDispatch::setSkipRegisterWrites(bool value) { + skipRegisterWrites=value; +} + +void DivDispatch::forceIns() { + +} + int DivDispatch::init(DivEngine* p, int channels, int sugRate, bool pal) { return 0; } diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 305e83405..c3ad0c7b2 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -31,7 +31,8 @@ static int orderedOps[4]={ 0,2,1,3 }; -#define rWrite(a,v) pendingWrites[a]=v; +#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} +#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v);} void DivPlatformArcade::acquire_nuked(short* bufL, short* bufR, size_t start, size_t len) { static int o[2]; @@ -167,14 +168,14 @@ int hScale(int note) { void DivPlatformArcade::tick() { for (int i=0; i<8; i++) { if (chan[i].keyOn || chan[i].keyOff) { - writes.emplace(0x08,i); + immWrite(0x08,i); chan[i].keyOff=false; } } for (int i=0; i<256; i++) { if (pendingWrites[i]!=oldWrites[i]) { - writes.emplace(i,pendingWrites[i]&0xff); + immWrite(i,pendingWrites[i]&0xff); oldWrites[i]=pendingWrites[i]; } } @@ -182,12 +183,12 @@ void DivPlatformArcade::tick() { for (int i=0; i<8; i++) { if (chan[i].freqChanged) { chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64; - writes.emplace(i+0x28,hScale(chan[i].freq>>6)); - writes.emplace(i+0x30,chan[i].freq<<2); + immWrite(i+0x28,hScale(chan[i].freq>>6)); + immWrite(i+0x30,chan[i].freq<<2); chan[i].freqChanged=false; } if (chan[i].keyOn) { - writes.emplace(0x08,0x78|i); + immWrite(0x08,0x78|i); chan[i].keyOn=false; } } @@ -209,6 +210,7 @@ int DivPlatformArcade::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { if (c.chan>7) { + if (skipRegisterWrites) break; chan[c.chan].pcm.sample=12*sampleBank+c.value%12; if (chan[c.chan].pcm.sample>=parent->song.sampleLen) { chan[c.chan].pcm.sample=-1; @@ -425,6 +427,12 @@ int DivPlatformArcade::dispatch(DivCommand c) { return 1; } +void DivPlatformArcade::forceIns() { + for (int i=0; i<13; i++) { + chan[i].insChanged=true; + } +} + void DivPlatformArcade::reset() { while (!writes.empty()) writes.pop(); if (useYMFM) { @@ -451,8 +459,8 @@ void DivPlatformArcade::reset() { delay=0; //rWrite(0x18,0x10); - writes.emplace(0x19,0x7f); - writes.emplace(0x19,0xff); + immWrite(0x19,0x7f); + immWrite(0x19,0xff); //rWrite(0x1b,0x00); extMode=false; diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index 43074bd31..cba403b69 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -64,6 +64,7 @@ class DivPlatformArcade: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void reset(); + void forceIns(); void tick(); void muteChannel(int ch, bool mute); bool isStereo(); diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index ce6887af7..5d83fd743 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -4,6 +4,8 @@ #define FREQ_BASE 277.0f +#define rWrite(a,v) if (!skipRegisterWrites) {sid.write(a,v);} + void DivPlatformC64::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t i=start; i>3); - sid.write(0x17,(filtRes<<4)|(chan[2].filter<<2)|(chan[1].filter<<1)|(chan[0].filter)); - sid.write(0x18,(filtControl<<4)|vol); + rWrite(0x15,filtCut&7); + rWrite(0x16,filtCut>>3); + rWrite(0x17,(filtRes<<4)|(chan[2].filter<<2)|(chan[1].filter<<1)|(chan[0].filter)); + rWrite(0x18,(filtControl<<4)|vol); } void DivPlatformC64::tick() { @@ -50,37 +52,37 @@ void DivPlatformC64::tick() { } if (chan[i].std.hadDuty) { chan[i].duty-=((signed char)chan[i].std.duty-12)*4; - sid.write(i*7+2,chan[i].duty&0xff); - sid.write(i*7+3,chan[i].duty>>8); + rWrite(i*7+2,chan[i].duty&0xff); + rWrite(i*7+3,chan[i].duty>>8); } if (chan[i].testWhen>0) { if (--chan[i].testWhen<1) { if (!chan[i].resetMask && !isMuted[i]) { - sid.write(i*7+5,0); - sid.write(i*7+6,0); - sid.write(i*7+4,(isMuted[i]?0:(chan[i].wave<<4))|8|(chan[i].ring<<2)|(chan[i].sync<<1)); + rWrite(i*7+5,0); + rWrite(i*7+6,0); + rWrite(i*7+4,(isMuted[i]?0:(chan[i].wave<<4))|8|(chan[i].ring<<2)|(chan[i].sync<<1)); } } } if (chan[i].std.hadWave) { chan[i].wave=chan[i].std.wave; - sid.write(i*7+4,(isMuted[i]?0:(chan[i].wave<<4))|(chan[i].ring<<2)|(chan[i].sync<<1)|chan[i].active); + rWrite(i*7+4,(isMuted[i]?0:(chan[i].wave<<4))|(chan[i].ring<<2)|(chan[i].sync<<1)|chan[i].active); } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { chan[i].freq=(chan[i].baseFreq*(ONE_SEMITONE+chan[i].pitch))/ONE_SEMITONE; if (chan[i].freq>0xffff) chan[i].freq=0xffff; if (chan[i].keyOn) { - sid.write(i*7+5,(chan[i].attack<<4)|(chan[i].decay)); - sid.write(i*7+6,(chan[i].sustain<<4)|(chan[i].release)); - sid.write(i*7+4,(isMuted[i]?0:(chan[i].wave<<4))|(chan[i].ring<<2)|(chan[i].sync<<1)|1); + rWrite(i*7+5,(chan[i].attack<<4)|(chan[i].decay)); + rWrite(i*7+6,(chan[i].sustain<<4)|(chan[i].release)); + rWrite(i*7+4,(isMuted[i]?0:(chan[i].wave<<4))|(chan[i].ring<<2)|(chan[i].sync<<1)|1); } if (chan[i].keyOff && !isMuted[i]) { - sid.write(i*7+5,(chan[i].attack<<4)|(chan[i].decay)); - sid.write(i*7+6,(chan[i].sustain<<4)|(chan[i].release)); - sid.write(i*7+4,(isMuted[i]?0:(chan[i].wave<<4))|(chan[i].ring<<2)|(chan[i].sync<<1)|0); + rWrite(i*7+5,(chan[i].attack<<4)|(chan[i].decay)); + rWrite(i*7+6,(chan[i].sustain<<4)|(chan[i].release)); + rWrite(i*7+4,(isMuted[i]?0:(chan[i].wave<<4))|(chan[i].ring<<2)|(chan[i].sync<<1)|0); } - sid.write(i*7,chan[i].freq&0xff); - sid.write(i*7+1,chan[i].freq>>8); + rWrite(i*7,chan[i].freq&0xff); + rWrite(i*7+1,chan[i].freq>>8); if (chan[i].keyOn) chan[i].keyOn=false; if (chan[i].keyOff) chan[i].keyOff=false; chan[i].freqChanged=false; @@ -99,8 +101,8 @@ int DivPlatformC64::dispatch(DivCommand c) { chan[c.chan].keyOn=true; if (chan[c.chan].insChanged || chan[c.chan].resetDuty || ins->std.waveMacroLen>0) { chan[c.chan].duty=(ins->c64.duty*4095)/100; - sid.write(c.chan*7+2,chan[c.chan].duty&0xff); - sid.write(c.chan*7+3,chan[c.chan].duty>>8); + rWrite(c.chan*7+2,chan[c.chan].duty&0xff); + rWrite(c.chan*7+3,chan[c.chan].duty>>8); } if (chan[c.chan].insChanged) { chan[c.chan].wave=(ins->c64.noiseOn<<3)|(ins->c64.pulseOn<<2)|(ins->c64.sawOn<<1)|(ins->c64.triOn); @@ -181,12 +183,12 @@ int DivPlatformC64::dispatch(DivCommand c) { } case DIV_CMD_STD_NOISE_MODE: chan[c.chan].duty=(c.value*4095)/100; - sid.write(c.chan*7+2,chan[c.chan].duty&0xff); - sid.write(c.chan*7+3,chan[c.chan].duty>>8); + rWrite(c.chan*7+2,chan[c.chan].duty&0xff); + rWrite(c.chan*7+3,chan[c.chan].duty>>8); break; case DIV_CMD_WAVE: chan[c.chan].wave=c.value; - sid.write(c.chan*7+4,(chan[c.chan].wave<<4)|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|chan[c.chan].active); + rWrite(c.chan*7+4,(chan[c.chan].wave<<4)|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|chan[c.chan].active); break; case DIV_CMD_LEGATO: chan[c.chan].baseFreq=round(FREQ_BASE*pow(2.0f,((float)(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp-12):(0)))/12.0f))); @@ -236,8 +238,8 @@ int DivPlatformC64::dispatch(DivCommand c) { if (c.value&15) { DivInstrument* ins=parent->getIns(chan[c.chan].ins); chan[c.chan].duty=(ins->c64.duty*4095)/100; - sid.write(c.chan*7+2,chan[c.chan].duty&0xff); - sid.write(c.chan*7+3,chan[c.chan].duty>>8); + rWrite(c.chan*7+2,chan[c.chan].duty&0xff); + rWrite(c.chan*7+3,chan[c.chan].duty>>8); } chan[c.chan].resetDuty=c.value>>4; break; @@ -257,11 +259,11 @@ int DivPlatformC64::dispatch(DivCommand c) { break; case 4: chan[c.chan].ring=c.value; - sid.write(c.chan*7+4,(chan[c.chan].wave<<4)|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|chan[c.chan].active); + rWrite(c.chan*7+4,(chan[c.chan].wave<<4)|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|chan[c.chan].active); break; case 5: chan[c.chan].sync=c.value; - sid.write(c.chan*7+4,(chan[c.chan].wave<<4)|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|chan[c.chan].active); + rWrite(c.chan*7+4,(chan[c.chan].wave<<4)|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|chan[c.chan].active); break; case 6: filtControl&=7; @@ -280,7 +282,14 @@ int DivPlatformC64::dispatch(DivCommand c) { void DivPlatformC64::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - sid.write(ch*7+4,(isMuted[ch]?0:(chan[ch].wave<<4))|(chan[ch].ring<<2)|(chan[ch].sync<<1)|chan[ch].active); + rWrite(ch*7+4,(isMuted[ch]?0:(chan[ch].wave<<4))|(chan[ch].ring<<2)|(chan[ch].sync<<1)|chan[ch].active); +} + +void DivPlatformC64::forceIns() { + for (int i=0; i<3; i++) { + chan[i].insChanged=true; + chan[i].testWhen=0; + } } void DivPlatformC64::reset() { @@ -290,7 +299,7 @@ void DivPlatformC64::reset() { sid.reset(); - sid.write(0x18,0x0f); + rWrite(0x18,0x0f); filtControl=0; filtRes=0; diff --git a/src/engine/platform/c64.h b/src/engine/platform/c64.h index 67b0a3e28..9638bd57c 100644 --- a/src/engine/platform/c64.h +++ b/src/engine/platform/c64.h @@ -57,6 +57,7 @@ class DivPlatformC64: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void reset(); + void forceIns(); void tick(); void muteChannel(int ch, bool mute); void setPAL(bool pal); diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 653feb735..21e95c6f6 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -3,7 +3,7 @@ #include //#define rWrite(a,v) pendingWrites[a]=v; -#define rWrite(a,v) GB_apu_write(gb,a,v); +#define rWrite(a,v) if (!skipRegisterWrites) {GB_apu_write(gb,a,v);} #define FREQ_BASE 8015.85f @@ -286,6 +286,14 @@ int DivPlatformGB::dispatch(DivCommand c) { return 1; } +void DivPlatformGB::forceIns() { + for (int i=0; i<4; i++) { + chan[i].insChanged=true; + } + GB_apu_write(gb,0x25,procMute()); + updateWave(); +} + void DivPlatformGB::reset() { for (int i=0; i<4; i++) { chan[i]=DivPlatformGB::Channel(); diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index 6866b3ab1..7cb9624b7 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -41,6 +41,7 @@ class DivPlatformGB: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void reset(); + void forceIns(); void tick(); void muteChannel(int ch, bool mute); bool isStereo(); diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 89e38fff5..dd40bfa84 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -23,9 +23,9 @@ void DivPlatformGenesis::acquire(short* bufL, short* bufR, size_t start, size_t DivSample* s=parent->song.sample[dacSample]; if (!isMuted[5]) { if (s->depth==8) { - writes.emplace(0x2a,(unsigned char)s->rendData[dacPos++]+0x80); + immWrite(0x2a,(unsigned char)s->rendData[dacPos++]+0x80); } else { - writes.emplace(0x2a,((unsigned short)s->rendData[dacPos++]+0x8000)>>8); + immWrite(0x2a,((unsigned short)s->rendData[dacPos++]+0x8000)>>8); } } if (dacPos>=s->rendLength) { @@ -82,14 +82,14 @@ void DivPlatformGenesis::tick() { for (int i=0; i<6; i++) { if (i==2 && extMode) continue; if (chan[i].keyOn || chan[i].keyOff) { - writes.emplace(0x28,0x00|konOffs[i]); + immWrite(0x28,0x00|konOffs[i]); chan[i].keyOff=false; } } for (int i=0; i<512; i++) { if (pendingWrites[i]!=oldWrites[i]) { - writes.emplace(i,pendingWrites[i]&0xff); + immWrite(i,pendingWrites[i]&0xff); oldWrites[i]=pendingWrites[i]; } } @@ -99,12 +99,12 @@ void DivPlatformGenesis::tick() { if (chan[i].freqChanged) { chan[i].freq=(chan[i].baseFreq*(ONE_SEMITONE+chan[i].pitch))/ONE_SEMITONE; int freqt=toFreq(chan[i].freq); - writes.emplace(chanOffs[i]+0xa4,freqt>>8); - writes.emplace(chanOffs[i]+0xa0,freqt&0xff); + immWrite(chanOffs[i]+0xa4,freqt>>8); + immWrite(chanOffs[i]+0xa0,freqt&0xff); chan[i].freqChanged=false; } if (chan[i].keyOn) { - writes.emplace(0x28,0xf0|konOffs[i]); + immWrite(0x28,0xf0|konOffs[i]); chan[i].keyOn=false; } } @@ -171,6 +171,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { if (c.chan==5 && dacMode) { + if (skipRegisterWrites) break; dacSample=12*sampleBank+c.value%12; if (dacSample>=parent->song.sampleLen) { dacSample=-1; @@ -370,6 +371,15 @@ int DivPlatformGenesis::dispatch(DivCommand c) { return 1; } +void DivPlatformGenesis::forceIns() { + for (int i=0; i<10; i++) { + chan[i].insChanged=true; + } + if (dacMode) { + rWrite(0x2b,0x80); + } +} + void DivPlatformGenesis::reset() { while (!writes.empty()) writes.pop(); OPN2_Reset(&fm); @@ -394,7 +404,7 @@ void DivPlatformGenesis::reset() { extMode=false; // LFO - writes.emplace(0x22,0x08); + immWrite(0x22,0x08); delay=0; diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index b40c87c30..427c628cd 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -53,6 +53,7 @@ class DivPlatformGenesis: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void reset(); + void forceIns(); void tick(); void muteChannel(int ch, bool mute); bool isStereo(); diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index 63aa10aaa..980e637a8 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -231,7 +231,7 @@ void DivPlatformGenesisExt::tick() { } } if (writeSomething) { - writes.emplace(0x28,writeMask); + immWrite(0x28,writeMask); } } @@ -267,8 +267,8 @@ void DivPlatformGenesisExt::tick() { opChan[i].freqH=(opChan[i].freq>>8)&7; opChan[i].freqL=opChan[i].freq&0xff; } - writes.emplace(opChanOffsH[i],opChan[i].freqH); - writes.emplace(opChanOffsL[i],opChan[i].freqL); + immWrite(opChanOffsH[i],opChan[i].freqH); + immWrite(opChanOffsL[i],opChan[i].freqL); } writeMask|=opChan[i].active<<(4+i); if (opChan[i].keyOn) { @@ -278,7 +278,14 @@ void DivPlatformGenesisExt::tick() { } } if (writeNoteOn) { - writes.emplace(0x28,writeMask); + immWrite(0x28,writeMask); + } +} + +void DivPlatformGenesisExt::forceIns() { + DivPlatformGenesis::forceIns(); + for (int i=0; i<4; i++) { + opChan[i].insChanged=true; } } @@ -291,7 +298,7 @@ void DivPlatformGenesisExt::reset() { } // channel 3 mode - writes.emplace(0x27,0x40); + immWrite(0x27,0x40); extMode=true; } diff --git a/src/engine/platform/genesisext.h b/src/engine/platform/genesisext.h index 506a3e66b..de77c085f 100644 --- a/src/engine/platform/genesisext.h +++ b/src/engine/platform/genesisext.h @@ -18,6 +18,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { public: int dispatch(DivCommand c); void reset(); + void forceIns(); void tick(); void muteChannel(int ch, bool mute); bool keyOffAffectsArp(int ch); diff --git a/src/engine/platform/genesisshared.h b/src/engine/platform/genesisshared.h index cf0047e70..5036f3ed1 100644 --- a/src/engine/platform/genesisshared.h +++ b/src/engine/platform/genesisshared.h @@ -23,4 +23,5 @@ static int orderedOps[4]={ 0,2,1,3 }; -#define rWrite(a,v) pendingWrites[a]=v; +#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} +#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v);} diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index a26c24072..6575bf7b8 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -6,6 +6,8 @@ #define FREQ_BASE 3424.0f #define FREQ_BASE_PAL 3180.0f +#define rWrite(a,v) if (!skipRegisterWrites) {apu_wr_reg(a,v);} + void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t i=start; isong.sample[dacSample]; if (!isMuted[4]) { if (s->depth==8) { - apu_wr_reg(0x4011,((unsigned char)s->rendData[dacPos++]+0x80)>>1); + rWrite(0x4011,((unsigned char)s->rendData[dacPos++]+0x80)>>1); } else { - apu_wr_reg(0x4011,((unsigned short)s->rendData[dacPos++]+0x8000)>>9); + rWrite(0x4011,((unsigned short)s->rendData[dacPos++]+0x8000)>>9); } } if (dacPos>=s->rendLength) { @@ -72,10 +74,10 @@ void DivPlatformNES::tick() { chan[i].outVol=chan[i].std.vol-(15-chan[i].vol); if (chan[i].outVol<0) chan[i].outVol=0; if (i==2) { // triangle - apu_wr_reg(0x4000+i*4,(chan[i].outVol==0)?0:255); + rWrite(0x4000+i*4,(chan[i].outVol==0)?0:255); chan[i].freqChanged=true; } else { - apu_wr_reg(0x4000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6)); + rWrite(0x4000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6)); } } if (chan[i].std.hadArp) { @@ -107,7 +109,7 @@ void DivPlatformNES::tick() { chan[i].duty=chan[i].std.duty; if (i==3 && chan[i].duty>1) chan[i].duty=1; if (i!=2) { - apu_wr_reg(0x4000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6)); + rWrite(0x4000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6)); } if (i==3) { // noise chan[i].freqChanged=true; @@ -133,18 +135,18 @@ void DivPlatformNES::tick() { if (chan[i].keyOff) { //rWrite(16+i*5+2,8); if (i==2) { // triangle - apu_wr_reg(0x4000+i*4,0x00); + rWrite(0x4000+i*4,0x00); } else { - apu_wr_reg(0x4000+i*4,0x30); + rWrite(0x4000+i*4,0x30); } } if (i==3) { // noise - apu_wr_reg(0x4002+i*4,(chan[i].duty<<7)|chan[i].freq); - apu_wr_reg(0x4003+i*4,0xf0); + rWrite(0x4002+i*4,(chan[i].duty<<7)|chan[i].freq); + rWrite(0x4003+i*4,0xf0); } else { - apu_wr_reg(0x4002+i*4,chan[i].freq&0xff); + rWrite(0x4002+i*4,chan[i].freq&0xff); if ((chan[i].prevFreq>>8)!=(chan[i].freq>>8) || i==2) { - apu_wr_reg(0x4003+i*4,0xf8|(chan[i].freq>>8)); + rWrite(0x4003+i*4,0xf8|(chan[i].freq>>8)); } if (chan[i].freq!=65535 && chan[i].freq!=0) { chan[i].prevFreq=chan[i].freq; @@ -181,9 +183,9 @@ int DivPlatformNES::dispatch(DivCommand c) { chan[c.chan].keyOn=true; chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); if (c.chan==2) { - apu_wr_reg(0x4000+c.chan*4,0xff); + rWrite(0x4000+c.chan*4,0xff); } else { - apu_wr_reg(0x4000+c.chan*4,0x30|chan[c.chan].vol|((chan[c.chan].duty&3)<<6)); + rWrite(0x4000+c.chan*4,0x30|chan[c.chan].vol|((chan[c.chan].duty&3)<<6)); } break; case DIV_CMD_NOTE_OFF: @@ -204,9 +206,9 @@ int DivPlatformNES::dispatch(DivCommand c) { chan[c.chan].outVol=c.value; } if (c.chan==2) { - apu_wr_reg(0x4000+c.chan*4,0xff); + rWrite(0x4000+c.chan*4,0xff); } else { - apu_wr_reg(0x4000+c.chan*4,0x30|chan[c.chan].vol|((chan[c.chan].duty&3)<<6)); + rWrite(0x4000+c.chan*4,0x30|chan[c.chan].vol|((chan[c.chan].duty&3)<<6)); } } break; @@ -276,9 +278,16 @@ int DivPlatformNES::dispatch(DivCommand c) { void DivPlatformNES::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - apu_wr_reg(0x4015,(!isMuted[0])|((!isMuted[1])<<1)|((!isMuted[2])<<2)|((!isMuted[3])<<3)|((!isMuted[4])<<4)); + rWrite(0x4015,(!isMuted[0])|((!isMuted[1])<<1)|((!isMuted[2])<<2)|((!isMuted[3])<<3)|((!isMuted[4])<<4)); if (isMuted[4]) { - apu_wr_reg(0x4011,0); + rWrite(0x4011,0); + } +} + +void DivPlatformNES::forceIns() { + for (int i=0; i<5; i++) { + chan[i].insChanged=true; + chan[i].prevFreq=65535; } } @@ -297,9 +306,9 @@ void DivPlatformNES::reset() { apu.cpu_cycles=0; apu.cpu_opcode_cycle=0; - apu_wr_reg(0x4015,(!isMuted[0])|((!isMuted[1])<<1)|((!isMuted[2])<<2)|((!isMuted[3])<<3)|((!isMuted[4])<<4)); - apu_wr_reg(0x4001,0x08); - apu_wr_reg(0x4005,0x08); + rWrite(0x4015,(!isMuted[0])|((!isMuted[1])<<1)|((!isMuted[2])<<2)|((!isMuted[3])<<3)|((!isMuted[4])<<4)); + rWrite(0x4001,0x08); + rWrite(0x4005,0x08); } bool DivPlatformNES::keyOffAffectsArp(int ch) { diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index 115f39371..6a6fd9778 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -41,11 +41,11 @@ class DivPlatformNES: public DivDispatch { float freqBase; - void updateWave(); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void reset(); + void forceIns(); void tick(); void muteChannel(int ch, bool mute); bool keyOffAffectsArp(int ch); diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 63916c037..e7c163436 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -3,13 +3,15 @@ #include //#define rWrite(a,v) pendingWrites[a]=v; -#define rWrite(a,v) writes.emplace(a,v); +#define rWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v);} #define chWrite(c,a,v) \ - if (curChan!=c) { \ - curChan=c; \ - rWrite(0,curChan); \ - } \ - rWrite(a,v); + if (!skipRegisterWrites) { \ + if (curChan!=c) { \ + curChan=c; \ + rWrite(0,curChan); \ + } \ + rWrite(a,v); \ + } #define FREQ_BASE 1712.0f*2 @@ -268,6 +270,13 @@ void DivPlatformPCE::muteChannel(int ch, bool mute) { chWrite(ch,0x05,isMuted[ch]?0:chan[ch].pan); } +void DivPlatformPCE::forceIns() { + for (int i=0; i<6; i++) { + chan[i].insChanged=true; + updateWave(i); + } +} + void DivPlatformPCE::reset() { while (!writes.empty()) writes.pop(); for (int i=0; i<6; i++) { diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index f96ae6983..5c0bb3520 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -57,6 +57,7 @@ class DivPlatformPCE: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void reset(); + void forceIns(); void tick(); void muteChannel(int ch, bool mute); bool isStereo(); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 7167de51c..3d90383a8 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -104,14 +104,14 @@ void DivPlatformYM2610::tick() { for (int i=0; i<4; i++) { if (i==1 && extMode) continue; if (chan[i].keyOn || chan[i].keyOff) { - writes.emplace(0x28,0x00|konOffs[i]); + immWrite(0x28,0x00|konOffs[i]); chan[i].keyOff=false; } } for (int i=0; i<512; i++) { if (pendingWrites[i]!=oldWrites[i]) { - writes.emplace(i,pendingWrites[i]&0xff); + immWrite(i,pendingWrites[i]&0xff); oldWrites[i]=pendingWrites[i]; } } @@ -121,12 +121,12 @@ void DivPlatformYM2610::tick() { if (chan[i].freqChanged) { chan[i].freq=(chan[i].baseFreq*(ONE_SEMITONE+chan[i].pitch))/ONE_SEMITONE; int freqt=toFreq(chan[i].freq); - writes.emplace(chanOffs[i]+0xa4,freqt>>8); - writes.emplace(chanOffs[i]+0xa0,freqt&0xff); + immWrite(chanOffs[i]+0xa4,freqt>>8); + immWrite(chanOffs[i]+0xa0,freqt&0xff); chan[i].freqChanged=false; } if (chan[i].keyOn) { - writes.emplace(0x28,0xf0|konOffs[i]); + immWrite(0x28,0xf0|konOffs[i]); chan[i].keyOn=false; } } @@ -177,22 +177,23 @@ int DivPlatformYM2610::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { if (c.chan>6) { // ADPCM + if (skipRegisterWrites) break; if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { - writes.emplace(0x100,0x80|(1<<(c.chan-7))); - writes.emplace(0x110+c.chan-7,0); - writes.emplace(0x118+c.chan-7,0); - writes.emplace(0x120+c.chan-7,0); - writes.emplace(0x128+c.chan-7,0); + immWrite(0x100,0x80|(1<<(c.chan-7))); + immWrite(0x110+c.chan-7,0); + immWrite(0x118+c.chan-7,0); + immWrite(0x120+c.chan-7,0); + immWrite(0x128+c.chan-7,0); break; } DivSample* s=parent->song.sample[12*sampleBank+c.value%12]; - writes.emplace(0x110+c.chan-7,(s->rendOff>>8)&0xff); - writes.emplace(0x118+c.chan-7,s->rendOff>>16); + immWrite(0x110+c.chan-7,(s->rendOff>>8)&0xff); + immWrite(0x118+c.chan-7,s->rendOff>>16); int end=s->rendOff+s->adpcmRendLength-1; - writes.emplace(0x120+c.chan-7,(end>>8)&0xff); - writes.emplace(0x128+c.chan-7,end>>16); - writes.emplace(0x108+(c.chan-7),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); - writes.emplace(0x100,0x00|(1<<(c.chan-7))); + immWrite(0x120+c.chan-7,(end>>8)&0xff); + immWrite(0x128+c.chan-7,end>>16); + immWrite(0x108+(c.chan-7),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); + immWrite(0x100,0x00|(1<<(c.chan-7))); break; } DivInstrument* ins=parent->getIns(chan[c.chan].ins); @@ -247,7 +248,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { } case DIV_CMD_NOTE_OFF: if (c.chan>6) { - writes.emplace(0x100,0x80|(1<<(c.chan-7))); + immWrite(0x100,0x80|(1<<(c.chan-7))); break; } chan[c.chan].keyOff=true; @@ -258,7 +259,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { chan[c.chan].vol=c.value; DivInstrument* ins=parent->getIns(chan[c.chan].ins); if (c.chan>6) { // ADPCM - writes.emplace(0x108+(c.chan-7),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); + immWrite(0x108+(c.chan-7),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); break; } if (c.chan>3) { // PSG @@ -306,7 +307,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { break; } if (c.chan>6) { - writes.emplace(0x108+(c.chan-7),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); + immWrite(0x108+(c.chan-7),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); break; } if (c.chan>3) break; @@ -434,7 +435,8 @@ int DivPlatformYM2610::dispatch(DivCommand c) { break; case DIV_CMD_AY_ENVELOPE_SET: if (c.chan<4 || c.chan>6) break; - rWrite(0x0d,c.value>>4); + ayEnvMode=c.value>>4; + rWrite(0x0d,ayEnvMode); if (c.value&15) { chan[c.chan].psgMode|=4; } else { @@ -450,15 +452,15 @@ int DivPlatformYM2610::dispatch(DivCommand c) { if (c.chan<4 || c.chan>6) break; ayEnvPeriod&=0xff00; ayEnvPeriod|=c.value; - writes.emplace(0x0b,ayEnvPeriod); - writes.emplace(0x0c,ayEnvPeriod>>8); + immWrite(0x0b,ayEnvPeriod); + immWrite(0x0c,ayEnvPeriod>>8); break; case DIV_CMD_AY_ENVELOPE_HIGH: if (c.chan<4 || c.chan>6) break; ayEnvPeriod&=0xff; ayEnvPeriod|=c.value<<8; - writes.emplace(0x0b,ayEnvPeriod); - writes.emplace(0x0c,ayEnvPeriod>>8); + immWrite(0x0b,ayEnvPeriod); + immWrite(0x0c,ayEnvPeriod>>8); break; case DIV_ALWAYS_SET_VOLUME: return 0; @@ -486,7 +488,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { void DivPlatformYM2610::muteChannel(int ch, bool mute) { isMuted[ch]=mute; if (ch>6) { // ADPCM - writes.emplace(0x108+(ch-7),isMuted[ch]?0:((chan[ch].pan<<6)|chan[ch].vol)); + immWrite(0x108+(ch-7),isMuted[ch]?0:((chan[ch].pan<<6)|chan[ch].vol)); return; } if (ch>3) { // PSG @@ -502,6 +504,15 @@ void DivPlatformYM2610::muteChannel(int ch, bool mute) { rWrite(chanOffs[ch]+0xb4,(isMuted[ch]?0:(chan[ch].pan<<6))|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); } +void DivPlatformYM2610::forceIns() { + for (int i=0; i<13; i++) { + chan[i].insChanged=true; + } + immWrite(0x0b,ayEnvPeriod); + immWrite(0x0c,ayEnvPeriod>>8); + immWrite(0x0d,ayEnvMode); +} + void DivPlatformYM2610::reset() { while (!writes.empty()) writes.pop(); fm->reset(); @@ -531,16 +542,17 @@ void DivPlatformYM2610::reset() { dacSample=-1; sampleBank=0; ayEnvPeriod=0; + ayEnvMode=0; delay=0; extMode=false; // LFO - writes.emplace(0x22,0x08); + immWrite(0x22,0x08); // PCM volume - writes.emplace(0x101,0x3f); + immWrite(0x101,0x3f); } bool DivPlatformYM2610::isStereo() { diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index 65199efaf..edcc38b35 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -54,6 +54,7 @@ class DivPlatformYM2610: public DivDispatch { short oldWrites[512]; short pendingWrites[512]; + unsigned char ayEnvMode; unsigned short ayEnvPeriod; int octave(int freq); @@ -63,6 +64,7 @@ class DivPlatformYM2610: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void reset(); + void forceIns(); void tick(); void muteChannel(int ch, bool mute); bool isStereo(); diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index b392e9507..3505c9789 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -207,7 +207,7 @@ void DivPlatformYM2610Ext::tick() { } } if (writeSomething) { - writes.emplace(0x28,writeMask); + immWrite(0x28,writeMask); } } @@ -221,8 +221,8 @@ void DivPlatformYM2610Ext::tick() { int freqt=toFreq(opChan[i].freq); opChan[i].freqH=freqt>>8; opChan[i].freqL=freqt&0xff; - writes.emplace(opChanOffsH[i],opChan[i].freqH); - writes.emplace(opChanOffsL[i],opChan[i].freqL); + immWrite(opChanOffsH[i],opChan[i].freqH); + immWrite(opChanOffsL[i],opChan[i].freqL); opChan[i].freqChanged=false; } writeMask|=opChan[i].active<<(4+i); @@ -233,7 +233,7 @@ void DivPlatformYM2610Ext::tick() { } } if (writeNoteOn) { - writes.emplace(0x28,writeMask); + immWrite(0x28,writeMask); } } @@ -261,6 +261,13 @@ void DivPlatformYM2610Ext::muteChannel(int ch, bool mute) { } } +void DivPlatformYM2610Ext::forceIns() { + DivPlatformYM2610::forceIns(); + for (int i=0; i<4; i++) { + opChan[i].insChanged=true; + } +} + void DivPlatformYM2610Ext::reset() { DivPlatformYM2610::reset(); @@ -270,7 +277,7 @@ void DivPlatformYM2610Ext::reset() { } // channel 2 mode - writes.emplace(0x27,0x40); + immWrite(0x27,0x40); extMode=true; } diff --git a/src/engine/platform/ym2610ext.h b/src/engine/platform/ym2610ext.h index b2050a1df..46c085505 100644 --- a/src/engine/platform/ym2610ext.h +++ b/src/engine/platform/ym2610ext.h @@ -18,6 +18,7 @@ class DivPlatformYM2610Ext: public DivPlatformYM2610 { public: int dispatch(DivCommand c); void reset(); + void forceIns(); void tick(); void muteChannel(int ch, bool mute); bool keyOffAffectsArp(int ch); diff --git a/src/engine/platform/ym2610shared.h b/src/engine/platform/ym2610shared.h index e02785248..79c16102c 100644 --- a/src/engine/platform/ym2610shared.h +++ b/src/engine/platform/ym2610shared.h @@ -23,7 +23,8 @@ static int orderedOps[4]={ 0,2,1,3 }; -#define rWrite(a,v) pendingWrites[a]=v; +#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} +#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v);} #define FM_FREQ_BASE 622.0f #define PSG_FREQ_BASE 7640.0f