mindboost-rnbo-test-project/components/experiments/homepages/MusicGain.vue

240 lines
7.6 KiB
Vue

<template>
<div class="player">
<AudioElement
ref="Music"
key="1"
v-model:volume="volume"
:src="src"
:title="title"
@update:playing="handlePlayingUpdate2"
@update:canplay="handleCanPlayMusic"
>
<template #default="{ }">
<img
v-if="volume == 0"
class="slider-icon"
style="width: 25px; height: 25px;"
src="~/assets/image/music_muted.svg"
title="Click to unmute"
@click="toggleMute()"
>
<img
v-else
class="slider-icon"
style="width: 25px; height: 25px;"
src="~/assets/image/music.svg"
title="Click to mute"
@click="toggleMute()"
>
</template>
</AudioElement>
</div>
</template>
<script lang="ts">
import AudioElement from '../AudioElement.vue'
import { useAudioStore } from '../../../stores/audio'
export default {
name: 'MusicGain',
components: { AudioElement },
props: {
src: {
type: String,
required: true
},
title: {
type: String,
required: true
}
},
emits: ['musicReady'],
data () {
return {
audioContext: useAudioStore().getContext(),
createdNodes: {} as any,
musicReady: false,
fading: false,
connected: false,
muted: false,
volume: useAudioStore().getVolume,
previousVolume: useAudioStore().getVolume
}
},
watch: {
musicReady (value) {
this.$emit('musicReady', value)
this.handlePlayingUpdate(true)
}
},
mounted () {
this.applyStoredVolume()
},
beforeUnmount () {
this.disconnectNodes()
},
methods: {
disconnectNodes () {
if (typeof this.createdNodes === 'object' && this.createdNodes !== null) {
Object.values(this.createdNodes).forEach((node) => {
// Check if the node exists and has a disconnect method
if (node && typeof AudioNode) {
const tobedisconnected = node as AudioNode
tobedisconnected.disconnect()
node = null
}
})
this.createdNodes = null
}
},
toggleMute () {
const element = this.$refs.Music as typeof AudioElement
const audioElement = element.$refs.audioElement as HTMLMediaElement
if (this.muted) {
// Unmute: Stelle den vorherigen Lautstärkewert wieder her
this.muted = false
audioElement.muted = false
this.volume = this.previousVolume || 1 // Falls kein vorheriger Wert gespeichert ist, setze auf 1
audioElement.volume = this.volume
} else {
// Mute: Speichere den aktuellen Lautstärkewert und mute das Audio
this.previousVolume = this.volume
this.volume = 0
audioElement.volume = 0
this.muted = true
audioElement.muted = true
}
useAudioStore().setVolume(this.volume)
element.$emit('update:volume', this.volume)
},
mute () {
const element = this.$refs.Music as typeof AudioElement
const audioElement = element.$refs.audioElement as HTMLMediaElement
audioElement.muted = true
this.muted = audioElement.muted
},
unmute () {
const element = this.$refs.Music as typeof AudioElement
const audioElement = element.$refs.audioElement as HTMLMediaElement
audioElement.muted = false
this.muted = audioElement.muted
},
// This method helps to get the ressources free when we stop playing the audio
// without it would be louder each time we start playing
refreshAudioContext () {
const newAudioContext = new AudioContext()
this.audioContext.close()
useAudioStore().audioContext = newAudioContext
this.audioContext = useAudioStore().getContext()
},
fadeInGains () {
if (useAudioStore().playing !== true) {
logger.info('Skip interaction, because playing state is false.')
} else {
const element = this.$refs.Music as typeof AudioElement
const audioElement = element.$refs.audioElement as HTMLMediaElement
const fadeTime = this.audioContext.currentTime + 3.0
this.fading = true
this.unmute()
audioElement.play()
const musicGain = this.createdNodes.musicGain
this.createdNodes.musicGain.gain.setValueAtTime(0, this.audioContext.currentTime)
musicGain.gain.linearRampToValueAtTime(1.0, fadeTime)
setTimeout(() => {
this.fading = false
}, fadeTime * 1000)
}
},
fadeOutGains () {
if (this.createdNodes.musicGain) {
const musicGainValue = this.createdNodes.musicGainValue.gain.value
this.createdNodes.musicGain.gain.linearRampToValueAtTime(musicGainValue, this.audioContext.currentTime)
this.createdNodes.musicGain.gain.linearRampToValueAtTime(0, this.audioContext.currentTime + 1.3)
}
},
handleCanPlayMusic () {
this.musicReady = true
this.handlePlayingUpdate(true)
},
readyForWebaudio () {
if (!this.musicReady) {
return false
}
return true
},
handlePlayingUpdate2 (state: boolean) {
if (!state) {
this.mute()
return
}
if (this.readyForWebaudio()) {
if (state) {
this.handlePlayingUpdate(state)
} else {
this.fadeOutGains()
}
} else if (this.readyForWebaudio()) {
this.handlePlayingUpdate(state)
}
},
handlePlayingUpdate (state: boolean) {
if (state) {
const musicElement = this.$refs.Music as typeof AudioElement
const musicAudioElement = musicElement.$refs.audioElement as HTMLMediaElement
const audioContext = this.audioContext
const destination = this.audioContext.destination
this.createdNodes.musicGain ||= audioContext.createGain()
this.createdNodes.musicGain.gain.setValueAtTime(0, audioContext.currentTime)
if (musicAudioElement.currentSrc !== this.src) {
this.createdNodes.musicSource.disconnect()
this.createdNodes.musicSource = audioContext.createMediaElementSource(musicAudioElement)
this.createdNodes.musicSource.connect(this.createdNodes.musicGain)
this.createdNodes.musicGain.connect(destination)
}
this.createdNodes.musicSource ||= audioContext.createMediaElementSource(musicAudioElement)
this.createdNodes.musicSource.connect(this.createdNodes.musicGain)
this.createdNodes.musicGain.connect(destination)
this.createdNodes.musicGain.gain.cancelScheduledValues(this.audioContext.currentTime)
this.createdNodes.musicGain.gain.setValueAtTime(0, this.audioContext.currentTime)
this.connected = true
this.fadeInGains()
// useAudioStore().playing = true
} else {
// Music has just stopped react on it.
this.fadeOutGains()
this.createdNodes = []
this.refreshAudioContext()
this.connected = false
}
},
applyStoredVolume () {
const element = this.$refs.Music as typeof AudioElement
const audioElement = element.$refs.audioElement as HTMLMediaElement
// Setze die Lautstärke des Audio-Elements
audioElement.volume = this.volume
// Emitiere ein Event, um die Lautstärke in AudioElement zu aktualisieren
element.$emit('update:volume', this.volume)
},
updateMusicGain (volume: number) {
this.volume = volume // Lautstärke speichern
useAudioStore().setVolume(volume)
if (this.createdNodes.musicGain) {
this.createdNodes.musicGain.gain.linearRampToValueAtTime(volume, this.createdNodes.musicGain.context.currentTime + 1)
}
}
}
}
</script>