Sound effects and music for one listener, over one TuningFork stage.
A game emits the events that happened — :brick, {:explosion, {x, y}} — and supplies
a function from an event's name to the voice it makes. Each instance is a process; a
game with one player uses the default one, a served game starts one per session with a
sink that reaches that player.
Cauldron2D.Audio.start(sounds: &MyGame.Sound.voice/1, sfx: 0.85, music: 0.35)
Cauldron2D.Audio.play([:brick, {:wall, {12.0, 3.0}}])
Cauldron2D.Audio.bed(Cauldron2D.Audio, "mygame/level-3", fn -> MyGame.Music.render(3) end)
{:ok, audio} = Cauldron2D.Audio.start_link(name: nil, sink: {TuningFork.Sink.Pulse, server: "tcp:127.0.0.1:<port>"})
Cauldron2D.Audio.listener(audio, {player_x, player_y})
Cauldron2D.Audio.play(audio, events)Every function takes the instance first. The ones with a fixed number of arguments
default it to the process registered as Cauldron2D.Audio; play_piece/4 and bed/4
take it explicitly.
Rules
start/1orstart_link/1comes first. It records the sound table and opens the stage; when this machine has no sound the stage stays silent and every call is a no-op returning:ok.on?/1reports which.- An event is any term the table knows, or
{event, {x, y}}placing it. With a listener set, a placed event is scaled by its distance — full within one tile, silent at:earshottiles — and panned by its side; an unplaced one plays at full level, centred. - Effects and music have separate levels, set by
levels/3. - Beds are keyed by a string. A render runs once, in a task, and is kept in memory and
on disk via
TuningFork.Cache; a bed finishing after another key was asked for is dropped. A render that raises is logged and never plays. clear_bed/1andresume_bed/1cover both playback modes.- Music with sections and layers is
Cauldron2D.Audio.Music.
Summary
Functions
Loop the PCM render produces under key; see the module rules for caching.
Returns a specification to start this module under a supervisor.
Stop the music, live or rendered.
The effects and music levels an instance starts with: %{sfx: 0.85, music: 0.35}.
Set the effects and music levels, each 0.0 to 1.0.
Where the listener is, for placed events.
Silence everything, or restore it.
Whether a stage with somewhere to play is running.
Sound events in order through the table given at start: a name — any term — or {name, {x, y}} placed against the listener; one the table answers nil for, or has no clause for, is silent.
Play score on a loop, live or from a render, under key.
Sound voice directly, scaled by the effects level.
The key last given to bed/4 or play_piece/4, or nil.
Start the music last asked for again.
The stage this instance plays through, or nil.
Start the default instance, registered as Cauldron2D.Audio, replacing one already
running. Returns whether sound is possible.
Start an instance linked to the caller.
Types
@type instance() :: GenServer.server()
@type sound() :: TuningFork.Voice.t() | [{non_neg_integer(), TuningFork.Voice.t()}] | nil
Functions
Loop the PCM render produces under key; see the module rules for caching.
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec clear_bed(instance()) :: :ok
Stop the music, live or rendered.
The effects and music levels an instance starts with: %{sfx: 0.85, music: 0.35}.
Set the effects and music levels, each 0.0 to 1.0.
Where the listener is, for placed events.
Silence everything, or restore it.
Whether a stage with somewhere to play is running.
Sound events in order through the table given at start: a name — any term — or {name, {x, y}} placed against the listener; one the table answers nil for, or has no clause for, is silent.
@spec play_piece(instance(), String.t(), TuningFork.Score.t(), keyword()) :: :ok
Play score on a loop, live or from a render, under key.
Options
:mode—:liveor:rendered, overriding the instance's default:render— a zero-arity function returning the PCM to loop in:renderedmode. Default: rendersscoreat the stage's rate:fingerprint— keys the on-disk render together withkey. Default"0"
@spec play_voice(instance(), TuningFork.Voice.t()) :: :ok
Sound voice directly, scaled by the effects level.
The key last given to bed/4 or play_piece/4, or nil.
@spec resume_bed(instance()) :: :ok
Start the music last asked for again.
The stage this instance plays through, or nil.
Start the default instance, registered as Cauldron2D.Audio, replacing one already
running. Returns whether sound is possible.
Takes the options of start_link/1.
@spec start_link(keyword()) :: GenServer.on_start()
Start an instance linked to the caller.
The instance lives as long as the caller: when the caller exits, for any reason, the
instance stops, and a stage it started stops with it, closing its sink. A stage handed
in with :stage is left running.
Options
:name— a registered name, ornilfor none. DefaultCauldron2D.Audio:sounds— a function from an event name to asound/0. Default: silent:sink— aTuningFork.Sinkmodule, or{module, sink_opts}. Default:TuningFork.Sink.Speakerwhen that package is present, else nothing plays:stage— an already running stage to use instead of starting one:mode— the default forplay_piece/4,:liveor:rendered. Default:live:sfx,:music— levels 0.0 to 1.0. Defaultdefault_levels/0:earshot— tiles at which a placed event falls silent. Default30.0:music_dir— the directory rendered music is kept in; a game's isCauldron2D.Client.Game.music_dir/1. DefaultTuningFork.Cache.dir/0:static_music— play the first section cued and nothing after, rendered once and looped; seeCauldron2D.Audio.Music. Defaultfalse:parallel— synthesise the music's voices on every core, for one player on a machine of their own (the terminal, the desktop); a server with many players leaves it off. Defaultfalse:rate,:channels,:chunk,:voices,:lead,:fx— the stage's settings. Default44_100,2,256,12,2048,[]: the sink is kept 2048 frames (46 ms at 44.1 kHz) ahead of playback, in a ring of four times that, so a few milliseconds of scheduling jitter never leave it empty