void DspLimiter::Process(DspChunk& chunk) { if (chunk.IsEmpty()) return; if (!m_exclusive || (chunk.GetFormat() != DspFormat::Float && chunk.GetFormat() != DspFormat::Double)) { m_active = false; return; } m_active = true; // Analyze samples float peak; if (chunk.GetFormat() == DspFormat::Double) { double largePeak = GetPeak((double*)chunk.GetData(), chunk.GetSampleCount()); peak = std::nexttoward((float)largePeak, largePeak); } else { assert(chunk.GetFormat() == DspFormat::Float); peak = GetPeak((float*)chunk.GetData(), chunk.GetSampleCount()); } // Configure limiter if (peak > 1.0f) { if (m_holdWindow <= 0) { NewTreshold(std::max(peak, 1.4f)); } else if (peak > m_peak) { NewTreshold(peak); } m_holdWindow = (int64_t)m_rate * m_channels * 10; // 10 seconds } // Apply limiter if (m_holdWindow > 0) { if (chunk.GetFormat() == DspFormat::Double) { ApplyLimiter<double>((double*)chunk.GetData(), chunk.GetSampleCount(), m_threshold); } else { assert(chunk.GetFormat() == DspFormat::Float); ApplyLimiter((float*)chunk.GetData(), chunk.GetSampleCount(), m_threshold); } m_holdWindow -= chunk.GetSampleCount(); } }
void DesignAudioBiquadIIR_q31_t(q31_t_IIR_Coefficients *C,// Pointer to the IIR Structure uint8_t FilterType, float Fs, //System Sample Rate float f0, //("wherever it's happenin', man." Center Frequency or //Corner Frequency, or shelf midpoint frequency, depending //on which filter type. The "significant frequency".)*/ float Q,//(the EE kind of definition, except for peakingEQ in which A*Q is // the classic EE Q. That adjustment in definition was made so that // a boost of N dB followed by a cut of N dB for identical Q and // f0/Fs results in a precisely flat unity gain filter or "wire".)*/ float dBgain// (used only for peaking and shelving filters) ) { A = sqrt(pow(10,(dBgain/40))); if(Fs == 0) Fs = 1000; if(Q == 0) Q = 1.0; w0 = 2.0*3.141592654*f0/Fs; alpha = sin(w0)/(2.0 * Q); switch(FilterType) { default: case BIQUAD_LOW_PASS_FILTER : b0 = (1 - cos(w0))/2; b1 = 1 - cos(w0); b2 = (1 - cos(w0))/2; a0 = 1 + alpha; a1 = -2*cos(w0); a2 = 1 - alpha; break; case BIQUAD_HIGH_PASS_FILTER : b0 = (1 + cos(w0))/2; b1 = -(1 + cos(w0)); b2 = (1 + cos(w0))/2; a0 = 1 + alpha; a1 = -2*cos(w0); a2 = 1 - alpha; break; case BIQUAD_BAND_PASS_FILTER_CONSTANT_SKIRT_GAIN_PEAKGAIN_Q : b0 = Q*alpha; b1 = 0; b2 = -Q*alpha; a0 = 1 + alpha; a1 = -2*cos(w0); a2 = 1 - alpha; break; case BIQUAD_BAND_PASS_FILTER_CONSTANT_0_DB_PEAK_GAIN: b0 = alpha; b1 = 0; b2 = -alpha; a0 = 1 + alpha; a1 = -2*cos(w0); a2 = 1 - alpha; break; case BIQUAD_NOTCH_FILTER: b0 = 1; b1 = -2*cos(w0); b2 = 1; a0 = 1 + alpha; a1 = -2*cos(w0); a2 = 1 - alpha; break; case BIQUAD_ALL_PASS_FILTER: b0 = 1 - alpha; b1 = -2*cos(w0); b2 = 1 + alpha; a0 = 1 + alpha; a1 = -2*cos(w0); a2 = 1 - alpha; break; case BIQUAD_PEAKING_EQ: b0 = 1 + alpha*A; b1 = -2*cos(w0); b2 = 1 - alpha*A; a0 = 1 + alpha/A; a1 = -2*cos(w0); a2 = 1 - alpha/A; break; case BIQUAD_LOW_SHELF: b0 = A*( (A+1.0) - (A-1.0)*cos(w0) + 2.0*sqrt(A)*alpha ); b1 = 2.0*A*( (A-1.0) - (A+1.0)*cos(w0) ); b2 = A*( (A+1.0) - (A-1.0)*cos(w0) - 2.0*sqrt(A)*alpha ); a0 = (A+1.0) + (A-1.0)*cos(w0) + 2.0*sqrt(A)*alpha; a1 = -2.0*( (A-1.0) + (A+1.0)*cos(w0) ); a2 = (A+1.0) + (A-1.0)*cos(w0) - 2.0*sqrt(A)*alpha; break; case BIQUAD_HIGH_SHELF: b0 = A*( (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha ); b1 = -2*A*( (A-1) + (A+1)*cos(w0) ); b2 = A*( (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha ); a0 = (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha; a1 = 2*( (A-1) - (A+1)*cos(w0) ); a2 = (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha; break; } /* The most straight forward implementation would be the "Direct Form 1" (Eq 2): y[n] = (b0/a0)*x[n] + (b1/a0)*x[n-1] + (b2/a0)*x[n-2] - (a1/a0)*y[n-1] - (a2/a0)*y[n-2] (Eq 4) but to make things easier on the chip, we will do all adds: y[n] = (b0/a0)*x[n] + (b1/a0)*x[n-1] + (b2/a0)*x[n-2] + (a1/a0)*y[n-1] + (a2/a0)*y[n-2] (Eq 4) THis means that 2 feedback coef. have to be inverted */ b0 = b0/a0; b1 = b1/a0; b2 = b2/a0; a1 = a1/a0; a2 = a2/a0; a0 = 1.0; a1 = a1 * -1.0; a2 = a2 * -1.0; C->PostShift = 0; while(GetPeak(&coef[0],6) > 1.0) { C->PostShift++; b0 = b0/(float)(1<<C->PostShift); b1 = b1/(float)(1<<C->PostShift); b2 = b2/(float)(1<<C->PostShift); a1 = a1/(float)(1<<C->PostShift); a2 = a2/(float)(1<<C->PostShift); a0 = a0/(float)(1<<C->PostShift); } C->a[0] = (q31_t)(0x7FFFFFFF * a1); //a[0] in the IIR struct is actually a1 C->a[1] = (q31_t)(0x7FFFFFFF * a2); //a[1] in the IIR struct is actually a2 C->b[0] = (q31_t)(0x7FFFFFFF * b0); C->b[1] = (q31_t)(0x7FFFFFFF * b1); C->b[2] = (q31_t)(0x7FFFFFFF * b2); return; }