@thi.ng/dsp
Version:
Composable signal generators, oscillators, filters, FFT, spectrum, windowing & related DSP utils
107 lines (106 loc) • 2.65 kB
JavaScript
import { isFunction } from "@thi.ng/checks/is-function";
import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
import { wrap } from "@thi.ng/math/interval";
import { AProc } from "./aproc.js";
const delay = (n) => new Delay(n, 0);
const delayT = (n, off) => new Delay(n, off);
class Delay extends AProc {
/**
* Constructs new delay line of size `n` and initializes all
* elements to `empty`. If the latter is a function, the buffer will
* be initialized with the results of that function (called for each
* element).
*
* @param n -
* @param _empty -
*/
constructor(n, _empty) {
super(isFunction(_empty) ? _empty() : _empty);
this._empty = _empty;
if (n < 1) illegalArgs("delay size must be >= 1");
n >>>= 0;
this._wpos = n - 1;
this._rpos = 0;
this._buf = new Array(n);
this.clear();
}
_buf;
_rpos;
_wpos;
get length() {
return this._buf.length;
}
clear() {
const { _buf, _empty } = this;
if (isFunction(_empty)) {
for (let i = _buf.length; i-- > 0; ) {
this._buf[i] = _empty();
}
} else {
this._buf.fill(_empty);
}
}
copy() {
return new Delay(this._buf.length, this._empty);
}
/**
* Alias for {@link Delay.clear}
*/
reset() {
this.clear();
return this;
}
/**
* Returns the delayed value at current read position (i.e. `n`
* samples behind current write pos, where `n` is the length of this
* delay line).
*/
deref() {
return this._buf[this._rpos];
}
/**
* Reads value at `t` relative to current write position. `t` should
* be in `(-∞..0)` interval. E.g. `tap(-1)` returns the second
* most recent value written.
*
* @param t -
*/
tap(t) {
return this._buf[wrap((t | 0) + this._wpos, 0, this._buf.length - 1)];
}
/**
* Takes an array of offsets relative to current write position,
* calls {@link Delay.tap} for each, writes results to `out` and
* returns it.
*/
multiTap(t, out = []) {
for (let i = t.length; i-- > 0; ) {
out[i] = this.tap(t[i]);
}
return out;
}
/**
* Progresses read & write pos, stores new value and returns delayed value.
*
* @param x -
*/
next(x) {
this.step();
this._buf[this._wpos] = x;
return this._val = this._buf[this._rpos];
}
/**
* Moves read & write cursors one step forward. Useful for skipping
* elements and/or to create gaps in the delay line.
*/
step() {
const n = this._buf.length;
++this._wpos >= n && (this._wpos -= n);
++this._rpos >= n && (this._rpos -= n);
}
}
export {
Delay,
delay,
delayT
};