aboutsummaryrefslogtreecommitdiffstats
path: root/Alc/ALu.c
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2017-07-31 23:49:48 -0700
committerChris Robinson <[email protected]>2017-07-31 23:49:48 -0700
commit8a735d0ba9db9b4b992172dc197396cc655264d5 (patch)
tree870ee7ed74e6028d92f3fc431c9b3c3243e08070 /Alc/ALu.c
parent88c0d22e7c72109fb5d7b2ee3276680d36971368 (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.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/Alc/ALu.c b/Alc/ALu.c
index fa9634b8..5230d4c6 100644
--- a/Alc/ALu.c
+++ b/Alc/ALu.c
@@ -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);