AFRAME.registerComponent("networked-audio-analyser", { schema: {}, async init() { this.connected = false; this.el.addEventListener("sound-source-set", event => { const ctx = THREE.AudioContext.getContext(); this.analyser = ctx.createAnalyser(); this.analyser.fftSize = 32; this.levels = new Uint8Array(this.analyser.frequencyBinCount); event.detail.soundSource.connect(this.analyser); }); }, tick: function() { if (!this.analyser) return; this.analyser.getByteFrequencyData(this.levels); let sum = 0; for (let i = 0; i < this.levels.length; i++) { sum += this.levels[i]; } this.volume = sum / this.levels.length; this.el.emit("audioFrequencyChange", { volume: this.volume, levels: this.levels }); } }); AFRAME.registerComponent("matcolor-audio-feedback", { schema: { analyserSrc: { type: "selector" } }, init: function() { this.onAudioFrequencyChange = this.onAudioFrequencyChange.bind(this); }, play() { (this.data.analyserSrc || this.el).addEventListener("audioFrequencyChange", this.onAudioFrequencyChange); }, pause() { (this.data.analyserSrc || this.el).removeEventListener("audioFrequencyChange", this.onAudioFrequencyChange); }, onAudioFrequencyChange(e) { if (!this.mat) return; this.object3D.mesh.color.setScalar(1 + e.detail.volume / 255 * 2); } }); AFRAME.registerComponent("scale-audio-feedback", { schema: { analyserSrc: { type: "selector" }, minScale: { default: 1 }, maxScale: { default: 2 } }, init() { this.onAudioFrequencyChange = this.onAudioFrequencyChange.bind(this); }, play() { (this.data.analyserSrc || this.el).addEventListener("audioFrequencyChange", this.onAudioFrequencyChange); }, pause() { (this.data.analyserSrc || this.el).removeEventListener("audioFrequencyChange", this.onAudioFrequencyChange); }, onAudioFrequencyChange(e) { // TODO: come up with a cleaner way to handle this. // bone's are "hidden" by scaling them with bone-visibility, without this we would overwrite that. if (!this.el.object3D.visible) return; const { minScale, maxScale } = this.data; this.el.object3D.scale.setScalar(minScale + (maxScale - minScale) * e.detail.volume / 255); } });