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; chan[c.chan].inPorta=c.value;
break; break;
case DIV_CMD_SAMPLE_POS: case DIV_CMD_SAMPLE_POS:
if (c.chan<4) break;
chan[c.chan].dacPos=c.value; chan[c.chan].dacPos=c.value;
chan[c.chan].setPos=true; chan[c.chan].setPos=true;
break; break;

View file

@ -134,9 +134,13 @@ void DivPlatformLynx::acquire(short** buf, size_t len) {
if (s!=NULL) { if (s!=NULL) {
if (isMuted[i]) { if (isMuted[i]) {
WRITE_OUTPUT(i,0); WRITE_OUTPUT(i,0);
} else {
if (chan[i].samplePos<0 || chan[i].samplePos>=(int)s->samples) {
WRITE_OUTPUT(i,0);
} else { } else {
WRITE_OUTPUT(i,CLAMP((s->data8[chan[i].samplePos]*chan[i].outVol)>>7,-128,127)); WRITE_OUTPUT(i,CLAMP((s->data8[chan[i].samplePos]*chan[i].outVol)>>7,-128,127));
} }
}
chan[i].samplePos++; chan[i].samplePos++;
if (s->isLoopable() && chan[i].samplePos>=s->loopEnd) { if (s->isLoopable() && chan[i].samplePos>=s->loopEnd) {
@ -209,8 +213,12 @@ void DivPlatformLynx::tick(bool sysTick) {
if (chan[i].std.phaseReset.val==1) { if (chan[i].std.phaseReset.val==1) {
if (chan[i].pcm && chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) { if (chan[i].pcm && chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
chan[i].sampleAccum=0; chan[i].sampleAccum=0;
if (chan[i].setPos) {
chan[i].setPos=false;
} else {
chan[i].samplePos=0; chan[i].samplePos=0;
} }
}
WRITE_LFSR(i, 0); WRITE_LFSR(i, 0);
WRITE_OTHER(i, 0); WRITE_OTHER(i, 0);
} }
@ -294,8 +302,12 @@ int DivPlatformLynx::dispatch(DivCommand c) {
c.value=ins->amiga.getFreq(chan[c.chan].sampleNote); c.value=ins->amiga.getFreq(chan[c.chan].sampleNote);
} }
chan[c.chan].sampleAccum=0; chan[c.chan].sampleAccum=0;
if (chan[c.chan].setPos) {
chan[c.chan].setPos=false;
} else {
chan[c.chan].samplePos=0; chan[c.chan].samplePos=0;
} }
}
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
chan[c.chan].freqChanged=true; chan[c.chan].freqChanged=true;
@ -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); 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; chan[c.chan].inPorta=c.value;
break; break;
case DIV_CMD_SAMPLE_POS:
chan[c.chan].samplePos=c.value;
chan[c.chan].setPos=true;
break;
case DIV_CMD_GET_VOLMAX: case DIV_CMD_GET_VOLMAX:
return 127; return 127;
break; break;

View file

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

View file

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

View file

@ -62,7 +62,7 @@ void DivPlatformPCE::acquire(short** buf, size_t len) {
chan[i].dacPeriod+=chan[i].dacRate; chan[i].dacPeriod+=chan[i].dacRate;
if (chan[i].dacPeriod>rate) { if (chan[i].dacPeriod>rate) {
DivSample* s=parent->getSample(chan[i].dacSample); DivSample* s=parent->getSample(chan[i].dacSample);
if (s->samples<=0) { if (s->samples<=0 || chan[i].dacPos>=s->samples) {
chan[i].dacSample=-1; chan[i].dacSample=-1;
continue; 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].std.phaseReset.had && chan[i].std.phaseReset.val==1) {
if (chan[i].furnaceDac && chan[i].pcm) { if (chan[i].furnaceDac && chan[i].pcm) {
if (chan[i].active && chan[i].dacSample>=0 && chan[i].dacSample<parent->song.sampleLen) { if (chan[i].active && chan[i].dacSample>=0 && chan[i].dacSample<parent->song.sampleLen) {
if (chan[i].setPos) {
chan[i].setPos=false;
} else {
chan[i].dacPos=0; chan[i].dacPos=0;
}
chan[i].dacPeriod=0; chan[i].dacPeriod=0;
chWrite(i,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[i].vol)); chWrite(i,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[i].vol));
addWrite(0xffff0000+(i<<8),chan[i].dacSample); 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); addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample);
} }
} }
if (chan[c.chan].setPos) {
chan[c.chan].setPos=false;
} else {
chan[c.chan].dacPos=0; chan[c.chan].dacPos=0;
}
chan[c.chan].dacPeriod=0; chan[c.chan].dacPeriod=0;
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
@ -331,7 +339,11 @@ int DivPlatformPCE::dispatch(DivCommand c) {
} else { } else {
if (dumpWrites) addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample); if (dumpWrites) addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample);
} }
if (chan[c.chan].setPos) {
chan[c.chan].setPos=false;
} else {
chan[c.chan].dacPos=0; chan[c.chan].dacPos=0;
}
chan[c.chan].dacPeriod=0; chan[c.chan].dacPeriod=0;
chan[c.chan].dacRate=parent->getSample(chan[c.chan].dacSample)->rate; chan[c.chan].dacRate=parent->getSample(chan[c.chan].dacSample)->rate;
if (dumpWrites) { if (dumpWrites) {
@ -457,6 +469,10 @@ int DivPlatformPCE::dispatch(DivCommand c) {
sampleBank=parent->song.sample.size()/12; sampleBank=parent->song.sample.size()/12;
} }
break; break;
case DIV_CMD_SAMPLE_POS:
chan[c.chan].dacPos=c.value;
chan[c.chan].setPos=true;
break;
case DIV_CMD_PANNING: { case DIV_CMD_PANNING: {
chan[c.chan].pan=(c.value&0xf0)|(c.value2>>4); chan[c.chan].pan=(c.value&0xf0)|(c.value2>>4);
chWrite(c.chan,0x05,isMuted[c.chan]?0:chan[c.chan].pan); 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); 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].freq>0xefff) chan[i].freq=0xefff;
if (chan[i].keyOn) { if (chan[i].keyOn) {
if (chan[i].setPos) {
chan[i].setPos=false;
} else {
chan[i].audPos=0;
}
if (i<16) { if (i<16) {
rWrite(q1_reg_map[Q1V_BANK][i], qsound_bank); rWrite(q1_reg_map[Q1V_BANK][i], qsound_bank);
rWrite(q1_reg_map[Q1V_END][i], qsound_end); rWrite(q1_reg_map[Q1V_END][i], qsound_end);
rWrite(q1_reg_map[Q1V_LOOP][i], qsound_loop); 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); rWrite(q1_reg_map[Q1V_PHASE][i], 0x8000);
} else { } else {
rWrite(Q1A_KEYON+(i-16),0); rWrite(Q1A_KEYON+(i-16),0);
rWrite(q1a_bank_map[i-16], qsound_bank); rWrite(q1a_bank_map[i-16], qsound_bank);
rWrite(q1a_end_map[i-16], qsound_end); 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); 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); //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); 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; chan[c.chan].inPorta=c.value;
break; 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: case DIV_CMD_GET_VOLMAX:
return 255; return 255;
break; break;

View file

@ -29,6 +29,7 @@ class DivPlatformQSound: public DivDispatch {
int sample, wave; int sample, wave;
int panning; int panning;
int echo; int echo;
int audPos;
bool useWave, surround, isNewQSound, setPos; bool useWave, surround, isNewQSound, setPos;
Channel(): Channel():
SharedChannel<int>(255), SharedChannel<int>(255),
@ -37,6 +38,7 @@ class DivPlatformQSound: public DivDispatch {
wave(-1), wave(-1),
panning(0x10), panning(0x10),
echo(0), echo(0),
audPos(0),
useWave(false), useWave(false),
surround(true), surround(true),
isNewQSound(false), 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) {
if (chan[i].keyOn && !chan[i].keyOff) { if (chan[i].keyOn && !chan[i].keyOff) {
rWrite(0x86+(i<<3),3); rWrite(0x86+(i<<3),3);
if (chan[i].setPos) {
chan[i].setPos=false;
} else {
chan[i].pcm.pos=0; chan[i].pcm.pos=0;
}
if (chan[i].furnacePCM) { if (chan[i].furnacePCM) {
DivSample* s=parent->getSample(chan[i].pcm.sample); DivSample* s=parent->getSample(chan[i].pcm.sample);
int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)); int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT));
if (actualLength>0xfeff) actualLength=0xfeff; if (actualLength>0xfeff) actualLength=0xfeff;
rWrite(0x86+(i<<3),3+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3)); int actualPos=sampleOffSegaPCM[chan[i].pcm.sample]+chan[i].pcm.pos;
rWrite(0x84+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample])&0xff); rWrite(0x86+(i<<3),3+((actualPos>>16)<<3));
rWrite(0x85+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample]>>8)&0xff); rWrite(0x84+(i<<3),(actualPos)&0xff);
rWrite(0x85+(i<<3),(actualPos>>8)&0xff);
rWrite(6+(i<<3),sampleEndSegaPCM[chan[i].pcm.sample]); rWrite(6+(i<<3),sampleEndSegaPCM[chan[i].pcm.sample]);
if (!s->isLoopable()) { if (!s->isLoopable()) {
rWrite(0x86+(i<<3),2+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3)); rWrite(0x86+(i<<3),2+((actualPos>>16)<<3));
} else { } else {
int loopPos=(sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+loopStart; int loopPos=(actualPos&0xffff)+loopStart;
logV("sampleOff: %x loopPos: %x",sampleOffSegaPCM[chan[i].pcm.sample],loopPos); logV("sampleOff: %x loopPos: %x",actualPos,loopPos);
rWrite(4+(i<<3),loopPos&0xff); rWrite(4+(i<<3),loopPos&0xff);
rWrite(5+(i<<3),(loopPos>>8)&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 { } else {
DivSample* s=parent->getSample(chan[i].pcm.sample); DivSample* s=parent->getSample(chan[i].pcm.sample);
int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)); int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT));
if (actualLength>0xfeff) actualLength=0xfeff; if (actualLength>0xfeff) actualLength=0xfeff;
rWrite(0x86+(i<<3),3+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3)); int actualPos=sampleOffSegaPCM[chan[i].pcm.sample]+chan[i].pcm.pos;
rWrite(0x84+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample])&0xff); rWrite(0x86+(i<<3),3+((actualPos>>16)<<3));
rWrite(0x85+(i<<3),(sampleOffSegaPCM[chan[i].pcm.sample]>>8)&0xff); rWrite(0x84+(i<<3),(actualPos)&0xff);
rWrite(0x85+(i<<3),(actualPos>>8)&0xff);
rWrite(6+(i<<3),sampleEndSegaPCM[chan[i].pcm.sample]); rWrite(6+(i<<3),sampleEndSegaPCM[chan[i].pcm.sample]);
if (!s->isLoopable()) { if (!s->isLoopable()) {
rWrite(0x86+(i<<3),2+((sampleOffSegaPCM[chan[i].pcm.sample]>>16)<<3)); rWrite(0x86+(i<<3),2+((actualPos>>16)<<3));
} else { } else {
int loopPos=(sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+loopStart; int loopPos=(actualPos&0xffff)+loopStart;
rWrite(4+(i<<3),loopPos&0xff); rWrite(4+(i<<3),loopPos&0xff);
rWrite(5+(i<<3),(loopPos>>8)&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); rWrite(7+(i<<3),chan[i].pcm.freq);
} }
@ -335,6 +341,13 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
sampleBank=parent->song.sample.size()/12; sampleBank=parent->song.sample.size()/12;
} }
break; 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: case DIV_CMD_MACRO_OFF:
chan[c.chan].std.mask(c.value,true); chan[c.chan].std.mask(c.value,true);
break; break;

