You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It depends on LFO & math block side effects that are unintended
Description
No response
Additional information
audiofilters should have their own independent LFOs and should properly "tick" them every 256 samples when generating output samples. LFOs and other BlockInputs should never be shared between different audio-generating objects.
What happens right now is:
audiomixer will generate 512 (?) output samples from the synthesizer
during this time the synthesizer will tick the LFOs twice
audiomixer will generate 512 (?) output samples from the audiofilter
during this time the LFOs will tick zero times
so while this sort-of works, the LFO's effect on the filter is changing less frequently than it should, though at the same overall rate.
If the audiofilter correctly ticked its block inputs, but they were shared with the synthesizer, then it would advance at double the rate, ticked twice for synthesizer and twice for audiofilter; each user of the LFO would see different values and the values would be "jumpy".
There seems to be no way to force the "update LFOs every 256 samples" behavior through the whole stack; for instance imagine you have an audiomixer that goes into another audiomixer just so you can control audio levels of some channels in unison. Each audiomixer wants to produce some number of samples, not necessarily 256. And in fact a big point of audiomixer is to "re-block" audio output and reduce underruns.
This all feels kinda shabby and it's my design and my fault... but we need to do the best with it we can, and it feels like audiofilter needs to "do better", by properly ticking the block inputs that it uses. (by factoring some code out of synthio to be shared between it and audiofilters! .. and probably by forcing audiofilters to always work in SYNTHIO_MAX_DUR samples between ticks, or else making the new factored out layer work in scaled seconds instead of samples and reciprocal sample rate)
Sadly, this will end up incompatibly changing code that relied on the illegal side effect of using the synthesizer to tick them.
I would love a better solution if someone has one.
The text was updated successfully, but these errors were encountered:
@jepler Properly fixing this situation would require a rewrite of the audiosample API to always fill buffers in 256 sample segments and process BlockInput objects globally in between these segments. This is possible, but I wouldn't call it ideal and it would definitely be a breaking-change to existing code. Buffer sizes would also need to be validated to ensure that they fit this scheme.
It still may not be the best solution, but adding a blocks property to all modules which use BlockInput and leaving it up to the user to decide where BlockInput objects should be allocated should resolve this issue. Each module can then process the blocks they've been designated every 256 samples in the same manner as synthio.Synthesizer (refactoring as needed). This would allow existing code using these features to continue to function with the side effects you've identified, but present the opportunity to fix these side effects with proper implementation.
In some cases, it may be desirable to share an LFO object between audiosample objects which implement BlockInput and the side effect of one object stepping BlockInput objects at appropriate intervals and the other only between buffer fills may be an issue worth ignoring in these edge cases. I for one haven't noticed this error by ear up to this point.
CircuitPython version
main
Code/REPL
# https://gist.github.com/relic-se/77e48df1920b20d3e50762cbc06d1bb9
Behavior
It depends on LFO & math block side effects that are unintended
Description
No response
Additional information
audiofilters should have their own independent LFOs and should properly "tick" them every 256 samples when generating output samples. LFOs and other BlockInputs should never be shared between different audio-generating objects.
What happens right now is:
so while this sort-of works, the LFO's effect on the filter is changing less frequently than it should, though at the same overall rate.
If the audiofilter correctly ticked its block inputs, but they were shared with the synthesizer, then it would advance at double the rate, ticked twice for synthesizer and twice for audiofilter; each user of the LFO would see different values and the values would be "jumpy".
There seems to be no way to force the "update LFOs every 256 samples" behavior through the whole stack; for instance imagine you have an audiomixer that goes into another audiomixer just so you can control audio levels of some channels in unison. Each audiomixer wants to produce some number of samples, not necessarily 256. And in fact a big point of audiomixer is to "re-block" audio output and reduce underruns.
This all feels kinda shabby and it's my design and my fault... but we need to do the best with it we can, and it feels like audiofilter needs to "do better", by properly ticking the block inputs that it uses. (by factoring some code out of synthio to be shared between it and audiofilters! .. and probably by forcing audiofilters to always work in SYNTHIO_MAX_DUR samples between ticks, or else making the new factored out layer work in scaled seconds instead of samples and reciprocal sample rate)
Sadly, this will end up incompatibly changing code that relied on the illegal side effect of using the synthesizer to tick them.
I would love a better solution if someone has one.
The text was updated successfully, but these errors were encountered: