QuadTone: Fix PCM playback and add no hiss flag

This commit is contained in:
Natt Akuma 2024-02-03 06:16:35 +07:00
parent 731b7a1bd6
commit 1200e76469
3 changed files with 53 additions and 29 deletions

View file

@ -30,13 +30,14 @@ const char** DivPlatformZXBeeperQuadTone::getRegisterSheet() {
} }
void DivPlatformZXBeeperQuadTone::acquire(short** buf, size_t len) { void DivPlatformZXBeeperQuadTone::acquire(short** buf, size_t len) {
bool o=false;
for (size_t h=0; h<len; h++) { for (size_t h=0; h<len; h++) {
if (curSample>=0 && curSample<parent->song.sampleLen && !isMuted[4]) { bool sampleActive=false;
if (curSample>=0 && curSample<parent->song.sampleLen) {
sampleActive=!isMuted[4];
while (curSamplePeriod>=chan[4].freq) { while (curSamplePeriod>=chan[4].freq) {
DivSample* s=parent->getSample(curSample); DivSample* s=parent->getSample(curSample);
if (s->samples>0) { if (s->samples>0) {
if (!isMuted[4]) o=(s->data8[curSamplePos++]>0); chan[4].out=(s->data8[curSamplePos++]>0);
if (curSamplePos>=s->samples) curSample=-1; if (curSamplePos>=s->samples) curSample=-1;
// (theoretical) 32KiB limit // (theoretical) 32KiB limit
if (curSamplePos>=32768*8) curSample=-1; if (curSamplePos>=32768*8) curSample=-1;
@ -46,46 +47,49 @@ void DivPlatformZXBeeperQuadTone::acquire(short** buf, size_t len) {
curSamplePeriod-=chan[4].freq; curSamplePeriod-=chan[4].freq;
} }
curSamplePeriod+=40; curSamplePeriod+=40;
}
if (sampleActive) {
buf[0][h]=chan[4].out?32767:0;
if ((outputClock&3)==0) { if ((outputClock&3)==0) {
oscBuf[0]->data[oscBuf[0]->needle++]=0; oscBuf[0]->data[oscBuf[0]->needle++]=0;
oscBuf[1]->data[oscBuf[1]->needle++]=0; oscBuf[1]->data[oscBuf[1]->needle++]=0;
oscBuf[2]->data[oscBuf[2]->needle++]=0; oscBuf[2]->data[oscBuf[2]->needle++]=0;
oscBuf[3]->data[oscBuf[3]->needle++]=0; oscBuf[3]->data[oscBuf[3]->needle++]=0;
oscBuf[4]->data[oscBuf[4]->needle++]=o?32767:0; oscBuf[4]->data[oscBuf[4]->needle++]=buf[0][h];
} }
} else { } else {
int ch=outputClock/2; int ch=outputClock/2;
int b=ch*4; int b=ch*4;
bool o=false;
if ((outputClock&1)==0) { if ((outputClock&1)==0) {
short oscOut;
chan[ch].sPosition+=(regPool[1+b]<<8)|regPool[0+b]; chan[ch].sPosition+=(regPool[1+b]<<8)|regPool[0+b];
chan[ch].out=regPool[3+b]+((((chan[ch].sPosition>>8)&0xff)<regPool[2+b])?1:0); chan[ch].out=regPool[3+b]+((((chan[ch].sPosition>>8)&0xff)<regPool[2+b])?1:0);
if (isMuted[ch]) chan[ch].out=0; if ((chan[ch].out&0x18)==0x18) {
oscOut=32767;
} else if ((chan[ch].out&0x18)==0) {
oscOut=0;
} else {
oscOut=16383;
}
oscBuf[ch]->data[oscBuf[ch]->needle++]=oscOut;
} }
if ((outputClock&3)==0) { if ((outputClock&3)==0) {
oscBuf[4]->data[oscBuf[4]->needle++]=0; oscBuf[4]->data[oscBuf[4]->needle++]=0;
} }
o=chan[ch].out&0x10; if (!isMuted[ch]) o=chan[ch].out&0x10;
oscBuf[ch]->data[oscBuf[ch]->needle++]=o?32767:0; if (noHiss) {
chan[ch].out<<=1; deHisser[outputClock]=o;
buf[0][h]=-1;
// if muted, ztill run sample for (int i=0; i<8; i++) {
if (curSample>=0 && curSample<parent->song.sampleLen && isMuted[4]) { buf[0][h]+=deHisser[i]?4096:0;
while (curSamplePeriod>=chan[4].freq) { }
DivSample* s=parent->getSample(curSample);
if (s->samples>0) {
if (curSamplePos>=s->samples) curSample=-1;
// (theoretical) 32KiB limit
if (curSamplePos>=32768*8) curSample=-1;
} else { } else {
curSample=-1; buf[0][h]=o?32767:0;
}
curSamplePeriod-=chan[4].freq;
}
curSamplePeriod+=40;
} }
chan[ch].out<<=1;
} }
outputClock=(outputClock+1)&7; outputClock=(outputClock+1)&7;
buf[0][h]=o?32767:0;
} }
} }
@ -157,6 +161,7 @@ void DivPlatformZXBeeperQuadTone::tick(bool sysTick) {
chan[4].freq=parent->calcFreq(chan[4].baseFreq,chan[4].pitch,chan[4].fixedArp?chan[4].baseNoteOverride:chan[4].arpOff,chan[4].fixedArp,true,2,chan[4].pitch2,chipClock,off); chan[4].freq=parent->calcFreq(chan[4].baseFreq,chan[4].pitch,chan[4].fixedArp?chan[4].baseNoteOverride:chan[4].arpOff,chan[4].fixedArp,true,2,chan[4].pitch2,chipClock,off);
if (chan[4].freq>258) chan[4].freq=258; if (chan[4].freq>258) chan[4].freq=258;
if (chan[4].freq<3) chan[4].freq=3; if (chan[4].freq<3) chan[4].freq=3;
rWrite(16,(chan[4].freq-2)&255);
chan[4].freq*=13; chan[4].freq*=13;
} }
if (chan[4].keyOn) chan[4].keyOn=false; if (chan[4].keyOn) chan[4].keyOn=false;
@ -340,11 +345,12 @@ unsigned char* DivPlatformZXBeeperQuadTone::getRegisterPool() {
} }
int DivPlatformZXBeeperQuadTone::getRegisterPoolSize() { int DivPlatformZXBeeperQuadTone::getRegisterPoolSize() {
return 16; return 17;
} }
void DivPlatformZXBeeperQuadTone::reset() { void DivPlatformZXBeeperQuadTone::reset() {
memset(regPool,0,16); memset(regPool,0,17);
memset(deHisser,0,8);
for (int i=0; i<5; i++) { for (int i=0; i<5; i++) {
chan[i]=DivPlatformZXBeeperQuadTone::Channel(); chan[i]=DivPlatformZXBeeperQuadTone::Channel();
chan[i].std.setEngine(parent); chan[i].std.setEngine(parent);
@ -353,7 +359,6 @@ void DivPlatformZXBeeperQuadTone::reset() {
cycles=0; cycles=0;
curChan=0; curChan=0;
sOffTimer=0; sOffTimer=0;
ulaOut=0;
curSample=-1; curSample=-1;
curSamplePos=0; curSamplePos=0;
curSamplePeriod=0; curSamplePeriod=0;
@ -381,7 +386,8 @@ void DivPlatformZXBeeperQuadTone::setFlags(const DivConfig& flags) {
} }
CHECK_CUSTOM_CLOCK; CHECK_CUSTOM_CLOCK;
rate=chipClock/40; rate=chipClock/40;
for (int i=0; i<4; i++) { noHiss=flags.getBool("noHiss",false);
for (int i=0; i<5; i++) {
oscBuf[i]->rate=rate/4; oscBuf[i]->rate=rate/4;
} }
} }

View file

@ -36,12 +36,13 @@ class DivPlatformZXBeeperQuadTone: public DivDispatch {
Channel chan[5]; Channel chan[5];
DivDispatchOscBuffer* oscBuf[5]; DivDispatchOscBuffer* oscBuf[5];
bool isMuted[5]; bool isMuted[5];
unsigned char ulaOut; bool noHiss;
bool deHisser[8];
int cycles, curChan, sOffTimer, delay, curSample, curSamplePeriod; int cycles, curChan, sOffTimer, delay, curSample, curSamplePeriod;
unsigned int curSamplePos; unsigned int curSamplePos;
unsigned int outputClock; unsigned int outputClock;
unsigned char regPool[16]; unsigned char regPool[17];
friend void putDispatchChip(void*,int); friend void putDispatchChip(void*,int);
friend void putDispatchChan(void*,int,int); friend void putDispatchChan(void*,int,int);
public: public:

View file

@ -2270,6 +2270,23 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
} }
break; break;
} }
case DIV_SYSTEM_SFX_BEEPER_QUADTONE: {
bool sysPal=flags.getInt("clockSel",0);
bool noHiss=flags.getBool("noHiss",false);
if (ImGui::Checkbox("PAL",&sysPal)) {
altered=true;
}
if (ImGui::Checkbox("Disable hissing",&noHiss)) {
altered=true;
}
if (altered) {
e->lockSave([&]() {
flags.set("clockSel",(int)sysPal);
flags.set("noHiss",noHiss);
});
}
break;
}
case DIV_SYSTEM_SWAN: case DIV_SYSTEM_SWAN:
case DIV_SYSTEM_BUBSYS_WSG: case DIV_SYSTEM_BUBSYS_WSG:
case DIV_SYSTEM_PET: case DIV_SYSTEM_PET: