[pulseaudio-discuss] Rewind Handling in module-lfe-lp
tanuk at iki.fi
Wed Mar 27 01:35:18 PDT 2013
On Tue, 2013-03-26 at 19:34 -0700, Justin Chudgar wrote:
> First, thanks to both of you for helping me get this far. I've got a mostly
> correct (I think) filter setup based on Alexander's feedback. Now I'm trying to
> get rewind buffering done. I've read the wiki page that Tanu sent and I've been
> talking to ohsix on IRC.
> All of which has left me more educated but just as clueless about what to
> actually implement.... :(
> My understanding is that since I've got a causal filter, I need to do one of
> the two things when a rewind request appears:
> 1 - buffer the biquad samples so that I can restart filtering the rewound input
> memblock_q immediately
> - or -
> 2 - buffer the input samples for at least sample_rate/20 and when a rewind come
> in, set the biquad samples to 0.0 and filter the buffered input.
> Is this even remotely correct?
I think option 1 is better. Rewinding means that you jump back in time.
Let T be the point in time to which you jump. Option 1 ensures that you
restore exactly the same state that you had when you reached T the first
I don't know where that sample_rate/20 comes from, but I think I
understand what you mean in option 2 anyway. You'd save a bit more than
max_rewind amount of input samples in a history buffer. When a rewind
happens, you'd jump back in time a bit more than what was requested. Let
D be the difference between the requested rewind size and how much you
actually jumped back. You'd then set the biquad samples to zero and
process D amount of the history data, which should result in roughly the
same state as what option 1 would have achieved. The keyword is
"roughly", so there may be some discontinuity in the signal. It's not
exactly the same, because the filter has infinite impulse response, that
is, the very first input sample in the stream can affect all future
output samples, so for this approach to work perfectly, you'd have to
save all input you ever process and reprocess it all again on each
I have no idea how close the resulting state would be to the optimal
with this limited input history approach, maybe it would be virtually
perfect. But to avoid this uncertainty, I prefer option 1.
> Also, is it possible? likely? for a rewind to occur during the processing of a
> sink_input_pop_cb? Since this is where the filtering occurs, how does one
> manage locking of the shared userdata?
sink_input_pop_cb() and sink_input_process_rewind_cb() are both called
from the "IO thread" of the master sink, so they can't be called
concurrently. There's no need for locking.
> The more focused on my little bit of code, the better, and thanks again.
In sink_input_pop_cb(), I think you should push to the biquad history
buffer the amount that you return to the caller in the "chunk" function
argument, that is, the amount that you processed. If the history buffer,
as a result, contains more data than max_rewind, you should drop the
excessive history data.
sink_input_process_rewind_cb() is a bit more tricky, I have some trouble
wrapping my head around what is happening and what should be done...
nbytes is the amount of our old output that has been discarded and which
we should therefore regenerate. It sounds logical that this would be the
amount that we should jump back in the biquad sample history. But the
comment about resetting the filter is in a branch that is only executed
when we seek in u->memblockq, which would suggest that we should care
about the amount variable instead of (or in addition to) the nbytes
If u->memblockq contains data, it is unprocessed input, so I don't think
we should care about the amount of seeking we do in that buffer.
Unprocessed input hasn't yet had effect on our filter state. It seems to
me that the right thing to do is to care only about nbytes and jump back
in the biquad history buffer by that amount (and restore the filter
More information about the pulseaudio-discuss