Spaces:
Running
Running
File size: 4,204 Bytes
6bcb42f |
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 111 112 113 114 115 116 117 118 |
class RobotEffect {
constructor (audioContext, startTime, endTime) {
this.audioContext = audioContext;
this.input = this.audioContext.createGain();
this.output = this.audioContext.createGain();
this.passthrough = this.audioContext.createGain();
this.effectInput = this.audioContext.createGain();
this.passthrough.gain.value = 1;
this.effectInput.gain.value = 0;
this.passthrough.gain.setValueAtTime(0, startTime);
this.passthrough.gain.setValueAtTime(1, endTime);
this.effectInput.gain.setValueAtTime(1, startTime);
this.effectInput.gain.setValueAtTime(0, endTime);
// Ring modulator inspired by BBC Dalek voice
// http://recherche.ircam.fr/pub/dafx11/Papers/66_e.pdf
// https://github.com/bbc/webaudio.prototyping.bbc.co.uk
// > There are four parallel signal paths, two which process the
// > combination Vc + Vin / 2 and two which process Vc - Vin/2.
// > Each branch consists of a non-linearity [diode]...
const createDiodeNode = () => {
const node = this.audioContext.createWaveShaper();
// Piecewise function given by (2) in Parker paper
const transform = (v, vb = 0.2, vl = 0.4, h = 0.65) => {
if (v <= vb) return 0;
if (v <= vl) return h * (Math.pow(v - vb, 2) / ((2 * vl) - (2 * vb)));
return (h * v) - (h * vl) + (h * (Math.pow(v - vb, 2) / ((2 * vl) - (2 * vb))));
};
// Create the waveshaper curve with the voltage transform above
const bufferLength = 1024;
const curve = new Float32Array(bufferLength);
for (let i = 0; i < bufferLength; i++) {
const voltage = (2 * (i / bufferLength)) - 1;
curve[i] = transform(voltage);
}
node.curve = curve;
return node;
};
const oscillator = this.audioContext.createOscillator();
oscillator.frequency.value = 50;
oscillator.start(0);
const vInGain = this.audioContext.createGain();
vInGain.gain.value = 0.5;
const vInInverter1 = this.audioContext.createGain();
vInInverter1.gain.value = -1;
const vInInverter2 = this.audioContext.createGain();
vInInverter2.gain.value = -1;
const vInDiode1 = createDiodeNode(this.audioContext);
const vInDiode2 = createDiodeNode(this.audioContext);
const vInInverter3 = this.audioContext.createGain();
vInInverter3.gain.value = -1;
const vcInverter1 = this.audioContext.createGain();
vcInverter1.gain.value = -1;
const vcDiode3 = createDiodeNode(this.audioContext);
const vcDiode4 = createDiodeNode(this.audioContext);
const compressor = this.audioContext.createDynamicsCompressor();
compressor.threshold.value = -5;
compressor.knee.value = 15;
compressor.ratio.value = 12;
compressor.attack.value = 0;
compressor.release.value = 0.25;
const biquadFilter = this.audioContext.createBiquadFilter();
biquadFilter.type = 'highpass';
biquadFilter.frequency.value = 1000;
biquadFilter.gain.value = 1.25;
this.input.connect(this.effectInput);
this.input.connect(this.passthrough);
this.passthrough.connect(this.output);
this.effectInput.connect(vcInverter1);
this.effectInput.connect(vcDiode4);
vcInverter1.connect(vcDiode3);
oscillator.connect(vInGain);
vInGain.connect(vInInverter1);
vInGain.connect(vcInverter1);
vInGain.connect(vcDiode4);
vInInverter1.connect(vInInverter2);
vInInverter1.connect(vInDiode2);
vInInverter2.connect(vInDiode1);
vInDiode1.connect(vInInverter3);
vInDiode2.connect(vInInverter3);
vInInverter3.connect(compressor);
vcDiode3.connect(compressor);
vcDiode4.connect(compressor);
this.effectInput.connect(biquadFilter);
biquadFilter.connect(compressor);
compressor.connect(this.output);
}
}
export default RobotEffect;
|