Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | 355x 355x 355x 355x 355x 355x 355x 355x 355x 339x 158x 158x 85x 85x 20x 20x 181x 181x 37x 37x 37x 16x 16x 16x 16x 16x 35757x 35757x 35757x 35757x 35757x 35757x 35757x 35757x 35757x 59142x 59142x 59142x 84173441x 84173441x 84173441x 84173441x 84173441x 84173441x 84173441x 59142x 59142x 59142x 59142x | // Coefficients from the RBJ Audio EQ Cookbook: the second-order prototypes
// under a bilinear transform prewarped so the corner lands on `frequency`.
export class Biquad {
constructor(b0, b1, b2, a1, a2) {
this.b0 = b0;
this.b1 = b1;
this.b2 = b2;
this.a1 = a1;
this.a2 = a2;
this.x1 = 0;
this.x2 = 0;
this.y1 = 0;
this.y2 = 0;
}
static _fromUnnormalised(b0, b1, b2, a0, a1, a2) {
return new Biquad(b0 / a0, b1 / a0, b2 / a0, a1 / a0, a2 / a0);
}
static _prototype(sampleRate, frequency, q) {
const w0 = (2 * Math.PI * frequency) / sampleRate;
return { alpha: Math.sin(w0) / (2 * q), cosW0: Math.cos(w0) };
}
static lowPass(sampleRate, frequency, q) {
const { alpha, cosW0 } = Biquad._prototype(sampleRate, frequency, q);
return Biquad._fromUnnormalised((1 - cosW0) / 2, 1 - cosW0, (1 - cosW0) / 2, 1 + alpha, -2 * cosW0, 1 - alpha);
}
static highPass(sampleRate, frequency, q) {
const { alpha, cosW0 } = Biquad._prototype(sampleRate, frequency, q);
return Biquad._fromUnnormalised(
(1 + cosW0) / 2,
-(1 + cosW0),
(1 + cosW0) / 2,
1 + alpha,
-2 * cosW0,
1 - alpha,
);
}
/** A single RC high-pass: 6 dB per octave below the corner. */
static firstOrderHighPass(sampleRate, frequency) {
const k = Math.tan((Math.PI * frequency) / sampleRate);
return Biquad._fromUnnormalised(1, -1, 0, 1 + k, k - 1, 0);
}
static peaking(sampleRate, frequency, q, gainDb) {
const a = 10 ** (gainDb / 40);
const { alpha, cosW0 } = Biquad._prototype(sampleRate, frequency, q);
return Biquad._fromUnnormalised(
1 + alpha * a,
-2 * cosW0,
1 - alpha * a,
1 + alpha / a,
-2 * cosW0,
1 - alpha / a,
);
}
static highShelf(sampleRate, frequency, q, gainDb) {
const a = 10 ** (gainDb / 40);
const { alpha, cosW0 } = Biquad._prototype(sampleRate, frequency, q);
const root = 2 * Math.sqrt(a) * alpha;
return Biquad._fromUnnormalised(
a * (a + 1 + (a - 1) * cosW0 + root),
-2 * a * (a - 1 + (a + 1) * cosW0),
a * (a + 1 + (a - 1) * cosW0 - root),
a + 1 - (a - 1) * cosW0 + root,
2 * (a - 1 - (a + 1) * cosW0),
a + 1 - (a - 1) * cosW0 - root,
);
}
static gain(factor) {
return new Biquad(factor, 0, 0, 0, 0);
}
/** Magnitude response at `frequency`, as a linear factor. */
magnitudeAt(sampleRate, frequency) {
const w = (2 * Math.PI * frequency) / sampleRate;
const { b0, b1, b2, a1, a2 } = this;
const cos1 = Math.cos(w);
const sin1 = Math.sin(w);
const cos2 = Math.cos(2 * w);
const sin2 = Math.sin(2 * w);
const numerator = Math.hypot(b0 + b1 * cos1 + b2 * cos2, b1 * sin1 + b2 * sin2);
const denominator = Math.hypot(1 + a1 * cos1 + a2 * cos2, a1 * sin1 + a2 * sin2);
return numerator / denominator;
}
process(buffer, offset, length) {
const { b0, b1, b2, a1, a2 } = this;
let { x1, x2, y1, y2 } = this;
for (let i = offset; i < offset + length; ++i) {
const x = buffer[i];
const y = b0 * x + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2;
x2 = x1;
x1 = x;
y2 = y1;
y1 = y;
buffer[i] = y;
}
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
}
}
|