diff --git a/papers/doc/7-systems/ay8910.md b/papers/doc/7-systems/ay8910.md index ea0e894b9..3dd1049f6 100644 --- a/papers/doc/7-systems/ay8910.md +++ b/papers/doc/7-systems/ay8910.md @@ -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. \ No newline at end of file diff --git a/papers/doc/7-systems/ay8930.md b/papers/doc/7-systems/ay8930.md index a562765e5..720ecf047 100644 --- a/papers/doc/7-systems/ay8930.md +++ b/papers/doc/7-systems/ay8930.md @@ -38,4 +38,9 @@ while emulation of this chip is mostly complete, the additional noise setup regi - `25xx`: slide envelope period up. - `26xx`: slide envelope period down. - `27xx`: set noise AND mask. -- `28xx`: set noise OR mask. \ No newline at end of file +- `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. \ No newline at end of file diff --git a/papers/doc/7-systems/ym2610.md b/papers/doc/7-systems/ym2610.md index 575a4850c..dbe8b6a54 100644 --- a/papers/doc/7-systems/ym2610.md +++ b/papers/doc/7-systems/ym2610.md @@ -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. \ No newline at end of file diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index ef3190eeb..160191b4f 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -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, diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 2f3d62c4a..50e58703c 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -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; diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index f803c76b9..840dc8166 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -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]; diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 9b9cb26ba..84d8323de 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -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; diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index 408ee9238..6fe0d1c90 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -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]; diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 55443da5c..d624030da 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -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; diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index 8d3ee9b64..482f4aa47 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -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]; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 90855ef41..f474c56dc 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -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: