240 lines
7.6 KiB
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>
|