// createSound decodes an encoded clip (Ogg/Vorbis or WAV) once, then every
// play() starts a voice with no re-decode - cheap enough for rapid SFX. It is
// reactive-owned: the decoded clip is released and its voices stopped when the
// owning component unmounts, so there is nothing to clean up by hand.
//
// The source is a Uint8Array of encoded bytes. Here they come from a
// `with { type: "binary" }` import (see binary-import.tsx), so the clip is
// baked into the bundle and available synchronously. Bytes loaded at runtime
// (flux:fs, fetch) work the same once you have them.
//
// overlap defaults to true: tapping faster than the clip length stacks voices
// instead of restarting. The second sound sets overlap: false - each play()
// cuts off the previous voice, the single-voice behavior you want for e.g. a
// selection tick. playing() is a signal: true from play() until stop() (it
// does not flip back when a clip ends naturally).
//
// Sounds you can compute need no bytes at all: createPcmSound takes raw
// samples (here a 60 ms sine sweep in an Int16Array) and gives the same handle
// - generate it, do not ship it. Same reactive ownership as createSound.
//
// For a long track (music, ambience) do not load bytes at all: pass a file
// path to createSoundStream from the same module, which decodes from disk on
// demand and stays off the heap. Same play()/stop()/playing() surface,
// always single-voice.
import { render } from "@solidrt/core"
import { createPcmSound, createSound } from "@solidrt/core/audio"
import blipBytes from "./blip.wav" with { type: "binary" }
const RATE = 44100
// A short sweep from 880 Hz down to 440 Hz with a linear fade-out.
function sweep(): Int16Array {
let n = Math.round(RATE * 0.06)
let out = new Int16Array(n)
let phase = 0
for (let i = 0; i < n; i++) {
let t = i / n
phase += (2 * Math.PI * (880 - 440 * t)) / RATE
out[i] = Math.round(Math.sin(phase) * (1 - t) * 0.6 * 32767)
}
return out
}
function Button(props: { label: string; onTap: () => void }) {
return (
{props.label}
)
}
function App() {
let blip = createSound(blipBytes, { gain: 0.8 })
let tick = createSound(blipBytes, { overlap: false })
let synth = createPcmSound(sweep(), RATE)
return (
)
}
render(() => )