useSound
HookAPI 2Returns a deck of the toolbar’s own music and re-renders the component as the deck plays, pauses and stops. The sound is made with Web Audio in the toolbar’s world, so it needs no permission and never leaves the page.
| Signature | useSound(options?: { onEnd?: () => void }): SoundState & Sound |
|---|---|
| Take it from | const { useSound } = Bundleware; |
Parameters
| Parameter | Type | Description |
|---|---|---|
options | { onEnd?: () => void } | Optional. |
options.onEnd | () => void | Optional. Runs when a score finishes; ended is then true. Use it to play the next song. |
Return Value
A deck. It stops when its mount ends; a toolbar’s decks share one AudioContext, closed with the last.
| Member | Type | Description |
|---|---|---|
state | 'stopped' | 'playing' | 'paused' | What the deck is doing. |
ended | boolean | true when the deck stopped because the score finished. |
play(score, options?) | void | Plays score from the start, replacing what the deck was playing. Notes are scheduled 1.5 seconds ahead, so a busy page does not stall them. |
pause(), resume() | void | resume continues where pause left off. |
stop() | void | Stops the deck. |
set({ volume, room }) | void | Changes the mix while playing. |
Play Options
| Option | Values | Default |
|---|---|---|
speed | 0.25 to 4 | 1. A tempo multiplier; other values throw a RangeError. |
volume | 0 to 1 | 0.8 |
room | 0 to 1 | 0.2, the small room echo. |
loop | true or false | false |
instrument | sax, trumpet, flute, piano, keys, vibes, bass, pad | For notes without one: the track’s General MIDI family, or the piano. Sax, trumpet and flute play one note at a time. |
Example
A toolbar that plays one tune and plays it again when it ends. The Readout draws seven levels as block characters, so the widget needs no CSS.
// ==BundlewareToolbar==
// @id hold-music
// @name Hold Music
// @version 1.0.0
// @description Plays one public-domain tune, then plays it again.
// @api 2
// ==/BundlewareToolbar==
const { Toolbar, Readout, Icon, music, useSound, useLevels } = Bundleware;
const tune = music.readMidi(TUNE); // A MIDI file as Base64, kept in your script.
const status = { stopped: 'Not on hold', playing: 'Please continue to hold', paused: 'Hold paused' };
function HoldMusic() {
const sound = useSound({ onEnd: () => sound.play(tune) }); // Play it again.
const playing = sound.state === 'playing';
return (
<Toolbar icon={Icon.Sound} theme={{ brandColor: '#2f2470' }}>
<Toolbar.Button
title={playing ? 'Pause' : 'Play'}
onAction={() => {
if (playing) sound.pause();
else if (sound.state === 'paused') sound.resume();
else sound.play(tune, { instrument: 'vibes', room: 0.5 });
}}
/>
<Toolbar.Widget><Levels /></Toolbar.Widget>
<Toolbar.Right>
<Toolbar.Status dot={playing ? 'green' : 'yellow'} text={status[sound.state]} />
</Toolbar.Right>
</Toolbar>
);
}
function Levels() {
const levels = useLevels(7, { smoothing: 0.7 });
const meter = levels.map(level => '▁▂▃▄▅▆▇█'[Math.round(level * 7)]).join('');
return <Readout label="Level" value={meter} />;
}
Bundleware.defineToolbar(<HoldMusic />);What it renders
Hold Music while it plays. The host draws the button as an index tab, the Readout as a label cell and a value cell, and the status at the right edge.
Availability
| Applicable versions | API 2 and higher |
|---|---|
| Bundleware | 0.3.0, build 2026.10.30 |
| Permission | None. The sound is made with Web Audio in the toolbar’s world and never leaves the page. |
| Starts | After a click. Browsers start sound only after a click, so call play from an action or a click handler. |
| Ends | With its mount: when the toolbar is hidden, the page reloads, or navigation leaves its site rules. |
Related
| Name | Description |
|---|---|
useLevels(count?, options?) | Levels from 0 to 1 of everything the toolbar is playing. Re-renders every frame while sound plays. |
context.sound(onChange?) | The same deck outside components; reports { state, ended } to onChange. |
music.readMidi(data) | Reads a Standard MIDI File, as bytes or Base64, into { duration, notes, tracks }. |
music.melody(notes) | The top line of a part, for giving the melody its own instrument. |
jazz-bar.toolbar.tsx | The bundled Jazz Bar: moves to the next song on onEnd and draws its equalizer with useLevels. |