Spaces:
Sleeping
Sleeping
File size: 2,112 Bytes
1829efb | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | import { useCallback, useEffect, useMemo, useRef } from 'react'
import { useLoader, useThree } from '@react-three/fiber'
import * as THREE from 'three'
import { useAudioStore } from '../../store/audio'
import { useAudioReady } from './useAudioReady'
const BASE_VOLUME = 0.6
interface Props {
urls: string[]
}
function WorldAudioPlayer({ urls }: Props) {
const camera = useThree((state) => state.camera)
const muted = useAudioStore((state) => state.muted)
const buffers = useLoader(THREE.AudioLoader, urls) as AudioBuffer[]
const soundsRef = useRef<THREE.Audio[]>([])
const listener = useMemo(() => new THREE.AudioListener(), [])
const startSounds = useCallback(() => {
if (listener.context.state === 'suspended') listener.context.resume().catch(() => {})
soundsRef.current.forEach((sound) => {
if (!sound.isPlaying) sound.play()
})
}, [listener])
useEffect(() => {
camera.add(listener)
return () => {
listener.removeFromParent()
}
}, [camera, listener])
useEffect(() => {
const sounds = buffers.map((buffer) => {
const sound = new THREE.Audio(listener)
sound.setBuffer(buffer)
sound.setLoop(true)
sound.setVolume(useAudioStore.getState().muted ? 0 : BASE_VOLUME)
return sound
})
soundsRef.current = sounds
if (!useAudioStore.getState().muted) startSounds()
return () => {
sounds.forEach((sound) => {
if (sound.isPlaying) sound.stop()
sound.disconnect()
})
soundsRef.current = []
}
}, [buffers, listener, startSounds])
useEffect(() => {
soundsRef.current.forEach((sound) => {
sound.setVolume(muted ? 0 : BASE_VOLUME)
})
if (muted) {
soundsRef.current.forEach((sound) => {
if (sound.isPlaying) sound.stop()
})
} else {
startSounds()
}
}, [muted, startSounds])
return null
}
export function AudioManager({ urls }: Props) {
const ready = useAudioReady()
const audioKey = urls.join('\0')
if (!ready || urls.length === 0) return null
return <WorldAudioPlayer key={audioKey} urls={urls} />
}
|