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
{{ message }}
Repository navigation
[Bug]: playback runs the audio graph at the output device's rate, costing up to 19x the DSP and 4x the RAM for no added quality #578
StemDeck creates its AudioContext with no sampleRate, so the graph runs at whatever the operating system's output device is set to. On a machine set to 24-bit/192 kHz, everything downstream runs at 192 kHz.
Nothing in StemDeck benefits from that. Every stem the pipeline produces is 44.1 kHz, 16-bit stereo, fixed at -ar 44100 in app/pipeline/runner.py. At a 192 kHz context the browser upsamples those 44.1 kHz stems on decode and then does several times the work on interpolated samples that carry no information the 44.1 kHz originals did not already have.
What it costs
The pitch chain's WSOLA search is O(overlap x seek) per sequence and both windows are set in milliseconds, so the cost per second of audio is quadratic in the context rate. One active pitch chain, offline render through the real soundtouch-processor.js, as a share of real time:
Context rate
Cost
44.1 kHz
2.1%
48 kHz
2.4%
96 kHz
7.3%
192 kHz
28.2%
Memory scales linearly with the same number. Decoded AudioBuffers for a five minute, six stem track:
Context rate
RAM
44.1 kHz
606 MB
48 kHz
659 MB
96 kHz
1.3 GB
192 kHz
2.6 GB
2.6 GB of buffers for a five minute track is enough to put a tab under memory pressure on its own, before any DSP runs.
Who this affects
Anyone who has deliberately set a high output rate, which is exactly the audiophile audience most likely to be running a DAC. #575 was reported by someone running 24-bit/192 kHz for Apple Music and Spotify Hi-Fi.
This is a separate problem from #576. That one was twelve pitch chains doing work on silence, which #577 fixes. This one is real work done at four times thenecessary resolution, and it remains after #577 lands: a single transposed laneat 192 kHz still costs 28% of the audio thread's budget where the same lane at44.1 kHz costs 2%.
Constraints for whoever fixes this
There are four AudioContext creation sites: static/js/audioEngine.js, static/js/chunkedAudioEngine.js, static/js/player.js (the footer waveform's decode-only context) and static/mobile/app.js (the shared, gesture-unlocked context the mobile UI passes in). A fix in one engine only is not a fix.
new AudioContext({ sampleRate }) is honoured in Chrome, Firefox and Safari, and the browser resamples to the device on output. I verified in Chromium that a requested 44100 and 48000 are both granted and that baseLatency does not change.
Whether the browser's output resampling to 192 kHz is clean on Windows WASAPI
is not something I can test without the hardware. It has to be confirmed on a
real 192 kHz device before this ships.
Lowering the rate for everybody is not obviously right. At 44.1 and 48 kHz the current behaviour is correct and costs nothing, and pinning would introduce a resample where there is none today. Capping only above 48 kHz leaves the common case untouched.
The context's rate is fixed when it is constructed, so the device rate has to be read before the real context is built, or the app has to be restarted after a device change. It already behaves that way today.
Activity
fix(player): cap the audio graph's sample rate instead of inheriting …
Stop the pitch worklet burning the audio thread at zero transpose and…