📄 hxeqengine.c
字号:
/* apply ramping pregain */ pwr = (eq->pregain - prev_pregain)/(float)(nsamps/eq->nchans); for (chan = 0; chan < eq->nchans; chan++) { eq->pregain = prev_pregain; optr = eq->itlbuf + chan; for (n = 0; n < nsamps; n += eq->nchans) { ftmp = *optr; ftmp *= eq->pregain; *optr = ftmp; eq->pregain += pwr; optr += eq->nchans; } } }} #else // _EQ_X86_WINDOWSstatic int FillOutputShorts(EQPTR eq, short *outpcm, int nsamps){ float *optr, ftmp; int ltmp, n, nclips; unsigned int max_samp; nclips = 0; max_samp = 0; /* store output with Auto-Gain adjustments */ if (eq->autopregain == 1) { /* store output */ optr = eq->itlbuf; for (n = 0; n < nsamps; n ++) { ftmp = *optr++; ltmp = RoundFtoL((eq->pregain*ftmp)); if (ltmp > 32767) { eq->pregain *= 32767.f/(float)ltmp; ltmp = 32767; } else if (ltmp < -32768) { eq->pregain *= -32768.f/(float)ltmp; ltmp = -32768; } outpcm[n] = (short)ltmp; max_samp |= ((ltmp)^(ltmp>>31)); } /* only update if we get some audible audio */ if (max_samp > 0x0800) { /* Update the time averaged maximum measurement */ if (max_samp > eq->pwrLevelMeasure) eq->pwrLevelMeasure = (float)max_samp; else eq->pwrLevelMeasure = 0.99f * eq->pwrLevelMeasure + 0.01f * (float)max_samp; if (eq->pwrLevelMeasure < 8192.f) { eq->pregain += 0.004f; } } /* bound the pregain to +/-18 dB */ if (eq->pregain > powertab[EQ_MAXGAIN-EQ_MINGAIN]) eq->pregain = powertab[EQ_MAXGAIN-EQ_MINGAIN]; else if (eq->pregain < powertab[0]) eq->pregain = powertab[0]; } else { /* store output */ optr = eq->itlbuf; for (n = 0; n < nsamps; n ++) { ftmp = *optr++; ltmp = RoundFtoL(eq->pregain*ftmp); if (ltmp > 32767) { ltmp = 32767; nclips++; } else if (ltmp < -32768) { ltmp = -32768; nclips++; } outpcm[n] = (short)ltmp; } } return nclips;}#endif // _EQ_X86_WINDOWS/* * Process a buffer of mono/stereo samples. * * Requires nsamps to be a multiple of nchans. * * Returns a count of clipped outputs, intended to drive * a clipping indicator. */intEQProcess(EQPTR eq, short *inpcm, short *outpcm, int nsamps){ int nclips, chan; int chunk, maxchunk;#ifdef _EQ_X86_WINDOWS int *fixedbuf;#endif nclips = 0; maxchunk = EQ_MAXSAMPS * eq->nchans; /* double, if stereo */ /* process in chunks no bigger than maxchunk */ while (nsamps > 0) { /* size of next chunk */ chunk = (nsamps < maxchunk ? nsamps : maxchunk); /* add reverb to input samples -- applies to both channels if stereo */ AddReverb(eq, inpcm, chunk); /* process all channels */ for (chan = 0; chan < eq->nchans; chan++) { /* apply equalizer filtering to samples stored in eq->eqhist. */ /* The output is written as interleaved 'floats' to eq->inlbuf. */ ProcessBlock(eq, chunk, chan); }#ifdef _EQ_X86_WINDOWS /* perform auto pre-gain control and apply gain */ /* On x86 the auto pre-gain is based on signal power */ /* and the subsequent limiter will handle clipping */ ApplyGain(eq, chunk); /* Convert the floating point numbers to 32-bit fixed point */ fixedbuf = (int *)eq->itlbuf; FloatToFixed32(eq->itlbuf, fixedbuf, chunk, EQ_FLT2FIX_SCALE); /* Apply limiter */ LimiterProcess(fixedbuf, chunk, eq->limState); LimiterOutput16(fixedbuf, outpcm, chunk, eq->limState);#else /* fill the output pcm data, handle clipping, and auto gain */ /* (excellent place for a dynamic range compressor) */ /* On non-x86, (automatic) pre-gain is also handled here */ nclips += FillOutputShorts(eq, outpcm, chunk);#endif inpcm += chunk; outpcm += chunk; nsamps -= chunk; } return nclips;}/* * Set the EQ gains. * * dbgain[] is an array of gain settings. * units are in 1/8 dB, where 0 = 0 dB. * gains above EQ_MAXGAIN are clamped to +18dB. * gains below EQ_MINGAIN are clamped to -18dB. */voidEQSetGain(EQPTR eq, int *dbgain){ int i, igain, highgain, chan; highgain = 0; for (i = 0; i < eq->nbands; i++) { igain = dbgain[i]; /* clamp to +/-18dB */ if (igain > EQ_MAXGAIN) igain = EQ_MAXGAIN; if (igain < EQ_MINGAIN) igain = EQ_MINGAIN; /* find the highest positive gain */ if (igain > highgain) highgain = igain; /* * Now convert from 1/8 dB to filter gain. * Since bandpass filters are added to a unity-gain passthru, * filter gain g results in response of 20*log10(1 + g) dB. * The inverse is g[i] = 10^(i/20) - 1. * * filtgain = (float)pow(10.0, igain/(8.0 * 20.0)) - 1.0f; */ eq->filtgain[i] = powertab[igain-EQ_MINGAIN] - 1.0f; } /* init history to zero */ for (chan = 0; chan < EQ_MAXCHANS; chan++) { eq->ihist[chan][0] = 0.0f; eq->ihist[chan][1] = 0.0f; for (i = 0; i < 2 * EQ_MAXBANDS; i++) eq->ohist[chan][i] = 0.0f; }}/* * Set the pre-gain. * * 'pregain' is the pregain setting. * units are in 1/8 dB, where 0 = 0 dB. * gains above EQ_MAXGAIN are clamped to +18dB. * gains below EQ_MINGAIN are clamped to -18dB. */voidEQSetPreGain(EQPTR eq, int pregain){ int igain; igain = pregain; /* clamp to +/-18dB */ if (igain > EQ_MAXGAIN) igain = EQ_MAXGAIN; if (igain < EQ_MINGAIN) igain = EQ_MINGAIN; /* * Now convert from 1/8 dB to filter gain. * Since bandpass filters are added to a unity-gain passthru, * filter gain g results in response of 20*log10(1 + g) dB. * The inverse is g[i] = 10^(i/20) - 1. * * pregain = (float)pow(10.0, igain/(8.0 * 20.0)) - 1.0f; */ eq->pregain = powertab[igain-EQ_MINGAIN];}/* * Set the Reverb settings. * * roomsize: 0-12 sets the size of the room to be simulated. * 0: no reverb, 1: very small room, 12: very large room * reverb: 0-12 sets the amount of echo. * 0: no echo, 1: little echo, 12: tons of echo */void EQSetReverb(EQPTR eq, int roomsize, int reverb){ int echo, delay; // Assign the reverb settings eq->roomsize = roomsize; eq->reverb = reverb; // setup delays/gains eq->gain = feedbackgain_tab[reverb]; for (echo = 0; echo < REVERB_NUM_ECHOS; echo++) { delay = (ratetab[eq->ratecode] * delay_tab[roomsize][echo] * (eq->nchans) / 1000) + echo; if ((eq->nchans == 2) && (delay & 1)) delay--; eq->echoPtr[echo] = eq->eqhist_head - delay; while (eq->echoPtr[echo] < eq->eqhist) eq->echoPtr[echo] += eq->eqhist_end - eq->eqhist; }}/* * Get the Reverb settings. * * roomsize: 0-12 sets the size of the room to be simulated. * 0: no reverb, 1: very small room, 12: very large room * reverb: 0-12 sets the amount of echo. * 0: no echo, 1: little echo, 12: tons of echo */voidEQGetReverb(EQPTR eq, int *roomsize, int *reverb){ // Assign the reverb settings *roomsize = eq->roomsize; *reverb = eq->reverb;} /* * Enables the automatic pregain control. * * enable: 0: off, 1: on */voidEQEnableAutoPreGain(EQPTR eq, int enable){ eq->autopregain = enable;}/* * Get the pre-gain. * * 'pregain' is a pointer to the pregain setting. * units are in 1/8 dB, where 0 = 0 dB. * gains above EQ_MAXGAIN are clamped to +18dB. * gains below EQ_MINGAIN are clamped to -18dB. */voidEQGetPreGain(EQPTR eq, int *pregain){ int i; for (i = 0; i < EQ_MAXGAIN-EQ_MINGAIN+1; i++) if (eq->pregain < powertab[i]) break; *pregain = i + EQ_MINGAIN;}/* * Resets the reverb echo buffers. */voidEQResetReverb(EQPTR eq){ memset(eq->eqhist, 0, (eq->eqhist_end - eq->eqhist + (EQ_MAXSAMPS * eq->nchans)) * sizeof(float));}/* * Free an EQ instance. */voidEQFree(EQPTR eq){ if (eq) { if (eq->eqhist) { free(eq->eqhist); eq->eqhist = NULL; } if (eq->itlbuf) { free(eq->itlbuf); eq->itlbuf = NULL; } #ifdef _EQ_X86_WINDOWS LimiterFree(eq->limState);#endif free(eq); /* free all memory */ eq = NULL; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -