raea/audio

Sound: Audio, the master Mix, speech, sound in 3D space, and a song's energy map.

View as Markdown

<Audio> plays sound in step with the frame. <Mix> masters everything under it to a loudness and a true-peak ceiling (-14 LUFS and -1 dBTP suit the major platforms). song() and useSong() read the energy map raea song writes, so cuts can land on beats and drops. <Speech> speaks a line, and <Sound3D> places a sound in a 3D scene.

TSX
import { staticFile } from "raea";
import { Audio, Mix } from "raea/audio";

function Soundtrack() {
  return (
    <Mix lufs={-14} ceiling={-1}>
      <Audio src={staticFile("media/voice.wav")} bus="voice" />
      <Audio src={staticFile("media/bed.m4a")} bus="music" gainDb={-12} fadeOut={1.5} />
    </Mix>
  );
}
TS
import { Audio, Mix, music, prepareSpeech } from "raea/audio"

raea/audio exports 6 components, 1 hook, 7 functions, 1 value, 25 types. Bevy's counterpart: bevy_audio; raea plays it with seedling on its own mixer. Source: sdk/raea/src/audio.ts.

Components

Audio

Sound in step with the frame; no picture. A muted or ended Audio is silent.

PropTypeWhat it does
src (required)string | GeneratedAsseta file URL, or a generated asset from lyria() or sao()

Also takes the props of MediaProps.

Mix

The master: every sound in the composition brought to lufs integrated loudness (-14) under a true-peak limiter at ceiling dBTP (-1.5), as the platforms play back. Put one in the composition, around the soundtrack or anywhere.

PropTypeWhat it does
lufsnumberintegrated loudness the mix is brought to (EBU R128, LUFS)
ceilingnumberthe limiter's true-peak ceiling (dBTP)
childrenReactNodewhat it masters, when it's written around the soundtrack (): rendered as they are

Seedling

A game's sample, played by bevy_seedling on raea's mixer from the frame it first shows until it leaves the page, with its effects in its chain. A render and a live play hear the same. Give a repeated one-shot a new id each time: {hit && <Seedling src={staticFile("hit.wav")} id={hit-${hits}} />}.

PropTypeWhat it does
src (required)string | GeneratedAssetthe sample: a media file (staticFile), or a generated sound (sao(...), tokensynth(...)) from the asset store
idstringthe player's identity while it plays: a new id starts a new player (default: the src)
volumenumberlinear gain, from the first frame (default 1)
speednumberplayback speed (default 1); may change frame to frame
loopbooleanstart again from the beginning when it ends
fxSeedlingFx[]a serial chain of effects on this player
at[number, number, number]where it sounds from in the 3D scene (metres, the Canvas3D's frame): heard from the scene's camera, panned, fading and dulling with distance, pitched by its speed toward or away (doppler); may move frame to frame. Unset: a sound with no place
mufflenumbera lowpass (Hz) for what stands between it and the camera: a wall, a window

SongPlot

The map drawn for a human to check: section bands named, the energy curve with builds, stops, dips and drops on it, hits, the feature lanes, and the pacing (cuts per bar). raea song FILE --plot OUT.png renders it.

PropTypeWhat it does
map (required)SongMapthe song's map, from `raea song`
widthnumberin px
heightnumberin px
titlestringthe heading (the song's name, tempo, metre and length by default)

Sound3D

A sound in the 3D scene: a at a place (at), heard from the scene's camera as it moves, in a render and in a game alike. A moving emitter (a car, a fly, a pan sliding) takes its place frame by frame.

<Sound3D src={staticFile("kettle.wav")} at={onRun(right, 2.7, 0.35, 1.1)} loop volume={0.6} />

Also takes the props of SeedlingProps.

Speech

A line said on the frames it's rendered: heard from start (made ahead while start is null), stopped at the next word after cut. Keep it rendered until the line ends (speechAt's ended): taken off the page it stops at once (faded over 10 ms).

PropTypeWhat it does
start (required)number | nullthe frame it's heard from; null: not yet (made ahead, not heard)
cutnumber | nullthe frame it's interrupted at: it stops at the next word's start; null: said to its end
volumenumbergain (1)

Also takes the props of Line (text, voice, seed, temperature).

Hooks

useSong

Where the song is at the current frame (frame 0 of the enclosing Sequence is offset seconds into the song), with the map bound to the composition's fps as song.

TS
function useSong(map: SongMap, options?: UseSongOptions): SongMoment & { song: Song; }

Functions

prepareSpeech

Starts making a line now (or finds it made): call it as soon as the text is known.

TS
function prepareSpeech(line: Line): void

song

A song map bound to a frame rate (and where frame 0 sits in the song): frames from song times, and the reverse.

TS
function song(map: SongMap, options: SongOptions): Song

songAt

Where the song is at t seconds: a pure function of the map.

TS
function songAt(map: SongMap, t: number): SongMoment

speechAt

Where line (heard from start, cut at cut) is at frame: which word, whether it has ended, and where it ends. Pure: a function of the line and the frame, so a game may fold it into its state. Waits for the engine if the line hasn't been made that far yet (a render always waits; live play rarely has to).

TS
function speechAt(line: Line & { start: number; cut?: number | null; }, frame: number, fps: number): SpeechState

speechDuration

A line's length in seconds (waits until all of it is made; pure).

TS
function speechDuration(line: Line): number

speechMade

How much of a line has been made so far. Display-only: it depends on the machine and the moment.

TS
function speechMade(line: Line): { seconds: number; done: boolean; }

speechStart

The frame a line asked for at frame should start: SPEECH_LEAD later.

TS
function speechStart(frame: number, fps: number, lead?: number): number

Values

SPEECH_LEAD

How long after a request a line should start, so live play never waits for it (seconds).

Types

AudioProps

The props of Audio, tabled there.

CutOptions

FieldTypeWhat it is
by"section" | "bar""section" (default) takes each section's rate, steady across it; "bar" each bar's own
scalenumbermultiplies every rate (2: twice as many cuts), kept on the ladder 0.25..4
dropsbooleancut on every drop (default true)
stopsbooleancut on a stop's hits (default true)
buildsbooleandouble the rate through a build's second half (default true)
minGapnumbercuts closer than this many frames are merged, the earlier kept (default a quarter second)
fromnumberfirst frame (inclusive), default 0
tonumberlast frame (exclusive), default the song's end

FrameRange

FieldTypeWhat it is
fromnumberfirst frame (inclusive), default 0
tonumberlast frame (exclusive), default the song's end

Line

FieldTypeWhat it is
text (required)stringthe words to say
voicestringa Pocket voice ("alba", "marius",...), a clip in ~/.raea-feed/voices by name ("watts"), or a WAV ("/media/narrator.wav" or staticFile("narrator.wav")); the default is "watts" when that clip's there, else alba
seednumberwhich take: another seed says it another way (0)
temperaturenumberPocket's sampling temperature: lower is calmer and more even, higher livelier (0.7)

MixProps

The props of Mix, tabled there.

music

SeedlingFx

FieldTypeWhat it is
kind (required)stringone of raea/tone's effect classes by name: Filter, Reverb, Freeverb, FeedbackDelay, Compressor, EQ3,...
optionsRecord<string, unknown>its options, by Tone's names

SeedlingProps

The props of Seedling, tabled there.

Song

FieldTypeWhat it is
map (required)SongMapthe song's map, from `raea song`
fps (required)numberthe composition's frame rate, that frames are counted in
offset (required)numberseconds into the song frame 0 falls on (0)
frame (required)(seconds: number) => numberthe frame a song time falls on
seconds (required)(frame: number) => numberthe song's seconds at a frame
at (required)(frame: number) => SongMomentwhere the song is at a frame
onBeat (required)(every?: number | undefined, range?: FrameRange | undefined) => number[]frames of every every-th beat (1: each beat), counted from the song's first
onDownbeat (required)(every?: number | undefined, range?: FrameRange | undefined) => number[]frames of every every-th downbeat
eventsOf (required)(kind: SongEventKind, range?: FrameRange | undefined) => { frame: number; event: SongEv…frames of every event of a kind (a build's or stop's start), with the event
cutsAt (required)(options?: CutOptions | undefined) => number[]frames to cut on, paced to the energy: each section's (or bar's) rate, on its beats, plus drops, a stop's hits, and a build's second half at double rate

SongBar

FieldTypeWhat it is
time (required)numberseconds from the song's start where the bar begins (its downbeat)
beat (required)numberthe index of its first beat
beats (required)numberhow many beats it holds
energy (required)numberits mean energy, 0..1
cuts (required)numbersuggested cuts in this bar: 0.25, 0.5, 1, 2 or 4

SongEvent

FieldTypeWhat it is
kind (required)SongEventKindwhat the event is: build, drop, stop, hit, dip or break
time (required)numberseconds from the song's start: a beat (drop, a downbeat) or the grid's nearest beat or half beat (hit)
endnumberspans (build, stop, dip, break) end here
beat (required)numberthe index of the beat it starts on, in SongMap.beats
bar (required)numberthe index of the bar it starts in
beatsnumbera span: how many beats it lasts
strength (required)number0..1
intonumber | nulla build or stop: the drop it leads into, seconds
hitsSongHit[]a stop: its sparse hits
risenumbera drop: the energy of the bar after minus the bar before (negative when the band cuts after one big hit)
holdsbooleana drop: the bar after stays up (false: one hit, then the band cuts out)
afterStopbooleana drop: it comes straight out of a stop
afterBuildbooleana drop: it lands at the end of a build (within two bars of it)
gapBeforebooleana drop: a breath of near-silence just before it
atnumbera hit: the onset's own time; how far over the groove it stands
overnumbera hit: how far over the groove it stands

SongEventKind

TS
type SongEventKind = "build" | "drop" | "stop" | "hit" | "dip" | "break"

SongFeatures

FieldTypeWhat it is
loudness (required)number[]loudness (RMS) a beat, 0..1 over the song
onsets (required)number[]onset strength (spectral flux) a beat, 0..1: how much is struck
brightness (required)number[]brightness (spectral centroid) a beat, 0..1
low (required)number[]the low end (kick and bass, under 150 Hz) a beat, 0..1
high (required)number[]the high band (over 3 kHz) a beat, 0..1
energy (required)number[]the combined energy a beat, 0..1: loudness, low end, onsets and highs together

SongHit

A hit inside a stop: time on the beat grid (a beat or half beat), at where the onset is.

FieldTypeWhat it is
time (required)numberseconds from the song's start, snapped to the beat grid (a beat or half beat)
at (required)numberseconds from the song's start where the onset itself is
strength (required)numberhow hard the hit is, 0..1

SongLevel

TS
type SongLevel = "intro" | "low" | "mid" | "high" | "outro"

SongMap

FieldTypeWhat it is
version (required)numberthe map format's version (1)
duration (required)numberthe song's length in seconds
tempo (required)number | nullbeats per minute, or null when no beat was found
beatsPerBar (required)numberbeats in a bar (4 for 4/4)
beats (required)number[]every beat's time in seconds, ascending
downbeats (required)number[]every bar's first beat, in seconds
features (required)SongFeaturesone value a beat, 0..1 over the song
bars (required)SongBar[]the bars in order, each with its energy and suggested cut rate
sections (required)SongSection[]the song's sections in order (intro, verse, chorus and so on)
events (required)SongEvent[]builds, drops, stops, hits, dips and breaks, in time order
sectionsFrom"markers" | "novelty"where the sections came from: the song file's markers, or novelty in the music itself
boundaries{ time: number; beat: number; bar: number; strength: number }[]the candidate section boundaries novelty found, each with its strength 0..1
sourcestring | nullthe song file's name

SongMoment

Where a moment of the song is. Seconds are the song's; infinities when there's no such event.

FieldTypeWhat it is
time (required)numberthe moment, seconds from the song's start
beat (required)numberthe beat at or before time (-1 before the first)
bar (required)numberthe bar at or before time (-1 before the first beat)
beatInBar (required)number0-based position in the bar
phase (required)number0..1 through the beat, and through the bar
barPhase (required)number0..1 through the bar
energy (required)numberthe features at time, interpolated between beats
loudness (required)numberloudness at time, 0..1
onsets (required)numberonset strength at time, 0..1
brightness (required)numberbrightness at time, 0..1
low (required)numberthe low end at time, 0..1
section (required)SongSection | nullthe section time is in (null before the first)
sectionIndex (required)numberthat section's index in SongMap.sections (-1 for none)
sectionProgress (required)number0..1 through the section
cutsPerBar (required)numberthe bar's suggested cut rate (cuts per bar)
drop (required)SongEvent | nullthe last drop at or before time, the next after it
nextDrop (required)SongEvent | nullthe next drop after time
sinceDrop (required)numberseconds since the last drop (Infinity when there's none)
untilDrop (required)numberseconds until the next drop (Infinity when there's none)
build (required)SongEvent | nullthe build time is in, and 0..1 through it
inBuild (required)booleanwhether time is inside a build
buildProgress (required)number0..1 through that build
stop (required)SongEvent | nullthe stop time is in
inStop (required)booleanwhether time is inside a stop
dip (required)SongEvent | nullthe dip or break time is in
next (required)SongEvent | nullthe next event of any kind after time

SongOptions

FieldTypeWhat it is
fps (required)numberthe composition's frame rate
offsetnumberseconds into the song at frame 0 (where an

SongPlotProps

The props of SongPlot, tabled there.

SongSection

FieldTypeWhat it is
name (required)stringthe section's marker name when the song file has markers, else its level
level (required)SongLevelhow high the section sits in the song: intro, low, mid, high or outro
time (required)numberseconds from the song's start where the section begins
end (required)numberseconds from the song's start where it ends
beat (required)numberthe index of its first beat
bar (required)numberthe index of its first bar
energy (required)numberits mean energy, 0..1
cuts (required)numbersuggested cuts per bar: 0.25, 0.5, 1, 2 or 4

SpeechProps

The props of Speech, tabled there.

SpeechState

Where a line is at a frame.

FieldTypeWhat it is
started (required)booleanthe frame is at or past its start
word (required)numberthe word being spoken (an index into words), -1 before the first
ended (required)booleanit has finished (said to its end, or stopped at its cut)
endFrame (required)number | nullthe frame it ends on, once that's known (always known for a cut line, and for any line once it's all made)
words (required)string[]the line's words as Pocket says them (so far: a long line's later sentences are added as they're reached)

Tone

UseSongOptions

FieldTypeWhat it is
offsetnumberseconds into the song at frame 0 of the enclosing Sequence

VolumeProp

TS
type VolumeProp = number | ((mediaFrame: number) => number)