diff options
author | Chris Robinson <[email protected]> | 2017-07-31 23:49:48 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2017-07-31 23:49:48 -0700 |
commit | 8a735d0ba9db9b4b992172dc197396cc655264d5 (patch) | |
tree | 870ee7ed74e6028d92f3fc431c9b3c3243e08070 /Alc/ALu.c | |
parent | 88c0d22e7c72109fb5d7b2ee3276680d36971368 (diff) |
Add a front-stablizer config option for surround sound modes
This improves a stereo (front-left + front-right) sound "image" by generating a
front-center channel signal. Done correctly, it helps reduce the comb effects
and phase errors associated with using only two speakers to simulate center
sounds.
Note that it shouldn't be used if the front-center channel is already included
in the positional audio mix (the dialog effect is okay). In general, it may
actually be better to exclude the front-center channel from the positional
audio mix and use this to generate front-center output.
Diffstat (limited to 'Alc/ALu.c')
-rw-r--r-- | Alc/ALu.c | 59 |
1 files changed, 59 insertions, 0 deletions
@@ -1483,6 +1483,54 @@ static void UpdateContextSources(ALCcontext *ctx, const struct ALeffectslotArray } +static void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*restrict Buffer)[BUFFERSIZE], + int lidx, int ridx, int cidx, ALsizei SamplesToDo, + ALsizei NumChannels) +{ + ALfloat (*restrict lsplit)[BUFFERSIZE] = ASSUME_ALIGNED(Stablizer->LSplit, 16); + ALfloat (*restrict rsplit)[BUFFERSIZE] = ASSUME_ALIGNED(Stablizer->RSplit, 16); + ALsizei i; + + /* Apply an all-pass to all channels, except the front-left and front- + * right, so they maintain the same relative phase. + */ + for(i = 0;i < NumChannels;i++) + { + if(i == lidx || i == ridx) + continue; + splitterap_process(&Stablizer->APFilter[i], Buffer[i], SamplesToDo); + } + + bandsplit_process(&Stablizer->LFilter, lsplit[1], lsplit[0], Buffer[lidx], SamplesToDo); + bandsplit_process(&Stablizer->RFilter, rsplit[1], rsplit[0], Buffer[ridx], SamplesToDo); + + for(i = 0;i < SamplesToDo;i++) + { + ALfloat lfsum, hfsum; + ALfloat m, s, c; + + lfsum = lsplit[0][i] + rsplit[0][i]; + hfsum = lsplit[1][i] + rsplit[1][i]; + s = lsplit[0][i] + lsplit[1][i] - rsplit[0][i] - rsplit[1][i]; + + /* This pans the separate low- and high-frequency sums between being on + * the center channel and the left/right channels. The low-frequency + * sum is 1/3rd toward center (2/3rds on left/right) and the high- + * frequency sum is 1/4th toward center (3/4ths on left/right). These + * values can be tweaked. + */ + m = lfsum*cosf(1.0f/3.0f * F_PI_2) + hfsum*cosf(1.0f/4.0f * F_PI_2); + c = lfsum*sinf(1.0f/3.0f * F_PI_2) + hfsum*sinf(1.0f/4.0f * F_PI_2); + + /* The generated center channel signal adds to the existing signal, + * while the modified left and right channels replace. + */ + Buffer[lidx][i] = (m + s) * 0.5f; + Buffer[ridx][i] = (m - s) * 0.5f; + Buffer[cidx][i] += c * 0.5f; + } +} + static void ApplyDistanceComp(ALfloatBUFFERSIZE *restrict Samples, DistanceComp *distcomp, ALfloat *restrict Values, ALsizei SamplesToDo, ALsizei numchans) { @@ -1756,6 +1804,17 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) ALfloat (*Buffer)[BUFFERSIZE] = device->RealOut.Buffer; ALsizei Channels = device->RealOut.NumChannels; + if(device->Stablizer) + { + int lidx = GetChannelIdxByName(device->RealOut, FrontLeft); + int ridx = GetChannelIdxByName(device->RealOut, FrontRight); + int cidx = GetChannelIdxByName(device->RealOut, FrontCenter); + assert(lidx >= 0 && ridx >= 0 && cidx >= 0); + + ApplyStablizer(device->Stablizer, Buffer, lidx, ridx, cidx, + SamplesToDo, Channels); + } + /* Use NFCtrlData for temp value storage. */ ApplyDistanceComp(Buffer, device->ChannelDelay, device->NFCtrlData, SamplesToDo, Channels); |