mirror of
https://github.com/troisjs/trois.git
synced 2024-11-24 12:22:03 +08:00
wip integrating audio components to the project
This commit is contained in:
parent
8c5dd149b9
commit
62b0db0cd5
83
src/audio/Audio.ts
Normal file
83
src/audio/Audio.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import { Audio as StaticAudio, PositionalAudio, AudioLoader } from 'three'
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import Object3D from '../core/Object3D'
|
||||||
|
import { bindProp } from '../tools'
|
||||||
|
|
||||||
|
export interface AudioSetupInterface {
|
||||||
|
streamMediaElement?: HTMLAudioElement
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConcreteAudio = StaticAudio | PositionalAudio
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
extends: Object3D,
|
||||||
|
name: 'Audio',
|
||||||
|
props: {
|
||||||
|
src: String,
|
||||||
|
volume: { type: Number, default: 1.0 },
|
||||||
|
isStreamed: { type: Boolean, default: true }
|
||||||
|
},
|
||||||
|
setup (): AudioSetupInterface {
|
||||||
|
let streamMediaElement = new Audio();
|
||||||
|
return { streamMediaElement }
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initAudio(audio: ConcreteAudio) {
|
||||||
|
this.initObject3D(audio)
|
||||||
|
this.bindProps(audio)
|
||||||
|
this.loadAudioAndPlay(audio)
|
||||||
|
},
|
||||||
|
bindProps(audio: ConcreteAudio) {
|
||||||
|
['volume', 'isStreamed'].forEach(p => {
|
||||||
|
bindProp(this.$props, p, audio)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
loadAudioAndPlay(audio: ConcreteAudio) {
|
||||||
|
if (!this.src) return undefined
|
||||||
|
|
||||||
|
if (this.isStreamed) {
|
||||||
|
this.loadAudioFromStream(audio, this.src)
|
||||||
|
} else {
|
||||||
|
this.loadAudioFromMemory(audio, this.src)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loadAudioFromMemory(audio:ConcreteAudio, src:string) {
|
||||||
|
const audioLoader = new AudioLoader();
|
||||||
|
const instance = this
|
||||||
|
audioLoader.load( src, function( buffer ) {
|
||||||
|
audio.setBuffer( buffer );
|
||||||
|
instance.play(audio)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
loadAudioFromStream(audio:ConcreteAudio, src:string) {
|
||||||
|
this.streamMediaElement = new Audio(src);
|
||||||
|
this.streamMediaElement.loop = true;
|
||||||
|
this.streamMediaElement.preload = 'metadata';
|
||||||
|
this.streamMediaElement.crossOrigin = 'anonymous';
|
||||||
|
const instance = this
|
||||||
|
this.streamMediaElement.addEventListener("loadedmetadata", function(_event) {
|
||||||
|
console.log('loaded the stream')
|
||||||
|
instance.play(audio)
|
||||||
|
});
|
||||||
|
audio.setMediaElementSource(this.streamMediaElement)
|
||||||
|
},
|
||||||
|
play(audio:ConcreteAudio) {
|
||||||
|
if (this.isStreamed) {
|
||||||
|
if (!this.streamMediaElement) { return }
|
||||||
|
this.streamMediaElement.play()
|
||||||
|
} else {
|
||||||
|
audio.play()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
stop(audio:ConcreteAudio) {
|
||||||
|
if (this.isStreamed) {
|
||||||
|
if (!this.streamMediaElement) { return }
|
||||||
|
this.streamMediaElement.pause()
|
||||||
|
this.streamMediaElement.currentTime = 0;
|
||||||
|
} else {
|
||||||
|
audio.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
__hmrId: 'Audio',
|
||||||
|
})
|
32
src/audio/AudioListener.ts
Normal file
32
src/audio/AudioListener.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { defineComponent, ComponentPublicInstance, InjectionKey, inject } from 'vue'
|
||||||
|
import { AudioListener } from 'three'
|
||||||
|
import Object3D from '../core/Object3D'
|
||||||
|
import { RendererInjectionKey } from './../core/Renderer'
|
||||||
|
|
||||||
|
//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...
|
||||||
|
|
||||||
|
export interface AudioListenerSetupInterface {
|
||||||
|
audioListener?: AudioListener
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
extends: Object3D,
|
||||||
|
name: 'AudioListener',
|
||||||
|
setup():AudioListenerSetupInterface {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.audioListener = new AudioListener()
|
||||||
|
this.initObject3D(this.audioListener)
|
||||||
|
const renderer = inject(RendererInjectionKey)
|
||||||
|
if (!renderer) {
|
||||||
|
console.error('Renderer not found')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
renderer.audioListener = this.audioListener
|
||||||
|
},
|
||||||
|
__hmrId: 'AudioListener',
|
||||||
|
})
|
39
src/audio/PositionalAudio.ts
Normal file
39
src/audio/PositionalAudio.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { defineComponent, inject } from 'vue'
|
||||||
|
import { PositionalAudio } from 'three'
|
||||||
|
import { RendererInjectionKey } from './../core/Renderer'
|
||||||
|
import Audio from './Audio'
|
||||||
|
import { bindProp } from '../tools'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
extends: Audio,
|
||||||
|
name: 'PositionalAudio',
|
||||||
|
props: {
|
||||||
|
refDistance: { type: Number, default: 1.0 },
|
||||||
|
rolloffFactor: { type: Number, default: 1.0 }
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
const renderer = inject(RendererInjectionKey)
|
||||||
|
|
||||||
|
if (!renderer) {
|
||||||
|
console.error('Renderer not found')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!renderer.audioListener) {
|
||||||
|
console.error("No AudioListener component found in the Renderer's child components tree!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const positionalAudio = new PositionalAudio(renderer.audioListener)
|
||||||
|
this.initAudio(positionalAudio)
|
||||||
|
this.bindProps(positionalAudio)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
bindProps(audio: PositionalAudio) {
|
||||||
|
['refDistance', 'rolloffFactor'].forEach(p => {
|
||||||
|
bindProp(this.$props, p, audio)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
__hmrId: 'AudioTest',
|
||||||
|
})
|
26
src/audio/StaticAudio.ts
Normal file
26
src/audio/StaticAudio.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { defineComponent, inject } from 'vue'
|
||||||
|
import { Audio as StaticAudio } from 'three'
|
||||||
|
import { RendererInjectionKey } from './../core/Renderer'
|
||||||
|
import Audio from './Audio'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
extends: Audio,
|
||||||
|
name: 'StaticAudio',
|
||||||
|
created() {
|
||||||
|
const renderer = inject(RendererInjectionKey)
|
||||||
|
|
||||||
|
if (!renderer) {
|
||||||
|
console.error('Renderer not found')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!renderer.audioListener) {
|
||||||
|
console.error("No AudioListener component found in the Renderer's child components tree!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const staticAudio = new StaticAudio(renderer.audioListener)
|
||||||
|
this.initAudio( staticAudio )
|
||||||
|
},
|
||||||
|
__hmrId: 'StaticAudio',
|
||||||
|
})
|
3
src/audio/index.ts
Normal file
3
src/audio/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export { default as AudioListener } from './AudioListener'
|
||||||
|
export { default as PositionalAudio } from './PositionalAudio'
|
||||||
|
export { default as StaticAudio } from './StaticAudio'
|
@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable no-use-before-define */
|
/* 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 { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'
|
||||||
import { ComponentPublicInstance, defineComponent, InjectionKey, PropType, watchEffect } from 'vue'
|
import { ComponentPublicInstance, defineComponent, InjectionKey, PropType, watchEffect } from 'vue'
|
||||||
import { bindObjectProp } from '../tools'
|
import { bindObjectProp } from '../tools'
|
||||||
@ -75,6 +75,7 @@ export interface RendererInterface extends RendererSetupInterface {
|
|||||||
scene?: Scene
|
scene?: Scene
|
||||||
camera?: Camera
|
camera?: Camera
|
||||||
composer?: EffectComposer
|
composer?: EffectComposer
|
||||||
|
audioListener?: AudioListener
|
||||||
|
|
||||||
onInit(cb: InitCallbackType): void
|
onInit(cb: InitCallbackType): void
|
||||||
onMounted(cb: MountedCallbackType): void
|
onMounted(cb: MountedCallbackType): void
|
||||||
@ -181,6 +182,10 @@ export default defineComponent({
|
|||||||
get: function(): EffectComposer | undefined { return this.three.composer },
|
get: function(): EffectComposer | undefined { return this.three.composer },
|
||||||
set: function(composer: EffectComposer): void { this.three.composer = 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() {
|
provide() {
|
||||||
return {
|
return {
|
||||||
|
@ -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 { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
|
||||||
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js'
|
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js'
|
||||||
import usePointer, { PointerConfigInterface, PointerPublicConfigInterface, PointerInterface } from './usePointer'
|
import usePointer, { PointerConfigInterface, PointerPublicConfigInterface, PointerInterface } from './usePointer'
|
||||||
@ -32,6 +32,7 @@ export interface ThreeInterface {
|
|||||||
composer?: EffectComposer
|
composer?: EffectComposer
|
||||||
camera?: Camera
|
camera?: Camera
|
||||||
cameraCtrl?: OrbitControls
|
cameraCtrl?: OrbitControls
|
||||||
|
audioListener?: AudioListener
|
||||||
scene?: Scene
|
scene?: Scene
|
||||||
pointer?: PointerInterface
|
pointer?: PointerInterface
|
||||||
size: SizeInterface
|
size: SizeInterface
|
||||||
|
@ -5,6 +5,7 @@ export * from './materials/index'
|
|||||||
export * from './meshes/index'
|
export * from './meshes/index'
|
||||||
export * from './models/index'
|
export * from './models/index'
|
||||||
export * from './effects/index'
|
export * from './effects/index'
|
||||||
|
export * from './audio/index'
|
||||||
|
|
||||||
// export * from './components/index'
|
// export * from './components/index'
|
||||||
|
|
||||||
|
@ -77,6 +77,10 @@ export const TroisJSVuePlugin = {
|
|||||||
'TiltShiftPass',
|
'TiltShiftPass',
|
||||||
'UnrealBloomPass',
|
'UnrealBloomPass',
|
||||||
'ZoomBlurPass',
|
'ZoomBlurPass',
|
||||||
|
|
||||||
|
'AudioListener',
|
||||||
|
'PositionalAudio',
|
||||||
|
'StaticAudio'
|
||||||
]
|
]
|
||||||
|
|
||||||
comps.forEach(comp => {
|
comps.forEach(comp => {
|
||||||
|
Loading…
Reference in New Issue
Block a user