aboutsummaryrefslogtreecommitdiffstats
path: root/static/mic-worklet.js
diff options
context:
space:
mode:
authorPinapelz <yukais@pinapelz.com>2026-10-29 19:58:05 -0700
committerPinapelz <yukais@pinapelz.com>2026-10-29 19:58:05 -0700
commit96bfe2e1505b4ae250f2d5201f9541ceb01cec84 (patch)
treeb2164a76dc3aa5b69e160d1135d3385bcbe6108d /static/mic-worklet.js
parent150858067059ba615c548f826bb343589993b4bb (diff)
ts web slopify code
Diffstat (limited to 'static/mic-worklet.js')
-rw-r--r--static/mic-worklet.js60
1 files changed, 60 insertions, 0 deletions
diff --git a/static/mic-worklet.js b/static/mic-worklet.js
new file mode 100644
index 0000000..814bf6a
--- /dev/null
+++ b/static/mic-worklet.js
@@ -0,0 +1,60 @@
+// Microphone capture worklet: resamples the context rate to 48 kHz mono and
+// posts 20 ms frames (960 Float32 samples) together with their RMS level.
+const OUT_RATE = 48000;
+const FRAME_SAMPLES = 960;
+
+class Ts6MicCapture extends AudioWorkletProcessor {
+ constructor() {
+ super();
+ this.ratio = sampleRate / OUT_RATE; // input samples per output sample
+ this.t = 0; // fractional read position; -1 refers to `last`
+ this.last = 0;
+ this.frame = new Float32Array(FRAME_SAMPLES);
+ this.offset = 0;
+ }
+
+ push(sample) {
+ this.frame[this.offset++] = sample;
+ if (this.offset < FRAME_SAMPLES) return;
+ let sum = 0;
+ for (let i = 0; i < FRAME_SAMPLES; i++) sum += this.frame[i] * this.frame[i];
+ const frame = this.frame;
+ this.frame = new Float32Array(FRAME_SAMPLES);
+ this.offset = 0;
+ this.port.postMessage({ samples: frame, rms: Math.sqrt(sum / FRAME_SAMPLES) }, [frame.buffer]);
+ }
+
+ process(inputs, outputs) {
+ const output = outputs[0] && outputs[0][0];
+ if (output) output.fill(0);
+ const channels = inputs[0];
+ if (!channels || channels.length === 0) return true;
+
+ // Downmix to mono.
+ let input = channels[0];
+ if (channels.length > 1) {
+ input = new Float32Array(input.length);
+ for (const ch of channels) for (let i = 0; i < input.length; i++) input[i] += ch[i] / channels.length;
+ }
+
+ if (this.ratio === 1) {
+ for (let i = 0; i < input.length; i++) this.push(input[i]);
+ return true;
+ }
+ // Linear interpolation resampler.
+ const len = input.length;
+ while (this.t < len - 1) {
+ const i0 = Math.floor(this.t);
+ const frac = this.t - i0;
+ const a = i0 < 0 ? this.last : input[i0];
+ const b = input[i0 + 1];
+ this.push(a + (b - a) * frac);
+ this.t += this.ratio;
+ }
+ this.t -= len;
+ this.last = input[len - 1];
+ return true;
+ }
+}
+
+registerProcessor("ts6-mic-capture", Ts6MicCapture);
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage