Skip to main content

SoundState

getSoundState returns a SoundStateInfo: everything a player interface needs about one sound in a single object. Its state field uses the SoundState enum.

export interface SoundStateInfo {
progress: number;
startTime: number;
currentTime: number;
elapsedTime: number;
adjustedElapsedTime: number;
duration: number;
rawDuration: number | null;
playbackRate: number | null;
state: SoundState;
volume: number;
pan: number;
panSpatialPosition: { x: number; y: number; z: number };
}

export enum SoundState {
Playing = "playing",
Paused = "paused",
Stopped = "stopped",
}
FieldTypeDescription
progressnumberHow far along the sound is, from 0 to 1.
startTimenumberThe AudioContext time the hub counts the position from, in seconds. 0 before the first play. For a stream, the start offset.
currentTimenumberPosition in the file, in seconds, whatever the playback rate.
elapsedTimenumberPosition in the file, in seconds. For a loop it equals currentTime.
adjustedElapsedTimenumberThe time it took to hear that far, at the current playback rate: elapsedTime divided by the rate.
durationnumberLength of the file, in seconds.
rawDurationnumber | nullLength of the file itself, in seconds.
playbackRatenumber | nullThe current playback rate.
stateSoundState'playing', 'paused' or 'stopped'.
volumenumberThe sound's volume, 0 to 1.
pannumberStereo pan, -1 (left) to 1 (right).
panSpatialPosition{ x, y, z }The sound's 3D position.

SoundState is exported from soundhub as a value, SoundStateInfo as a type.

File time

Every time is a position in the file, for buffered sounds and streams alike, as it is for an HTMLMediaElement. At double speed, half a second after the start, currentTime is 1. A position stays valid when the rate changes, and currentTime / duration is the progress. Only adjustedElapsedTime counts the time it took to hear. Before 6.4.0 a buffered sound divided currentTime, elapsedTime and duration by the rate.

Example​

import { SoundHub, SoundState } from 'soundhub';

const soundHub = new SoundHub();
await soundHub.loadSound('music', '/audio/theme.mp3');
soundHub.play('music', { volume: 0.7, pan: -0.5 });

const state = soundHub.getSoundState('music');
state.state; // 'playing'
state.volume; // 0.7
state.pan; // -0.5

// A progress bar driven by the state
function render() {
const { progress, currentTime, duration, state } = soundHub.getSoundState('music');

bar.style.width = `${progress * 100}%`;
label.textContent = `${currentTime.toFixed(1)}s / ${duration.toFixed(1)}s`;

if (state === SoundState.Playing) {
requestAnimationFrame(render);
}
}

render();

Try it​

Play, pause and stop the sound and watch every field of SoundStateInfo update live.

Try it

Ask a sound where it is

Idle
isPlaying()false
isPaused()false
isStopped()true

Exactly one of the three is true at any moment. The values are read five times a second.

Code
Your clicks show up here as soundhub calls

Good to know​

  • For an id that is not loaded you get a neutral, stopped state instead of an error: every time is 0, volume is the config's defaultVolume and playbackRate its defaultPlaybackRate. That makes it safe to call from a render loop.
  • The time values and progress are rounded to 4 decimals with roundValue.
  • A looping sound reports where it is inside the file, so currentTime goes back to 0 at every loop.
  • Each overlapping instance, played with overlap: true, has its own state under its instance id, like 'click:1'. getSoundIds lists them.
  • For a quick yes or no, isPlaying, isPaused and isStopped read more clearly than comparing state.
  • The full state also comes with every progress event, in event.state.

See also​