Improve the front stablizer
Apply the all-pass+band-split only once, after generating the mid and side signals separately.
This commit is contained in:
parent
fcec76663f
commit
deac36a1eb
@ -2096,13 +2096,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
|
|||||||
if(GetConfigValueBool(device->DeviceName.c_str(), nullptr, "front-stablizer", 0))
|
if(GetConfigValueBool(device->DeviceName.c_str(), nullptr, "front-stablizer", 0))
|
||||||
{
|
{
|
||||||
auto stablizer = std::make_unique<FrontStablizer>();
|
auto stablizer = std::make_unique<FrontStablizer>();
|
||||||
/* Initialize band-splitting filters for the front-left and front-
|
/* Initialize band-splitting filter for the mid signal, with a
|
||||||
* right channels, with a crossover at 5khz (could be higher).
|
* crossover at 5khz (could be higher).
|
||||||
*/
|
*/
|
||||||
const float scale{5000.0f / static_cast<float>(device->Frequency)};
|
stablizer->MidFilter.init(5000.0f / static_cast<float>(device->Frequency));
|
||||||
|
|
||||||
stablizer->LFilter.init(scale);
|
|
||||||
stablizer->RFilter = stablizer->LFilter;
|
|
||||||
|
|
||||||
device->Stablizer = std::move(stablizer);
|
device->Stablizer = std::move(stablizer);
|
||||||
/* NOTE: Don't know why this has to be "copied" into a local static
|
/* NOTE: Don't know why this has to be "copied" into a local static
|
||||||
|
75
alc/alu.cpp
75
alc/alu.cpp
@ -1830,45 +1830,51 @@ void ApplyStablizer(FrontStablizer *Stablizer, const al::span<FloatBufferLine> B
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float (&lsplit)[2][BUFFERSIZE] = Stablizer->LSplit;
|
al::span<float> tmpbuf{Stablizer->TempBuf, SamplesToDo+FrontStablizer::DelayLength};
|
||||||
float (&rsplit)[2][BUFFERSIZE] = Stablizer->RSplit;
|
|
||||||
const al::span<float> tmpbuf{Stablizer->TempBuf, SamplesToDo+FrontStablizer::DelayLength};
|
|
||||||
|
|
||||||
/* This applies the band-splitter, preserving phase at the cost of some
|
/* Use the right delay buf for the side signal delay. Combine the delayed
|
||||||
* delay. The shorter the delay, the more error seeps into the result.
|
* signal with the incoming signal.
|
||||||
*/
|
*/
|
||||||
auto apply_splitter = [tmpbuf,SamplesToDo](const FloatBufferLine &InBuf,
|
auto tmpiter = std::copy_n(std::begin(Stablizer->DelayBuf[ridx]), FrontStablizer::DelayLength,
|
||||||
const al::span<float,FrontStablizer::DelayLength> DelayBuf, BandSplitter &Filter,
|
|
||||||
float (&splitbuf)[2][BUFFERSIZE]) -> void
|
|
||||||
{
|
|
||||||
/* Combine the input and delayed samples into a temp buffer in reverse,
|
|
||||||
* then copy the final samples into the delay buffer for next time.
|
|
||||||
* Note that the delay buffer's samples are stored backwards here.
|
|
||||||
*/
|
|
||||||
auto tmp_iter = std::reverse_copy(InBuf.cbegin(), InBuf.cbegin()+SamplesToDo,
|
|
||||||
tmpbuf.begin());
|
tmpbuf.begin());
|
||||||
std::copy(DelayBuf.cbegin(), DelayBuf.cend(), tmp_iter);
|
for(size_t i{0};i < SamplesToDo;++i,++tmpiter)
|
||||||
std::copy_n(tmpbuf.cbegin(), DelayBuf.size(), DelayBuf.begin());
|
*tmpiter = Buffer[lidx][i] - Buffer[ridx][i];
|
||||||
|
/* Hold on to the beginning for later, and save the end for next time. */
|
||||||
|
std::copy_n(tmpbuf.begin(), SamplesToDo, std::begin(Stablizer->Side));
|
||||||
|
std::copy_n(tmpbuf.begin()+SamplesToDo, FrontStablizer::DelayLength,
|
||||||
|
std::begin(Stablizer->DelayBuf[ridx]));
|
||||||
|
|
||||||
/* Apply an all-pass on the reversed signal, then reverse the samples
|
/* Use the left delay buf for the mid signal delay. Combine the delayed
|
||||||
* to get the forward signal with a reversed phase shift.
|
* signal with the incoming signal. Note that the samples are stored and
|
||||||
|
* combined in reverse, so the newest samples are at the front and the
|
||||||
|
* oldest at the back.
|
||||||
*/
|
*/
|
||||||
Filter.applyAllpass(tmpbuf);
|
tmpiter = tmpbuf.begin() + SamplesToDo;
|
||||||
|
std::copy_n(std::cbegin(Stablizer->DelayBuf[lidx]), FrontStablizer::DelayLength, tmpiter);
|
||||||
|
for(size_t i{0};i < SamplesToDo;++i)
|
||||||
|
*--tmpiter = Buffer[lidx][i] + Buffer[ridx][i];
|
||||||
|
/* Save the newest samples for next time. */
|
||||||
|
std::copy_n(tmpbuf.cbegin(), FrontStablizer::DelayLength,
|
||||||
|
std::begin(Stablizer->DelayBuf[lidx]));
|
||||||
|
|
||||||
|
/* Apply an all-pass on the reversed signal, then reverse the samples to
|
||||||
|
* get the forward signal with a reversed phase shift. The future samples
|
||||||
|
* are included with the all-pass to reduce the error in the output
|
||||||
|
* samples (the smaller the delay, the more error is introduced).
|
||||||
|
*/
|
||||||
|
Stablizer->MidFilter.applyAllpass(tmpbuf);
|
||||||
|
tmpbuf = tmpbuf.subspan<FrontStablizer::DelayLength>();
|
||||||
std::reverse(tmpbuf.begin(), tmpbuf.end());
|
std::reverse(tmpbuf.begin(), tmpbuf.end());
|
||||||
|
|
||||||
/* Now apply the band-splitter, combining its phase shift with the
|
/* Now apply the band-splitter, combining its phase shift with the reversed
|
||||||
* reversed phase shift, restoring the original phase on the split
|
* phase shift, restoring the original phase on the split signal.
|
||||||
* signal.
|
|
||||||
*/
|
*/
|
||||||
Filter.process(tmpbuf.first(SamplesToDo), splitbuf[1], splitbuf[0]);
|
Stablizer->MidFilter.process(tmpbuf, Stablizer->MidHF, Stablizer->MidLF);
|
||||||
};
|
|
||||||
apply_splitter(Buffer[lidx], Stablizer->DelayBuf[lidx], Stablizer->LFilter, lsplit);
|
|
||||||
apply_splitter(Buffer[ridx], Stablizer->DelayBuf[ridx], Stablizer->RFilter, rsplit);
|
|
||||||
|
|
||||||
/* This pans the separate low- and high-frequency sums between being on the
|
/* This pans the separate low- and high-frequency signals between being on
|
||||||
* center channel and the left/right channels. The low-frequency sum is
|
* the center channel and the left+right channels. The low-frequency signal
|
||||||
* 1/3rd toward center (2/3rds on left/right) and the high-frequency sum is
|
* is panned 1/3rd toward center and the high-frequency signal is panned
|
||||||
* 1/4th toward center (3/4ths on left/right). These values can be tweaked.
|
* 1/4th toward center. These values can be tweaked.
|
||||||
*/
|
*/
|
||||||
const float cos_lf{std::cos(1.0f/3.0f * (al::MathDefs<float>::Pi()*0.5f))};
|
const float cos_lf{std::cos(1.0f/3.0f * (al::MathDefs<float>::Pi()*0.5f))};
|
||||||
const float cos_hf{std::cos(1.0f/4.0f * (al::MathDefs<float>::Pi()*0.5f))};
|
const float cos_hf{std::cos(1.0f/4.0f * (al::MathDefs<float>::Pi()*0.5f))};
|
||||||
@ -1876,12 +1882,9 @@ void ApplyStablizer(FrontStablizer *Stablizer, const al::span<FloatBufferLine> B
|
|||||||
const float sin_hf{std::sin(1.0f/4.0f * (al::MathDefs<float>::Pi()*0.5f))};
|
const float sin_hf{std::sin(1.0f/4.0f * (al::MathDefs<float>::Pi()*0.5f))};
|
||||||
for(ALuint i{0};i < SamplesToDo;i++)
|
for(ALuint i{0};i < SamplesToDo;i++)
|
||||||
{
|
{
|
||||||
float lfsum{lsplit[0][i] + rsplit[0][i]};
|
const float m{Stablizer->MidLF[i]*cos_lf + Stablizer->MidHF[i]*cos_hf};
|
||||||
float hfsum{lsplit[1][i] + rsplit[1][i]};
|
const float c{Stablizer->MidLF[i]*sin_lf + Stablizer->MidHF[i]*sin_hf};
|
||||||
float s{lsplit[0][i] + lsplit[1][i] - rsplit[0][i] - rsplit[1][i]};
|
const float s{Stablizer->Side[i]};
|
||||||
|
|
||||||
float m{lfsum*cos_lf + hfsum*cos_hf};
|
|
||||||
float c{lfsum*sin_lf + hfsum*sin_hf};
|
|
||||||
|
|
||||||
/* The generated center channel signal adds to the existing signal,
|
/* The generated center channel signal adds to the existing signal,
|
||||||
* while the modified left and right channels replace.
|
* while the modified left and right channels replace.
|
||||||
|
@ -10,14 +10,15 @@
|
|||||||
struct FrontStablizer {
|
struct FrontStablizer {
|
||||||
static constexpr size_t DelayLength{256u};
|
static constexpr size_t DelayLength{256u};
|
||||||
|
|
||||||
alignas(16) float DelayBuf[MAX_OUTPUT_CHANNELS][DelayLength];
|
BandSplitter MidFilter;
|
||||||
|
alignas(16) float MidLF[BUFFERSIZE];
|
||||||
BandSplitter LFilter, RFilter;
|
alignas(16) float MidHF[BUFFERSIZE];
|
||||||
alignas(16) float LSplit[2][BUFFERSIZE];
|
alignas(16) float Side[BUFFERSIZE];
|
||||||
alignas(16) float RSplit[2][BUFFERSIZE];
|
|
||||||
|
|
||||||
alignas(16) float TempBuf[BUFFERSIZE + DelayLength];
|
alignas(16) float TempBuf[BUFFERSIZE + DelayLength];
|
||||||
|
|
||||||
|
alignas(16) float DelayBuf[MAX_OUTPUT_CHANNELS][DelayLength];
|
||||||
|
|
||||||
DEF_NEWDEL(FrontStablizer)
|
DEF_NEWDEL(FrontStablizer)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user