diff options
author | Chris Robinson <[email protected]> | 2013-05-20 04:16:48 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2013-05-20 04:16:48 -0700 |
commit | 5b706f3bdc1a8c8f064a253b53b4e86f9d88da8d (patch) | |
tree | 611e350eb0fe6986423e7a0522b6a42af436187c /Alc | |
parent | 80459b13e45306958f9fa2087ef750f1e736818b (diff) |
Process 64 samples at a time for some effects
This should help with the non-interleaved samples of the output, and
allow skipping channels that don't contribute to the output.
Diffstat (limited to 'Alc')
-rw-r--r-- | Alc/alcDedicated.c | 3 | ||||
-rw-r--r-- | Alc/alcDistortion.c | 157 | ||||
-rw-r--r-- | Alc/alcEcho.c | 48 | ||||
-rw-r--r-- | Alc/alcEqualizer.c | 76 | ||||
-rw-r--r-- | Alc/alcModulator.c | 34 |
5 files changed, 201 insertions, 117 deletions
diff --git a/Alc/alcDedicated.c b/Alc/alcDedicated.c index e10ad9e9..bb82bbcb 100644 --- a/Alc/alcDedicated.c +++ b/Alc/alcDedicated.c @@ -73,6 +73,9 @@ static ALvoid DedicatedProcess(ALeffectState *effect, ALuint SamplesToDo, const for(c = 0;c < MaxChannels;c++) { + if(!(gains[c] > 0.00001f)) + continue; + for(i = 0;i < SamplesToDo;i++) SamplesOut[c][i] = SamplesIn[i] * gains[c]; } diff --git a/Alc/alcDistortion.c b/Alc/alcDistortion.c index 05833680..315a7761 100644 --- a/Alc/alcDistortion.c +++ b/Alc/alcDistortion.c @@ -58,9 +58,6 @@ typedef struct ALdistortionState { ALfloat frequency; ALfloat attenuation; ALfloat edge_coeff; - - /* Oversample data */ - ALfloat oversample_buffer[BUFFERSIZE][4]; } ALdistortionState; static ALvoid DistortionDestroy(ALeffectState *effect) @@ -134,81 +131,103 @@ static ALvoid DistortionUpdate(ALeffectState *effect, ALCdevice *Device, const A static ALvoid DistortionProcess(ALeffectState *effect, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE]) { ALdistortionState *state = GET_PARENT_TYPE(ALdistortionState, ALeffectState, effect); - float *RESTRICT oversample_buffer = &state->oversample_buffer[0][0]; + const ALfloat fc = state->edge_coeff; + float oversample_buffer[64][4]; ALfloat tempsmp; + ALuint base; ALuint it; + ALuint ot; ALuint kt; - /* Perform 4x oversampling to avoid aliasing. */ - /* Oversampling greatly improves distortion */ - /* quality and allows to implement lowpass and */ - /* bandpass filters using high frequencies, at */ - /* which classic IIR filters became unstable. */ - - /* Fill oversample buffer using zero stuffing */ - for(it = 0; it < SamplesToDo; it++) + for(base = 0;base < SamplesToDo;) { - oversample_buffer[it*4 + 0] = SamplesIn[it]; - oversample_buffer[it*4 + 1] = 0.0f; - oversample_buffer[it*4 + 2] = 0.0f; - oversample_buffer[it*4 + 3] = 0.0f; - } + ALfloat temps[64]; + ALuint td = minu(SamplesToDo-base, 64); - /* First step, do lowpass filtering of original signal, */ - /* additionally perform buffer interpolation and lowpass */ - /* cutoff for oversampling (which is fortunately first */ - /* step of distortion). So combine three operations into */ - /* the one. */ - for(it = 0; it < SamplesToDo * 4; it++) - { - tempsmp = state->lowpass.b[0] / state->lowpass.a[0] * oversample_buffer[it] + - state->lowpass.b[1] / state->lowpass.a[0] * state->lowpass.x[0] + - state->lowpass.b[2] / state->lowpass.a[0] * state->lowpass.x[1] - - state->lowpass.a[1] / state->lowpass.a[0] * state->lowpass.y[0] - - state->lowpass.a[2] / state->lowpass.a[0] * state->lowpass.y[1]; - - state->lowpass.x[1] = state->lowpass.x[0]; - state->lowpass.x[0] = oversample_buffer[it]; - state->lowpass.y[1] = state->lowpass.y[0]; - state->lowpass.y[0] = tempsmp; - /* Restore signal power by multiplying sample by amount of oversampling */ - oversample_buffer[it] = tempsmp * 4.0f; - } + /* Perform 4x oversampling to avoid aliasing. */ + /* Oversampling greatly improves distortion */ + /* quality and allows to implement lowpass and */ + /* bandpass filters using high frequencies, at */ + /* which classic IIR filters became unstable. */ - for(it = 0; it < SamplesToDo * 4; it++) - { - ALfloat smp = oversample_buffer[it]; - ALfloat fc = state->edge_coeff; - - /* Second step, do distortion using waveshaper function */ - /* to emulate signal processing during tube overdriving. */ - /* Three steps of waveshaping are intended to modify */ - /* waveform without boost/clipping/attenuation process. */ - smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)); - smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)) * -1.0f; - smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)); - - /* Third step, do bandpass filtering of distorted signal */ - tempsmp = state->bandpass.b[0] / state->bandpass.a[0] * smp + - state->bandpass.b[1] / state->bandpass.a[0] * state->bandpass.x[0] + - state->bandpass.b[2] / state->bandpass.a[0] * state->bandpass.x[1] - - state->bandpass.a[1] / state->bandpass.a[0] * state->bandpass.y[0] - - state->bandpass.a[2] / state->bandpass.a[0] * state->bandpass.y[1]; - - state->bandpass.x[1] = state->bandpass.x[0]; - state->bandpass.x[0] = smp; - state->bandpass.y[1] = state->bandpass.y[0]; - state->bandpass.y[0] = tempsmp; - smp = tempsmp; - - /* Fourth step, final, do attenuation and perform decimation, */ - /* store only one sample out of 4. */ - if(!(it&3)) + /* Fill oversample buffer using zero stuffing */ + for(it = 0;it < td;it++) + { + oversample_buffer[it][0] = SamplesIn[it+base]; + oversample_buffer[it][1] = 0.0f; + oversample_buffer[it][2] = 0.0f; + oversample_buffer[it][3] = 0.0f; + } + + /* First step, do lowpass filtering of original signal, */ + /* additionally perform buffer interpolation and lowpass */ + /* cutoff for oversampling (which is fortunately first */ + /* step of distortion). So combine three operations into */ + /* the one. */ + for(it = 0;it < td;it++) { - smp *= state->attenuation; - for(kt = 0; kt < MaxChannels; kt++) - SamplesOut[kt][it>>2] += state->Gain[kt] * smp; + for(ot = 0;ot < 4;ot++) + { + tempsmp = state->lowpass.b[0] / state->lowpass.a[0] * oversample_buffer[it][ot] + + state->lowpass.b[1] / state->lowpass.a[0] * state->lowpass.x[0] + + state->lowpass.b[2] / state->lowpass.a[0] * state->lowpass.x[1] - + state->lowpass.a[1] / state->lowpass.a[0] * state->lowpass.y[0] - + state->lowpass.a[2] / state->lowpass.a[0] * state->lowpass.y[1]; + + state->lowpass.x[1] = state->lowpass.x[0]; + state->lowpass.x[0] = oversample_buffer[it][ot]; + state->lowpass.y[1] = state->lowpass.y[0]; + state->lowpass.y[0] = tempsmp; + /* Restore signal power by multiplying sample by amount of oversampling */ + oversample_buffer[it][ot] = tempsmp * 4.0f; + } } + + for(it = 0;it < td;it++) + { + /* Second step, do distortion using waveshaper function */ + /* to emulate signal processing during tube overdriving. */ + /* Three steps of waveshaping are intended to modify */ + /* waveform without boost/clipping/attenuation process. */ + for(ot = 0;ot < 4;ot++) + { + ALfloat smp = oversample_buffer[it][ot]; + + smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)); + smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)) * -1.0f; + smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)); + + /* Third step, do bandpass filtering of distorted signal */ + tempsmp = state->bandpass.b[0] / state->bandpass.a[0] * smp + + state->bandpass.b[1] / state->bandpass.a[0] * state->bandpass.x[0] + + state->bandpass.b[2] / state->bandpass.a[0] * state->bandpass.x[1] - + state->bandpass.a[1] / state->bandpass.a[0] * state->bandpass.y[0] - + state->bandpass.a[2] / state->bandpass.a[0] * state->bandpass.y[1]; + + state->bandpass.x[1] = state->bandpass.x[0]; + state->bandpass.x[0] = smp; + state->bandpass.y[1] = state->bandpass.y[0]; + state->bandpass.y[0] = tempsmp; + + oversample_buffer[it][ot] = tempsmp; + } + + /* Fourth step, final, do attenuation and perform decimation, */ + /* store only one sample out of 4. */ + temps[it] = oversample_buffer[it][0] * state->attenuation; + } + + for(kt = 0;kt < MaxChannels;kt++) + { + ALfloat gain = state->Gain[kt]; + if(!(gain > 0.00001f)) + continue; + + for(it = 0;it < td;it++) + SamplesOut[kt][base+it] += gain * temps[it]; + } + + base += td; } } diff --git a/Alc/alcEcho.c b/Alc/alcEcho.c index 1d06e68a..498ebbc7 100644 --- a/Alc/alcEcho.c +++ b/Alc/alcEcho.c @@ -133,25 +133,47 @@ static ALvoid EchoProcess(ALeffectState *effect, ALuint SamplesToDo, const ALflo const ALuint tap2 = state->Tap[1].delay; ALuint offset = state->Offset; ALfloat smp; + ALuint base; ALuint i, k; - for(i = 0;i < SamplesToDo;i++,offset++) + for(base = 0;base < SamplesToDo;) { - /* First tap */ - smp = state->SampleBuffer[(offset-tap1) & mask]; - for(k = 0;k < MaxChannels;k++) - SamplesOut[k][i] += smp * state->Gain[0][k]; + ALfloat temps[64][2]; + ALuint td = minu(SamplesToDo-base, 64); + + for(i = 0;i < td;i++) + { + /* First tap */ + temps[i][0] = state->SampleBuffer[(offset-tap1) & mask]; + /* Second tap */ + temps[i][1] = state->SampleBuffer[(offset-tap2) & mask]; + + // Apply damping and feedback gain to the second tap, and mix in the + // new sample + smp = lpFilter2P(&state->iirFilter, 0, temps[i][1]+SamplesIn[i]); + state->SampleBuffer[offset&mask] = smp * state->FeedGain; + } - /* Second tap */ - smp = state->SampleBuffer[(offset-tap2) & mask]; for(k = 0;k < MaxChannels;k++) - SamplesOut[k][i] += smp * state->Gain[1][k]; - - // Apply damping and feedback gain to the second tap, and mix in the - // new sample - smp = lpFilter2P(&state->iirFilter, 0, smp+SamplesIn[i]); - state->SampleBuffer[offset&mask] = smp * state->FeedGain; + { + ALfloat gain = state->Gain[0][k]; + if(gain > 0.00001f) + { + for(i = 0;i < td;i++) + SamplesOut[k][i+base] += temps[i][0] * gain; + } + + gain = state->Gain[1][k]; + if(gain > 0.00001f) + { + for(i = 0;i < td;i++) + SamplesOut[k][i+base] += temps[i][1] * gain; + } + } + + base += td; } + state->Offset = offset; } diff --git a/Alc/alcEqualizer.c b/Alc/alcEqualizer.c index c10eba2a..d4b4f855 100644 --- a/Alc/alcEqualizer.c +++ b/Alc/alcEqualizer.c @@ -162,20 +162,24 @@ static ALvoid EqualizerUpdate(ALeffectState *effect, ALCdevice *Device, const AL switch(state->bandfilter[it].type) { case LOW_SHELF: - alpha = sinf(w0) / 2.0f * - sqrtf((gain + 1.0f / gain) * (1.0f / 0.75f - 1.0f) + 2.0f); + alpha = sinf(w0) / 2.0f * sqrtf((gain + 1.0f / gain) * + (1.0f / 0.75f - 1.0f) + 2.0f); state->bandfilter[it].b[0] = gain * ((gain + 1.0f) - - (gain - 1.0f) * cosf(w0) + 2.0f * sqrtf(gain) * alpha); + (gain - 1.0f) * cosf(w0) + + 2.0f * sqrtf(gain) * alpha); state->bandfilter[it].b[1] = 2.0f * gain * ((gain - 1.0f) - - (gain + 1.0f) * cosf(w0)); + (gain + 1.0f) * cosf(w0)); state->bandfilter[it].b[2] = gain * ((gain + 1.0f) - - (gain - 1.0f) * cosf(w0) - 2.0f * sqrtf(gain) * alpha); - state->bandfilter[it].a[0] = (gain + 1.0f) + (gain - 1.0f) * - cosf(w0) + 2.0f * sqrtf(gain) * alpha; + (gain - 1.0f) * cosf(w0) - + 2.0f * sqrtf(gain) * alpha); + state->bandfilter[it].a[0] = (gain + 1.0f) + + (gain - 1.0f) * cosf(w0) + + 2.0f * sqrtf(gain) * alpha; state->bandfilter[it].a[1] = -2.0f * ((gain - 1.0f) + - (gain + 1.0f) * cosf(w0)); - state->bandfilter[it].a[2] = (gain + 1.0f) + (gain - 1.0f) * - cosf(w0) - 2.0f * sqrtf(gain) * alpha; + (gain + 1.0f) * cosf(w0)); + state->bandfilter[it].a[2] = (gain + 1.0f) + + (gain - 1.0f) * cosf(w0) - + 2.0f * sqrtf(gain) * alpha; break; case HIGH_SHELF: alpha = sinf(w0) / 2.0f * sqrtf((gain + 1.0f / gain) * @@ -214,32 +218,52 @@ static ALvoid EqualizerUpdate(ALeffectState *effect, ALCdevice *Device, const AL static ALvoid EqualizerProcess(ALeffectState *effect, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE]) { ALequalizerState *state = GET_PARENT_TYPE(ALequalizerState, ALeffectState, effect); + ALuint base; ALuint it; ALuint kt; ALuint ft; - for (it = 0; it < SamplesToDo; it++) + for(base = 0;base < SamplesToDo;) { - ALfloat tempsmp; - ALfloat smp = SamplesIn[it]; + ALfloat temps[64]; + ALuint td = minu(SamplesToDo-base, 64); - for(ft = 0;ft < 4;ft++) + for(it = 0;it < td;it++) { - tempsmp = state->bandfilter[ft].b[0] / state->bandfilter[ft].a[0] * smp + - state->bandfilter[ft].b[1] / state->bandfilter[ft].a[0] * state->bandfilter[ft].x[0] + - state->bandfilter[ft].b[2] / state->bandfilter[ft].a[0] * state->bandfilter[ft].x[1] - - state->bandfilter[ft].a[1] / state->bandfilter[ft].a[0] * state->bandfilter[ft].y[0] - - state->bandfilter[ft].a[2] / state->bandfilter[ft].a[0] * state->bandfilter[ft].y[1]; - - state->bandfilter[ft].x[1] = state->bandfilter[ft].x[0]; - state->bandfilter[ft].x[0] = smp; - state->bandfilter[ft].y[1] = state->bandfilter[ft].y[0]; - state->bandfilter[ft].y[0] = tempsmp; - smp = tempsmp; + ALfloat smp = SamplesIn[base+it]; + ALfloat tempsmp; + + for(ft = 0;ft < 4;ft++) + { + ALEQFilter *filter = &state->bandfilter[ft]; + + tempsmp = filter->b[0] / filter->a[0] * smp + + filter->b[1] / filter->a[0] * filter->x[0] + + filter->b[2] / filter->a[0] * filter->x[1] - + filter->a[1] / filter->a[0] * filter->y[0] - + filter->a[2] / filter->a[0] * filter->y[1]; + + filter->x[1] = filter->x[0]; + filter->x[0] = smp; + filter->y[1] = filter->y[0]; + filter->y[0] = tempsmp; + smp = tempsmp; + } + + temps[it] = smp; } for(kt = 0;kt < MaxChannels;kt++) - SamplesOut[kt][it] += state->Gain[kt] * smp; + { + ALfloat gain = state->Gain[kt]; + if(!(gain > 0.00001f)) + continue; + + for(it = 0;it < td;it++) + SamplesOut[kt][base+it] += gain * temps[it]; + } + + base += td; } } diff --git a/Alc/alcModulator.c b/Alc/alcModulator.c index d33811ba..c9f1edf4 100644 --- a/Alc/alcModulator.c +++ b/Alc/alcModulator.c @@ -88,20 +88,36 @@ static void Process##func(ALmodulatorState *state, ALuint SamplesToDo, \ { \ const ALuint step = state->step; \ ALuint index = state->index; \ - ALfloat samp; \ - ALuint i, k; \ + ALuint base; \ \ - for(i = 0;i < SamplesToDo;i++) \ + for(base = 0;base < SamplesToDo;) \ { \ - samp = SamplesIn[i]; \ - samp = hpFilter1P(&state->iirFilter, 0, samp); \ + ALfloat temps[64]; \ + ALuint td = minu(SamplesToDo-base, 64); \ + ALuint i, k; \ \ - index += step; \ - index &= WAVEFORM_FRACMASK; \ - samp *= func(index); \ + for(i = 0;i < td;i++) \ + { \ + ALfloat samp; \ + samp = SamplesIn[base+i]; \ + samp = hpFilter1P(&state->iirFilter, 0, samp); \ + \ + index += step; \ + index &= WAVEFORM_FRACMASK; \ + temps[i] = samp * func(index); \ + } \ \ for(k = 0;k < MaxChannels;k++) \ - SamplesOut[k][i] += state->Gain[k] * samp; \ + { \ + ALfloat gain = state->Gain[k]; \ + if(!(gain > 0.00001f)) \ + continue; \ + \ + for(i = 0;i < td;i++) \ + SamplesOut[k][base+i] += gain * temps[i]; \ + } \ + \ + base += td; \ } \ state->index = index; \ } |