janisozaur
There are many cases which are not able to be handled by SDL's audio conversion routines, including too low (negative) rate, too high rate (impossible to allocate).
This patch aims to report such issues early and handle others in a graceful manner. The "INT32_MAX / RESAMPLER_SAMPLES_PER_ZERO_CROSSING" value is the conservative approach in terms of what can _technically_ be supported, but its value is 4'194'303, or just shy of 4.2MHz. I highly doubt any sane person would use such rates, especially in SDL2, so I would like to drive this limit further down, but would need some assistance to do that, as doing so would have to introduce an arbitrary value. Are you OK with such approach? What would a good value be? Wikipedia (https://en.wikipedia.org/wiki/High-resolution_audio) lists 96kHz as the highest sampling rate in use, even if I quadruple it for a good measure, to 384kHz it's still an order of magnitude lower than 4MHz.
(I thought padding size ranged from 5 frames to ~30 frames (based around
RESAMPLER_ZERO_CROSSINGS, which is 5), but it's actually between 512 and
several thousands (based on RESAMPLER_SAMPLES_PER_ZERO_CROSSING)). It gets
big fast when downsampling.
--HG--
extra : rebase_source : 17870d2f7b9e1cf9657ead1969cfe090c4a9e094
Previously, the padding was silence, which was a problem when streaming since
you would sample a little bit of this silence between each buffer.
We still need a means to get padding data for the right hand side, but this
patch makes the resampler output more correct.
--HG--
extra : amend_source : 0cc91e0b0d6c2314a435a252d88c123c8fa58bfc
This time it's using real math from a real whitepaper instead of my previous
amateur, fast-but-low-quality attempt. The new resampler does "bandlimited
interpolation," as described here: https://ccrma.stanford.edu/~jos/resample/
The output appears to sound cleaner, especially at high frequencies, and of
course works with non-power-of-two rate conversions.
There are some obvious optimizations to be done to this still, and there is
other fallout: this doesn't resample a buffer in-place, the 2-channels-Sint16
fast path is gone because this resampler does a _lot_ of floating point math.
There is a nasty hack to make it work with SDL_AudioCVT.
It's possible these issues are solvable, but they aren't solved as of yet.
Still, I hope this effort is slouching in the right direction.
--HG--
extra : rebase_source : 2178d7f422d118dfb76608964f63d290b18c7408
extra : histedit_source : 5461b7f3025ed6c09213910a563318c95d185bf3%2C4a6a6c4c38784b4bc5f241d963c0d752c73ea5b9
Simon Hug
This issue actually raises the question if this API change (requirement of initialized audio subsystem) is breaking backwards compatibility. I don't see the documentation saying it is needed in 2.0.5.
"Major changes, roughly in order of appearance:
- Use float math everywhere, instead of promoting to double and casting back
all the time.
- Conserve sound energy when downmixing any channel into two other channels.
- Add a QuadToStereo filter. (The previous technique of reusing StereoToMono
never worked, since it assumed an incorrect channel layout for 4.0.)
- Add a 71to51 filter. This removes just under half of the cases the previous
code would silently break in.
- Add a QuadTo51 filter. More silent breakage fixed.
- Add a 51to71 filter, removing another almost-half of the silently broken
cases.
- Add 8 to the list of values SDL_SupportedChannelCount will accept.
- Change SDL_BuildAudioCVT's channel-related logic to handle every case, and
to actually fail if it fails instead of silently corrupting sound data and/or
crashing down the road."
(Note that SDL doesn't otherwise support 7.1 audio yet, but hopefully it will
soon and the 7.1 converters are an important piece of that. --ryan.)
Fixes Bugzilla #3727.
--HG--
extra : rebase_source : c61476a6434b4cfe1655f5d30332280cb4cd7af9
Simon Hug
There's a chance that an audio conversion from many channels to a few can use more than 9 audio filters. SDL_AudioCVT has 10 SDL_AudioFilter pointers of which one has to be the terminating NULL pointer. The SDL code has no checks for this limit. If it overflows there can be stack or heap corruption or a call to 0xa.
Attached patch adds a function that checks for this limit and throws an error if it is reached. Also adds some documentation.
Test parameters that trigger this issue:
AUDIO_U16MSB with 224 channels at 46359 Hz
V
AUDIO_S16MSB with 6 channels at 27463 Hz
The fuzzer program I uploaded in bug 3667 has more of them.
Fixes failures where SDL_AudioStreamGet() incorrectly thinks it got a partial
sample frame request.
--HG--
extra : rebase_source : e3c0970c4f954a1296220ebc4b04c8e95a32d5f3
This defaults to the internal SDL resampler, since that's the likely default
without a system-wide install of libsamplerate, but those that need more can
tweak this.
--HG--
extra : amend_source : 804f3d3dc636b5f28f7194b48b492c6c3fe05bf5
This currently favors libsamplerate over the fast path (quality over speed),
but I'm not sure that's the correct approach, as there may be surprising
changes in performance metrics depending on what packages are available on
a user's system. That being said, currently, the only thing with access to
SDL_AudioStream is an SDL audio device's thread, and it might be mostly idle
otherwise, so maybe this is generally good.
Turns out that iterating from 0 to channels-1 was a serious performance hit!
These cases now tend to match or beat the original audio resampler's speed!
This allows us to avoid an extra copy, allocate less memory and reduce cache
pressure. On the downside: we have to do a lot of tapdancing to resample the
buffer in reverse when the output is growing.
--HG--
extra : rebase_source : cab98b19216722eae3749cc1e1429d1c802e9782
It's expensive and (hopefully) unnecessary. If this becomes an overflow
problem, we could multiply both values by 0.5f before adding them, but let's
see if we can get by without the extra multiplication first.
--HG--
extra : rebase_source : b7b47e961eb974510e133882548ea36b40f6d7e3
We never seem to overflow the source buffer now; this might have been a
leftover from a bug that was covered by Vitaly's fixes?
Removing this conditional makes the resampler 10-20% faster. Left an
assert in there for debug builds, in case this still happens.
--HG--
extra : rebase_source : c05a536f5a80f065c0872b35d77d4f70a56b4e3e