add auto-envelope mode (29xy effect)

this closes #32
This commit is contained in:
tildearrow 2022-01-20 03:23:03 -05:00
parent 04240ffa46
commit 75ce5f4e2a
11 changed files with 64 additions and 8 deletions

View file

@ -33,3 +33,8 @@ the chip's powerful sound comes from the envelope...
- `24xx`: set envelope period high byte.
- `25xx`: slide envelope period up.
- `26xx`: slide envelope period down.
- `29xy`: enable auto-envelope mode.
- in this mode the envelope period is set to the channel's notes, multiplied by a fraction.
- `x` is the numerator.
- `y` is the denominator.
- if `x` or `y` are 0 this will disable auto-envelope mode.

View file

@ -39,3 +39,8 @@ while emulation of this chip is mostly complete, the additional noise setup regi
- `26xx`: slide envelope period down.
- `27xx`: set noise AND mask.
- `28xx`: set noise OR mask.
- `29xy`: enable auto-envelope mode.
- in this mode the envelope period is set to the channel's notes, multiplied by a fraction.
- `x` is the numerator.
- `y` is the denominator.
- if `x` or `y` are 0 this will disable auto-envelope mode.

View file

@ -29,7 +29,7 @@ its soundchip is a 3-in-1: FM, YM2149 (AY-3-8910 clone) and ADPCM in a single pa
- `00`: square
- `01`: noise
- `02`: square and noise
- `03`: envelope
- `03`: nothing (apparently)
- `04`: envelope and square
- `05`: envelope and noise
- `06`: envelope and square and noise
@ -52,3 +52,8 @@ its soundchip is a 3-in-1: FM, YM2149 (AY-3-8910 clone) and ADPCM in a single pa
- `24xx`: set envelope period high byte.
- `25xx`: slide envelope period up.
- `26xx`: slide envelope period down.
- `29xy`: enable SSG auto-envelope mode.
- in this mode the envelope period is set to the channel's notes, multiplied by a fraction.
- `x` is the numerator.
- `y` is the denominator.
- if `x` or `y` are 0 this will disable auto-envelope mode.

View file

@ -68,6 +68,7 @@ enum DivDispatchCmds {
DIV_CMD_AY_ENVELOPE_SLIDE,
DIV_CMD_AY_NOISE_MASK_AND,
DIV_CMD_AY_NOISE_MASK_OR,
DIV_CMD_AY_AUTO_ENVELOPE,
DIV_CMD_SAA_ENVELOPE,

View file

@ -82,6 +82,11 @@ void DivPlatformAY8910::tick() {
rWrite(1+((i)<<1),chan[i].freq>>8);
if (chan[i].keyOn) chan[i].keyOn=false;
if (chan[i].keyOff) chan[i].keyOff=false;
if (chan[i].freqChanged && chan[i].autoEnvNum>0 && chan[i].autoEnvDen>0) {
ayEnvPeriod=(chan[i].freq*chan[i].autoEnvDen/chan[i].autoEnvNum)>>4;
immWrite(0x0b,ayEnvPeriod);
immWrite(0x0c,ayEnvPeriod>>8);
}
chan[i].freqChanged=false;
}
}
@ -241,6 +246,11 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
case DIV_CMD_AY_ENVELOPE_SLIDE:
ayEnvSlide=c.value;
break;
case DIV_CMD_AY_AUTO_ENVELOPE:
chan[c.chan].autoEnvNum=c.value>>4;
chan[c.chan].autoEnvDen=c.value&15;
chan[c.chan].freqChanged=true;
break;
case DIV_ALWAYS_SET_VOLUME:
return 0;
break;

View file

@ -10,13 +10,13 @@ class DivPlatformAY8910: public DivDispatch {
struct Channel {
unsigned char freqH, freqL;
int freq, baseFreq, pitch;
unsigned char ins, note, psgMode;
unsigned char ins, note, psgMode, autoEnvNum, autoEnvDen;
signed char konCycles;
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta;
int vol, outVol;
unsigned char pan;
DivMacroInt std;
Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), ins(-1), note(0), psgMode(1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15), pan(3) {}
Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), ins(-1), note(0), psgMode(1), autoEnvNum(0), autoEnvDen(0), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15), pan(3) {}
};
Channel chan[3];
bool isMuted[3];

View file

@ -108,6 +108,11 @@ void DivPlatformAY8930::tick() {
rWrite(1+((i)<<1),chan[i].freq>>8);
if (chan[i].keyOn) chan[i].keyOn=false;
if (chan[i].keyOff) chan[i].keyOff=false;
if (chan[i].freqChanged && chan[i].autoEnvNum>0 && chan[i].autoEnvDen>0) {
ayEnvPeriod[i]=(chan[i].freq*chan[i].autoEnvDen/chan[i].autoEnvNum)>>4;
immWrite(regPeriodL[i],ayEnvPeriod[i]);
immWrite(regPeriodH[i],ayEnvPeriod[i]>>8);
}
chan[i].freqChanged=false;
}
@ -281,6 +286,11 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
ayNoiseOr=c.value;
immWrite(0x1a,ayNoiseOr);
break;
case DIV_CMD_AY_AUTO_ENVELOPE:
chan[c.chan].autoEnvNum=c.value>>4;
chan[c.chan].autoEnvDen=c.value&15;
chan[c.chan].freqChanged=true;
break;
case DIV_ALWAYS_SET_VOLUME:
return 0;
break;

View file

@ -10,13 +10,13 @@ class DivPlatformAY8930: public DivDispatch {
struct Channel {
unsigned char freqH, freqL;
int freq, baseFreq, pitch;
unsigned char ins, note, psgMode, duty;
unsigned char ins, note, psgMode, autoEnvNum, autoEnvDen, duty;
signed char konCycles;
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta;
int vol, outVol;
unsigned char pan;
DivMacroInt std;
Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), ins(-1), note(0), psgMode(1), duty(4), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(31), pan(3) {}
Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), ins(-1), note(0), psgMode(1), autoEnvNum(0), autoEnvDen(0), duty(4), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(31), pan(3) {}
};
Channel chan[3];
bool isMuted[3];

View file

@ -92,6 +92,11 @@ void DivPlatformYM2610::tick() {
rWrite(1+((i-4)<<1),chan[i].freq>>8);
if (chan[i].keyOn) chan[i].keyOn=false;
if (chan[i].keyOff) chan[i].keyOff=false;
if (chan[i].freqChanged && chan[i].autoEnvNum>0 && chan[i].autoEnvDen>0) {
ayEnvPeriod=(chan[i].freq*chan[i].autoEnvDen/chan[i].autoEnvNum)>>4;
immWrite(0x0b,ayEnvPeriod);
immWrite(0x0c,ayEnvPeriod>>8);
}
chan[i].freqChanged=false;
}
}
@ -503,6 +508,12 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
if (c.chan<4 || c.chan>6) break;
ayEnvSlide=c.value;
break;
case DIV_CMD_AY_AUTO_ENVELOPE:
if (c.chan<4 || c.chan>6) break;
chan[c.chan].autoEnvNum=c.value>>4;
chan[c.chan].autoEnvDen=c.value&15;
chan[c.chan].freqChanged=true;
break;
case DIV_ALWAYS_SET_VOLUME:
return 0;
break;

View file

@ -19,13 +19,13 @@ class DivPlatformYM2610: public DivDispatch {
struct Channel {
unsigned char freqH, freqL;
int freq, baseFreq, pitch;
unsigned char ins, note, psgMode;
unsigned char ins, note, psgMode, autoEnvNum, autoEnvDen;
signed char konCycles;
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta;
int vol, outVol;
unsigned char pan;
DivMacroInt std;
Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), ins(-1), note(0), psgMode(1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15), pan(3) {}
Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), ins(-1), note(0), psgMode(1), autoEnvNum(0), autoEnvDen(0), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15), pan(3) {}
};
Channel chan[13];
bool isMuted[13];

View file

@ -80,6 +80,7 @@ const char* cmdName[DIV_CMD_MAX]={
"AY_ENVELOPE_SLIDE",
"AY_NOISE_MASK_AND",
"AY_NOISE_MASK_OR",
"AY_AUTO_ENVELOPE",
"SAA_ENVELOPE",
@ -286,6 +287,11 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SLIDE,ch,effectVal));
}
break;
case 0x29: // auto-envelope
if (sysOfChan[ch]==DIV_SYSTEM_YM2610 || sysOfChan[ch]==DIV_SYSTEM_YM2610_EXT) {
dispatchCmd(DivCommand(DIV_CMD_AY_AUTO_ENVELOPE,ch,effectVal));
}
break;
default:
return false;
}
@ -369,6 +375,9 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
case 0x28: // noise or mask
dispatchCmd(DivCommand(DIV_CMD_AY_NOISE_MASK_OR,ch,effectVal));
break;
case 0x29: // auto-envelope
dispatchCmd(DivCommand(DIV_CMD_AY_AUTO_ENVELOPE,ch,effectVal));
break;
}
break;
case DIV_SYSTEM_SAA1099: