@audio/effect-lofi 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +5 -0
  2. package/lofi.js +67 -0
  3. package/package.json +29 -0
package/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # @audio/effect-lofi
2
+
3
+ > Lo-fi character — wow/flutter, vinyl noise, crackle, bandwidth ceiling (RC-20 class)
4
+
5
+ Planned — not implemented yet. See the umbrella README for status and sources.
package/lofi.js ADDED
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Lo-fi character (RC-20 class) — wow/flutter via LFO-modulated fractional delay,
3
+ * bandwidth ceiling/floor one-poles, tape saturation, vinyl noise bed + sparse crackle.
4
+ * Deterministic noise (seeded LCG) so renders are reproducible.
5
+ */
6
+
7
+ let { sin, tanh, exp, PI } = Math
8
+
9
+ export default function lofi (data, params) {
10
+ let wow = params.wow ?? 0.3 // 0..1 — slow pitch drift (~0.7 Hz, up to 3 ms)
11
+ let flutter = params.flutter ?? 0.2 // 0..1 — fast wobble (~7 Hz, up to 0.4 ms)
12
+ let noise = params.noise ?? 0.1 // 0..1 — hiss bed level
13
+ let crackle = params.crackle ?? 0.1 // 0..1 — impulse density/level
14
+ let lowpass = params.lowpass ?? 6000 // bandwidth ceiling, Hz
15
+ let highpass = params.highpass ?? 60 // rumble floor, Hz
16
+ let drive = params.drive ?? 0.3 // 0..1 tape saturation
17
+ let fs = params.fs || 44100
18
+
19
+ let maxDelay = ((0.004 * fs) | 0) + 4
20
+ if (!params._buf) {
21
+ params._buf = new Float64Array(maxDelay * 2)
22
+ params._w = 0; params._ph1 = 0; params._ph2 = 0
23
+ params._lp1 = 0; params._lp2 = 0; params._lp3 = 0; params._hp = 0
24
+ params._rnd = params.seed ?? 0x2545f491
25
+ params._crk = 0
26
+ }
27
+ let buf = params._buf, N = buf.length, w = params._w
28
+ let ph1 = params._ph1, ph2 = params._ph2, hp = params._hp
29
+ let rnd = () => ((params._rnd = (params._rnd * 1664525 + 1013904223) >>> 0) / 4294967296)
30
+
31
+ let aLp = 1 - exp(-2 * PI * lowpass / fs)
32
+ let aHp = 1 - exp(-2 * PI * highpass / fs)
33
+ let g = 1 + drive * 4
34
+ let base = 0.004 * fs / 2 // center read offset
35
+
36
+ for (let i = 0, l = data.length; i < l; i++) {
37
+ buf[w] = data[i]
38
+ // modulated fractional-delay read: wow + flutter
39
+ let m = base + wow * 0.0015 * fs * sin(ph1) + flutter * 0.0002 * fs * sin(ph2)
40
+ ph1 += 2 * PI * 0.7 / fs; ph2 += 2 * PI * 7 / fs
41
+ let pos = w - m
42
+ let b0 = Math.floor(pos), frac = pos - b0
43
+ let s0 = buf[((b0 % N) + N) % N], s1 = buf[(((b0 + 1) % N) + N) % N]
44
+ let x = s0 + frac * (s1 - s0)
45
+ w = (w + 1) % N
46
+
47
+ // tape saturation, gain-compensated
48
+ if (drive > 0) x = tanh(x * g) / tanh(g)
49
+
50
+ // vinyl bed: hiss + crackle impulses with exponential tails
51
+ if (noise > 0) x += (rnd() - 0.5) * noise * 0.02
52
+ if (crackle > 0) {
53
+ if (rnd() < crackle * 0.0004) params._crk = (rnd() - 0.5) * crackle * 0.8
54
+ x += params._crk
55
+ params._crk *= 0.92
56
+ }
57
+
58
+ // bandwidth: 3-pole LP ceiling (−18 dB/oct, tape-class), one-pole HP floor
59
+ params._lp1 += aLp * (x - params._lp1)
60
+ params._lp2 += aLp * (params._lp1 - params._lp2)
61
+ params._lp3 += aLp * (params._lp2 - params._lp3)
62
+ hp += aHp * (params._lp3 - hp)
63
+ data[i] = params._lp3 - hp
64
+ }
65
+ params._w = w; params._ph1 = ph1; params._ph2 = ph2; params._hp = hp
66
+ return data
67
+ }
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@audio/effect-lofi",
3
+ "version": "1.0.0",
4
+ "description": "Lo-fi character — wow/flutter, vinyl noise, crackle, bandwidth ceiling (RC-20 class)",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "keywords": [
8
+ "audio",
9
+ "dsp",
10
+ "effect",
11
+ "lofi"
12
+ ],
13
+ "license": "MIT",
14
+ "author": "Dmitry Iv. <dfcreative@gmail.com>",
15
+ "engines": {
16
+ "node": ">=18"
17
+ },
18
+ "main": "lofi.js",
19
+ "exports": {
20
+ ".": "./lofi.js",
21
+ "./package.json": "./package.json"
22
+ },
23
+ "files": [
24
+ "lofi.js"
25
+ ],
26
+ "publishConfig": {
27
+ "access": "public"
28
+ }
29
+ }