Mental model#
Five concepts are enough to think clearly about libYSE.
System#
YSE::system is the engine itself — a singleton you access through
the free function YSE::System(). It owns the audio device, the DSP
threads, and the scheduler that turns play() calls into samples on the
sound card.
The lifecycle is:
YSE::System().init()once at startup.YSE::System().update()once per frame.YSE::System().close()once at shutdown.
Between init and close, the engine is alive and accepting commands.
Listener#
YSE::listener is a singleton representing the position and
orientation of the “ear” in the virtual scene. Update its position every
frame; the engine computes panning, distance attenuation, and doppler shift
relative to it.
YSE::Listener().pos(YSE::Pos(playerX, playerY, playerZ));
YSE::Listener().orient(facingDirection, upVector);
Sound#
YSE::sound is a playable instance — one sound object per
voice you want in the scene. The source can be a file, an in-memory buffer,
a custom DSP source, or a patcher graph. Sounds can move, loop, fade,
stop, and seek; the engine reuses buffers under the hood when the same
file is loaded into multiple sounds.
Channel#
YSE::channel is a node in a mixing tree. Every sound is attached
to a channel; channels can themselves be attached to a parent channel,
forming a tree rooted at MainMix. Child channels dispatch their DSP work
to a thread pool, so spreading sounds across channels lets the engine
parallelise mixing across cores.
A small set of pre-built channels (ChannelMaster, ChannelMusic,
ChannelAmbient, ChannelVoice, ChannelGui, ChannelFX) is
created for you. Use them as-is or as roots for your own subtrees.
A typical scene looks like:
ChannelMaster (root, all output flows here)
├── ChannelMusic ← background tracks
├── ChannelAmbient ← environment loops
├── ChannelVoice ← dialogue
├── ChannelGui ← UI feedback
└── ChannelFX ← short SFX
Reverb#
YSE::reverb is a positioned reverb zone — a sphere in the scene
that lends its parameters to any nearby listener. Multiple reverbs can
overlap; the engine blends them by proximity so the listener transitions
smoothly between cave, hall, and bathroom as they walk.
A “global” reverb (YSE::System().getGlobalReverb()) acts as the fallback
everywhere no positioned zone reaches.
Patcher#
YSE::patcher is a Max/MSP-style modular DSP graph: a
collection of small objects (oscillators, filters, math, MIDI, GUI
controls) wired together by inlets and outlets. Use it when a sound is
not a file to play but a network to evaluate — procedural synthesis,
parameter mapping, generative MIDI.
YSE::patcher p;
p.create();
auto osc = p.CreateObject(YSE::OBJ::D_SINE, "440");
auto out = p.CreateObject(YSE::OBJ::D_DAC);
p.Connect(osc, 0, out, 0);
sound.create(p, ChannelMaster); // play the patcher as a sound source
Graphs can be serialised with DumpJSON() and rebuilt with
ParseJSON() — pair the engine with an external editor or ship
presets as plain text.
The full set of registered object types — every inlet, outlet, parameter, and accepted message type — is listed on the Patcher object reference reference page, generated directly from the engine source so it can never drift.
Putting it together#
The interaction looks like this on every frame:
The application calls
System().update()to advance engine state.The application updates the
Listenerposition to wherever the player / camera is.Sounds attached to channels render through the channel tree.
Positioned reverbs nearest the listener are blended into the output.
That is the whole picture. Everything else — DSP processors, patchers, the
note player — is built on top of these five concepts.