ZX beeper: implement overlay drums

1-bit samples up to 2048 bits in length triggered with 17xx
This commit is contained in:
tildearrow 2022-05-19 11:10:00 -05:00
parent 6ec8674072
commit 2ada4ee393
4 changed files with 44 additions and 25 deletions

View file

@ -1,7 +1,6 @@
# to-do for 0.6pre1 # to-do for 0.6pre1
- RF5C68 system - RF5C68 system
- ZX beeper system overlay percussion
- ADPCM chips - ADPCM chips
- Game Boy envelope macro/sequence - Game Boy envelope macro/sequence
- rewrite the system name detection function anyway - rewrite the system name detection function anyway

View file

@ -43,6 +43,25 @@ void DivPlatformZXBeeper::acquire(short* bufL, short* bufR, size_t start, size_t
for (size_t h=start; h<start+len; h++) { for (size_t h=start; h<start+len; h++) {
// clock here // clock here
bool o=false; bool o=false;
if (curSample>=0 && curSample<parent->song.sampleLen) {
if (--curSamplePeriod<0) {
DivSample* s=parent->getSample(curSample);
if (s->samples<=0) {
curSample=-1;
continue;
}
o=s->data8[curSamplePos++];
bufL[h]=o?16384:0;
if (curSamplePos>=s->samples) curSample=-1;
// 256 bits
if (curSamplePos>2047) curSample=-1;
curSamplePeriod=15;
}
continue;
}
unsigned short oldPos=chan[curChan].sPosition; unsigned short oldPos=chan[curChan].sPosition;
if (sOffTimer) { if (sOffTimer) {
@ -128,9 +147,7 @@ int DivPlatformZXBeeper::dispatch(DivCommand c) {
break; break;
} }
case DIV_CMD_NOTE_OFF: case DIV_CMD_NOTE_OFF:
chan[c.chan].dacSample=-1;
if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0);
chan[c.chan].pcm=false;
chan[c.chan].active=false; chan[c.chan].active=false;
chan[c.chan].keyOff=true; chan[c.chan].keyOff=true;
chan[c.chan].macroInit(NULL); chan[c.chan].macroInit(NULL);
@ -190,13 +207,9 @@ int DivPlatformZXBeeper::dispatch(DivCommand c) {
chan[c.chan].duty=c.value; chan[c.chan].duty=c.value;
break; break;
case DIV_CMD_SAMPLE_MODE: case DIV_CMD_SAMPLE_MODE:
chan[c.chan].pcm=c.value; curSample=c.value;
break; curSamplePos=0;
case DIV_CMD_SAMPLE_BANK: curSamplePeriod=0;
sampleBank=c.value;
if (sampleBank>(parent->song.sample.size()/12)) {
sampleBank=parent->song.sample.size()/12;
}
break; break;
case DIV_CMD_LEGATO: case DIV_CMD_LEGATO:
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
@ -265,8 +278,10 @@ void DivPlatformZXBeeper::reset() {
cycles=0; cycles=0;
curChan=0; curChan=0;
sOffTimer=0; sOffTimer=0;
sampleBank=0;
ulaOut=0; ulaOut=0;
curSample=-1;
curSamplePos=0;
curSamplePeriod=0;
} }
bool DivPlatformZXBeeper::keyOffAffectsArp(int ch) { bool DivPlatformZXBeeper::keyOffAffectsArp(int ch) {

View file

@ -27,10 +27,8 @@
class DivPlatformZXBeeper: public DivDispatch { class DivPlatformZXBeeper: public DivDispatch {
struct Channel { struct Channel {
int freq, baseFreq, pitch, pitch2, note; int freq, baseFreq, pitch, pitch2, note;
int dacPeriod, dacRate; int ins;
unsigned int dacPos; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
int dacSample, ins;
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, noise, pcm, furnaceDac;
signed char vol, outVol; signed char vol, outVol;
unsigned short sPosition; unsigned short sPosition;
unsigned char duty; unsigned char duty;
@ -45,10 +43,6 @@ class DivPlatformZXBeeper: public DivDispatch {
pitch(0), pitch(0),
pitch2(0), pitch2(0),
note(0), note(0),
dacPeriod(0),
dacRate(0),
dacPos(0),
dacSample(-1),
ins(-1), ins(-1),
active(false), active(false),
insChanged(true), insChanged(true),
@ -56,9 +50,6 @@ class DivPlatformZXBeeper: public DivDispatch {
keyOn(false), keyOn(false),
keyOff(false), keyOff(false),
inPorta(false), inPorta(false),
noise(false),
pcm(false),
furnaceDac(false),
vol(1), vol(1),
outVol(1), outVol(1),
sPosition(0), sPosition(0),
@ -75,10 +66,10 @@ class DivPlatformZXBeeper: public DivDispatch {
std::queue<QueuedWrite> writes; std::queue<QueuedWrite> writes;
unsigned char lastPan, ulaOut; unsigned char lastPan, ulaOut;
int cycles, curChan, sOffTimer, delay; int cycles, curChan, sOffTimer, delay, curSample, curSamplePeriod;
unsigned int curSamplePos;
int tempL[32]; int tempL[32];
int tempR[32]; int tempR[32];
unsigned char sampleBank, lfoMode, lfoSpeed;
unsigned char regPool[128]; unsigned char regPool[128];
friend void putDispatchChan(void*,int,int); friend void putDispatchChan(void*,int,int);
public: public:

View file

@ -1522,7 +1522,21 @@ void DivEngine::registerSystems() {
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6"}, {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6"},
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6"}, {"CH1", "CH2", "CH3", "CH4", "CH5", "CH6"},
{DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE},
{DIV_INS_BEEPER, DIV_INS_BEEPER, DIV_INS_BEEPER, DIV_INS_BEEPER, DIV_INS_BEEPER, DIV_INS_BEEPER} {DIV_INS_BEEPER, DIV_INS_BEEPER, DIV_INS_BEEPER, DIV_INS_BEEPER, DIV_INS_BEEPER, DIV_INS_BEEPER},
{},
[this](int ch, unsigned char effect, unsigned char effectVal) -> bool {
switch (effect) {
case 0x12: // pulse width
dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal));
break;
case 0x17: // overlay sample
dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,effectVal));
break;
default:
return false;
}
return true;
}
); );
sysDefs[DIV_SYSTEM_YM2612_EXT]=new DivSysDef( sysDefs[DIV_SYSTEM_YM2612_EXT]=new DivSysDef(