267 lines
11 KiB
Vue
267 lines
11 KiB
Vue
<template>
|
|
<div class="player">
|
|
<div v-if="deviceReady">RNBOValues: {{ createdNodes.noiseDevice }}</div>
|
|
<Microphone ref="Microphone" @update:attach="setupMicrophone" />
|
|
<AudioElement
|
|
ref="Noise"
|
|
key="5"
|
|
:src="noise_src"
|
|
title="Noise"
|
|
@update:volume="updateNoiseGain"
|
|
@update:canplay="handleCanPlayNoise"
|
|
@update:playing="handlePlayingUpdate2"
|
|
>
|
|
<template #default="{}">
|
|
<img v-if="!muted" style="width: 25px; height: 25px;" src="~/assets/image/sound.svg" title="Click to mute" @click="toggleMute()">
|
|
<img v-if="muted" style="width: 25px; height: 25px;" src="~/assets/image/sound_muted.svg" title="Click to unmute" @click="toggleMute()">
|
|
</template>
|
|
</AudioElement>
|
|
</div>
|
|
</template>
|
|
<script lang="ts">
|
|
import type { Device } from '@rnbo/js'
|
|
import AudioElement from '../AudioElement.vue'
|
|
import { useAudioStore } from '../../../stores/audio'
|
|
import Microphone from '../tests/Microphone.vue'
|
|
import { useDevicesStore } from '../../../stores/device'
|
|
|
|
export default {
|
|
name: 'RNBODevice',
|
|
components: { AudioElement, Microphone },
|
|
emits: { 'update:control-value': null },
|
|
data () {
|
|
return {
|
|
audioContext: useAudioStore().getContext(),
|
|
createdNodes: {} as any,
|
|
noiseReady: false,
|
|
micReady: false,
|
|
deviceReady: false,
|
|
noise_src: window.location.origin + useRuntimeConfig().public.noise_src as string,
|
|
fading: false,
|
|
connected: false,
|
|
muted: false
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
|
|
toggleMute () {
|
|
const noiseElement = this.$refs.Noise as typeof AudioElement
|
|
const noiseAudioElement = noiseElement.$refs.audioElement as HTMLMediaElement
|
|
noiseAudioElement.muted = !noiseAudioElement.muted
|
|
this.muted = noiseAudioElement.muted
|
|
},
|
|
mute () {
|
|
const noiseElement = this.$refs.Noise as typeof AudioElement
|
|
const noiseAudioElement = noiseElement.$refs.audioElement as HTMLMediaElement
|
|
noiseAudioElement.muted = true
|
|
this.muted = true
|
|
},
|
|
unmute () {
|
|
const noiseElement = this.$refs.Noise as typeof AudioElement
|
|
const noiseAudioElement = noiseElement.$refs.audioElement as HTMLMediaElement
|
|
noiseAudioElement.muted = false
|
|
this.muted = false
|
|
},
|
|
// This methodd gets a microphone stream from the micorphone component and creates the microphone node
|
|
// need to be called before the noise device is connected to the audio graph
|
|
setupMicrophone (stream:MediaStream) {
|
|
useNuxtApp().$logger.log('setup Microphone')
|
|
try {
|
|
this.createdNodes.microphone ||= this.audioContext.createMediaStreamSource(stream)
|
|
this.micReady = true
|
|
} catch (error: any) {
|
|
this.micReady = false
|
|
throw new Error(error.message)
|
|
}
|
|
},
|
|
// This method setup a RNBO Device, it gets the name of the Patch and add the noise audio node to createdNodes
|
|
async setupDevice () {
|
|
await useAudioStore().ensureAudioContextRunning()
|
|
useNuxtApp().$logger.log('setup Device')
|
|
try {
|
|
const deviceStore = useDevicesStore()
|
|
const device = await deviceStore.createNoiseDevice('adaptive_masking_controller_NoMusic') as Device // ich bekomme keine analyse Werte raus
|
|
this.createdNodes.noiseDevice = deviceStore.getDeviceAudioNode('adaptive_masking_controller_NoMusic')
|
|
this.deviceReady = true
|
|
this.attachDBValueListener(device)
|
|
} catch (error) {
|
|
useNuxtApp().$logger.error('Error setting up device, fall back.', { error })
|
|
this.deviceReady = false
|
|
}
|
|
},
|
|
|
|
// This method takes the controll value before ramp and controls the volume of music
|
|
attachDBValueListener (noiseDevice: Device) {
|
|
noiseDevice.messageEvent.subscribe((ev: any) => {
|
|
try {
|
|
// if (ev.tag === 'out4') { // out4 represents controll value before Timeramp
|
|
if (ev.tag === 'out3') { // out3 represents controll value in dB after Timeramp
|
|
const newValue = ev.payload
|
|
useNuxtApp().$logger.log('out3= ' + newValue[0])
|
|
}
|
|
if (ev.tag === 'out4') { // out3 represents controll value in dB after Timeramp
|
|
const newValue = ev.payload
|
|
useNuxtApp().$logger.log('out4= ' + newValue[0])
|
|
}
|
|
if (ev.tag === 'out5') { // out3 represents controll value in dB after Timeramp
|
|
const newValue = ev.payload
|
|
useNuxtApp().$logger.log('out5= ' + newValue[0])
|
|
}
|
|
if (ev.tag === 'ou6') { // out3 represents controll value in dB after Timeramp
|
|
const newValue = ev.payload
|
|
useNuxtApp().$logger.log('out6= ' + newValue[0])
|
|
}
|
|
if (ev.tag === 'out7') { // out3 represents controll value in dB after Timeramp
|
|
const newValue = ev.payload
|
|
useNuxtApp().$logger.log('out7= ' + newValue[0])
|
|
}
|
|
if (ev.tag === 'out8') { // out3 represents controll value in dB after Timeramp
|
|
const newValue = ev.payload
|
|
useNuxtApp().$logger.log('out8= ' + newValue[0])
|
|
}
|
|
if (ev.tag === 'out9= ') { // out3 represents controll value in dB after Timeramp
|
|
const newValue = ev.payload
|
|
useNuxtApp().$logger.log('Band 1000 = ' + newValue)
|
|
this.$emit('update:control-value', newValue[0])
|
|
}
|
|
} catch (error: any) {
|
|
// this.$logger.warn('Failed to attach a control value listener, music is not gain controlled.')
|
|
}
|
|
})
|
|
},
|
|
// 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 () {
|
|
this.unmute()
|
|
// useNuxtApp().$logger.log('Fade In Gains')
|
|
if (useAudioStore().playing !== true) { return }
|
|
const fadeTime = this.audioContext.currentTime + 3.0
|
|
|
|
setTimeout(() => {
|
|
this.fading = true
|
|
const noiseGain = this.createdNodes.noiseGain
|
|
noiseGain.gain.linearRampToValueAtTime(1.0, fadeTime)
|
|
}, 450)
|
|
setTimeout(() => {
|
|
this.fading = false
|
|
}, fadeTime * 1000)
|
|
},
|
|
fadeOutGains () {
|
|
if (this.createdNodes.noiseGain) {
|
|
const noiseGainValue = this.createdNodes.noiseGain.gain.value
|
|
this.createdNodes.noiseGain.gain.linearRampToValueAtTime(noiseGainValue, this.audioContext.currentTime)
|
|
this.createdNodes.noiseGain.gain.linearRampToValueAtTime(0, this.audioContext.currentTime + 1.3)
|
|
}
|
|
},
|
|
|
|
handleCanPlayNoise (state: boolean) {
|
|
// useNuxtApp().$logger.log('NoiseElement has now playingstate: ' + state)
|
|
this.noiseReady = state
|
|
},
|
|
readyForWebaudio () {
|
|
if (!this.noiseReady) {
|
|
return false
|
|
}
|
|
if (!this.micReady) {
|
|
return false
|
|
}
|
|
if (!this.deviceReady) {
|
|
return false
|
|
}
|
|
return true
|
|
},
|
|
async handlePlayingUpdate2 (state: boolean) {
|
|
useNuxtApp().$logger.log('handling Playing Update2= ' + state, this.audioContext.state)
|
|
if (!state) {
|
|
this.mute()
|
|
return
|
|
}
|
|
if (this.readyForWebaudio()) {
|
|
this.handlePlayingUpdate(true)
|
|
} else {
|
|
if (!this.deviceReady) {
|
|
useNuxtApp().$logger.log('Device is not ready, create it now')
|
|
await this.setupDevice()
|
|
}
|
|
if (!this.micReady) {
|
|
// await this.setupMicrophone(Microphone)
|
|
useNuxtApp().$logger.log('micophone not yet ready attach it!! ')
|
|
// useNuxtApp().$logger.log('microphone attached' + stream)
|
|
}
|
|
if (this.readyForWebaudio()) {
|
|
useNuxtApp().$logger.log('everything is now ready start play')
|
|
this.handlePlayingUpdate(true)
|
|
} else {
|
|
useNuxtApp().$logger.log('Waiting for all devices to be ready')
|
|
}
|
|
}
|
|
},
|
|
handlePlayingUpdate (state: boolean) {
|
|
try {
|
|
// Stop the music again, mute it and set the noiseReady or musicReady to true
|
|
if (state) {
|
|
useNuxtApp().$logger.log('stop playing')
|
|
const noiseElement = this.$refs.Noise as typeof AudioElement
|
|
const noiseAudioElement = noiseElement.$refs.audioElement as HTMLMediaElement
|
|
const audioContext = this.audioContext
|
|
const destination = this.audioContext.destination
|
|
audioContext.resume()
|
|
this.createdNodes.noiseGain ||= audioContext.createGain()
|
|
this.createdNodes.noiseGain.gain.setValueAtTime(0, audioContext.currentTime)
|
|
|
|
this.createdNodes.noiseSource ||= audioContext.createMediaElementSource(noiseAudioElement)
|
|
|
|
// HERE THE NOISE PATCH COMES INTO PLAY
|
|
|
|
this.createdNodes.micSplitter ||= audioContext.createChannelSplitter(2)
|
|
this.createdNodes.noiseInputChannelSplitter ||= audioContext.createChannelSplitter(2)
|
|
this.createdNodes.microphone.connect(this.createdNodes.micSplitter)
|
|
this.createdNodes.noiseSource.connect(this.createdNodes.noiseInputChannelSplitter)
|
|
this.createdNodes.micSplitter.connect(this.createdNodes.noiseDevice, 0, 0)
|
|
this.createdNodes.noiseInputChannelSplitter.connect(this.createdNodes.noiseDevice, 0, 1)
|
|
this.createdNodes.noiseInputChannelSplitter.connect(this.createdNodes.noiseDevice, 1, 2)
|
|
|
|
this.createdNodes.noiseDevice.connect(this.createdNodes.noiseGain)
|
|
|
|
this.createdNodes.noiseGain.connect(destination)
|
|
this.createdNodes.noiseGain.gain.cancelScheduledValues(this.audioContext.currentTime)
|
|
this.createdNodes.noiseGain.gain.setValueAtTime(0, this.audioContext.currentTime)
|
|
noiseAudioElement.muted = false
|
|
this.connected = true
|
|
this.unmute()
|
|
this.fadeInGains()
|
|
useAudioStore().playing = true
|
|
this.$logger.info('RNBO Patch successfully connected and playing')
|
|
} else {
|
|
// Music has just stopped react on it.
|
|
this.$logger.info('Stopping audio and disconnecting RNBO Patch')
|
|
this.fadeOutGains()
|
|
this.createdNodes = []
|
|
this.refreshAudioContext()
|
|
this.connected = false
|
|
}
|
|
} catch (error) {
|
|
this.$logger.info('Error in handlePlayingUpdate')
|
|
this.connected = false
|
|
useAudioStore().playing = false
|
|
// You might want to show an error message to the user here
|
|
}
|
|
},
|
|
updateNoiseGain (volume: number) {
|
|
if (this.createdNodes.noiseGain) {
|
|
useNuxtApp().$logger.log('volume= ' + volume)
|
|
this.createdNodes.noiseGain.gain.linearRampToValueAtTime(volume, this.createdNodes.noiseGain.context.currentTime + 0.30)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
</script>
|