1
0
mirror of https://github.com/troisjs/trois.git synced 2024-11-24 04:12:02 +08:00

Merge branch 'audio' into develop

This commit is contained in:
dataexcess 2022-12-08 22:15:16 +01:00
commit 5cb0efcce1
9 changed files with 198 additions and 2 deletions

87
src/audio/Audio.ts Normal file
View File

@ -0,0 +1,87 @@
import { Audio as StaticAudio, PositionalAudio, AudioLoader } from 'three'
import { defineComponent, watch } from 'vue'
import Object3D from '../core/Object3D'
type ConcreteAudio = StaticAudio | PositionalAudio
export interface AudioSetupInterface {
audio?: ConcreteAudio
streamedAudio?: HTMLAudioElement
}
export default defineComponent({
extends: Object3D,
name: 'Audio',
props: {
src: { type: String, required: false },
volume: { type: Number, default: 1.0 },
isStreamed: { type: Boolean, default: true }
},
setup (): AudioSetupInterface {
let streamedAudio = new Audio();
return { streamedAudio }
},
watch: {
volume: function(value) {
this.audio?.setVolume(value)
},
src: function(value) {
this.stop()
this.loadAudioAndPlay()
}
},
methods: {
initAudio(audio: ConcreteAudio) {
this.audio = audio
this.initObject3D(this.audio)
this.loadAudioAndPlay()
},
loadAudioAndPlay() {
if (!this.src) return undefined
if (this.isStreamed) {
this.loadAudioFromStream()
} else {
this.loadAudioFromMemory()
}
},
loadAudioFromMemory() {
const audioLoader = new AudioLoader();
const instance = this
audioLoader.load(this.src!, function( buffer ) {
console.log('loaded audio from memory')
instance.audio?.setBuffer( buffer );
instance.play()
});
},
loadAudioFromStream() {
this.streamedAudio = new Audio(this.src);
this.streamedAudio.loop = true;
this.streamedAudio.preload = 'metadata';
this.streamedAudio.crossOrigin = 'anonymous';
const instance = this
this.streamedAudio.addEventListener("loadedmetadata", function(_event) {
console.log('loaded audio from stream')
instance.play()
});
this.audio?.setMediaElementSource(this.streamedAudio)
},
play() {
if (this.isStreamed) {
this.streamedAudio?.play()
} else {
this.audio?.play()
}
},
stop() {
if (this.isStreamed) {
if (!this.streamedAudio) { return }
this.streamedAudio.pause()
this.streamedAudio.currentTime = 0;
} else {
this.audio?.stop()
}
}
},
__hmrId: 'Audio',
})

View File

@ -0,0 +1,31 @@
import { defineComponent, ComponentPublicInstance, InjectionKey, inject } from 'vue'
import { AudioListener } from 'three'
import Object3D from '../core/Object3D'
//TODO: currently the AudioListener is inheriting Object3D so it must be a
// child of Scene. However the AudioListener should actually be possible to be
// a child of Camera... Then again Camera is said to extend Object3D in the
// future... so might be better to refactor Camera first?
export interface AudioListenerSetupInterface {
audioListener?: AudioListener
}
export default defineComponent({
extends: Object3D,
name: 'AudioListener',
setup():AudioListenerSetupInterface {
return {}
},
created() {
this.audioListener = new AudioListener()
this.initObject3D(this.audioListener)
if (!this.renderer) {
console.error('Renderer not found')
return
}
this.renderer.audioListener = this.audioListener
},
__hmrId: 'AudioListener',
})

View File

