// Simple 2-poles resonant filter void module_renderer::SetupChannelFilter(modplug::tracker::modchannel_t *pChn, bool bReset, int flt_modifier) const //---------------------------------------------------------------------------------------- { float fs = (float)deprecated_global_mixing_freq; float fg, fb0, fb1, fc, dmpfac; /* if (pChn->pHeader) { fc = (float)CutOffToFrequency(pChn->nCutOff, flt_modifier); dmpfac = pow(10.0f, -((24.0f / 128.0f)*(float)pChn->nResonance) / 20.0f); } else {*/ int cutoff = 0; if(!GetModFlag(MSF_OLDVOLSWING)) { if(pChn->nCutSwing) { pChn->nCutOff += pChn->nCutSwing; if(pChn->nCutOff > 127) pChn->nCutOff = 127; if(pChn->nCutOff < 0) pChn->nCutOff = 0; pChn->nCutSwing = 0; } if(pChn->nResSwing) { pChn->nResonance += pChn->nResSwing; if(pChn->nResonance > 127) pChn->nResonance = 127; if(pChn->nResonance < 0) pChn->nResonance = 0; pChn->nResSwing = 0; } cutoff = bad_max( bad_min((int)pChn->nCutOff,127), 0); // cap cutoff fc = (float)CutOffToFrequency(cutoff, flt_modifier); dmpfac = pow(10.0f, -((24.0f / 128.0f)*(float)((pChn->nResonance)&0x7F)) / 20.0f); } else { cutoff = bad_max( bad_min((int)pChn->nCutOff+(int)pChn->nCutSwing,127), 0); // cap cutoff fc = (float)CutOffToFrequency(cutoff, flt_modifier); dmpfac = pow(10.0f, -((24.0f / 128.0f)*(float)((pChn->nResonance+pChn->nResSwing)&0x7F)) / 20.0f); } // } fc *= (float)(2.0*3.14159265358/fs); float d = (1.0f-2.0f*dmpfac)* fc; if (d>2.0) d = 2.0; d = (2.0f*dmpfac - d)/fc; float e = pow(1.0f/fc,2.0f); fg=1/(1+d+e); fb0=(d+e+e)/(1+d+e); fb1=-e/(1+d+e); switch(pChn->nFilterMode) { case FLTMODE_HIGHPASS: pChn->nFilter_A0 = 1.0f - fg; pChn->nFilter_B0 = fb0; pChn->nFilter_B1 = fb1; pChn->nFilter_HP = 1; break; default: pChn->nFilter_A0 = fg; pChn->nFilter_B0 = fb0; pChn->nFilter_B1 = fb1; pChn->nFilter_HP = 0; } if (bReset) { pChn->nFilter_Y1 = pChn->nFilter_Y2 = 0; pChn->nFilter_Y3 = pChn->nFilter_Y4 = 0; } pChn->flags |= CHN_FILTER; }
// Simple 2-poles resonant filter void CSoundFile::SetupChannelFilter(ModChannel *pChn, bool bReset, int flt_modifier) const //---------------------------------------------------------------------------------------- { int cutoff = (int)pChn->nCutOff + (int)pChn->nCutSwing; int resonance = (int)(pChn->nResonance & 0x7F) + (int)pChn->nResSwing; Limit(cutoff, 0, 127); Limit(resonance, 0, 127); if(!GetModFlag(MSF_OLDVOLSWING)) { pChn->nCutOff = (uint8)cutoff; pChn->nCutSwing = 0; pChn->nResonance = (uint8)resonance; pChn->nResSwing = 0; } float d, e; // flt_modifier is in [-256, 256], so cutoff is in [0, 127 * 2] after this calculation. const int computedCutoff = cutoff * (flt_modifier + 256) / 256; // Filtering is only ever done in IT if either cutoff is not full or if resonance is set. if(IsCompatibleMode(TRK_IMPULSETRACKER) && resonance == 0 && computedCutoff >= 254) { if(pChn->rowCommand.IsNote() && !pChn->dwFlags[CHN_PORTAMENTO] && !pChn->nMasterChn && m_SongFlags[SONG_FIRSTTICK]) { // Z7F next to a note disables the filter, however in other cases this should not happen. // Test cases: filter-reset.it, filter-reset-carry.it, filter-nna.it pChn->dwFlags.reset(CHN_FILTER); } return; } pChn->dwFlags.set(CHN_FILTER); if(UseITFilterMode()) { const float freqParameterMultiplier = 128.0f / (24.0f * 256.0f); // 2 ^ (i / 24 * 256) float frequency = 110.0f * pow(2.0f, 0.25f + (float)computedCutoff * freqParameterMultiplier); LimitMax(frequency, (float)(m_MixerSettings.gdwMixingFreq / 2)); const float r = (float)m_MixerSettings.gdwMixingFreq / (2.0f * (float)M_PI * frequency); d = ITResonanceTable[resonance] * r + ITResonanceTable[resonance] - 1.0f; e = r * r; } else { float fc = (float)CutOffToFrequency(cutoff, flt_modifier); const float dmpfac = pow(10.0f, -((24.0f / 128.0f) * (float)resonance) / 20.0f); fc *= (float)(2.0f * (float)M_PI / (float)m_MixerSettings.gdwMixingFreq); d = (1.0f - 2.0f * dmpfac) * fc; LimitMax(d, 2.0f); d = (2.0f * dmpfac - d) / fc; e = pow(1.0f / fc, 2.0f); } float fg = 1.0f / (1.0f + d + e); float fb0 = (d + e + e) / (1 + d + e); float fb1 = -e / (1.0f + d + e); switch(pChn->nFilterMode) { case FLTMODE_HIGHPASS: pChn->nFilter_A0 = 1.0f - fg; pChn->nFilter_B0 = fb0; pChn->nFilter_B1 = fb1; pChn->nFilter_HP = -1; break; default: pChn->nFilter_A0 = fg; pChn->nFilter_B0 = fb0; pChn->nFilter_B1 = fb1; pChn->nFilter_HP = 0; break; } if (bReset) { pChn->nFilter_Y1 = pChn->nFilter_Y2 = 0; pChn->nFilter_Y3 = pChn->nFilter_Y4 = 0; } }