The limit
The pitch stage is an AudioWorklet, which browsers expose only on a secure context. https:// and localhost qualify. A plain http://192.168.x.x does not, so a client opening a networked StemDeck is never given the API and the SoundTouch stage cannot be built at all.
Measured in Chromium against the same page served three ways:
http://127.0.0.1:8777/ secureContext=true audioWorklet=true
http://localhost:8777/ secureContext=true audioWorklet=true
http://192.168.1.14:8777/ secureContext=false audioWorklet=false
Reported as #552. That issue covers the messaging, which was wrong, and is fixed separately. This one is the capability.
There is a way
createScriptProcessor is not secure-context gated. Same probe, same insecure origin:
http://192.168.1.14:8778/ secure=false worklet=false scriptProcessor=true
So a ScriptProcessorNode path would make transpose work over a plain LAN IP with no certificate, no new dependency, and nothing for the user to configure.
What it costs
Three things make this a project rather than a patch.
It has to reimplement the whole worklet, not just the pitch part. The worklet also owns tempo, through stNode.parameters.get('tempo'). Without it, speed resamples the sources, which already moves the key. Adding a pitch shifter on top of that stacks two shifts and the result is incoherent. So the fallback needs both.
The graph shape does not port. The worklet is built with 13 inputs, one per semitone, because a lane's transpose is a connection rather than a parameter. ScriptProcessorNode has exactly one input. The workable design is probably one processor per distinct semitone actually in use, usually one, which is a second pitch architecture rather than a port of the first.
It runs on the main thread. StemDeck redraws waveforms, VU meters and the playhead continuously. Audio dropouts under UI load are the likely failure, on exactly the machine this is meant to help, which is already a remote client on a LAN.
There is also a hint in the tree worth knowing before starting: static/vendor/soundtouch-processor.js redefines PITCH_MIN_SEMITONES and PITCH_MAX_SEMITONES locally rather than importing them from pitchBus.js, even though that module exists to stop the mapping being written twice. Someone chose duplication over a worklet import. Extracting a shared DSP core may run into whatever reason that was.
Suggested first step
Prototype before building. One question decides it: does main-thread audio hold up while the waveform is redrawing? Everything else follows. An afternoon spent answering that is cheaper than a week spent discovering it.
Not in scope
Serving HTTPS. It needs a certificate, generating one needs cryptography, and adding that changes uv.lock, which sends every existing desktop install to a full re-download instead of an in-app update.
The limit
The pitch stage is an
AudioWorklet, which browsers expose only on a secure context.https://andlocalhostqualify. A plainhttp://192.168.x.xdoes not, so a client opening a networked StemDeck is never given the API and the SoundTouch stage cannot be built at all.Measured in Chromium against the same page served three ways:
Reported as #552. That issue covers the messaging, which was wrong, and is fixed separately. This one is the capability.
There is a way
createScriptProcessoris not secure-context gated. Same probe, same insecure origin:So a ScriptProcessorNode path would make transpose work over a plain LAN IP with no certificate, no new dependency, and nothing for the user to configure.
What it costs
Three things make this a project rather than a patch.
It has to reimplement the whole worklet, not just the pitch part. The worklet also owns tempo, through
stNode.parameters.get('tempo'). Without it, speed resamples the sources, which already moves the key. Adding a pitch shifter on top of that stacks two shifts and the result is incoherent. So the fallback needs both.The graph shape does not port. The worklet is built with 13 inputs, one per semitone, because a lane's transpose is a connection rather than a parameter. ScriptProcessorNode has exactly one input. The workable design is probably one processor per distinct semitone actually in use, usually one, which is a second pitch architecture rather than a port of the first.
It runs on the main thread. StemDeck redraws waveforms, VU meters and the playhead continuously. Audio dropouts under UI load are the likely failure, on exactly the machine this is meant to help, which is already a remote client on a LAN.
There is also a hint in the tree worth knowing before starting:
static/vendor/soundtouch-processor.jsredefinesPITCH_MIN_SEMITONESandPITCH_MAX_SEMITONESlocally rather than importing them frompitchBus.js, even though that module exists to stop the mapping being written twice. Someone chose duplication over a worklet import. Extracting a shared DSP core may run into whatever reason that was.Suggested first step
Prototype before building. One question decides it: does main-thread audio hold up while the waveform is redrawing? Everything else follows. An afternoon spent answering that is cheaper than a week spent discovering it.
Not in scope
Serving HTTPS. It needs a certificate, generating one needs
cryptography, and adding that changesuv.lock, which sends every existing desktop install to a full re-download instead of an in-app update.