@audio/spectral-edit 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/edit.js +47 -0
  3. package/package.json +33 -0
package/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # @audio/spectral-edit
2
+
3
+ > Spectral editing — delete/attenuate/boost time×frequency regions (Audacity spectral edit; FFmpeg afftfilt class)
4
+
5
+ Planned — not implemented yet. See the umbrella README for status and sources.
package/edit.js ADDED
@@ -0,0 +1,47 @@
1
+ // Spectral editing — apply gain to time×frequency regions (delete / attenuate / boost).
2
+ // STFT → per-region bin gains → weighted overlap-add resynthesis (COLA-normalized).
3
+ // Audacity spectral-edit / FFmpeg afftfilt class.
4
+
5
+ import { fft, ifft } from 'fourier-transform'
6
+
7
+ /**
8
+ * @param {Float32Array} data — mono PCM
9
+ * @param {object} opts — { fs, frameSize=2048, hop=frameSize/4,
10
+ * regions: [{ t0=0, t1=∞ (seconds), f0=0, f1=fs/2 (Hz), gain=0 (linear) }] }
11
+ * @returns {Float32Array} edited copy
12
+ */
13
+ export default function edit (data, { fs = 44100, frameSize = 2048, hop = frameSize / 4, regions = [] } = {}) {
14
+ let half = frameSize / 2
15
+ let win = new Float64Array(frameSize)
16
+ for (let i = 0; i < frameSize; i++) win[i] = 0.5 - 0.5 * Math.cos(2 * Math.PI * i / frameSize)
17
+
18
+ let out = new Float64Array(data.length)
19
+ let norm = new Float64Array(data.length)
20
+ let buf = new Float64Array(frameSize)
21
+
22
+ for (let pos = 0; pos + frameSize <= data.length + frameSize - hop; pos += hop) {
23
+ for (let i = 0; i < frameSize; i++) buf[i] = (data[pos + i] || 0) * win[i]
24
+ let [re, im] = fft(buf)
25
+
26
+ let tMid = (pos + frameSize / 2) / fs
27
+ for (let r of regions) {
28
+ if (tMid < (r.t0 ?? 0) || tMid > (r.t1 ?? Infinity)) continue
29
+ let k0 = Math.max(0, Math.floor((r.f0 ?? 0) * frameSize / fs))
30
+ let k1 = Math.min(half, Math.ceil((r.f1 ?? fs / 2) * frameSize / fs))
31
+ let g = r.gain ?? 0
32
+ for (let k = k0; k <= k1; k++) { re[k] *= g; im[k] *= g }
33
+ }
34
+
35
+ let frame = ifft(re, im)
36
+ for (let i = 0; i < frameSize; i++) {
37
+ let j = pos + i
38
+ if (j >= data.length) break
39
+ out[j] += frame[i] * win[i]
40
+ norm[j] += win[i] * win[i]
41
+ }
42
+ }
43
+
44
+ let res = new Float32Array(data.length)
45
+ for (let i = 0; i < data.length; i++) res[i] = norm[i] > 1e-9 ? out[i] / norm[i] : data[i]
46
+ return res
47
+ }
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@audio/spectral-edit",
3
+ "version": "1.0.0",
4
+ "description": "Spectral editing — gain on time×frequency regions via COLA-normalized STFT (Audacity/afftfilt class)",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "main": "edit.js",
8
+ "exports": {
9
+ ".": "./edit.js",
10
+ "./package.json": "./package.json"
11
+ },
12
+ "files": [
13
+ "edit.js"
14
+ ],
15
+ "dependencies": {
16
+ "fourier-transform": "^2.2.0"
17
+ },
18
+ "keywords": [
19
+ "audio",
20
+ "dsp",
21
+ "spectral",
22
+ "spectral-edit",
23
+ "stft"
24
+ ],
25
+ "license": "MIT",
26
+ "author": "Dmitry Iv. <dfcreative@gmail.com>",
27
+ "engines": {
28
+ "node": ">=18"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ }
33
+ }