Player methods
The engine is a full player — Player → Methods.
import WaveformSounds from '@arraypress/waveform-sounds';
const list = new WaveformSounds('#pack', { manifest: '/previews/sounds.json' });await list.ready;new WaveformSounds(container, options?) takes an element or a selector. It throws [WaveformSounds] Container not found: … for a selector that matches nothing.
The list is built after the constructor returns, on a later microtask (after the manifest fetch, if there is one) — so listeners attached straight after new WaveformSounds() see ready and the first filter. ready is a promise that resolves once it’s built. It never rejects: a failed build (the manifest 404s, say) resolves it too and is reported through onError and waveformsounds:error.
Calls made before it’s built are honoured: setFilter() and setSort() show in the controls once built, and play() waits for the list.
| Method | Description |
|---|---|
play(target?, opts?): void |
Play a sound — by index (in the original order), by id string, or by Sound object — or, with no target, resume the current one (else play the first visible). opts.at (0..1) starts it at that position; on the current sound it seeks there. |
pause(): void |
Pause the current sound. |
toggle(target?): void |
The current sound plays / pauses; any other sound starts. |
next(): void |
Play the next visible sound (in the current filter and sort), revealing it if it’s past the current page. No wrap at the end. |
previous(): void |
Play the previous visible sound. |
setLoop(on: boolean): void |
Loop the current sound (and every sound after it) on or off, and update the Loop toggle. When the list marks its loops, only loops repeat. |
setFilter(patch): void |
Merge patch into the current filter and re-apply it; back to the first page. Keys: query, type, key, bpmMin, bpmMax. The controls are updated to match. |
clearFilters(): void |
Reset every filter. The sort stays. |
setSort(by): void |
Change the order: 'default' | 'title' | 'bpm' | 'key' | 'duration' (anything else is 'default'). |
showMore(): void |
Reveal the next page of rows. |
destroy(): void |
Tear down listeners, observers, timers and the engine. Markup the instance rendered is restored to what the container held before (its own classes and the measured --ws-surface too); adopted server markup is left as it is now — rows may be re-sorted, hidden or marked current — so re-render it before building a new instance over it. |
list.setFilter({ type: 'Bass', bpmMin: 120, bpmMax: 130 });list.setSort('bpm');list.play('sound-3', { at: 0.5 });| Property | Type | Description |
|---|---|---|
container |
HTMLElement |
The element. |
options |
WaveformSoundsOptions |
The resolved options (defaults, constructor and data-* merged). |
ready |
Promise<void> |
Resolves once the list is built. Never rejects. |
sounds |
Sound[] |
Every sound, normalised, in the original order. |
visible |
Sound[] |
The sounds passing the filter, in sort order (all of them, not only the page shown). A getter. |
current |
Sound | null |
The playing or paused sound. A getter. |
filter |
SoundsFilter |
The current filter: { query, type, key, bpmMin, bpmMax, loop }. |
sortBy |
SoundsSort |
The current order. |
playing |
boolean |
Whether a sound is playing. |
engine |
WaveformPlayer | null |
The engine player — the full player API. Built when the list is ready (when a player class is available), else on the first play. |
| Method / property | Description |
|---|---|
WaveformSounds.init(root = document): WaveformSounds[] |
Initialise every [data-waveform-sounds] under root (and root itself) that isn’t initialised yet; returns the new instances. Per-element errors are caught and logged. Run it after inserting markup. |
WaveformSounds.getInstance(el): WaveformSounds | null |
The instance on an element or selector. |
WaveformSounds.prune(): void |
Destroy the instances whose element has left the document — after a client-side navigation. Stops their audio. |
WaveformSounds.instances |
Map<Element, WaveformSounds> of every live instance. |
WaveformSounds.DEFAULT_OPTIONS |
Every option’s default — see Options. |
WaveformSounds.DEFAULT_STRINGS |
The English strings — see Strings & i18n. |
WaveformSounds.utils |
The pure data helpers — see utils. |
document.addEventListener('waveformsounds:ready', () => { WaveformSounds.getInstance('#pack')?.setFilter({ type: 'Drums' });});Every event is a bubbling CustomEvent dispatched from the container, so you can listen on the element or on document. Each detail carries the instance.
| Event | detail |
Fires |
|---|---|---|
waveformsounds:ready |
{ sounds: number, instance } |
The list is built. sounds is the count. |
waveformsounds:play |
{ sound, index, instance } |
A sound starts playing. |
waveformsounds:pause |
{ sound, index, instance } |
The playing sound pauses. |
waveformsounds:end |
{ sound, index, instance } |
A sound plays to its end. |
waveformsounds:filter |
{ visible: number, total: number, filter, sort, instance } |
After every filter, sort or page change, and once when the list is built. visible is the number of matching sounds. |
waveformsounds:error |
{ error, sound?, index?, instance } |
The list failed to build (no sound), or a sound failed to load or play. |
index is the sound’s position in sounds. The events are typed on HTMLElementEventMap, so addEventListener('waveformsounds:play', (e) => e.detail.sound.title) type-checks.
document.addEventListener('waveformsounds:filter', (e) => { const { visible, total, filter } = e.detail; if (filter.query) analytics.track('sound_search', { query: filter.query, visible, total });});The engine is a regular player, so its own waveformplayer:* events fire too — that’s what WaveformTracker listens to.
| Import | What it is |
|---|---|
@arraypress/waveform-sounds |
The runtime. Registers window.WaveformSounds and initialises every [data-waveform-sounds] element when the DOM is ready. |
@arraypress/waveform-sounds/no-autoinit |
The same exports without the import-time scan. |
@arraypress/waveform-sounds/render |
The DOM-free server renderer. |
@arraypress/waveform-sounds/styles.css |
The stylesheet. |
The main entry’s named exports: WaveformSounds (also the default), DEFAULT_OPTIONS, DEFAULT_STRINGS, encodePeaks, decodePeaks, normalizeKey, normalizeSounds, parseManifest, facets, matches, sortSounds, formatDuration, renderSounds and renderSoundsElement.
/no-autoinitFor frameworks and anything else that decides when lists are built. Importing it registers window.WaveformSounds but scans nothing; construct instances yourself, or call WaveformSounds.init() when you’re ready. The framework wrappers import it. (<html data-waveform-autoinit="false"> does the same for the main entry.)
import WaveformSounds from '@arraypress/waveform-sounds/no-autoinit';/renderThe half that writes markup, and never touches window or document — safe in Node, an edge runtime or a static build.
import { renderSounds, renderSoundsElement } from '@arraypress/waveform-sounds/render';
// The inside of a [data-waveform-sounds] element:const inner = renderSounds(sounds, { pageSize: 100, columns: ['type', 'bpm', 'key'] });
// Or the whole element, wrapper included:const html = renderSoundsElement(sounds, { player: 'strip' }, 'my-extra-class');| Function | Returns |
|---|---|
renderSounds(sounds, options?) |
The component’s inner markup: toolbar, rows (with every field written back as data-*, so the runtime can rebuild the sounds from them) and footer. sounds may be raw or normalised. |
renderSoundsElement(sounds, options?, className?) |
The whole element: <div class="waveform-sounds waveform-sounds--<player> …" data-waveform-sounds data-player="…"> around renderSounds(). |
The renderer reads the options that shape the markup: player, search, filters, sorts, showCount, menuSearch, maxTypeChips, loopToggle, pageSize, columns, idPrefix and strings. When the runtime finds that markup in the container it adopts it rather than rebuilding — so give the runtime the same options (as data-* on the container, or constructor options). See Server rendering.
/render also exports DEFAULT_STRINGS, escapeHtml, normalizeSounds, parseManifest, encodePeaks, decodePeaks, normalizeKey, facets and formatDuration.
WaveformSounds.utils (and the same-named exports) are the pure data helpers the list runs on — the same functions on the server and in the browser.
| Function | Description |
|---|---|
encodePeaks(peaks: number[]): string |
Peaks 0..1 → the 8-bit hex string (two characters per bar). waveform-gen --manifest encodes byte-for-byte the same way. |
decodePeaks(value, scale = 1): number[] | null |
A hex string, an array of 0..1, or an integer array with its scale → peaks 0..1. null for nothing usable. |
normalizeKey(key): string |
Any common key spelling → the short form ("F minor" → Fm, "C♯" → C#). Unparseable keys come back trimmed, as given. |
normalizeSounds(list, peakScale = 1): Sound[] |
Normalise a list: drop sounds without a url, fill in titles and ids, de-duplicate ids. |
parseManifest(manifest): Sound[] |
Read a manifest object (or a bare array), honouring peakScale. |
facets(sounds) |
What the controls would offer: { types: {name, count}[], keys: string[], bpm: {min, max} | null, hasDuration: boolean, loops: number, oneShots: number }. |
matches(sound, filter?): boolean |
Whether a sound passes a filter — the same search and filter rules as the list. |
sortSounds(sounds, by = 'default'): Sound[] |
A sorted copy. Missing values sort last. |
formatDuration(seconds): string |
m:ss; tenths under a second (0.4s, 0.1.3+); '' when unknown. |
renderSounds(sounds, options?): string |
As above. |
const sounds = WaveformSounds.utils.parseManifest(await (await fetch('/previews/sounds.json')).json());const bassIn128 = sounds.filter((s) => WaveformSounds.utils.matches(s, { type: 'Bass', bpmMin: 128, bpmMax: 128 }));The package ships hand-written typings (index.d.ts); the framework wrappers derive their props from them.
| Type | Shape |
|---|---|
WaveformSoundsOptions |
Every option. |
SoundInput |
A sound as given — see Sound fields. |
Sound |
A normalised sound: { id: string, url: string, title: string, type: string, bpm: number | null, key: string, duration: number | null, tags: string[], peaks: number[] | null, waveform: string | null, download: string | null, loop: boolean }. |
SoundsManifest |
{ version?: number, peakScale?: number, sounds: SoundInput[] }. |
SoundsFilter |
{ query: string, type: string, key: string, bpmMin: number | string, bpmMax: number | string, loop?: SoundsLoopFilter }. '' means “any”. |
SoundsLoopFilter |
'' | 'loop' | 'one-shot' |
SoundsSort |
'default' | 'title' | 'bpm' | 'key' | 'duration' |
SoundsLayout |
'inline' | 'strip' |
SoundsFilterControl |
'type' | 'key' | 'bpm' | 'loop' |
SoundsColumn |
'type' | 'bpm' | 'key' | 'duration' |
WaveformSoundsStrings |
Every string. |
WaveformSoundsEventMap |
The waveformsounds:* events and their detail. |
Call destroy() when removing a list in a single-page app — it stops the audio (the engine is destroyed), and drops every listener and observer. After a client-side navigation that replaced the page, WaveformSounds.prune() does the same for every list whose element is gone.
list.destroy();Player methods
The engine is a full player — Player → Methods.
Sounds manifest
Writing the JSON this reads — Generator → Sounds manifest.