View file

@ -60,7 +60,7 @@ void DivPlatformSwan::acquire(short** buf, size_t len) {
dacPeriod+=dacRate; dacPeriod+=dacRate;
while (dacPeriod>rate) { while (dacPeriod>rate) {
DivSample* s=parent->getSample(dacSample); DivSample* s=parent->getSample(dacSample);
if (s->samples<=0) { if (s->samples<=0 || dacPos>=s->samples) {
dacSample=-1; dacSample=-1;
dacPeriod=0; dacPeriod=0;
break; break;
@ -262,7 +262,11 @@ int DivPlatformSwan::dispatch(DivCommand c) {
} }
if (pcm) { if (pcm) {
if (skipRegisterWrites) break; if (skipRegisterWrites) break;
if (setPos) {
setPos=false;
} else {
dacPos=0; dacPos=0;
}
dacPeriod=0; dacPeriod=0;
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
@ -435,6 +439,10 @@ int DivPlatformSwan::dispatch(DivCommand c) {
sampleBank=parent->song.sample.size()/12; sampleBank=parent->song.sample.size()/12;
} }
break; break;
case DIV_CMD_SAMPLE_POS:
dacPos=c.value;
setPos=true;
break;
case DIV_CMD_PANNING: { case DIV_CMD_PANNING: {
chan[c.chan].pan=(c.value&0xf0)|(c.value2>>4); 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); 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; return regCheatSheetVERA;
} }
// TODO: possible sample offset latency...
void DivPlatformVERA::acquire(short** buf, size_t len) { void DivPlatformVERA::acquire(short** buf, size_t len) {
// both PSG part and PCM part output a full 16-bit range, putting bufL/R // both PSG part and PCM part output a full 16-bit range, putting bufL/R
// argument right into both could cause an overflow // argument right into both could cause an overflow
@ -63,7 +64,7 @@ void DivPlatformVERA::acquire(short** buf, size_t len) {
size_t pos=0; size_t pos=0;
DivSample* s=parent->getSample(chan[16].pcm.sample); DivSample* s=parent->getSample(chan[16].pcm.sample);
while (len>0) { while (len>0) {
if (s->samples>0) { if (s->samples>0 && chan[16].pcm.pos<s->samples) {
while (pcm_is_fifo_almost_empty(pcm)) { while (pcm_is_fifo_almost_empty(pcm)) {
short tmp_l=0; short tmp_l=0;
short tmp_r=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) { if (chan[16].pcm.sample<0 || chan[16].pcm.sample>=parent->song.sampleLen) {
chan[16].pcm.sample=-1; chan[16].pcm.sample=-1;
} }
if (chan[16].pcm.setPos) {
chan[16].pcm.setPos=false;
} else {
chan[16].pcm.pos=0; chan[16].pcm.pos=0;
}
DivSample* s=parent->getSample(chan[16].pcm.sample); DivSample* s=parent->getSample(chan[16].pcm.sample);
unsigned char ctrl=0x90|chan[16].vol; // always stereo unsigned char ctrl=0x90|chan[16].vol; // always stereo
if (s->depth==DIV_SAMPLE_DEPTH_16BIT) { if (s->depth==DIV_SAMPLE_DEPTH_16BIT) {
@ -426,6 +431,11 @@ int DivPlatformVERA::dispatch(DivCommand c) {
} }
break; 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: case DIV_CMD_GET_VOLMAX:
if (c.chan<16) { if (c.chan<16) {
return 63; return 63;

View file

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