Skip to content
Snippets Groups Projects
Commit 508ceff3 authored by netpro2k's avatar netpro2k
Browse files

Break up audio feedback into multiple components and add local audio feedback

parent 9921c112
No related branches found
No related tags found
No related merge requests found
......@@ -31,9 +31,10 @@
<a-entity
class="head"
gltf-model="#dodec-avatar-head"
position="0 0 0"
networked-audio-source
audio-feedback
networked-audio-analyser
matcolor-audio-feedback="objectName: DodecAvatar_Head_0"
scale-audio-feedback
avatar-customization
></a-entity>
</script>
......@@ -77,7 +78,14 @@
networked="template:#hand-template;showLocalTemplate:false;"
>
<a-entity id="watch" gltf-model="assets/hud/watch.gltf" position="0 0.0015 0.147" rotation="3.5 0 0">
<a-circle mute-state-indicator="" position="0 0.023 0" rotation="-90 0 0" scale="0.04 0.04 0.04" material="color:#d8eece;shader:flat"></a-circle>
<a-circle
mute-state-indicator
scale-audio-feedback="analyserSrc: #head; minScale: 0.035; maxScale: 0.08;"
position="0 0.023 0"
rotation="-90 0 0"
scale="0.04 0.04 0.04"
material="color:#d8eece;shader:flat">
</a-circle>
</a-entity>
</a-entity>
......
// @TODO break this up into 2 components
// 1. a component that just adds an analyser node and reads audio data
// 2. a component that uses the other component's data to apply some effect
// Communication either happens by dispatching some event or by component 2 directly reading componet 1
AFRAME.registerComponent("audio-feedback", {
schema: {
audioSource: { type: "selector" }
},
init: function() {
// @TODO using an arbitrary timeout here which is very bad. Needs to wait on model loading and audio source being connected
setTimeout(() => {
const audioComponent = (this.data.audioSource || this.el).components[
"networked-audio-source"
];
const waitForConnected = function() {
return new Promise(resolve => {
NAF.clientId
? resolve()
: document.body.addEventListener("connected", resolve);
});
};
const audioSource = audioComponent && audioComponent.sound;
if (!audioSource) return;
this.mat = this.el.object3D.getObjectByName(
"DodecAvatar_Head_0"
).material;
this.analyser = audioSource.context.createAnalyser();
this.levels = new Uint8Array(this.analyser.frequencyBinCount);
audioSource.disconnect();
audioSource.setFilter(this.analyser);
audioSource.connect();
console.log(audioSource.filters, audioSource.isPlaying);
}, 5000);
AFRAME.registerComponent("networked-audio-analyser", {
schema: {},
init() {
waitForConnected()
.then(() => {
const networkedEl = NAF.utils.getNetworkedEntity(this.el);
if (!networkedEl) {
return Promise.reject(
"Audio Analyzer must be added on a node, or a child of a node, with the `networked` component."
);
}
const ownerId = networkedEl.components.networked.data.owner;
console.log("audio Analyser for " + ownerId);
return NAF.connection.adapter.getMediaStream(ownerId);
})
.then(stream => {
const ctx = THREE.AudioContext.getContext();
const source = ctx.createMediaStreamSource(stream);
this.analyser = ctx.createAnalyser();
this.levels = new Uint8Array(this.analyser.frequencyBinCount);
source.connect(this.analyser);
console.log(source, this.analyser);
});
},
tick: function() {
......@@ -39,7 +41,80 @@ AFRAME.registerComponent("audio-feedback", {
sum += this.levels[i];
}
this.volume = sum / this.levels.length;
this.mat.color.setScalar(1 + this.volume / 255 * 2);
this.el.object3D.scale.setScalar(1 + this.volume / 255);
this.el.emit("audioFrequencyChange", {
volume: this.volume,
levels: this.levels
});
}
});
AFRAME.registerComponent("matcolor-audio-feedback", {
schema: {
analyserSrc: { type: "selector" },
objectName: { type: "string" }
},
init: function() {
this.onAudioFrequencyChange = this.onAudioFrequencyChange.bind(this);
this.el.addEventListener("model-loaded", () => {
console.log(this.data.objectName);
this.mat = this.el.object3D.getObjectByName(
this.data.objectName
).material;
console.log("mat", this.mat);
});
},
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.mat.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) {
const { minScale, maxScale } = this.data;
this.el.object3D.scale.setScalar(
minScale + (maxScale - minScale) * e.detail.volume / 255
);
}
});
......@@ -12,8 +12,8 @@ AFRAME.registerComponent("mute-state-indicator", {
},
pause() {
this.el.sceneEl.addEventListener("stateadded", this.onStateToggled);
this.el.sceneEl.addEventListener("stateremoved", this.onStateToggled);
this.el.sceneEl.removeEventListener("stateadded", this.onStateToggled);
this.el.sceneEl.removeEventListener("stateremoved", this.onStateToggled);
},
onStateToggled(e) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment