The audio is recursively decoded and encoded without any other alteration, there's an unusual amount of artifacts.
By restoring the code back to the pcm samples copying behavior, the artifacts are gone, or at least imperceptible.
The samples are using 512 kbps VBR, yes, even the highest bitrate won't save it. sample.7z.gz
May I ask what are the reasons of adding this DC rejection filter, other than to address the problem with DC offset?
Not all audio have DC offset problem, in fact they should and will be actively corrected in mixing stage.
While not all audio being encoded by libopus will have gone through mixing stage, it's still not worth risking all audios just for a few problematic ones, since we now know the damage it can do, rather than being inaudible.
My suggestion is following the guidance of this philosophy:
Does Opus have an echo canceller like Speex does?
Echo cancellation is completely independent from codecs.
You can use any echo canceller (including the one from libspeexdsp) along with Opus.
DC rejection is completely independent from codecs.
You can use any DC rejector (including the one from libopus???) along with Opus.
DC rejection is linked to how each Opus component works and (e.g.) is different for SILK and CELT. Due to the CELT design, DC can mess up the coding and produce LF noise (which is why it got added). Now there may be ways to improve it, but it is needed in some form.
My point is that not all audio has DC offset, or do you mean any waveform that might at some point "dip" below 3 Hz is considered has DC offset?
Some LF noise is probably better (or "less bad") than generational loss?
Making it optional is an API change so we'd need to be sure to get it right. Also, the proposed patch would glitch when you change the setting mid-stream, which I'd like to avoid. There may be other side effect that I haven't thought about too. So before betting there I'd like to understand what real problem this is causing. Can you explain a bit more?
Well, it may be hard to find someone that encode the audio stream dozens of times, so in reality the problem could be "nothing".
But it's not hard to imagine, if there's severe generational loss, then maybe the very first pass already has some imperceptible problem.
And yes, this is a lossy codec, but a loss caused by unnecessary filtering (for most streams) is better avoided, don't you think?
So you're seeing much better tandeming performance without the high-pass than with the high-pass. Is that only for synchronous tandeming (i.e. encode/decode always with the same alignment) or are you also seeing that with asynchronous tandeming (random alignment every time)? The latter tends to be much worse, so I'm curious if the filtering makes a difference in that case.
To my surprise, the unalignment makes this generational loss almost gone, tested at 512 kbps to minimize side effects, but of course the other generational loss caused by unalignment is much, much worse when bitrate is lower.
Activity
jmvalin commentedon Sep 15, 2025
Care to elaborate a bit?
Mr-Z-2697 commentedon Sep 15, 2025
The audio is recursively decoded and encoded without any other alteration, there's an unusual amount of artifacts.
By restoring the code back to the pcm samples copying behavior, the artifacts are gone, or at least imperceptible.
The samples are using 512 kbps VBR, yes, even the highest bitrate won't save it.
sample.7z.gz
Some additional discussion at:
https://forum.doom9.org/showthread.php?t=186465&page=3
Mr-Z-2697 commentedon Sep 17, 2025
May I ask what are the reasons of adding this DC rejection filter, other than to address the problem with DC offset?
Not all audio have DC offset problem, in fact they should and will be actively corrected in mixing stage.
While not all audio being encoded by libopus will have gone through mixing stage, it's still not worth risking all audios just for a few problematic ones, since we now know the damage it can do, rather than being inaudible.
My suggestion is following the guidance of this philosophy:
DC rejection is completely independent from codecs.
You can use any DC rejector (including the one from libopus???) along with Opus.
Or at least make it adaptive.
Mr-Z-2697 commentedon Sep 30, 2025
Hello, it's been 2 weeks, do we have any progress?
jmvalin commentedon Oct 7, 2025
DC rejection is linked to how each Opus component works and (e.g.) is different for SILK and CELT. Due to the CELT design, DC can mess up the coding and produce LF noise (which is why it got added). Now there may be ways to improve it, but it is needed in some form.
Mr-Z-2697 commentedon Oct 7, 2025
My point is that not all audio has DC offset, or do you mean any waveform that might at some point "dip" below 3 Hz is considered has DC offset?
Some LF noise is probably better (or "less bad") than generational loss?
Mr-Z-2697 commentedon Oct 9, 2025
Making it optional is the first step to improve it.
jmvalin commentedon Oct 22, 2025
Making it optional is an API change so we'd need to be sure to get it right. Also, the proposed patch would glitch when you change the setting mid-stream, which I'd like to avoid. There may be other side effect that I haven't thought about too. So before betting there I'd like to understand what real problem this is causing. Can you explain a bit more?
Mr-Z-2697 commentedon Oct 22, 2025
Well, it may be hard to find someone that encode the audio stream dozens of times, so in reality the problem could be "nothing".
But it's not hard to imagine, if there's severe generational loss, then maybe the very first pass already has some imperceptible problem.
And yes, this is a lossy codec, but a loss caused by unnecessary filtering (for most streams) is better avoided, don't you think?
jmvalin commentedon Oct 23, 2025
So you're seeing much better tandeming performance without the high-pass than with the high-pass. Is that only for synchronous tandeming (i.e. encode/decode always with the same alignment) or are you also seeing that with asynchronous tandeming (random alignment every time)? The latter tends to be much worse, so I'm curious if the filtering makes a difference in that case.
Mr-Z-2697 commentedon Oct 24, 2025
To my surprise, the unalignment makes this generational loss almost gone, tested at 512 kbps to minimize side effects, but of course the other generational loss caused by unalignment is much, much worse when bitrate is lower.
Mr-Z-2697 commentedon Oct 25, 2025
Is qext the intended fix for this, I mean among the other features it has, is this one of them?
jmvalin commentedon Oct 25, 2025
qext is a totally different thing. See https://datatracker.ietf.org/doc/draft-ietf-mlcodec-opus-scalable-quality-extension/
But in any case, it doesn't seem like the DC high-pass filter is hurting the general trandeming case.
Mr-Z-2697 commentedon Oct 26, 2025
I mean qext effectively disables the dc rejection filter.
opus/src/opus_encoder.c
Lines 1927 to 1932 in 43efb99
Mr-Z-2697 commentedon Nov 4, 2025
So, is this issue a "won't fix"?
a5632645 commentedon Dec 15, 2025
Why do you use an IIR high pass filter instead of simply taking the average of a block and then subtracting that value?
jmvalin commentedon Dec 15, 2025
That would result in a cutoff frequency around 50 Hz (or more for smaller frame sizes), along with blocking artifacts.
ValeZAA commentedon Aug 12, 2026
You claim CELT coding tool is causing LF noise because of 3 Hz stuff.
But generational loss overall is higher with this fix, so this means OVERALL quality is worse.
I am guessing the fix is to slightly move the audio around if this lowpass filter is also causing audio to move around.