107 lines
2.8 KiB
TypeScript
107 lines
2.8 KiB
TypeScript
// composables/useBufferStore.ts
|
|
import { db } from '../lib/db'
|
|
|
|
interface AudioNodeItem {
|
|
type: string;
|
|
node: AudioNode | null;
|
|
started?: boolean;
|
|
previousNodeName?:string;
|
|
nextNodeName?:string;
|
|
}
|
|
|
|
// Interner Buffer-Cache (nicht reaktiv)
|
|
const buffers = new Map<string, AudioBuffer>()
|
|
|
|
export const useBufferStore = () => ({
|
|
get: (id: string) => buffers.get(id),
|
|
set: (id: string, val: AudioBuffer) => buffers.set(id, val),
|
|
all: () => buffers
|
|
})
|
|
|
|
// Holt einen AudioBuffer aus dem Cache
|
|
export function getAudioBuffer(key: string): AudioBuffer | undefined {
|
|
return buffers.get(key)
|
|
}
|
|
|
|
// Holt oder erstellt einen BufferSourceNode mit geladenem AudioBuffer
|
|
export async function createBufferSource(
|
|
name: string,
|
|
audioContext: AudioContext
|
|
): Promise<AudioNodeItem> {
|
|
const store = useBufferStore()
|
|
const buffer = store.get(name)
|
|
|
|
if (!buffer) throw new Error(`Kein Buffer für "${name}" im Cache gefunden.`)
|
|
|
|
const source = audioContext.createBufferSource()
|
|
source.buffer = buffer
|
|
source.loop = true
|
|
|
|
return {
|
|
type: 'bufferSource',
|
|
node: source,
|
|
started: false,
|
|
}
|
|
}
|
|
|
|
// Speichert einen ArrayBuffer in IndexedDB unter gegebenem Namen
|
|
export async function saveBufferInIndexedDb(
|
|
fileName: string,
|
|
buffer: ArrayBuffer
|
|
): Promise<void> {
|
|
|
|
if (!db?.audiosources) {
|
|
console.warn('[BufferStore] Dexie DB nicht verfügbar')
|
|
return
|
|
}
|
|
|
|
try {
|
|
const existing = await db.audiosources.get({ name: fileName })
|
|
if (existing) {
|
|
await db.audiosources.update(existing.id!, { buffer })
|
|
console.info(`[BufferStore] Buffer für "${fileName}" aktualisiert`)
|
|
} else {
|
|
console.log("BUFFER", {buffer})
|
|
await db.audiosources.add({ name: fileName, buffer })
|
|
console.info(`[BufferStore] Buffer für "${fileName}" gespeichert`)
|
|
}
|
|
} catch (err) {
|
|
console.error('[BufferStore] Fehler beim Speichern in IndexedDB:', err)
|
|
}
|
|
}
|
|
|
|
// Lädt AudioBuffer aus IndexedDB oder via fetch
|
|
export async function fetchOrLoadBuffer(
|
|
name: string,
|
|
url: string,
|
|
audioContext: AudioContext
|
|
): Promise<AudioBuffer> {
|
|
const store = useBufferStore()
|
|
|
|
// Zuerst aus Cache
|
|
const cached = store.get(name)
|
|
if (cached) return cached
|
|
|
|
let arrayBuffer: ArrayBuffer
|
|
|
|
// Versuch aus IndexedDB
|
|
const existing = await db?.audiosources?.get({ name })
|
|
if (existing?.buffer) {
|
|
arrayBuffer = existing.buffer
|
|
console.info(`[BufferStore] Buffer für "${name}" aus IndexedDB geladen`)
|
|
} else {
|
|
// Fallback: fetch
|
|
const response = await fetch(url)
|
|
if (!response.ok) throw new Error(`Fetch fehlgeschlagen für ${url}`)
|
|
arrayBuffer = await response.arrayBuffer()
|
|
await saveBufferInIndexedDb(name, arrayBuffer)
|
|
}
|
|
|
|
// Dekodieren & speichern
|
|
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer.slice(0))
|
|
store.set(name, audioBuffer)
|
|
return audioBuffer
|
|
}
|
|
|
|
|