Sound

Synthesized UI feedback sounds, off by default.

VerifiedSince 0.6.0

API Reference

NameDescription
configureSound({ enabled, volume })Toggle and master volume (0–1, clamped); returns the resulting config
getSoundConfig()A copy of the current config
playSound(type | preset)Plays; returns whether it actually did
sound.click() / .key() / .toggle() / .success() / .error() / .open() / .close()Shorthands
isSoundSupported()Whether the browser has Web Audio
disposeSound()Closes the graph; the next play rebuilds it
SOUND_PRESETSThe preset table; read its parameters or start a custom cue from one

Off by Default

import { configureSound, sound } from '@talex-touch/tuffex/utils'

configureSound({ enabled: true, volume: 0.6 })
sound.click()
  • Until enabled, nothing plays and no AudioContext is created.
  • The graph is built lazily: browsers suspend an AudioContext created outside a user gesture, so a page that never plays shouldn't hold one.

Why Synthesis

A few oscillators and an envelope ship at zero bundle cost, stay crisp at any sample rate, and cannot 404. The trade-off is timbre: samples are richer.

Presets

Seven, deliberately. Peaks and lengths are measured sample by sample through an OfflineAudioContext.

PresetUsePeakLength
clickButton press0.10340ms
keyPer character in a field0.05627ms
toggleSwitch or checkbox turning on0.08965ms
successCompleted action (rising pair)0.090188ms
errorRejected action (falling pair)0.100216ms
openPanel or dialog opening0.07891ms
closePanel or dialog closing0.07791ms
  • key has the lowest peak: it fires per character, and at click's level it becomes a typewriter.
  • open and close mirror each other in peak and length, differing only in glide direction: direction carries the meaning, loudness does not.
  • Nothing clips; every peak sits between 0.06 and 0.11.
  • Tests enforce two length budgets: immediate feedback (click / key / toggle) ≤ 80ms, status cues (the rest) ≤ 250ms.

Custom Cues

playSound also takes a patch built on the spot:

import { playSound } from '@talex-touch/tuffex/utils'

playSound({
  layers: [
    { wave: 'sine', freq: [400, 700], gain: 0.09, decay: 0.12 },
    { wave: 'sine', freq: 900, gain: 0.06, decay: 0.1, delay: 0.08 },
  ],
})

Two values in freq make a glide; delay offsets the second voice so the pair reads as a figure rather than a chord.

Contract

  • Never throws: disabled, unsupported, or before the browser has seen a gesture, playSound quietly returns false.
  • A context parked by the autoplay policy is resumed on the next play; a rejected resume is swallowed.
  • Each voice disconnects its own envelope when it ends, so a typing burst leaves no dead nodes on the master gain.
  • The noise buffer is shared, not regenerated per keystroke.
  • A volume change applies to the existing graph immediately, with no rebuild.

Relationship to Vibration

useVibrate is the other feedback channel at this layer, with the same shape (preset table, main function, shorthand object). Don't fire sound and vibration for the same action: doubled feedback reads as a double trigger.

查看源码
packages/tuffex/packages/components/src/sound/index.ts