3.6.0: implement audio playback speed using resampling #1511
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes #1503.
It's unclear whether AL_PITCH attribute in OpenAL actually means playback speed or not, the available specification is not clear about this, and in the mojoAL implementation we're using AL_PITCH scales the sample pitch but not the frequency, therefore speed stays the same.
This PR implements playback speed by resampling a portion of sound before we pass it into OpenAL. The result should be equivalent to pre-3.6.0 functionality where the dynamic frequency shift was supported by allegro 4.
So far the only problem I experienced was with calculating playback position, as we no longer may rely only on offset time the OpenAL reports. This is solved by keeping a record of speed and "sped up" time per each queued buffer, and applying these as the buffers are processed.
There's still some mistake which I was not able to track down to the end, which causes the calculated position jump back a little when the speed is changed from high to low (or maybe vice versa too, but that's harder to notice). To avoid confusing game scripts would they rely on sound pos, the audio player remembers last reported position and clamps new calculated value to it.
But it's still best to test this more to ensure that the position matches (or is at least close enough to) the original un-sped playback, and that it reaches the full duration in the end.