From 154ef3f9a3aaaf9fbee3e90f713882c88fc4e543 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 26 Mar 2022 23:39:20 -0500 Subject: [PATCH] Amiga: filter emulation --- papers/doc/7-systems/amiga.md | 2 +- src/engine/dispatch.h | 2 ++ src/engine/fileOps.cpp | 5 +++- src/engine/platform/amiga.cpp | 43 ++++++++++++++++++++++++++++++----- src/engine/platform/amiga.h | 6 +++++ src/engine/playback.cpp | 11 +++++++++ 6 files changed, 61 insertions(+), 8 deletions(-) diff --git a/papers/doc/7-systems/amiga.md b/papers/doc/7-systems/amiga.md index fba62c430..713300c29 100644 --- a/papers/doc/7-systems/amiga.md +++ b/papers/doc/7-systems/amiga.md @@ -6,4 +6,4 @@ in this very computer music trackers were born... # effects -none. as of this moment the Amiga doesn't need any effects in particular, but some may be added in a future. +- `10xx`: toggle low-pass filter. `0` turns it off and `1` turns it on. \ No newline at end of file diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index a3cd1e810..b535df52d 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -106,6 +106,8 @@ enum DivDispatchCmds { DIV_CMD_SAA_ENVELOPE, + DIV_CMD_AMIGA_FILTER, + DIV_CMD_LYNX_LFSR_LOAD, DIV_CMD_QSOUND_ECHO_FEEDBACK, diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index d9806db57..0e82b6b79 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -1573,6 +1573,9 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { fxTyp=fxVal>>4; fxVal&=0x0f; switch (fxTyp) { + case 0: + writeFxCol(0x10,!fxVal); + break; case 1: // single note slide up case 2: // single note slide down writeFxCol(fxTyp-1+0xf1,fxVal); @@ -1613,7 +1616,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { ds.systemLen=(chCount+3)/4; for(int i=0; i1 || bypassLimits)?2:0); // PAL } for(int i=0; i=0 && chan[i].samplesong.sampleLen) { chan[i].audSub-=AMIGA_DIVIDER; @@ -102,14 +112,20 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le } if (!isMuted[i]) { if (i==0 || i==3) { - bufL[h]+=((chan[i].audDat*chan[i].outVol)*sep1)>>7; - bufR[h]+=((chan[i].audDat*chan[i].outVol)*sep2)>>7; + outL+=((chan[i].audDat*chan[i].outVol)*sep1)>>7; + outR+=((chan[i].audDat*chan[i].outVol)*sep2)>>7; } else { - bufL[h]+=((chan[i].audDat*chan[i].outVol)*sep2)>>7; - bufR[h]+=((chan[i].audDat*chan[i].outVol)*sep1)>>7; + outL+=((chan[i].audDat*chan[i].outVol)*sep2)>>7; + outR+=((chan[i].audDat*chan[i].outVol)*sep1)>>7; } } } + filter[0][0]+=(filtConst*(outL-filter[0][0]))>>12; + filter[0][1]+=(filtConst*(filter[0][0]-filter[0][1]))>>12; + filter[1][0]+=(filtConst*(outR-filter[1][0]))>>12; + filter[1][1]+=(filtConst*(filter[1][0]-filter[1][1]))>>12; + bufL[h]=filter[0][1]; + bufR[h]=filter[1][1]; } } @@ -299,6 +315,10 @@ int DivPlatformAmiga::dispatch(DivCommand c) { chan[c.chan].audPos=c.value; chan[c.chan].setPos=true; break; + case DIV_CMD_AMIGA_FILTER: + filterOn=c.value; + filtConst=filterOn?filtConstOn:filtConstOff; + break; case DIV_CMD_GET_VOLMAX: return 64; break; @@ -332,7 +352,11 @@ void* DivPlatformAmiga::getChanState(int ch) { void DivPlatformAmiga::reset() { for (int i=0; i<4; i++) { chan[i]=DivPlatformAmiga::Channel(); + filter[0][i]=0; + filter[1][i]=0; } + filterOn=false; + filtConst=filterOn?filtConstOn:filtConstOff; } bool DivPlatformAmiga::isStereo() { @@ -372,6 +396,13 @@ void DivPlatformAmiga::setFlags(unsigned int flags) { sep2=127-((flags>>8)&127); amigaModel=flags&2; bypassLimits=flags&4; + if (amigaModel) { + filtConstOff=4000; + filtConstOn=sin(M_PI*8000.0/(double)rate)*4096.0; + } else { + filtConstOff=sin(M_PI*16000.0/(double)rate)*4096.0; + filtConstOn=sin(M_PI*5500.0/(double)rate)*4096.0; + } } int DivPlatformAmiga::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { diff --git a/src/engine/platform/amiga.h b/src/engine/platform/amiga.h index 02dcb3de9..d73918e96 100644 --- a/src/engine/platform/amiga.h +++ b/src/engine/platform/amiga.h @@ -68,6 +68,11 @@ class DivPlatformAmiga: public DivDispatch { bool isMuted[4]; bool bypassLimits; bool amigaModel; + bool filterOn; + + int filter[2][4]; + int filtConst; + int filtConstOff, filtConstOn; int sep1, sep2; @@ -88,6 +93,7 @@ class DivPlatformAmiga: public DivDispatch { void notifyWaveChange(int wave); void notifyInsDeletion(void* ins); const char** getRegisterSheet(); + const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); }; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 71fd58ddd..7d089e609 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -113,6 +113,8 @@ const char* cmdName[DIV_CMD_MAX]={ "AY_AUTO_PWM", "SAA_ENVELOPE", + + "AMIGA_FILTER", "LYNX_LFSR_LOAD", @@ -649,6 +651,15 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char return false; } break; + case DIV_SYSTEM_AMIGA: + switch (effect) { + case 0x10: // toggle filter + dispatchCmd(DivCommand(DIV_CMD_AMIGA_FILTER,ch,effectVal)); + break; + default: + return false; + } + break; case DIV_SYSTEM_SEGAPCM: case DIV_SYSTEM_SEGAPCM_COMPAT: switch (effect) {