add dexie as indexedDB buffer store
parent
833de3656e
commit
3f213c021a
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"name": "audio-app",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
"deploy": "rm -rf ../audio-host/public/audio-app/* && vite build && cp -r dist/* ../audio-host/public/audio-app/"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "~5.8.3",
|
||||
"vite": "^6.3.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@rnbo/js": "^1.3.4",
|
||||
"dexie": "^4.0.11"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
// 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
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import { Dexie, type Table } from 'dexie'
|
||||
|
||||
export interface AudioSource {
|
||||
id?: number;
|
||||
name: string;
|
||||
buffer: ArrayBuffer;
|
||||
}
|
||||
|
||||
export default class Database extends Dexie {
|
||||
// 'audiosources' is added by dexie when declaring the stores()
|
||||
// We just tell the typing system this is the case
|
||||
audiosources!: Table<AudioSource>
|
||||
|
||||
constructor () {
|
||||
super('audiosources')
|
||||
this.version(1).stores({
|
||||
audiosources: '++id, &name' // Primary key and indexed props
|
||||
})
|
||||
}
|
||||
}
|
||||
export const db = new Database()
|
Loading…
Reference in New Issue