diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index e8a28512..6ee69145 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1015,9 +1015,17 @@ void DivEngine::renderSamples() { sPreview.pos=0; sPreview.dir=false; + // step 0: make sample format mask + unsigned int formatMask=1U<<16; // 16-bit is always on + for (int i=0; isampleFormatMask; + } + // step 1: render samples for (int i=0; irender(); + song.sample[i]->render(formatMask); } // step 2: render samples to dispatch diff --git a/src/engine/engine.h b/src/engine/engine.h index ff01d2e1..0e56b12f 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -227,6 +227,7 @@ struct DivSysDef { int channels; bool isFM, isSTD, isCompound; unsigned int vgmVersion; + unsigned int sampleFormatMask; const char* chanNames[DIV_MAX_CHANS]; const char* chanShortNames[DIV_MAX_CHANS]; int chanTypes[DIV_MAX_CHANS]; @@ -237,7 +238,7 @@ struct DivSysDef { const EffectHandlerMap postEffectHandlers; DivSysDef( const char* sysName, const char* sysNameJ, unsigned char fileID, unsigned char fileID_DMF, int chans, - bool isFMChip, bool isSTDChip, unsigned int vgmVer, bool compound, const char* desc, + bool isFMChip, bool isSTDChip, unsigned int vgmVer, bool compound, unsigned int formatMask, const char* desc, std::initializer_list chNames, std::initializer_list chShortNames, std::initializer_list chTypes, @@ -255,6 +256,7 @@ struct DivSysDef { isSTD(isSTDChip), isCompound(compound), vgmVersion(vgmVer), + sampleFormatMask(formatMask), effectHandlers(fxHandlers_), postEffectHandlers(postFxHandlers_) { memset(chanNames,0,DIV_MAX_CHANS*sizeof(void*)); diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index ad133c08..2719f0bb 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -115,7 +115,7 @@ const unsigned char dacLogTableAY[256]={ void DivPlatformAY8910::runDAC() { for (int i=0; i<3; i++) { - if (chan[i].active && chan[i].psgMode.dac && chan[i].dac.sample!=-1) { + if (chan[i].active && chan[i].currPSGMode.dac && chan[i].dac.sample!=-1) { chan[i].dac.period+=chan[i].dac.rate; bool end=false; bool changed=false; @@ -215,22 +215,22 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l void DivPlatformAY8910::updateOutSel(bool immediate) { if (immediate) { immWrite(0x07, - ~((chan[0].psgMode.getTone())| - ((chan[1].psgMode.getTone())<<1)| - ((chan[2].psgMode.getTone())<<2)| - ((chan[0].psgMode.getNoise())<<2)| - ((chan[1].psgMode.getNoise())<<3)| - ((chan[2].psgMode.getNoise())<<4)| + ~((chan[0].currPSGMode.getTone())| + ((chan[1].currPSGMode.getTone())<<1)| + ((chan[2].currPSGMode.getTone())<<2)| + ((chan[0].currPSGMode.getNoise())<<2)| + ((chan[1].currPSGMode.getNoise())<<3)| + ((chan[2].currPSGMode.getNoise())<<4)| ((!ioPortA)<<6)| ((!ioPortB)<<7))); } else { rWrite(0x07, - ~((chan[0].psgMode.getTone())| - ((chan[1].psgMode.getTone())<<1)| - ((chan[2].psgMode.getTone())<<2)| - ((chan[0].psgMode.getNoise())<<2)| - ((chan[1].psgMode.getNoise())<<3)| - ((chan[2].psgMode.getNoise())<<4)| + ~((chan[0].currPSGMode.getTone())| + ((chan[1].currPSGMode.getTone())<<1)| + ((chan[2].currPSGMode.getTone())<<2)| + ((chan[0].currPSGMode.getNoise())<<2)| + ((chan[1].currPSGMode.getNoise())<<3)| + ((chan[2].currPSGMode.getNoise())<<4)| ((!ioPortA)<<6)| ((!ioPortB)<<7))); } @@ -243,13 +243,13 @@ void DivPlatformAY8910::tick(bool sysTick) { if (chan[i].std.vol.had) { chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15)); if (chan[i].outVol<0) chan[i].outVol=0; - if (!chan[i].psgMode.dac) { + if (!chan[i].nextPSGMode.dac) { if (isMuted[i]) { rWrite(0x08+i,0); - } else if (intellivision && (chan[i].psgMode.getEnvelope())) { + } else if (intellivision && (chan[i].nextPSGMode.getEnvelope())) { rWrite(0x08+i,(chan[i].outVol&0xc)<<2); } else { - rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode.getEnvelope())<<2)); + rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].nextPSGMode.getEnvelope())<<2)); } } } @@ -263,14 +263,17 @@ void DivPlatformAY8910::tick(bool sysTick) { rWrite(0x06,31-chan[i].std.duty.val); } if (chan[i].std.wave.had) { - if (!chan[i].psgMode.dac) { - chan[i].psgMode.val=(chan[i].std.wave.val+1)&7; + if (!chan[i].nextPSGMode.dac) { + chan[i].nextPSGMode.val=(chan[i].std.wave.val+1)&7; + if (chan[i].active) { + chan[i].currPSGMode.val=chan[i].nextPSGMode.val; + } if (isMuted[i]) { rWrite(0x08+i,0); - } else if (intellivision && (chan[i].psgMode.getEnvelope())) { + } else if (intellivision && (chan[i].nextPSGMode.getEnvelope())) { rWrite(0x08+i,(chan[i].outVol&0xc)<<2); } else { - rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode.getEnvelope())<<2)); + rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].nextPSGMode.getEnvelope())<<2)); } } } @@ -285,7 +288,7 @@ void DivPlatformAY8910::tick(bool sysTick) { } if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { - if (chan[i].psgMode.dac) { + if (chan[i].nextPSGMode.dac) { if (dumpWrites) addWrite(0xffff0002+(i<<8),0); DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AY); chan[i].dac.sample=ins->amiga.getSample(chan[i].note); @@ -336,12 +339,12 @@ void DivPlatformAY8910::tick(bool sysTick) { if (chan[i].keyOn) { //rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63))); //rWrite(16+i*5+2,((chan[i].vol<<4))|(ins->gb.envLen&7)|((ins->gb.envDir&1)<<3)); - if (chan[i].psgMode.val==0) { - chan[i].psgMode.val=1; + if (!chan[i].nextPSGMode.dac) { + chan[i].currPSGMode.val=chan[i].nextPSGMode.val; } } if (chan[i].keyOff) { - chan[i].psgMode.val=0; + chan[i].currPSGMode.val=0; rWrite(0x08+i,0); } rWrite((i)<<1,chan[i].freq&0xff); @@ -392,11 +395,11 @@ int DivPlatformAY8910::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY); if (!parent->song.disableSampleMacro && (ins->type==DIV_INS_AMIGA || ins->amiga.useSample)) { - chan[c.chan].psgMode.dac=true; + chan[c.chan].nextPSGMode.dac=true; } else if (chan[c.chan].dac.furnaceDAC) { - chan[c.chan].psgMode.dac=false; + chan[c.chan].nextPSGMode.dac=false; } - if (chan[c.chan].psgMode.dac) { + if (chan[c.chan].nextPSGMode.dac) { if (skipRegisterWrites) break; if (!parent->song.disableSampleMacro && (ins->type==DIV_INS_AMIGA || ins->amiga.useSample)) { chan[c.chan].dac.sample=ins->amiga.getSample(c.value); @@ -445,6 +448,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) { } chan[c.chan].dac.furnaceDAC=false; } + chan[c.chan].currPSGMode.dac=chan[c.chan].nextPSGMode.dac; break; } if (c.value!=DIV_NOTE_NULL) { @@ -458,13 +462,13 @@ int DivPlatformAY8910::dispatch(DivCommand c) { if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } - if (!chan[c.chan].psgMode.dac) { + if (!chan[c.chan].nextPSGMode.dac) { if (isMuted[c.chan]) { rWrite(0x08+c.chan,0); - } else if (intellivision && (chan[c.chan].psgMode.getEnvelope())) { + } else if (intellivision && (chan[c.chan].nextPSGMode.getEnvelope())) { rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2); } else { - rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode.getEnvelope())<<2)); + rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].nextPSGMode.getEnvelope())<<2)); } } break; @@ -472,7 +476,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) { case DIV_CMD_NOTE_OFF: chan[c.chan].dac.sample=-1; if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); - chan[c.chan].psgMode.dac=false; + chan[c.chan].nextPSGMode.dac=false; chan[c.chan].keyOff=true; chan[c.chan].active=false; chan[c.chan].macroInit(NULL); @@ -486,15 +490,15 @@ int DivPlatformAY8910::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } - if (!chan[c.chan].psgMode.dac) { + if (!chan[c.chan].nextPSGMode.dac) { if (isMuted[c.chan]) { rWrite(0x08+c.chan,0); } else { if (chan[c.chan].active) { - if (intellivision && (chan[c.chan].psgMode.getEnvelope())) { + if (intellivision && (chan[c.chan].nextPSGMode.getEnvelope())) { rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2); } else { - rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode.getEnvelope())<<2)); + rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].nextPSGMode.getEnvelope())<<2)); } } } @@ -545,16 +549,19 @@ int DivPlatformAY8910::dispatch(DivCommand c) { break; } case DIV_CMD_STD_NOISE_MODE: - if (!chan[c.chan].psgMode.dac) { + if (!chan[c.chan].nextPSGMode.dac) { if (c.value<16) { - chan[c.chan].psgMode.val=(c.value+1)&7; + chan[c.chan].nextPSGMode.val=(c.value+1)&7; + if (chan[c.chan].active) { + chan[c.chan].currPSGMode.val=chan[c.chan].nextPSGMode.val; + } if (isMuted[c.chan]) { rWrite(0x08+c.chan,0); } else if (chan[c.chan].active) { - if (intellivision && (chan[c.chan].psgMode.getEnvelope())) { + if (intellivision && (chan[c.chan].nextPSGMode.getEnvelope())) { rWrite(0x08+c.chan,(chan[c.chan].outVol&0xc)<<2); } else { - rWrite(0x08+c.chan,(chan[c.chan].outVol&15)|((chan[c.chan].psgMode.getEnvelope())<<2)); + rWrite(0x08+c.chan,(chan[c.chan].outVol&15)|((chan[c.chan].nextPSGMode.getEnvelope())<<2)); } } } @@ -567,16 +574,19 @@ int DivPlatformAY8910::dispatch(DivCommand c) { ayEnvMode=c.value>>4; rWrite(0x0d,ayEnvMode); if (c.value&15) { - chan[c.chan].psgMode.envelope|=1; + chan[c.chan].nextPSGMode.envelope|=1; } else { - chan[c.chan].psgMode.envelope&=~1; + chan[c.chan].nextPSGMode.envelope&=~1; + } + if (!chan[c.chan].nextPSGMode.dac && chan[c.chan].active) { + chan[c.chan].currPSGMode.val=chan[c.chan].nextPSGMode.val; } if (isMuted[c.chan]) { rWrite(0x08+c.chan,0); - } else if (intellivision && (chan[c.chan].psgMode.getEnvelope())) { + } else if (intellivision && (chan[c.chan].nextPSGMode.getEnvelope())) { rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2); } else { - rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode.getEnvelope())<<2)); + rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].nextPSGMode.getEnvelope())<<2)); } break; case DIV_CMD_AY_ENVELOPE_LOW: @@ -614,7 +624,10 @@ int DivPlatformAY8910::dispatch(DivCommand c) { immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal)); break; case DIV_CMD_SAMPLE_MODE: - chan[c.chan].psgMode.dac=(c.value>0)?1:0; + chan[c.chan].nextPSGMode.dac=(c.value>0)?1:0; + if (chan[c.chan].active) { + chan[c.chan].currPSGMode.dac=chan[c.chan].nextPSGMode.dac; + } break; case DIV_CMD_SAMPLE_BANK: sampleBank=c.value; @@ -650,13 +663,13 @@ void DivPlatformAY8910::muteChannel(int ch, bool mute) { isMuted[ch]=mute; if (isMuted[ch]) { rWrite(0x08+ch,0); - } else if (chan[ch].active && chan[ch].psgMode.dac) { + } else if (chan[ch].active && chan[ch].nextPSGMode.dac) { rWrite(0x08+ch,chan[ch].dac.out); } else { - if (intellivision && (chan[ch].psgMode.getEnvelope()) && chan[ch].active) { + if (intellivision && (chan[ch].nextPSGMode.getEnvelope()) && chan[ch].active) { rWrite(0x08+ch,(chan[ch].vol&0xc)<<2); } else if (chan[ch].active) { - rWrite(0x08+ch,(chan[ch].outVol&15)|((chan[ch].psgMode.getEnvelope())<<2)); + rWrite(0x08+ch,(chan[ch].outVol&15)|((chan[ch].nextPSGMode.getEnvelope())<<2)); } } } diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index e359b3d7..6a8dbc3d 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -54,9 +54,11 @@ class DivPlatformAY8910: public DivDispatch { return dac?0:(envelope<<2); } - PSGMode(): - val(1) {} - } psgMode; + PSGMode(unsigned char v=0): + val(v) {} + }; + PSGMode currPSGMode; + PSGMode nextPSGMode; struct DAC { int sample, rate, period, pos, out; @@ -83,7 +85,8 @@ class DivPlatformAY8910: public DivDispatch { pitch2=0; } Channel(): - psgMode(PSGMode()), + currPSGMode(PSGMode(0)), + nextPSGMode(PSGMode(1)), dac(DAC()), freq(0), baseFreq(0), diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 412d53f9..8bb34ae9 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -111,7 +111,7 @@ const unsigned char dacLogTableAY8930[256]={ void DivPlatformAY8930::runDAC() { for (int i=0; i<3; i++) { - if (chan[i].active && chan[i].psgMode.dac && chan[i].dac.sample!=-1) { + if (chan[i].active && chan[i].currPSGMode.dac && chan[i].dac.sample!=-1) { chan[i].dac.period+=chan[i].dac.rate; bool end=false; bool changed=false; @@ -195,22 +195,22 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l void DivPlatformAY8930::updateOutSel(bool immediate) { if (immediate) { immWrite(0x07, - ~((chan[0].psgMode.getTone())| - ((chan[1].psgMode.getTone())<<1)| - ((chan[2].psgMode.getTone())<<2)| - ((chan[0].psgMode.getNoise())<<2)| - ((chan[1].psgMode.getNoise())<<3)| - ((chan[2].psgMode.getNoise())<<4)| + ~((chan[0].currPSGMode.getTone())| + ((chan[1].currPSGMode.getTone())<<1)| + ((chan[2].currPSGMode.getTone())<<2)| + ((chan[0].currPSGMode.getNoise())<<2)| + ((chan[1].currPSGMode.getNoise())<<3)| + ((chan[2].currPSGMode.getNoise())<<4)| ((!ioPortA)<<6)| ((!ioPortB)<<7))); } else { rWrite(0x07, - ~((chan[0].psgMode.getTone())| - ((chan[1].psgMode.getTone())<<1)| - ((chan[2].psgMode.getTone())<<2)| - ((chan[0].psgMode.getNoise())<<2)| - ((chan[1].psgMode.getNoise())<<3)| - ((chan[2].psgMode.getNoise())<<4)| + ~((chan[0].currPSGMode.getTone())| + ((chan[1].currPSGMode.getTone())<<1)| + ((chan[2].currPSGMode.getTone())<<2)| + ((chan[0].currPSGMode.getNoise())<<2)| + ((chan[1].currPSGMode.getNoise())<<3)| + ((chan[2].currPSGMode.getNoise())<<4)| ((!ioPortA)<<6)| ((!ioPortB)<<7))); } @@ -235,11 +235,11 @@ void DivPlatformAY8930::tick(bool sysTick) { if (chan[i].std.vol.had) { chan[i].outVol=MIN(31,chan[i].std.vol.val)-(31-(chan[i].vol&31)); if (chan[i].outVol<0) chan[i].outVol=0; - if (!chan[i].psgMode.dac) { + if (!chan[i].nextPSGMode.dac) { if (isMuted[i]) { rWrite(0x08+i,0); } else { - rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode.getEnvelope())<<3)); + rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].nextPSGMode.getEnvelope())<<3)); } } } @@ -253,13 +253,16 @@ void DivPlatformAY8930::tick(bool sysTick) { rWrite(0x06,chan[i].std.duty.val); } if (chan[i].std.wave.had) { - if (!chan[i].psgMode.dac) { - chan[i].psgMode.val=(chan[i].std.wave.val+1)&7; - if (isMuted[i]) { - rWrite(0x08+i,0); - } else { - rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode.getEnvelope())<<3)); - } + if (!chan[i].nextPSGMode.dac) { + chan[i].nextPSGMode.val=(chan[i].std.wave.val+1)&7; + if (chan[i].active) { + chan[i].currPSGMode.val=chan[i].nextPSGMode.val; + } + if (isMuted[i]) { + rWrite(0x08+i,0); + } else { + rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].nextPSGMode.getEnvelope())<<3)); + } } } if (chan[i].std.pitch.had) { @@ -273,7 +276,7 @@ void DivPlatformAY8930::tick(bool sysTick) { } if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { - if (chan[i].psgMode.dac) { + if (chan[i].nextPSGMode.dac) { if (dumpWrites) addWrite(0xffff0002+(i<<8),0); DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AY8930); chan[i].dac.sample=ins->amiga.getSample(chan[i].note); @@ -333,8 +336,8 @@ void DivPlatformAY8930::tick(bool sysTick) { } if (chan[i].freq>65535) chan[i].freq=65535; if (chan[i].keyOn) { - if (chan[i].psgMode.val==0) { - chan[i].psgMode.val=1; + if (!chan[i].nextPSGMode.dac) { + chan[i].currPSGMode.val=chan[i].nextPSGMode.val; } if (chan[i].insChanged) { if (!chan[i].std.ex1.will) immWrite(0x16+i,chan[i].duty); @@ -342,7 +345,7 @@ void DivPlatformAY8930::tick(bool sysTick) { } } if (chan[i].keyOff) { - chan[i].psgMode.val=0; + chan[i].currPSGMode.val=0; rWrite(0x08+i,0); } rWrite((i)<<1,chan[i].freq&0xff); @@ -393,11 +396,11 @@ int DivPlatformAY8930::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY8930); if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { - chan[c.chan].psgMode.dac=true; + chan[c.chan].nextPSGMode.dac=true; } else if (chan[c.chan].dac.furnaceDAC) { - chan[c.chan].psgMode.dac=false; + chan[c.chan].nextPSGMode.dac=false; } - if (chan[c.chan].psgMode.dac) { + if (chan[c.chan].nextPSGMode.dac) { if (skipRegisterWrites) break; if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { chan[c.chan].dac.sample=ins->amiga.getSample(c.value); @@ -446,6 +449,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) { } chan[c.chan].dac.furnaceDAC=false; } + chan[c.chan].currPSGMode.dac=chan[c.chan].nextPSGMode.dac; break; } if (c.value!=DIV_NOTE_NULL) { @@ -459,11 +463,11 @@ int DivPlatformAY8930::dispatch(DivCommand c) { if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } - if (!chan[c.chan].psgMode.dac) { + if (!chan[c.chan].nextPSGMode.dac) { if (isMuted[c.chan]) { rWrite(0x08+c.chan,0); } else { - rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode.getEnvelope())<<3)); + rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].nextPSGMode.getEnvelope())<<3)); } } break; @@ -471,7 +475,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) { case DIV_CMD_NOTE_OFF: chan[c.chan].dac.sample=-1; if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); - chan[c.chan].psgMode.dac=false; + chan[c.chan].nextPSGMode.dac=false; chan[c.chan].keyOff=true; chan[c.chan].active=false; chan[c.chan].macroInit(NULL); @@ -485,11 +489,11 @@ int DivPlatformAY8930::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } - if (!chan[c.chan].psgMode.dac) { + if (!chan[c.chan].nextPSGMode.dac) { if (isMuted[c.chan]) { rWrite(0x08+c.chan,0); } else { - if (chan[c.chan].active) rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode.getEnvelope())<<3)); + if (chan[c.chan].active) rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].nextPSGMode.getEnvelope())<<3)); } break; } @@ -540,12 +544,15 @@ int DivPlatformAY8930::dispatch(DivCommand c) { } case DIV_CMD_STD_NOISE_MODE: if (c.value<0x10) { - if (!chan[c.chan].psgMode.dac) { - chan[c.chan].psgMode.val=(c.value+1)&7; + if (!chan[c.chan].nextPSGMode.dac) { + chan[c.chan].nextPSGMode.val=(c.value+1)&7; + if (chan[c.chan].active) { + chan[c.chan].currPSGMode.val=chan[c.chan].nextPSGMode.val; + } if (isMuted[c.chan]) { rWrite(0x08+c.chan,0); } else if (chan[c.chan].active) { - rWrite(0x08+c.chan,(chan[c.chan].outVol&31)|((chan[c.chan].psgMode.getEnvelope())<<3)); + rWrite(0x08+c.chan,(chan[c.chan].outVol&31)|((chan[c.chan].nextPSGMode.getEnvelope())<<3)); } } } else { @@ -560,14 +567,17 @@ int DivPlatformAY8930::dispatch(DivCommand c) { chan[c.chan].envelope.mode=c.value>>4; rWrite(regMode[c.chan],chan[c.chan].envelope.mode); if (c.value&15) { - chan[c.chan].psgMode.envelope|=1; + chan[c.chan].nextPSGMode.envelope|=1; } else { - chan[c.chan].psgMode.envelope&=~1; + chan[c.chan].nextPSGMode.envelope&=~1; + } + if (!chan[c.chan].nextPSGMode.dac && chan[c.chan].active) { + chan[c.chan].currPSGMode.val=chan[c.chan].nextPSGMode.val; } if (isMuted[c.chan]) { rWrite(0x08+c.chan,0); } else { - rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode.getEnvelope())<<3)); + rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].nextPSGMode.getEnvelope())<<3)); } break; case DIV_CMD_AY_ENVELOPE_LOW: @@ -616,7 +626,8 @@ int DivPlatformAY8930::dispatch(DivCommand c) { immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal)); break; case DIV_CMD_SAMPLE_MODE: - chan[c.chan].psgMode.dac=(c.value>0)?1:0; + chan[c.chan].nextPSGMode.dac=(c.value>0)?1:0; + chan[c.chan].currPSGMode.dac=chan[c.chan].nextPSGMode.dac; break; case DIV_CMD_SAMPLE_BANK: sampleBank=c.value; @@ -651,10 +662,10 @@ void DivPlatformAY8930::muteChannel(int ch, bool mute) { if (isMuted[ch]) { rWrite(0x08+ch,0); } else if (chan[ch].active) { - if (chan[ch].psgMode.dac) { + if (chan[ch].nextPSGMode.dac) { rWrite(0x08+ch,chan[ch].dac.out&31); } else { - rWrite(0x08+ch,(chan[ch].outVol&31)|((chan[ch].psgMode.getEnvelope())<<3)); + rWrite(0x08+ch,(chan[ch].outVol&31)|((chan[ch].nextPSGMode.getEnvelope())<<3)); } } } diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index fdfaa7a6..2ec12c31 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -62,9 +62,11 @@ class DivPlatformAY8930: public DivDispatch { return dac?0:(envelope<<2); } - PSGMode(): - val(1) {} - } psgMode; + PSGMode(unsigned char v=0): + val(v) {} + }; + PSGMode currPSGMode; + PSGMode nextPSGMode; struct DAC { int sample, rate, period, pos, out; @@ -92,7 +94,8 @@ class DivPlatformAY8930: public DivDispatch { } Channel(): envelope(Envelope()), - psgMode(PSGMode()), + currPSGMode(PSGMode(0)), + nextPSGMode(PSGMode(1)), dac(DAC()), freq(0), baseFreq(0), diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index 6839a370..f4a0d98b 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -814,7 +814,9 @@ bool DivSample::resample(double r, int filter) { return false; } -void DivSample::render() { +#define NOT_IN_FORMAT(x) (depth!=x && formatMask&(1U<<(unsigned int)x)) + +void DivSample::render(unsigned int formatMask) { // step 1: convert to 16-bit if needed if (depth!=DIV_SAMPLE_DEPTH_16BIT) { if (!initInternal(DIV_SAMPLE_DEPTH_16BIT,samples)) return; @@ -863,7 +865,7 @@ void DivSample::render() { } // step 2: render to other formats - if (depth!=DIV_SAMPLE_DEPTH_1BIT) { // 1-bit + if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_1BIT)) { // 1-bit if (!initInternal(DIV_SAMPLE_DEPTH_1BIT,samples)) return; for (unsigned int i=0; i0) { @@ -871,7 +873,7 @@ void DivSample::render() { } } } - if (depth!=DIV_SAMPLE_DEPTH_1BIT_DPCM) { // DPCM + if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_1BIT_DPCM)) { // DPCM if (!initInternal(DIV_SAMPLE_DEPTH_1BIT_DPCM,samples)) return; int accum=63; for (unsigned int i=0; i127) accum=127; } } - if (depth!=DIV_SAMPLE_DEPTH_YMZ_ADPCM) { // YMZ ADPCM + if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_YMZ_ADPCM)) { // YMZ ADPCM if (!initInternal(DIV_SAMPLE_DEPTH_YMZ_ADPCM,samples)) return; ymz_encode(data16,dataZ,(samples+7)&(~0x7)); } - if (depth!=DIV_SAMPLE_DEPTH_QSOUND_ADPCM) { // QSound ADPCM + if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_QSOUND_ADPCM)) { // QSound ADPCM if (!initInternal(DIV_SAMPLE_DEPTH_QSOUND_ADPCM,samples)) return; bs_encode(data16,dataQSoundA,samples); } // TODO: pad to 256. - if (depth!=DIV_SAMPLE_DEPTH_ADPCM_A) { // ADPCM-A + if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_ADPCM_A)) { // ADPCM-A if (!initInternal(DIV_SAMPLE_DEPTH_ADPCM_A,samples)) return; yma_encode(data16,dataA,(samples+511)&(~0x1ff)); } - if (depth!=DIV_SAMPLE_DEPTH_ADPCM_B) { // ADPCM-B + if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_ADPCM_B)) { // ADPCM-B if (!initInternal(DIV_SAMPLE_DEPTH_ADPCM_B,samples)) return; ymb_encode(data16,dataB,(samples+511)&(~0x1ff)); } - if (depth!=DIV_SAMPLE_DEPTH_8BIT) { // 8-bit PCM + if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_8BIT)) { // 8-bit PCM if (!initInternal(DIV_SAMPLE_DEPTH_8BIT,samples)) return; for (unsigned int i=0; i>8; } } - if (depth!=DIV_SAMPLE_DEPTH_BRR) { // BRR + if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_BRR)) { // BRR if (!initInternal(DIV_SAMPLE_DEPTH_BRR,samples)) return; brrEncode(data16,dataBRR,(samples+15)&(~15),loop?loopStart:-1); } - if (depth!=DIV_SAMPLE_DEPTH_VOX) { // VOX + if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_VOX)) { // VOX if (!initInternal(DIV_SAMPLE_DEPTH_VOX,samples)) return; oki_encode(data16,dataVOX,samples); } diff --git a/src/engine/sample.h b/src/engine/sample.h index 3a054304..30b4c0dd 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -248,7 +248,7 @@ struct DivSample { /** * initialize the rest of sample formats for this sample. */ - void render(); + void render(unsigned int formatMask=0xffffffff); /** * get the sample data for the current depth. diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index cd8d369a..7cc9d65b 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -594,8 +594,9 @@ void DivEngine::registerSystems() { // SysDefs + // this chip uses YMZ ADPCM, but the emulator uses ADPCM-B because I got it wrong back then. sysDefs[DIV_SYSTEM_YMU759]=new DivSysDef( - "Yamaha YMU759 (MA-2)", NULL, 0x01, 0x01, 17, true, false, 0, false, + "Yamaha YMU759 (MA-2)", NULL, 0x01, 0x01, 17, true, false, 0, false, (1U<", {}, {}, {}, {} ); sysDefs[DIV_SYSTEM_GENESIS_EXT]=new DivSysDef( - "Sega Genesis Extended Channel 3", NULL, 0x42, 0x42, 13, true, true, 0, true, + "Sega Genesis Extended Channel 3", NULL, 0x42, 0x42, 13, true, true, 0, true, 0, "", {}, {}, {}, {} ); sysDefs[DIV_SYSTEM_SMS]=new DivSysDef( - "TI SN76489", NULL, 0x03, 0x03, 4, false, true, 0x150, false, + "TI SN76489", NULL, 0x03, 0x03, 4, false, true, 0x150, false, 0, "a square/noise sound chip found on the Sega Master System, ColecoVision, Tandy, TI's own 99/4A and a few other places.", {"Square 1", "Square 2", "Square 3", "Noise"}, {"S1", "S2", "S3", "NO"}, @@ -629,13 +630,13 @@ void DivEngine::registerSystems() { ); sysDefs[DIV_SYSTEM_SMS_OPLL]=new DivSysDef( - "Sega Master System + FM Expansion", NULL, 0x43, 0x43, 13, true, true, 0, true, + "Sega Master System + FM Expansion", NULL, 0x43, 0x43, 13, true, true, 0, true, 0, "", {}, {}, {}, {} ); sysDefs[DIV_SYSTEM_GB]=new DivSysDef( - "Game Boy", NULL, 0x04, 0x04, 4, false, true, 0x161, false, + "Game Boy", NULL, 0x04, 0x04, 4, false, true, 0x161, false, 0, "the most popular portable game console of the era.", {"Pulse 1", "Pulse 2", "Wavetable", "Noise"}, {"S1", "S2", "WA", "NO"}, @@ -652,7 +653,7 @@ void DivEngine::registerSystems() { ); sysDefs[DIV_SYSTEM_PCE]=new DivSysDef( - "PC Engine/TurboGrafx-16", NULL, 0x05, 0x05, 6, false, true, 0x161, false, + "PC Engine/TurboGrafx-16", NULL, 0x05, 0x05, 6, false, true, 0x161, false, 1U<", {}, {}, {}, {} ); sysDefs[DIV_SYSTEM_NES_FDS]=new DivSysDef( - "Famicom Disk System", NULL, 0, 0x86, 6, false, true, 0, true, + "Famicom Disk System", NULL, 0, 0x86, 6, false, true, 0, true, 0, "", {}, {}, {}, {} ); sysDefs[DIV_SYSTEM_C64_6581]=new DivSysDef( - "Commodore 64 (6581)", NULL, 0x47, 0x47, 3, false, true, 0, false, + "Commodore 64 (6581)", NULL, 0x47, 0x47, 3, false, true, 0, false, 0, "this computer is powered by the SID chip, which had synthesizer features like a filter and ADSR.", {"Channel 1", "Channel 2", "Channel 3"}, {"CH1", "CH2", "CH3"}, @@ -710,7 +711,7 @@ void DivEngine::registerSystems() { ); sysDefs[DIV_SYSTEM_C64_8580]=new DivSysDef( - "Commodore 64 (8580)", NULL, 0x07, 0x07, 3, false, true, 0, false, + "Commodore 64 (8580)", NULL, 0x07, 0x07, 3, false, true, 0, false, 0, "this computer is powered by the SID chip, which had synthesizer features like a filter and ADSR.\nthis is the newer revision of the chip.", {"Channel 1", "Channel 2", "Channel 3"}, {"CH1", "CH2", "CH3"}, @@ -722,13 +723,13 @@ void DivEngine::registerSystems() { ); sysDefs[DIV_SYSTEM_ARCADE]=new DivSysDef( - "DefleCade", NULL, 0x08, 0x08, 13, true, false, 0, true, + "DefleCade", NULL, 0x08, 0x08, 13, true, false, 0, true, 0, "", {}, {}, {}, {} ); sysDefs[DIV_SYSTEM_YM2610]=new DivSysDef( - "Neo Geo CD", NULL, 0x09, 0x09, 13, true, true, 0x151, false, + "Neo Geo CD", NULL, 0x09, 0x09, 13, true, true, 0x151, false, (1U<note); ImGui::Text("- ins: %d",ch->ins); ImGui::Text("* psgMode:"); - ImGui::Text(" - tone: %d",ch->psgMode.tone); - ImGui::Text(" - noise: %d",ch->psgMode.noise); - ImGui::Text(" - envelope: %d",ch->psgMode.envelope); - ImGui::Text(" - dac: %d",ch->psgMode.dac); + ImGui::Text(" * curr:"); + ImGui::Text(" - tone: %d",ch->currPSGMode.tone); + ImGui::Text(" - noise: %d",ch->currPSGMode.noise); + ImGui::Text(" - envelope: %d",ch->currPSGMode.envelope); + ImGui::Text(" - dac: %d",ch->currPSGMode.dac); + ImGui::Text(" * next:"); + ImGui::Text(" - tone: %d",ch->nextPSGMode.tone); + ImGui::Text(" - noise: %d",ch->nextPSGMode.noise); + ImGui::Text(" - envelope: %d",ch->nextPSGMode.envelope); + ImGui::Text(" - dac: %d",ch->nextPSGMode.dac); ImGui::Text("* DAC:"); ImGui::Text(" - sample: %d",ch->dac.sample); ImGui::Text(" - rate: %d",ch->dac.rate); @@ -886,10 +892,16 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text(" * slide: %d",ch->envelope.slide); ImGui::Text(" - low: %d",ch->envelope.slideLow); ImGui::Text("* psgMode:"); - ImGui::Text(" - tone: %d",ch->psgMode.tone); - ImGui::Text(" - noise: %d",ch->psgMode.noise); - ImGui::Text(" - envelope: %d",ch->psgMode.envelope); - ImGui::Text(" - dac: %d",ch->psgMode.dac); + ImGui::Text(" * curr:"); + ImGui::Text(" - tone: %d",ch->currPSGMode.tone); + ImGui::Text(" - noise: %d",ch->currPSGMode.noise); + ImGui::Text(" - envelope: %d",ch->currPSGMode.envelope); + ImGui::Text(" - dac: %d",ch->currPSGMode.dac); + ImGui::Text(" * next:"); + ImGui::Text(" - tone: %d",ch->nextPSGMode.tone); + ImGui::Text(" - noise: %d",ch->nextPSGMode.noise); + ImGui::Text(" - envelope: %d",ch->nextPSGMode.envelope); + ImGui::Text(" - dac: %d",ch->nextPSGMode.dac); ImGui::Text("* DAC:"); ImGui::Text(" - sample: %d",ch->dac.sample); ImGui::Text(" - rate: %d",ch->dac.rate); diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index a3e65e7c..d1909626 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -77,6 +77,9 @@ void FurnaceGUI::drawSampleEdit() { if (sampleDepths[i]==NULL) continue; if (ImGui::Selectable(sampleDepths[i])) { sample->prepareUndo(true); + e->lockEngine([sample]() { + sample->render(); + }); sample->depth=(DivSampleDepth)i; e->renderSamplesP(); updateSampleTex=true; @@ -633,6 +636,9 @@ void FurnaceGUI::drawSampleEdit() { if (sampleDepths[i]==NULL) continue; if (ImGui::Selectable(sampleDepths[i])) { sample->prepareUndo(true); + e->lockEngine([sample]() { + sample->render(); + }); sample->depth=(DivSampleDepth)i; e->renderSamplesP(); updateSampleTex=true;