1 #pragma once 2 3 #include "effects/effectprocessor.h" 4 #include "engine/filters/enginefilterdelay.h" 5 #include "util/defs.h" 6 #include "util/math.h" 7 #include "util/sample.h" 8 #include "util/types.h" 9 10 class LVMixEQEffectGroupStateConstants { 11 public: 12 LVMixEQEffectGroupStateConstants() = delete; 13 14 static constexpr SINT kMaxDelay = 3300; // allows a 30 Hz filter at 97346; 15 static constexpr SINT kRampDone = -1; 16 static constexpr double kStartupLoFreq = 246; 17 static constexpr double kStartupHiFreq = 2484; 18 }; 19 20 template<class LPF> 21 class LVMixEQEffectGroupState : public EffectState { 22 public: LVMixEQEffectGroupState(const mixxx::EngineParameters & bufferParameters)23 explicit LVMixEQEffectGroupState(const mixxx::EngineParameters& bufferParameters) 24 : EffectState(bufferParameters), 25 m_oldLow(1.0), 26 m_oldMid(1.0), 27 m_oldHigh(1.0), 28 m_rampHoldOff(LVMixEQEffectGroupStateConstants::kRampDone), 29 m_oldSampleRate(bufferParameters.sampleRate()), 30 m_loFreq(LVMixEQEffectGroupStateConstants::kStartupLoFreq), 31 m_hiFreq(LVMixEQEffectGroupStateConstants::kStartupHiFreq) { 32 m_pLowBuf = SampleUtil::alloc(bufferParameters.samplesPerBuffer()); 33 m_pBandBuf = SampleUtil::alloc(bufferParameters.samplesPerBuffer()); 34 m_pHighBuf = SampleUtil::alloc(bufferParameters.samplesPerBuffer()); 35 36 m_low1 = new LPF(bufferParameters.sampleRate(), 37 LVMixEQEffectGroupStateConstants::kStartupLoFreq); 38 m_low2 = new LPF(bufferParameters.sampleRate(), 39 LVMixEQEffectGroupStateConstants::kStartupHiFreq); 40 m_delay2 = new EngineFilterDelay<LVMixEQEffectGroupStateConstants::kMaxDelay>(); 41 m_delay3 = new EngineFilterDelay<LVMixEQEffectGroupStateConstants::kMaxDelay>(); 42 setFilters(bufferParameters.sampleRate(), 43 LVMixEQEffectGroupStateConstants::kStartupLoFreq, 44 LVMixEQEffectGroupStateConstants::kStartupHiFreq); 45 } 46 ~LVMixEQEffectGroupState()47 ~LVMixEQEffectGroupState() override { 48 delete m_low1; 49 delete m_low2; 50 delete m_delay2; 51 delete m_delay3; 52 SampleUtil::free(m_pLowBuf); 53 SampleUtil::free(m_pBandBuf); 54 SampleUtil::free(m_pHighBuf); 55 } 56 setFilters(mixxx::audio::SampleRate sampleRate,double lowFreq,double highFreq)57 void setFilters( 58 mixxx::audio::SampleRate sampleRate, 59 double lowFreq, 60 double highFreq) { 61 SINT delayLow1 = m_low1->setFrequencyCornersForIntDelay( 62 lowFreq / sampleRate, LVMixEQEffectGroupStateConstants::kMaxDelay); 63 SINT delayLow2 = m_low2->setFrequencyCornersForIntDelay( 64 highFreq / sampleRate, LVMixEQEffectGroupStateConstants::kMaxDelay); 65 66 m_delay2->setDelay((delayLow1 - delayLow2) * 2); 67 m_delay3->setDelay(delayLow1 * 2); 68 m_groupDelay = delayLow1 * 2; 69 } 70 processChannel(const CSAMPLE * pInput,CSAMPLE * pOutput,SINT numSamples,mixxx::audio::SampleRate sampleRate,double dLow,double dMid,double dHigh,double loFreq,double hiFreq)71 void processChannel( 72 const CSAMPLE* pInput, 73 CSAMPLE* pOutput, 74 SINT numSamples, 75 mixxx::audio::SampleRate sampleRate, 76 double dLow, 77 double dMid, 78 double dHigh, 79 double loFreq, 80 double hiFreq) { 81 if (m_oldSampleRate != sampleRate || 82 (m_loFreq != loFreq) || 83 (m_hiFreq != hiFreq)) { 84 m_loFreq = loFreq; 85 m_hiFreq = hiFreq; 86 m_oldSampleRate = sampleRate; 87 setFilters(sampleRate, loFreq, hiFreq); 88 } 89 90 // Since a Bessel Low pass Filter has a constant group delay in the pass band, 91 // we can subtract or add the filtered signal to the dry signal if we compensate this delay 92 // The dry signal represents the high gain 93 // Then the higher low pass is added and at least the lower low pass result. 94 auto fLow = static_cast<CSAMPLE>(dLow - dMid); 95 auto fMid = static_cast<CSAMPLE>(dMid - dHigh); 96 auto fHigh = static_cast<CSAMPLE>(dHigh); 97 98 // Note: We do not call pauseFilter() here because this will introduce a 99 // buffer size-dependent start delay. During such start delay some unwanted 100 // frequencies are slipping though or wanted frequencies are damped. 101 // We know the exact group delay here so we can just hold off the ramping. 102 if (fHigh != 0 || m_oldHigh != 0) { 103 m_delay3->process(pInput, m_pHighBuf, numSamples); 104 } 105 106 if (fMid != 0 || m_oldMid != 0) { 107 m_delay2->process(pInput, m_pBandBuf, numSamples); 108 m_low2->process(m_pBandBuf, m_pBandBuf, numSamples); 109 } 110 111 if (fLow != 0 || m_oldLow != 0) { 112 m_low1->process(pInput, m_pLowBuf, numSamples); 113 } 114 115 // Test code for comparing streams as two stereo channels 116 //for (SINT i = 0; i < numSamples; i +=2) { 117 // pOutput[i] = pState->m_pLowBuf[i]; 118 // pOutput[i + 1] = pState->m_pBandBuf[i]; 119 //} 120 121 if (fLow == m_oldLow && 122 fMid == m_oldMid && 123 fHigh == m_oldHigh) { 124 SampleUtil::copy3WithGain(pOutput, 125 m_pLowBuf, fLow, 126 m_pBandBuf, fMid, 127 m_pHighBuf, fHigh, 128 numSamples); 129 } else { 130 SINT copySamples = 0; 131 SINT rampingSamples = numSamples; 132 if ((fLow != 0 && m_oldLow == 0) || 133 (fMid != 0 && m_oldMid == 0) || 134 (fHigh != 0 && m_oldHigh == 0)) { 135 // we have just switched at least one filter on 136 // Hold off ramping for the group delay 137 if (m_rampHoldOff == LVMixEQEffectGroupStateConstants::kRampDone) { 138 // multiply the group delay * 2 to ensure that the filter is 139 // settled it is actually at a factor of 1,8 at default setting 140 m_rampHoldOff = m_groupDelay * 2; 141 // ensure that we have at least 128 samples for ramping 142 // (the smallest buffer, that suits for de-clicking) 143 SINT rampingSamples = numSamples - (m_rampHoldOff % numSamples); 144 if (rampingSamples < 128) { 145 m_rampHoldOff += rampingSamples; 146 } 147 } 148 149 // ramping is done in one of the following calls if 150 // pState->m_rampHoldOff >= numSamples; 151 copySamples = math_min(m_rampHoldOff, numSamples); 152 m_rampHoldOff -= copySamples; 153 rampingSamples = numSamples - copySamples; 154 155 SampleUtil::copy3WithGain(pOutput, 156 m_pLowBuf, m_oldLow, 157 m_pBandBuf, m_oldMid, 158 m_pHighBuf, m_oldHigh, 159 copySamples); 160 } 161 162 if (rampingSamples) { 163 SampleUtil::copy3WithRampingGain(&pOutput[copySamples], 164 &m_pLowBuf[copySamples], m_oldLow, fLow, 165 &m_pBandBuf[copySamples], m_oldMid, fMid, 166 &m_pHighBuf[copySamples], m_oldHigh, fHigh, 167 rampingSamples); 168 169 m_oldLow = fLow; 170 m_oldMid = fMid; 171 m_oldHigh = fHigh; 172 m_rampHoldOff = LVMixEQEffectGroupStateConstants::kRampDone; 173 } 174 } 175 } 176 processChannelAndPause(const CSAMPLE * pInput,CSAMPLE * pOutput,SINT numSamples)177 void processChannelAndPause( 178 const CSAMPLE* pInput, 179 CSAMPLE* pOutput, 180 SINT numSamples) { 181 // Note: We do not call pauseFilter() here because this will introduce a 182 // buffer size-dependent start delay. During such start delay some unwanted 183 // frequencies are slipping though or wanted frequencies are damped. 184 // We know the exact group delay here so we can just hold off the ramping. 185 m_delay3->processAndPauseFilter(pInput, m_pHighBuf, numSamples); 186 187 if (m_oldMid != 0) { 188 m_delay2->processAndPauseFilter(pInput, m_pBandBuf, numSamples); 189 m_low2->processAndPauseFilter(m_pBandBuf, m_pBandBuf, numSamples); 190 } 191 192 if (m_oldLow != 0) { 193 m_low1->processAndPauseFilter(pInput, m_pLowBuf, numSamples); 194 } 195 196 SampleUtil::copy3WithRampingGain(pOutput, 197 m_pLowBuf, m_oldLow, 0.0, 198 m_pBandBuf, m_oldMid, 0.0, 199 m_pHighBuf, m_oldHigh, 1.0, 200 numSamples); 201 } 202 203 /* 204 205 SINT copySamples = 0; 206 SINT rampingSamples = numSamples; 207 if ((fLow && !m_oldLow) || 208 (fMid && !m_oldMid) || 209 (fHigh && !m_oldHigh)) { 210 // we have just switched at least one filter on 211 // Hold off ramping for the group delay 212 if (m_rampHoldOff == LVMixEQEffectGroupStateConstants::kRampDone) { 213 // multiply the group delay * 2 to ensure that the filter is 214 // settled it is actually at a factor of 1,8 at default setting 215 m_rampHoldOff = m_groupDelay * 2; 216 // ensure that we have at least 128 samples for ramping 217 // (the smallest buffer, that suits for de-clicking) 218 SINT rampingSamples = numSamples - (m_rampHoldOff % numSamples); 219 if (rampingSamples < 128) { 220 m_rampHoldOff += rampingSamples; 221 } 222 } 223 224 // ramping is done in one of the following calls if 225 // pState->m_rampHoldOff >= numSamples; 226 copySamples = math_min(m_rampHoldOff, numSamples); 227 m_rampHoldOff -= copySamples; 228 rampingSamples = numSamples - copySamples; 229 230 SampleUtil::copy3WithGain(pOutput, 231 m_pLowBuf, m_oldLow, 232 m_pBandBuf, m_oldMid, 233 m_pHighBuf, m_oldHigh, 234 copySamples); 235 } 236 237 if (rampingSamples) { 238 SampleUtil::copy3WithRampingGain(&pOutput[copySamples], 239 &m_pLowBuf[copySamples], m_oldLow, fLow, 240 &m_pBandBuf[copySamples], m_oldMid, fMid, 241 &m_pHighBuf[copySamples], m_oldHigh, fHigh, 242 rampingSamples); 243 244 m_oldLow = fLow; 245 m_oldMid = fMid; 246 m_oldHigh = fHigh; 247 m_rampHoldOff = LVMixEQEffectGroupStateConstants::kRampDone; 248 249 } 250 } 251 252 */ 253 254 private: 255 LPF* m_low1; 256 LPF* m_low2; 257 EngineFilterDelay<LVMixEQEffectGroupStateConstants::kMaxDelay>* m_delay2; 258 EngineFilterDelay<LVMixEQEffectGroupStateConstants::kMaxDelay>* m_delay3; 259 260 CSAMPLE_GAIN m_oldLow; 261 CSAMPLE_GAIN m_oldMid; 262 CSAMPLE_GAIN m_oldHigh; 263 264 SINT m_rampHoldOff; 265 SINT m_groupDelay; 266 267 mixxx::audio::SampleRate m_oldSampleRate; 268 double m_loFreq; 269 double m_hiFreq; 270 271 CSAMPLE* m_pLowBuf; 272 CSAMPLE* m_pBandBuf; 273 CSAMPLE* m_pHighBuf; 274 }; 275