223 lines
8.2 KiB
TypeScript
223 lines
8.2 KiB
TypeScript
// stores/counter.js
|
|
import { defineStore, type _ActionsTree, type StoreDefinition, type StateTree } from 'pinia'
|
|
import { type AudioNodeItem } from '../AudioNodeItem'
|
|
import { useUserStore } from '../../user'
|
|
import { connectAudioNodes } from '~/lib/AudioFunctions'
|
|
import type Player from '~/components/Player/Player'
|
|
|
|
export const useAudioStore: StoreDefinition = defineStore<'audio', StateTree, _ActionsTree>('audio', {
|
|
state: () => {
|
|
return {
|
|
audioContext: new AudioContext() as AudioContext,
|
|
nodes: new Map() as Map<string, AudioNodeItem>,
|
|
playing: false,
|
|
scene: 'Lagoon',
|
|
acusticCheckResult: 0,
|
|
scenePlayer: null as Player | null,
|
|
noisePlayer: null as Player | null
|
|
}
|
|
},
|
|
|
|
actions: {
|
|
setPlayers ({ scenePlayer, noisePlayer }:any) {
|
|
this.scenePlayer = scenePlayer
|
|
this.noisePlayer = noisePlayer
|
|
},
|
|
//
|
|
// Audio Context Actions
|
|
//
|
|
isPlaying (): boolean {
|
|
return this.playing
|
|
},
|
|
|
|
pauseContext (): void {
|
|
const audioContext = this.getAudioContext()
|
|
if (audioContext) {
|
|
audioContext.playbackRate = 0
|
|
audioContext.suspend()
|
|
}
|
|
},
|
|
async getAudioContext () : Promise<AudioContext> {
|
|
// useNuxtApp().$logger.log('getAudioContext')
|
|
if (Howler.ctx) {
|
|
// useNuxtApp().$logger.log('Audio Context is there...')
|
|
if (Howler.ctx.state === 'suspended') { Howler.ctx.resume() }
|
|
return Howler.ctx
|
|
} else {
|
|
return await this.initializeAudioContext()
|
|
}
|
|
},
|
|
getContext () : AudioContext {
|
|
// useNuxtApp().$logger.log('getContext')
|
|
|
|
if (this.audioContext) { return this.audioContext } else {
|
|
this.audioContext = new AudioContext()
|
|
return this.audioContext
|
|
}
|
|
},
|
|
async initializeAudioContext (): Promise<AudioContext> {
|
|
// useNuxtApp().$logger.log('initializeAudioContext')
|
|
return await this.audioContext
|
|
},
|
|
|
|
resetAudioContext () {
|
|
if (Howler.ctx) {
|
|
// useNuxtApp().$logger.log('AudioContext has been reset')
|
|
Howler.unload()
|
|
} else if (this.audioContext instanceof AudioContext && this.audioContext.state !== 'closed') {
|
|
try {
|
|
Howler.stop()
|
|
Howler.unload()
|
|
this.audioContext = null
|
|
this.setPlaying(false)
|
|
// useNuxtApp().$logger.log('AudioContext has been reset')
|
|
} catch (_error) {
|
|
// useNuxtApp().$logger.error('Error closing AudioContext:', _error)
|
|
}
|
|
}
|
|
},
|
|
|
|
setPlaying (stateChange: boolean): void {
|
|
this.playing = stateChange
|
|
},
|
|
//
|
|
// Working with Web Audio Nodes
|
|
//
|
|
removeNodeByType (name: string): void {
|
|
if (this.nodes && this.nodes.has(name)) {
|
|
this.nodes.delete(name)
|
|
}
|
|
},
|
|
getNodeByType (name: string): AudioNodeItem | null {
|
|
if (this.nodes instanceof Map) {
|
|
return this.nodes.get(name) as AudioNodeItem
|
|
}
|
|
|
|
return null
|
|
},
|
|
getMicrophoneNode (): AudioNodeItem | null {
|
|
return this.nodes.get('microphone')
|
|
},
|
|
async getBufferSourceNode (name: string): Promise<AudioNodeItem | null> {
|
|
const node:AudioNodeItem = this.nodes.has(name)
|
|
if (node) {
|
|
// useNuxtApp().$logger.log('Node gibts schon')
|
|
return node
|
|
} else {
|
|
await this.createBufferSource(name)
|
|
const createdNode = this.getNodeByType(name)
|
|
// useNuxtApp().$logger.log('created node ', { createdNode })
|
|
return createdNode
|
|
}
|
|
},
|
|
async createMediaStreamNodeAsync (steam: MediaStream): Promise<MediaStreamAudioSourceNode> {
|
|
const audioCtx: AudioContext = await this.getAudioContext()
|
|
// useNuxtApp().$logger.log({ audioCtx })
|
|
const streamNode = audioCtx.createMediaStreamSource(steam)
|
|
this.addNode('microphone', streamNode)
|
|
return streamNode
|
|
},
|
|
createMediaStreamNode (steam: MediaStream, audioContext: AudioContext): MediaStreamAudioSourceNode {
|
|
const audioCtx: AudioContext = audioContext
|
|
// useNuxtApp().$logger.log({ audioCtx })
|
|
const streamNode = audioCtx.createMediaStreamSource(steam)
|
|
this.addNode('microphone', streamNode)
|
|
return streamNode
|
|
},
|
|
async createBufferSource (name:string): Promise<AudioNodeItem> {
|
|
const bufferStore = this.bufferStore()
|
|
const audioBuffer = await bufferStore.getAudioBufferByName(name)
|
|
// if (!audioBuffer) { useNuxtApp().$logger.log({ bufferStore }) }
|
|
const audioCtx = await this.getAudioContext()
|
|
const abn = audioCtx.createBufferSource()
|
|
abn.buffer = audioBuffer
|
|
const result = this.addNode(name, abn)
|
|
return result
|
|
},
|
|
disconnectAllNodes (): void {
|
|
if (this.nodes.length > 0) {
|
|
this.nodes.forEach((n:AudioNodeItem) => n.node?.disconnect())
|
|
this.nodes = {} as Map<string, AudioNodeItem>
|
|
}
|
|
},
|
|
startNode (node:AudioNodeItem) {
|
|
if (node.node instanceof AudioBufferSourceNode) {
|
|
node.node?.start(0)
|
|
// useNuxtApp().$logger.log('started Node' + node.type, { nod1 })
|
|
} else {
|
|
// useNuxtApp().$logger.error('Node not defined in start node ')
|
|
}
|
|
},
|
|
addNode (type: string, node: AudioNode): AudioNodeItem {
|
|
this.nodes.set(type, { type, node, started: false })
|
|
// useNuxtApp().$logger.log('adding node', { values: [...this.nodes.values()] })
|
|
return { type, node, started: false } as AudioNodeItem
|
|
},
|
|
connectNodes (nodeFrom: AudioNodeItem, nodeTo: AudioNodeItem, channelOutput?: number, channelInput?:number): void {
|
|
if (nodeFrom && nodeTo && !channelInput && !channelOutput) {
|
|
connectAudioNodes(nodeFrom.node as AudioNode, nodeTo.node as AudioNode)
|
|
}
|
|
if (nodeFrom && nodeTo && channelOutput && !channelInput) {
|
|
connectAudioNodes(nodeFrom.node as AudioNode, nodeTo.node as AudioNode, channelOutput)
|
|
}
|
|
if (nodeFrom && nodeTo && channelOutput && channelInput) {
|
|
connectAudioNodes(nodeFrom.node as AudioNode, nodeTo.node as AudioNode, channelOutput, channelInput)
|
|
}
|
|
|
|
// useNuxtApp().$logger.log('nodeTo tpye: ' + nodeTo.type)
|
|
if (nodeTo.type) { nodeFrom.nextNodeName = nodeTo.type }
|
|
nodeTo.previousNodeName = nodeFrom.type
|
|
},
|
|
startAllSources () : void {
|
|
const app = useNuxtApp()
|
|
// @ts-ignore
|
|
const user = useUserStore(app.$pinia)
|
|
const userObj = user.user as any
|
|
// useNuxtApp().$logger.log({ userObj })
|
|
this.nodes.forEach((node: AudioNodeItem, key: string) => {
|
|
const userSoundscape = userObj.settings.soundscape === 'Tropics' ? 'tropics' : userObj.settings.soundscape || 'meadow'
|
|
if (key === userSoundscape || key === 'noise') {
|
|
if (node.node instanceof AudioBufferSourceNode && !node.started) {
|
|
this.startBufferSourceNode(node.node)
|
|
}
|
|
}
|
|
})
|
|
},
|
|
startBufferSourceNode (node: AudioBufferSourceNode) {
|
|
// useNuxtApp().$logger.log('startBufferSourceNode ')
|
|
|
|
this.nodes.forEach((value: AudioNodeItem) => {
|
|
if (value.node === node) {
|
|
const c = value.node as AudioBufferSourceNode
|
|
// useNuxtApp().$logger.log('AudioContext ' + audioContext.state)
|
|
c.start(0)
|
|
value.started = true
|
|
}
|
|
})
|
|
},
|
|
replaceMusicNode (oldNode: AudioNodeItem, newNode: AudioNodeItem):AudioNodeItem {
|
|
if (!this.nodes.has(oldNode.type) || !this.nodes.has(newNode.type)) {
|
|
// this.$logger.warn('AudioNodes not present in nodes Map')
|
|
}
|
|
if (oldNode.node ! instanceof AudioBufferSourceNode || oldNode.node ! instanceof AudioBufferSourceNode) {
|
|
// createLogger().warn('AudioNodes not AudioBufferSourceNodes')
|
|
}
|
|
|
|
const nextNode = oldNode.nextNodeName ? this.nodes.get(oldNode.nextNodeName) : null
|
|
if (!nextNode || (nextNode && nextNode.node ! instanceof ChannelSplitterNode)) {
|
|
// createLogger().warn('AudioNodes not ChannelSplitterNodes')
|
|
} else {
|
|
oldNode.node?.disconnect()
|
|
oldNode.started = false
|
|
oldNode = {} as AudioNodeItem
|
|
if (newNode && newNode.node) {
|
|
if (nextNode.type) { newNode.nextNodeName = nextNode.type as string }
|
|
newNode.node.connect(nextNode?.node as AudioNode)
|
|
return newNode
|
|
}
|
|
}
|
|
return newNode
|
|
}
|
|
}
|
|
})
|