implement sample off for rest of chips except X1
This commit is contained in:
parent
84437bf0e3
commit
3989dffd58
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,8 +431,13 @@ 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;
|
||||||
} else {
|
} else {
|
||||||
return 15;
|
return 15;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue