Skip to content

verticalrectangle/silvertune-web

Repository files navigation

Silvertune Web

Browser-based real-time autotune. No backend, no dependencies — one HTML file and one AudioWorklet.

Live: silvertune.live


How it works

Microphone input is fed into an AudioWorklet running a hand-rolled YIN pitch detector. Detected pitch is snapped to the nearest note in the selected key/scale, and a 2-tap grain shifter (Hann-windowed COLA, phases 0 and ½) pitch-shifts the audio on the fly. A canvas piano visualises the detected note (blue) and the corrected target (white/pressed). Keys outside the active scale are masked out.

The companion app mode connects via WebSocket (ws://127.0.0.1:2747) and runs the same YIN + grain-shift stack natively using miniaudio, letting you use the browser just as a UI while processing goes through your real audio interface.


Controls

Control Range What it does
Key C – B Root key for the scale
Scale Chromatic / Major / Minor Scale to snap to; Chromatic disables correction
Speed 0 – 100 ms Exponential glide time to the target pitch ratio
Hold 0 – 200 ms How long a note must be held before correction commits
Wide 0 – 100% Stereo doubler blend (slightly detuned second grain)
(bottom right) Minimal mode — hides the canvas visualiser

Companion app

The companion bridges the browser UI to your audio interface. It runs the full audio pipeline natively (miniaudio) and streams pitch reports back to the page over a local WebSocket.

ws://127.0.0.1:2747

Messages sent to the companion (JSON):

{ "speed_ms": 0, "hold_ms": 0, "key_idx": 0, "scale_idx": 1, "wide": 0.0 }

Messages received from the companion (JSON):

{ "type": "pitch", "detectedNote": 60, "correctedNote": 60, "rms": 0.02 }

Running the companion

Linux / macOS

chmod +x silvertune-companion-linux   # or -macos
./silvertune-companion-linux

macOS — if your DAW won't scan the plugin

xattr -rd com.apple.quarantine Silvertune.clap

Windows — run silvertune-companion-windows.exe directly.


Architecture

Microphone
    │
    ▼
AudioWorkletNode  (worklet.js — dedicated audio thread)
    ├─ YIN pitch detection     BUF=1024  HALF=512  HOP=32
    ├─ Scale quantization
    └─ 2-tap grain shifter     grainSize=256, phases 0 / 0.5, Hann window
         │
         ├──▶ actx.destination          (live monitor)
         └──▶ MediaStreamDestination    (recording)

Main thread  (index.html)
    ├─ Canvas render loop  (requestAnimationFrame)
    │   ├─ Animated silver/white blob background
    │   ├─ Sonar rings + orb flashes on note events
    │   └─ Piano visualisation  (OffscreenCanvas cache for inactive keys)
    └─ XMB-style navigation  (FX · Sound · Rec · Settings)

Companion  (companion/src/)
    ├─ miniaudio audio I/O
    ├─ Hand-rolled YIN  (HOP_SIZE=128)
    ├─ GrainShifter     (BUF=4096)
    ├─ Hand-rolled WebSocket server  (port 2747)
    └─ Single-instance PID lock

Pitch detection

YIN difference function computed every HOP samples on a rolling circular buffer. Parabolic interpolation refines the period estimate. A stays_locked hysteresis (±0.4 semitones) prevents robo-vibrato on sustained notes while still tracking note changes. The Hold timer requires a new note to be stable for at least hold_ms before the correction ratio commits.

Grain shifter

Two overlapping grains at phase offsets 0 and 0.5 of the grain window. Each grain reads back at a position scaled by (1 - pitchRatio) and is windowed with a Hann envelope. The 0.5-offset pair sums to unity gain with no normalisation needed (COLA). A second slightly-detuned shifter feeds the Wide doubler.


Running locally

python3 -m http.server 8080
# open http://localhost:8080

AudioWorklets require a secure context (HTTPS or localhost).


Projector mode

projector.html is a standalone fullscreen canvas showing only the visualiser (blobs + piano). Designed for stage use — open it on a second screen while running the main UI on your primary display. It receives pitch data from the same WebSocket connection.


Deployment

GitHub Actions deploys to GitHub Pages on every push to master. Custom domain via CNAME.

About

Silvertune web implementation

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors