-
Notifications
You must be signed in to change notification settings - Fork 262
replace current_span_length in favor of parameters_changed #706
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
4678bb1
to
8204220
Compare
Sure thing. Don't have much time this week, will look into it after. |
af46244
to
481eed9
Compare
f1cf00e
to
8c8df80
Compare
Note: I split of the NonZero change into its own PR, please review that first then ill rebase this on it. |
b28c09b
to
24932ce
Compare
first benchmark data is in. Key takeaways:
I'd not expect those changes to be honest. Lets hope we can speed things up otherwise we have some hard choices to make. Lets not dwell on it, I have spend literally zero time on optimization and I have not written this with performance in mind (yet). Current master
This PR
|
All other sources have been marked as TODO using `todo!()`. This is such that the test suite can run. New tests need to be made for all non trivial implementations (those that do not simply forward the call to `parameters_changed`) - trivial implementations: TestSource, SamplesBuffer, chirp, delay, empty, empty_callback, mix, sawtooth, signal_generator, sine, square, triangle, zero, static_buffer - implemented: blt, buffered, position, repeat, skip, take_duration, uniform - marked as todo: all decoders, Mixer, Queue, source/from_iter Added some sources to make the implementation easier: - TakeSpan, takes up to a span of samples - TakeSamples, takes n samples or slightly less. Always ends frame aligned - Peekable, similar to Iterator::peekable.
also adds a new mod test support with a special test source that can be used to test span boundary/parameters_changed handling. adds two extra tests for `skip_duration` testing - parameters_changing during skip - ending on frame boundary
The removal of factories (like `source::amplify(unamplified, 1.2)` -> `unamplified.amplify(1.2)`) was already planned and is tracked in issue 622. Its not done now. I am working through it as I add tests for all the non-trivial source's.
This also improves the `TestSpan` in tests/test_support to prevent expected total duration not matching `sample_rate` * `channels` * `sample_count`
fix peekable & peekable tests + improve TestSource performance: remove `if` from PeekableSource::next
add tests for buffered, fix buffered `parameters_changed`
I ran into a lot of bugs while adding tests that had to do with channel being set to zero somewhere. While this change makes the API slightly less easy to use it prevents very hard to debug crashes/underflows etc. Performance might drop in decoders, the current implementation makes the bound check every time `channels` is called which is once per span. This could be cached to alleviate that.
d70b52a
to
58cd766
Compare
Semantics of channels, sample_rate & parameters_changedCurrent situation: greedySemantics are best explained with an example:
In words, before you call next you get that the parameters are going to change. Said differently you get whether the next sample has a different channel count or sample rate then the previous sample. Pro:
Cons:
Alternative: lazySemantics again explained with an example:
In words, after you call next you learn whether the sample you just got has a different sample rate or channel count then the samples before. Pro:
Cons:
Note that sources that need to know if the sample_rate or channel_count changes do not need to buffer across calls to
|
Interrupted because: ### Semantics of channels, sample_rate & parameters_changed ## Current situation: greedy Semantics are best explained with an example: - `next` -> (sample at sample_rate _S1_ and channel count _C1_) - `parameters_changed` -> false - `next` -> (sample at sample_rate _S1_ and channel count _C1_) - `parameters_changed` -> true - `next` -> (sample at sample_rate _S2_ and channel count _C2_) - `parameters_changed` -> false - `next` -> (sample at sample_rate _S2_ and channel count _C2_) - `parameters_changed` -> false - `next` -> (sample at sample_rate _S2_ and channel count _C2_) In words, before you call next you get that the parameters are going to change. Said differently you get whether the next sample has a different channel count or sample rate then the previous sample. **Pro:** - Sources that need to handle *channel count* and *sample rate* changes are simpler. - Similar semantics to `current_span_length`, you know ahead of time when to change. **Cons:** - Ever source that can cause sample_rate or channel_count gets rather complex, needing to know ahead of time if that is going to happen. - Seems slower to me because of all the `buffering` ## Alternative: lazy Semantics again explained with an example: - `next` -> (sample at sample_rate _S1_ and channel count _C1_) - `parameters_changed` -> false - `next` -> (sample at sample_rate _S1_ and channel count _C1_) - `parameters_changed` -> false - `next` -> (sample at sample_rate _S2_ and channel count _C2_) - `parameters_changed` -> true - `next` -> (sample at sample_rate _S2_ and channel count _C2_) - `parameters_changed` -> false - `next` -> (sample at sample_rate _S2_ and channel count _C2_) In words, after you call next you learn whether the sample you just got has a different sample rate or channel count then the samples before. **Pro:** - Ever source that can cause sample_rate or channel_count get simpler when they cause a change they can flip a `bool`, reset it after the next sample has been emitted (consumer calls `next`). - Similar semantics to `current_span_length`, you know ahead of time when to change. - Sources that need to handle *channel count* and *sample rate* changes are simpler. **Cons:** - Larger difference to how things are now - I just wrote 2.5k lines with the approach above and I do not want to change them 😢 Note that sources that need to know if the sample_rate or channel_count changes do not need to buffer across calls to `next`. They: - call next - call parameters_changed - realize they did - query the new parameters using `channel_count` and `sample_rate` - handle the sample together with the new parameters
EDIT: might not do the thing below but go for the greedy approach anyway, see: #706 (comment) changing semantics for lazy option above, todo list:
|
yet another idea: have both styles of |
Our linear resampler might be even broken. There are some comments that suggest it was not completely polished. It used numerator/divisor calculation which now may probably be more straightforward. I would leave this to a separate task. After this change is made. |
Regarding that greedy/lazy discussion. I do not really see how flagging before next frame may cause problems. I would like to keep changes to in-between frames only still. Sources that change number parameters themselves have all information about the change and should have no problems flagging it. The ones that do not change parameters or do not depend on them can just relay call to With that lazy option, flagging after reading next sample and releasing is depending on next() call is confusing. Next source would have to read the sample, keep it somewhere then read new parameters than maybe re-allocate its buffers and then put that sample as the first one... On other words it is not clear to me which problem it is supposed to solve. |
It does not cause problems but it may require a more complex implementation. Honestly both approaches are complex and it seems I have made a mistake making it worse. Ill get back on that later. I have been designing #712 yesterday and want to try working on that a while. Then we could compare performance and code complexity. Getting back to your question, lets say you are the queue source:
Thus you need to peek one sample ahead so you know if your current sample is actually the last. This kind of needing to peek one ahead happens a lot, I wrote a You might have already seen the mistake, we can just forbid spans of length one. They make no sense anyway, why would you want 1 sample (at 44_100 samples a second!) to have a different channel count? So peeking is simple again, removing this complexity. Quite a few sources need to know if 'the end is coming' so this unneeded complexity was duplicated at a few places. That is what prompted me to look at alternatives. I am still working on #712, I still think that is valuable and if its partially implemented we can compare its performance to this PR. |
implements #694
currently draft, due to high number of non trivial changes this PR also aims to dramatically extend the test suite of rodio. Hopefully that will catch most bugs.
@roderickvd I could use some help fixing the decoders, they now just have
todo!()
asparameters_changed
implementation. Let me know if you want to work on that. The branch is under the rodio repo so you can just pull it down and push your work to it.status (ill edit this along the way)