61 lines
2.1 KiB
TypeScript
61 lines
2.1 KiB
TypeScript
import { createAudioPanNode } from './audio-pan-node';
|
|
import type { GardenAudioGraph } from './garden-audio-graph';
|
|
import type { NoiseBurst } from './garden-audio-types';
|
|
|
|
const noiseBurstTuning = {
|
|
attackSeconds: 0.004,
|
|
filterQ: 1.4,
|
|
offsetRandomSeconds: 0.4,
|
|
scheduleAheadSeconds: 0.002,
|
|
silentGain: 0.0001,
|
|
filterType: 'bandpass' as BiquadFilterType,
|
|
};
|
|
|
|
export class NoiseBurstPlayer {
|
|
public constructor(private readonly graph: GardenAudioGraph) {}
|
|
|
|
public play({ startTime, durationSeconds, gain, filterHz, pan }: NoiseBurst): void {
|
|
const { context, eventBus, noiseBus, noiseBuffer } = this.graph;
|
|
const outputBus = noiseBus ?? eventBus;
|
|
if (!context || !outputBus || !noiseBuffer) {
|
|
return;
|
|
}
|
|
|
|
const scheduledStart = Math.max(
|
|
context.currentTime + noiseBurstTuning.scheduleAheadSeconds,
|
|
startTime
|
|
);
|
|
const source = context.createBufferSource();
|
|
const filter = context.createBiquadFilter();
|
|
const envelope = context.createGain();
|
|
const panNode = createAudioPanNode(context, pan, scheduledStart);
|
|
const stopAt = scheduledStart + durationSeconds;
|
|
|
|
source.buffer = noiseBuffer;
|
|
filter.type = noiseBurstTuning.filterType;
|
|
filter.frequency.setValueAtTime(filterHz, scheduledStart);
|
|
filter.Q.value = noiseBurstTuning.filterQ;
|
|
envelope.gain.setValueAtTime(noiseBurstTuning.silentGain, scheduledStart);
|
|
envelope.gain.exponentialRampToValueAtTime(
|
|
Math.max(noiseBurstTuning.silentGain, gain),
|
|
scheduledStart + noiseBurstTuning.attackSeconds
|
|
);
|
|
envelope.gain.exponentialRampToValueAtTime(noiseBurstTuning.silentGain, stopAt);
|
|
source.connect(filter);
|
|
filter.connect(envelope);
|
|
envelope.connect(panNode.input);
|
|
panNode.output.connect(outputBus);
|
|
source.start(scheduledStart, Math.random() * noiseBurstTuning.offsetRandomSeconds);
|
|
source.stop(stopAt);
|
|
source.addEventListener(
|
|
'ended',
|
|
() => {
|
|
source.disconnect();
|
|
filter.disconnect();
|
|
envelope.disconnect();
|
|
panNode.disconnect();
|
|
},
|
|
{ once: true }
|
|
);
|
|
}
|
|
}
|