implement sample off for rest of chips except X1

This commit is contained in:
tildearrow 2024-04-24 03:45:59 -05:00
parent 84437bf0e3
commit 3989dffd58
12 changed files with 171 additions and 43 deletions

View file

@ -468,6 +468,7 @@ int DivPlatformDave::dispatch(DivCommand c) {
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:
if (c.chan<4) break;
chan[c.chan].dacPos=c.value;
chan[c.chan].setPos=true;
break;

View file

@ -135,7 +135,11 @@ void DivPlatformLynx::acquire(short** buf, size_t len) {
if (isMuted[i]) {
WRITE_OUTPUT(i,0);
} else {
WRITE_OUTPUT(i,CLAMP((s->data8[chan[i].samplePos]*chan[i].outVol)>>7,-128,127));
if (chan[i].samplePos<0 || chan[i].samplePos>=(int)s->samples) {
WRITE_OUTPUT(i,0);
} else {
WRITE_OUTPUT(i,CLAMP((s->data8[chan[i].samplePos]*chan[i].outVol)>>7,-128,127));
}
}
chan[i].samplePos++;
@ -209,7 +213,11 @@ void DivPlatformLynx::tick(bool sysTick) {
if (chan[i].std.phaseReset.val==1) {
if (chan[i].pcm && chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
chan[i].sampleAccum=0;
chan[i].samplePos=0;
if (chan[i].setPos) {
chan[i].setPos=false;
} else {
chan[i].samplePos=0;
}
}
WRITE_LFSR(i, 0);
WRITE_OTHER(i, 0);
@ -294,7 +302,11 @@ int DivPlatformLynx::dispatch(DivCommand c) {
c.value=ins->amiga.getFreq(chan[c.chan].sampleNote);
}
chan[c.chan].sampleAccum=0;
chan[c.chan].samplePos=0;
if (chan[c.chan].setPos) {
chan[c.chan].setPos=false;
} else {
chan[c.chan].samplePos=0;
}
}
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
@ -400,6 +412,10 @@ int DivPlatformLynx::dispatch(DivCommand c) {
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:
chan[c.chan].samplePos=c.value;
chan[c.chan].setPos=true;
break;
case DIV_CMD_GET_VOLMAX:
return 127;
break;

View file

@ -49,7 +49,7 @@ void DivPlatformMMC5::acquire(short** buf, size_t len) {
dacPeriod+=dacRate;
if (dacPeriod>=rate) {
DivSample* s=parent->getSample(dacSample);
if (s->samples>0) {
if (s->samples>0 && dacPos<s->samples) {
if (!isMuted[2]) {
rWrite(0x5011,((unsigned char)s->data8[dacPos]+0x80));
}
@ -192,7 +192,11 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
} else {
if (dumpWrites) addWrite(0xffff0000,dacSample);
}
dacPos=0;
if (chan[c.chan].setPos) {
chan[c.chan].setPos=false;
} else {
dacPos=0;
}
dacPeriod=0;
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
@ -214,7 +218,11 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
} else {
if (dumpWrites) addWrite(0xffff0000,dacSample);
}
dacPos=0;
if (chan[c.chan].setPos) {
chan[c.chan].setPos=false;
} else {
dacPos=0;
}
dacPeriod=0;
dacRate=parent->getSample(dacSample)->rate;
if (dumpWrites) addWrite(0xffff0001,dacRate);
@ -307,6 +315,11 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
sampleBank=parent->song.sample.size()/12;
}
break;
case DIV_CMD_SAMPLE_POS:
if (c.chan!=2) break;
dacPos=c.value;
chan[c.chan].setPos=true;
break;
case DIV_CMD_LEGATO:
if (c.chan==2) {
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)),false);

View file

@ -81,7 +81,7 @@ void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) {
dacPeriod+=dacRate; \
if (dacPeriod>=rate) { \
DivSample* s=parent->getSample(dacSample); \
if (s->samples>0) { \
if (s->samples>0 && dacPos<s->samples) { \
if (!isMuted[4]) { \
unsigned char next=((unsigned char)s->data8[dacPos]+0x80)>>1; \
if (dacAntiClickOn && dacAntiClick<next) { \
@ -371,8 +371,9 @@ void DivPlatformNES::tick(bool sysTick) {
dacRate=MIN(chan[4].freq*off,32000);
if (chan[4].keyOn) {
if (dpcmMode && !skipRegisterWrites && dacSample>=0 && dacSample<parent->song.sampleLen) {
unsigned int dpcmAddr=sampleOffDPCM[dacSample];
unsigned int dpcmLen=parent->getSample(dacSample)->lengthDPCM>>4;
unsigned int dpcmAddr=sampleOffDPCM[dacSample]+(dacPos>>3);
int dpcmLen=(parent->getSample(dacSample)->lengthDPCM-(dacPos>>3))>>4;
if (dpcmLen<0) dpcmLen=0;
if (dpcmLen>255) dpcmLen=255;
goingToLoop=parent->getSample(dacSample)->isLoopable();
// write DPCM
@ -464,7 +465,11 @@ int DivPlatformNES::dispatch(DivCommand c) {
} else {
if (dumpWrites && !dpcmMode) addWrite(0xffff0000,dacSample);
}
dacPos=0;
if (chan[c.chan].setPos) {
chan[c.chan].setPos=false;
} else {
dacPos=0;
}
dacPeriod=0;
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
@ -486,14 +491,19 @@ int DivPlatformNES::dispatch(DivCommand c) {
} else {
if (dumpWrites && !dpcmMode) addWrite(0xffff0000,dacSample);
}
dacPos=0;
if (chan[c.chan].setPos) {
chan[c.chan].setPos=false;
} else {
dacPos=0;
}
dacPeriod=0;
dacRate=parent->getSample(dacSample)->rate;
if (dumpWrites && !dpcmMode) addWrite(0xffff0001,dacRate);
chan[c.chan].furnaceDac=false;
if (dpcmMode && !skipRegisterWrites) {
unsigned int dpcmAddr=sampleOffDPCM[dacSample];
unsigned int dpcmLen=parent->getSample(dacSample)->lengthDPCM>>4;
unsigned int dpcmAddr=sampleOffDPCM[dacSample]+(dacPos>>3);
int dpcmLen=(parent->getSample(dacSample)->lengthDPCM-(dacPos>>3))>>4;
if (dpcmLen<0) dpcmLen=0;
if (dpcmLen>255) dpcmLen=255;
goingToLoop=parent->getSample(dacSample)->isLoopable();
// write DPCM
@ -682,6 +692,15 @@ int DivPlatformNES::dispatch(DivCommand c) {
sampleBank=parent->song.sample.size()/12;
}
break;
case DIV_CMD_SAMPLE_POS:
if (c.chan!=4) break;
dacPos=c.value;
dpcmPos=c.value;
chan[c.chan].setPos=true;
if (chan[c.chan].active) {
chan[c.chan].keyOn=true;
}
break;
case DIV_CMD_LEGATO:
if (c.chan==3) break;
if (c.chan==4) {
@ -777,6 +796,7 @@ void DivPlatformNES::reset() {
dacPeriod=0;
dacPos=0;
dpcmPos=0;
dacRate=0;
dacSample=-1;
sampleBank=0;

View file

@ -44,7 +44,7 @@ class DivPlatformNES: public DivDispatch {
Channel chan[5];
DivDispatchOscBuffer* oscBuf[5];
bool isMuted[5];
int dacPeriod, dacRate;
int dacPeriod, dacRate, dpcmPos;
unsigned int dacPos, dacAntiClick;
int dacSample;
unsigned char* dpcmMem;

View file

@ -62,7 +62,7 @@ void DivPlatformPCE::acquire(short** buf, size_t len) {
chan[i].dacPeriod+=chan[i].dacRate;
if (chan[i].dacPeriod>rate) {
DivSample* s=parent->getSample(chan[i].dacSample);
if (s->samples<=0) {
if (s->samples<=0 || chan[i].dacPos>=s->samples) {
chan[i].dacSample=-1;
continue;
}
@ -204,7 +204,11 @@ void DivPlatformPCE::tick(bool sysTick) {
if (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1) {
if (chan[i].furnaceDac && chan[i].pcm) {
if (chan[i].active && chan[i].dacSample>=0 && chan[i].dacSample<parent->song.sampleLen) {
chan[i].dacPos=0;
if (chan[i].setPos) {
chan[i].setPos=false;
} else {
chan[i].dacPos=0;
}
chan[i].dacPeriod=0;
chWrite(i,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[i].vol));
addWrite(0xffff0000+(i<<8),chan[i].dacSample);
@ -302,7 +306,11 @@ int DivPlatformPCE::dispatch(DivCommand c) {
addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample);
}
}
chan[c.chan].dacPos=0;
if (chan[c.chan].setPos) {
chan[c.chan].setPos=false;
} else {
chan[c.chan].dacPos=0;
}
chan[c.chan].dacPeriod=0;
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
@ -331,7 +339,11 @@ int DivPlatformPCE::dispatch(DivCommand c) {
} else {
if (dumpWrites) addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample);
}
chan[c.chan].dacPos=0;
if (chan[c.chan].setPos) {
chan[c.chan].setPos=false;
} else {
chan[c.chan].dacPos=0;
}
chan[c.chan].dacPeriod=0;
chan[c.chan].dacRate=parent->getSample(chan[c.chan].dacSample)->rate;
if (dumpWrites) {
@ -457,6 +469,10 @@ int DivPlatformPCE::dispatch(DivCommand c) {
sampleBank=parent->song.sample.size()/12;
}
break;
case DIV_CMD_SAMPLE_POS:
chan[c.chan].dacPos=c.value;
chan[c.chan].setPos=true;
break;
case DIV_CMD_PANNING: {
chan[c.chan].pan=(c.value&0xf0)|(c.value2>>4);
chWrite(c.chan,0x05,isMuted[c.chan]?0:chan[c.chan].pan);

View file

@ -391,17 +391,23 @@ void DivPlatformQSound::tick(bool sysTick) {
chan[i].freq=off*parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,2,chan[i].pitch2,440.0,4096.0);
if (chan[i].freq>0xefff) chan[i].freq=0xefff;
if (chan[i].keyOn) {
if (chan[i].setPos) {
chan[i].setPos=false;
} else {
chan[i].audPos=0;
}
if (i<16) {
rWrite(q1_reg_map[Q1V_BANK][i], qsound_bank);
rWrite(q1_reg_map[Q1V_END][i], qsound_end);
rWrite(q1_reg_map[Q1V_LOOP][i], qsound_loop);
rWrite(q1_reg_map[Q1V_START][i], qsound_addr);
rWrite(q1_reg_map[Q1V_START][i], qsound_addr+chan[i].audPos);
rWrite(q1_reg_map[Q1V_PHASE][i], 0x8000);
} else {
rWrite(Q1A_KEYON+(i-16),0);
rWrite(q1a_bank_map[i-16], qsound_bank);
rWrite(q1a_end_map[i-16], qsound_end);
rWrite(q1a_start_map[i-16], qsound_addr);
rWrite(q1a_start_map[i-16], qsound_addr+chan[i].audPos);
rWrite(Q1A_KEYON+(i-16),1);
}
//logV("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!",i,qsound_bank,qsound_addr,qsound_end,qsound_loop);
@ -580,6 +586,13 @@ int DivPlatformQSound::dispatch(DivCommand c) {
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=QS_NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:
chan[c.chan].audPos=c.value;
chan[c.chan].setPos=true;
if (chan[c.chan].active) {
chan[c.chan].keyOn=true;
}
break;
case DIV_CMD_GET_VOLMAX:
return 255;
break;

View file

@ -29,6 +29,7 @@ class DivPlatformQSound: public DivDispatch {
int sample, wave;
int panning;
int echo;
int audPos;
bool useWave, surround, isNewQSound, setPos;
Channel():
SharedChannel<int>(255),
@ -37,6 +38,7 @@ class DivPlatformQSound: public DivDispatch {
wave(-1),
panning(0x10),
echo(0),
audPos(0),
useWave(false),
surround(true),
isNewQSound(false),

View file

@ -128,41 +128,47 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
if (chan[i].keyOn || chan[i].keyOff) {
if (chan[i].keyOn && !chan[i].keyOff) {
rWrite(0x86+(i<<3),3);
chan[i].pcm.pos=0;
if (chan[i].setPos) {
chan[i].setPos=false;
} else {
chan[i].pcm.pos=0;
}
if (chan[i].furnacePCM) {
DivSample* s=parent->getSample(chan[i].pcm.sample);
int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT));
if (actualLength>0xfeff) actualLength=0xfeff;
rWrite(0x86+(i<<3),3+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
rWrite(0x84+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample])&0xff);
rWrite(0x85+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample]>>8)&0xff);
int actualPos=sampleOffSegaPCM[chan[i].pcm.sample]+chan[i].pcm.pos;
rWrite(0x86+(i<<3),3+((actualPos>>16)<<3));
rWrite(0x84+(i<<3),(actualPos)&0xff);
rWrite(0x85+(i<<3),(actualPos>>8)&0xff);
rWrite(6+(i<<3),sampleEndSegaPCM[chan[i].pcm.sample]);
if (!s->isLoopable()) {
rWrite(0x86+(i<<3),2+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
rWrite(0x86+(i<<3),2+((actualPos>>16)<<3));
} else {
int loopPos=(sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+loopStart;
logV("sampleOff: %x loopPos: %x",sampleOffSegaPCM[chan[i].pcm.sample],loopPos);
int loopPos=(actualPos&0xffff)+loopStart;
logV("sampleOff: %x loopPos: %x",actualPos,loopPos);
rWrite(4+(i<<3),loopPos&0xff);
rWrite(5+(i<<3),(loopPos>>8)&0xff);
rWrite(0x86+(i<<3),((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
rWrite(0x86+(i<<3),((actualPos>>16)<<3));
}
} else {
DivSample* s=parent->getSample(chan[i].pcm.sample);
int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT));
if (actualLength>0xfeff) actualLength=0xfeff;
rWrite(0x86+(i<<3),3+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
rWrite(0x84+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample])&0xff);
rWrite(0x85+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample]>>8)&0xff);
int actualPos=sampleOffSegaPCM[chan[i].pcm.sample]+chan[i].pcm.pos;
rWrite(0x86+(i<<3),3+((actualPos>>16)<<3));
rWrite(0x84+(i<<3),(actualPos)&0xff);
rWrite(0x85+(i<<3),(actualPos>>8)&0xff);
rWrite(6+(i<<3),sampleEndSegaPCM[chan[i].pcm.sample]);
if (!s->isLoopable()) {
rWrite(0x86+(i<<3),2+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
rWrite(0x86+(i<<3),2+((actualPos>>16)<<3));
} else {
int loopPos=(sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+loopStart;
int loopPos=(actualPos&0xffff)+loopStart;
rWrite(4+(i<<3),loopPos&0xff);
rWrite(5+(i<<3),(loopPos>>8)&0xff);
rWrite(0x86+(i<<3),((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3));
rWrite(0x86+(i<<3),((actualPos>>16)<<3));
}
rWrite(7+(i<<3),chan[i].pcm.freq);
}
@ -335,6 +341,13 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
sampleBank=parent->song.sample.size()/12;
}
break;
case DIV_CMD_SAMPLE_POS:
chan[c.chan].pcm.pos=c.value;
chan[c.chan].setPos=true;
if (chan[c.chan].active) {
chan[c.chan].keyOn=true;
}
break;
case DIV_CMD_MACRO_OFF:
chan[c.chan].std.mask(c.value,true);
break;

View file

@ -60,7 +60,7 @@ void DivPlatformSwan::acquire(short** buf, size_t len) {
dacPeriod+=dacRate;
while (dacPeriod>rate) {
DivSample* s=parent->getSample(dacSample);
if (s->samples<=0) {
if (s->samples<=0 || dacPos>=s->samples) {
dacSample=-1;
dacPeriod=0;
break;
@ -262,7 +262,11 @@ int DivPlatformSwan::dispatch(DivCommand c) {
}
if (pcm) {
if (skipRegisterWrites) break;
dacPos=0;
if (setPos) {
setPos=false;
} else {
dacPos=0;
}
dacPeriod=0;
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
if (c.value!=DIV_NOTE_NULL) {
@ -435,6 +439,10 @@ int DivPlatformSwan::dispatch(DivCommand c) {
sampleBank=parent->song.sample.size()/12;
}
break;
case DIV_CMD_SAMPLE_POS:
dacPos=c.value;
setPos=true;
break;
case DIV_CMD_PANNING: {
chan[c.chan].pan=(c.value&0xf0)|(c.value2>>4);
calcAndWriteOutVol(c.chan,chan[c.chan].std.vol.will?chan[c.chan].std.vol.val:15);

View file

@ -56,6 +56,7 @@ const char** DivPlatformVERA::getRegisterSheet() {
return regCheatSheetVERA;
}
// TODO: possible sample offset latency...
void DivPlatformVERA::acquire(short** buf, size_t len) {
// both PSG part and PCM part output a full 16-bit range, putting bufL/R
// argument right into both could cause an overflow
@ -63,7 +64,7 @@ void DivPlatformVERA::acquire(short** buf, size_t len) {
size_t pos=0;
DivSample* s=parent->getSample(chan[16].pcm.sample);
while (len>0) {
if (s->samples>0) {
if (s->samples>0 && chan[16].pcm.pos<s->samples) {
while (pcm_is_fifo_almost_empty(pcm)) {
short tmp_l=0;
short tmp_r=0;
@ -312,7 +313,11 @@ int DivPlatformVERA::dispatch(DivCommand c) {
if (chan[16].pcm.sample<0 || chan[16].pcm.sample>=parent->song.sampleLen) {
chan[16].pcm.sample=-1;
}
chan[16].pcm.pos=0;
if (chan[16].pcm.setPos) {
chan[16].pcm.setPos=false;
} else {
chan[16].pcm.pos=0;
}
DivSample* s=parent->getSample(chan[16].pcm.sample);
unsigned char ctrl=0x90|chan[16].vol; // always stereo
if (s->depth==DIV_SAMPLE_DEPTH_16BIT) {
@ -426,8 +431,13 @@ int DivPlatformVERA::dispatch(DivCommand c) {
}
break;
}
case DIV_CMD_SAMPLE_POS:
if (c.chan!=16) break;
chan[c.chan].pcm.pos=c.value;
chan[c.chan].pcm.setPos=true;
break;
case DIV_CMD_GET_VOLMAX:
if(c.chan<16) {
if (c.chan<16) {
return 63;
} else {
return 15;

View file

@ -54,7 +54,7 @@ void DivPlatformVRC6::acquire(short** buf, size_t len) {
chan[i].dacPeriod+=chan[i].dacRate;
if (chan[i].dacPeriod>rate) {
DivSample* s=parent->getSample(chan[i].dacSample);
if (s->samples<=0) {
if (s->samples<=0 || chan[i].dacPos>=s->samples) {
chan[i].dacSample=-1;
chWrite(i,0,0);
continue;
@ -185,7 +185,11 @@ void DivPlatformVRC6::tick(bool sysTick) {
chWrite(i,0,isMuted[i]?0:0x80);
addWrite(0xffff0000+(i<<8),chan[i].dacSample);
}
chan[i].dacPos=0;
if (chan[i].setPos) {
chan[i].setPos=false;
} else {
chan[i].dacPos=0;
}
chan[i].dacPeriod=0;
chan[i].keyOn=true;
}
@ -262,7 +266,11 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample);
}
}
chan[c.chan].dacPos=0;
if (chan[c.chan].setPos) {
chan[c.chan].setPos=false;
} else {
chan[c.chan].dacPos=0;
}
chan[c.chan].dacPeriod=0;
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
@ -290,7 +298,11 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
} else {
if (dumpWrites) addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample);
}
chan[c.chan].dacPos=0;
if (chan[c.chan].setPos) {
chan[c.chan].setPos=false;
} else {
chan[c.chan].dacPos=0;
}
chan[c.chan].dacPeriod=0;
chan[c.chan].dacRate=parent->getSample(chan[c.chan].dacSample)->rate;
if (dumpWrites) {
@ -405,6 +417,10 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
sampleBank=parent->song.sample.size()/12;
}
break;
case DIV_CMD_SAMPLE_POS:
chan[c.chan].dacPos=c.value;
chan[c.chan].setPos=true;
break;
case DIV_CMD_LEGATO:
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;