@audio/filter-oberheim 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.
- package/oberheim.js +60 -0
- package/package.json +38 -0
package/oberheim.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Oberheim SEM state-variable filter (–12 dB/oct multimode).
|
|
3
|
+
* Zero-delay feedback (ZDF) via trapezoidal integration.
|
|
4
|
+
*
|
|
5
|
+
* Ref: Zavalishin, "The Art of VA Filter Design" (2012), Ch. 4–5.
|
|
6
|
+
*
|
|
7
|
+
* 2-pole SVF with continuous mode selection (lowpass, highpass, bandpass, notch).
|
|
8
|
+
* Two trapezoidal integrators with tanh saturation in the feedback path
|
|
9
|
+
* give the warm, musical character of the original SEM hardware.
|
|
10
|
+
*
|
|
11
|
+
* @module audio-filter/analog/oberheim
|
|
12
|
+
* @param {Float32Array|Float64Array} data - audio buffer (modified in place)
|
|
13
|
+
* @param {Object} params
|
|
14
|
+
* @param {number} [params.fc=1000] - cutoff frequency Hz
|
|
15
|
+
* @param {number} [params.resonance=0] - resonance 0–1 (max resonance at 1)
|
|
16
|
+
* @param {number} [params.fs=44100] - sample rate
|
|
17
|
+
* @param {string} [params.type='lowpass'] - 'lowpass'|'highpass'|'bandpass'|'notch'
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
let {tan, tanh, PI, min} = Math
|
|
21
|
+
|
|
22
|
+
export default function oberheim (data, params) {
|
|
23
|
+
let fc = params.fc || 1000
|
|
24
|
+
let res = params.resonance != null ? params.resonance : 0
|
|
25
|
+
let fs = params.fs || 44100
|
|
26
|
+
let type = params.type || 'lowpass'
|
|
27
|
+
|
|
28
|
+
// Trapezoidal integrator coefficient
|
|
29
|
+
let g = tan(PI * min(fc, fs * 0.49) / fs)
|
|
30
|
+
let R = 1 - res // damping: 1 = no resonance, 0 = max resonance
|
|
31
|
+
|
|
32
|
+
// State: 2 integrator states (bandpass, lowpass)
|
|
33
|
+
if (!params._s) params._s = new Float64Array(2)
|
|
34
|
+
let s = params._s
|
|
35
|
+
|
|
36
|
+
for (let i = 0, n = data.length; i < n; i++) {
|
|
37
|
+
// Implicit solve for highpass (ZDF: no unit delay in feedback)
|
|
38
|
+
let hp = (data[i] - 2 * R * s[0] - g * s[0] - s[1]) / (1 + 2 * R * g + g * g)
|
|
39
|
+
|
|
40
|
+
// Bandpass integrator (trapezoidal)
|
|
41
|
+
let bp = g * hp + s[0]
|
|
42
|
+
s[0] = g * hp + bp
|
|
43
|
+
|
|
44
|
+
// Lowpass integrator (trapezoidal)
|
|
45
|
+
let lp = g * bp + s[1]
|
|
46
|
+
s[1] = g * bp + lp
|
|
47
|
+
|
|
48
|
+
// Saturate feedback states (analog character)
|
|
49
|
+
s[0] = tanh(s[0])
|
|
50
|
+
s[1] = tanh(s[1])
|
|
51
|
+
|
|
52
|
+
// Mode select
|
|
53
|
+
data[i] = type === 'bandpass' ? bp
|
|
54
|
+
: type === 'highpass' ? hp
|
|
55
|
+
: type === 'notch' ? hp + lp
|
|
56
|
+
: lp
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return data
|
|
60
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@audio/filter-oberheim",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Oberheim SEM state-variable filter (–12 dB/oct multimode)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"main": "oberheim.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./oberheim.js",
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"oberheim.js"
|
|
14
|
+
],
|
|
15
|
+
"keywords": [
|
|
16
|
+
"audio",
|
|
17
|
+
"dsp",
|
|
18
|
+
"filter",
|
|
19
|
+
"oberheim"
|
|
20
|
+
],
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"author": "Dmitry Iv. <dfcreative@gmail.com>",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/audiojs/filter.git",
|
|
26
|
+
"directory": "packages/filter-oberheim"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/audiojs/filter/tree/main/packages/filter-oberheim",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/audiojs/filter/issues"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18"
|
|
34
|
+
},
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
}
|
|
38
|
+
}
|