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
|
class CustomProcessor extends AudioWorkletProcessor {
static get parameterDescriptors() {
return [
{ name: 'gain', defaultValue: 1.0, minValue: 0.0, maxValue: 2000.0 },
// Add parameters for the 8 biquad filters here
...Array.from({ length: 8 }, (_, index) => [
{ name: `b0_${index}`, defaultValue: 1.0 },
{ name: `b1_${index}`, defaultValue: 0.0 },
{ name: `b2_${index}`, defaultValue: 0.0 },
{ name: `a1_${index}`, defaultValue: 0.0 },
{ name: `a2_${index}`, defaultValue: 0.0 }
]).flat()
];
}
constructor() {
super();
this.sampleRate = sampleRate; // `sampleRate` is available globally here
console.log('Sample rate:', this.sampleRate);
// Set up state variables for the 8 biquad filters, initialize to 0
this.biquadState = Array.from({ length: 8 }, () => ({ state1: 0.0, state2: 0.0 }));
this.volumeEnvelope = [];
this.wavetablemode = false;
this.envelopeIndex = 0;
this.currentSample = 0;
this.port.onmessage = (event) => {
if (event.data.type === 'volumeEnvelope') {
this.volumeEnvelope = event.data.envelope;
this.dx = event.data.dx;
this.envelopeIndex = 0;
this.currentSample = 0;
this.wavetablemode = event.data.wavetablemode;
}
};
}
process(inputs, outputs, parameters) {
const input = inputs[0];
const output = outputs[0];
const gainParam = parameters.gain;
const pregain = gainParam[0];
for (let channel = 0; channel < input.length; channel++) {
const inputChannel = input[channel];
const outputChannel = output[channel];
let cs = this.currentSample;
let dx = this.dx;
for (let i = 0; i < inputChannel.length; i++, cs++) {
let currentSample = inputChannel[i];
// Run through 8 biquad filters in series
if (1) for (let biquadIndex = 0; biquadIndex < 8; biquadIndex++) {
const b0 = parameters[`b0_${biquadIndex}`][0];
const b1 = parameters[`b1_${biquadIndex}`][0];
const b2 = parameters[`b2_${biquadIndex}`][0];
const a1 = parameters[`a1_${biquadIndex}`][0];
const a2 = parameters[`a2_${biquadIndex}`][0];
const state = this.biquadState[biquadIndex];
// Apply Direct Form II Transposed structure
const output = currentSample * b0 + state.state1;
state.state1 = currentSample * b1 - a1 * output + state.state2;
state.state2 = currentSample * b2 - a2 * output;
currentSample = output;
}
let postgain = 1.0;
if (this.volumeEnvelope.length > 0) {
let x = cs * dx;
if (this.wavetablemode) x=x%1;
while (this.envelopeIndex < this.volumeEnvelope.length - 2 && x >= this.volumeEnvelope[this.envelopeIndex + 1].x)
this.envelopeIndex++;
while (this.envelopeIndex > 0 && x < this.volumeEnvelope[this.envelopeIndex].x)
this.envelopeIndex--;
const p1 = this.volumeEnvelope[this.envelopeIndex];
const p2 = this.volumeEnvelope[this.envelopeIndex + 1];
const t = Math.min(1, (x - p1.x) / (p2.x - p1.x));
postgain = p1.y + (p2.y - p1.y) * Math.pow(t, p1.power);
//if (cs < 16) postgain *= cs / 16;
}
outputChannel[i] = /*Math.tanh*/(currentSample * pregain) * postgain;
}
}
if (input.length > 0)
this.currentSample += input[0].length;
return true;
}
}
registerProcessor('custom-processor', CustomProcessor);
|