UNPKG

@thi.ng/dsp

Version:

Composable signal generators, oscillators, filters, FFT, spectrum, windowing & related DSP utils

158 lines (157 loc) 3.5 kB
import { clamp01 } from "@thi.ng/math/interval"; import { add } from "./add.js"; import { AGen } from "./agen.js"; import { curve } from "./curve.js"; var EnvPhase = /* @__PURE__ */ ((EnvPhase2) => { EnvPhase2[EnvPhase2["ATTACK"] = 0] = "ATTACK"; EnvPhase2[EnvPhase2["DECAY"] = 1] = "DECAY"; EnvPhase2[EnvPhase2["SUSTAIN"] = 2] = "SUSTAIN"; EnvPhase2[EnvPhase2["RELEASE"] = 3] = "RELEASE"; EnvPhase2[EnvPhase2["IDLE"] = 4] = "IDLE"; return EnvPhase2; })(EnvPhase || {}); const adsr = (opts) => new ADSR(opts); class ADSR extends AGen { _phase; _curve; _atime; _dtime; _rtime; _acurve; _dcurve; _sustain; _speriod; _gain; constructor(opts) { super(0); opts = { a: 0, d: 0, s: 1, r: 0, acurve: 0.1, dcurve: 1e-3, slen: Infinity, gain: 1, ...opts }; this.setAttack(opts.a); this.setDecay(opts.d); this.setRelease(opts.r); this.setSustain(opts.s, opts.slen); this.setCurveA(opts.acurve); this.setCurveD(opts.dcurve); this.setGain(opts.gain); this.reset(); } copy() { return new ADSR({ a: this._atime, d: this._dtime, s: this._sustain, r: this._rtime, acurve: this._acurve, dcurve: this._dcurve, gain: this._gain, slen: this._speriod }); } reset() { this._phase = 0 /* ATTACK */; this._curve = curve(0, 1, this._atime + 1, this._acurve, true); this._val = 0; return this; } release() { if (this._phase < 3 /* RELEASE */) { this._phase = 3 /* RELEASE */; this._curve = curve( this._sustain, 0, this._rtime + 1, this._dcurve, true ); } } isSustained() { return this._phase === 2 /* SUSTAIN */; } isDone() { return this._phase === 4 /* IDLE */; } next() { let v; switch (this._phase) { case 4 /* IDLE */: return 0; case 0 /* ATTACK */: v = this._curve.next(); if (v >= 1) { v = 1; this._phase = 1 /* DECAY */; this._curve = curve( 1, this._sustain, this._dtime + 1, this._dcurve, true ); } break; case 1 /* DECAY */: v = this._curve.next(); if (v <= this._sustain) { v = this._sustain; this._phase = 2 /* SUSTAIN */; this._curve = add(1, 1); } break; case 2 /* SUSTAIN */: if (this._curve.next() >= this._speriod) { this.release(); } return this._val; case 3 /* RELEASE */: v = this._curve.next(); if (v < 0) { v = 0; this._phase = 4 /* IDLE */; } } return this._val = v * this._gain; } setAttack(steps) { this._atime = Math.max(steps, 0); } setDecay(steps) { this._dtime = Math.max(steps, 0); } setRelease(steps) { this._rtime = Math.max(steps, 0); } /** * Sets sustain level & duration. If the latter is omitted, the * current value will be retained. * * @param level - * @param duration - */ setSustain(level, duration) { this._sustain = clamp01(level); duration !== void 0 && (this._speriod = duration); } setCurveA(ratio) { this._acurve = Math.max(ratio, 1e-9); } setCurveD(ratio) { this._dcurve = Math.max(ratio, 1e-9); } setGain(gain) { this._gain = gain; } } export { ADSR, adsr };