@ -0,0 +1,40 @@
import { defineComponent, inject } from 'vue'
import { PositionalAudio } from 'three'
import Audio from './Audio'
import { bindProp } from '../tools'
export default defineComponent({
extends: Audio,
name: 'PositionalAudio',
props: {
refDistance: { type: Number, default: 1.0 },
maxDistance: { type: Number, default: 1.0 },
rolloffFactor: { type: Number, default: 1.0 },
distanceModel: { type: String, default: 'inverse' },
},
created() {
if (!this.renderer) {
console.error('Renderer not found')
return
}
if (!this.renderer.audioListener) {
console.error("No AudioListener component found in the Renderer's child components tree!")
return
}
const positionalAudio = new PositionalAudio(this.renderer.audioListener)
this.initAudio(positionalAudio)
this.bindProps()
},
methods: {
bindProps() {
['refDistance', 'maxDistance', 'rolloffFactor', 'distanceModel'].forEach(p => {
console.log('initialised positionalAudio props')
bindProp(this.$props, p, (this.audio as PositionalAudio).panner)
})
},
},
__hmrId: 'AudioTest',
})

24
src/audio/StaticAudio.ts Normal file
View File

@ -0,0 +1,24 @@
import { defineComponent, inject } from 'vue'
import { Audio as StaticAudio } from 'three'
import Audio from './Audio'
export default defineComponent({
extends: Audio,
name: 'StaticAudio',
created() {
if (!this.renderer) {
console.error('Renderer not found')
return
}
if (!this.renderer.audioListener) {
console.error("No AudioListener component found in the Renderer's child components tree!")
return
}
const staticAudio = new StaticAudio(this.renderer.audioListener)
this.initAudio( staticAudio )
},
__hmrId: 'StaticAudio',
})

3
src/audio/index.ts Normal file
View File

@ -0,0 +1,3 @@
export { default as AudioListener } from './AudioListener'
export { default as PositionalAudio } from './PositionalAudio'
export { default as StaticAudio } from './StaticAudio'

View File

@ -1,5 +1,5 @@
/* eslint-disable no-use-before-define */
import { Camera, Scene, WebGLRenderer, WebGLRendererParameters } from 'three'
import { Camera, Scene, WebGLRenderer, WebGLRendererParameters, AudioListener } from 'three'
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'
import { ComponentPublicInstance, defineComponent, InjectionKey, PropType, watchEffect } from 'vue'
import { bindObjectProp } from '../tools'
@ -75,6 +75,7 @@ export interface RendererInterface extends RendererSetupInterface {
scene?: Scene
camera?: Camera
composer?: EffectComposer
audioListener?: AudioListener
onInit(cb: InitCallbackType): void
onMounted(cb: MountedCallbackType): void
@ -181,6 +182,10 @@ export default defineComponent({
get: function(): EffectComposer | undefined { return this.three.composer },
set: function(composer: EffectComposer): void { this.three.composer = composer },
},
audioListener: {
get: function(): AudioListener | undefined { return this.three.audioListener },
set: function(audioListener: AudioListener): void { this.three.audioListener = audioListener },
}
},
provide() {
return {

View File

@ -1,4 +1,4 @@
import { Camera, Object3D, OrthographicCamera, PerspectiveCamera, Scene, WebGLRenderer, WebGLRendererParameters } from 'three'
import { Camera, Object3D, OrthographicCamera, PerspectiveCamera, Scene, WebGLRenderer, WebGLRendererParameters, AudioListener } from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js'
import usePointer, { PointerConfigInterface, PointerPublicConfigInterface, PointerInterface } from './usePointer'
@ -32,6 +32,7 @@ export interface ThreeInterface {
composer?: EffectComposer
camera?: Camera
cameraCtrl?: OrbitControls
audioListener?: AudioListener
scene?: Scene
pointer?: PointerInterface
size: SizeInterface

View File

@ -5,6 +5,7 @@ export * from './materials/index'
export * from './meshes/index'
export * from './models/index'
export * from './effects/index'
export * from './audio/index'
// export * from './components/index'

View File

@ -77,6 +77,10 @@ export const TroisJSVuePlugin = {
'TiltShiftPass',
'UnrealBloomPass',
'ZoomBlurPass',
'AudioListener',
'PositionalAudio',
'StaticAudio'
]
comps.forEach(comp => {