@omnimedia/omnitool
Version:
open source video processing tools
93 lines • 2.89 kB
JavaScript
import { measureAudioLevel } from '../../parts/audio-level.js';
export class AudioLevels {
context;
time;
isPlaying;
#meters = new Set();
#items = new Map();
#frame = null;
#running = false;
constructor(context, time, isPlaying) {
this.context = context;
this.time = time;
this.isPlaying = isPlaying;
}
on(items, listener) {
const silent = this.context.createGain();
const analyser = this.context.createAnalyser();
silent.gain.value = 0;
analyser.smoothingTimeConstant = 0;
analyser.connect(silent);
silent.connect(this.context.destination);
const meter = {
items,
silent,
listener,
analyser,
nodes: new Set(),
samples: new Float32Array(analyser.fftSize)
};
this.#meters.add(meter);
if (this.isPlaying())
this.start();
return () => {
if (!this.#meters.delete(meter))
return;
for (const node of meter.nodes)
node.disconnect(analyser);
analyser.disconnect();
silent.disconnect();
if (!this.#meters.size)
this.stop();
};
}
attach(itemId, node) {
this.#items.set(node, itemId);
}
detach(node) {
this.#items.delete(node);
for (const meter of this.#meters) {
if (meter.nodes.delete(node))
node.disconnect(meter.analyser);
}
}
start() {
if (this.#running || !this.#meters.size)
return;
this.#running = true;
this.#frame = requestAnimationFrame(() => this.#tick());
}
stop() {
this.#running = false;
if (this.#frame !== null)
cancelAnimationFrame(this.#frame);
this.#frame = null;
}
#tick() {
if (!this.#running)
return;
for (const meter of this.#meters) {
this.#sync(meter);
meter.analyser.getFloatTimeDomainData(meter.samples);
meter.listener({ time: this.time(), ...measureAudioLevel(meter.samples) });
}
if (this.#running)
this.#frame = requestAnimationFrame(() => this.#tick());
}
#sync(meter) {
const selected = new Set(meter.items());
for (const [node, itemId] of this.#items) {
const connected = meter.nodes.has(node);
const shouldConnect = selected.has(itemId);
if (shouldConnect && !connected) {
node.connect(meter.analyser);
meter.nodes.add(node);
}
else if (!shouldConnect && connected) {
node.disconnect(meter.analyser);
meter.nodes.delete(node);
}
}
}
}
//# sourceMappingURL=audio-levels.js.map