What's New in v0.9.6-beta¶
Release Date: 2026 Target Framework: .NET 10
v0.9.6-beta is a complete audio overhaul and introduces post-processing effects to the GPU renderer.
Highlights¶
Complete Audio Overhaul¶
The audio system has been redesigned from the ground up. The old channel-based IAudioService has been replaced with a track-based IAudioPlayer that provides fine-grained per-track control, audio buses for group operations, crossfading, and spatial audio.
Track-Based Playback¶
PlaySound now returns a nint track handle you can use to control a specific instance:
// Play a sound and get a handle
nint track = Audio.PlaySound(_explosion, volume: 0.8f, pan: -0.3f, pitch: 1.1f);
// Control it later
Audio.SetTrackVolume(track, 0.5f);
Audio.SetTrackPan(track, 0.5f);
Audio.SetTrackPitch(track, 0.75f);
Audio.PauseTrack(track);
Audio.ResumeTrack(track);
Audio.StopTrack(track);
// Check if still playing
if (Audio.IsTrackAlive(track)) { ... }
Audio Buses¶
Tag tracks to control groups of sounds together:
// Tag at play time (atomic -- can't be missed by PauseBus)
nint track = Audio.PlaySound(_footstep, bus: "sfx");
nint uiTrack = Audio.PlaySound(_click, bus: "ui");
// Or tag after
Audio.TagTrack(track, "ambient");
// Group operations
Audio.SetBusVolume("sfx", 0.6f);
Audio.PauseBus("ui");
Audio.ResumeBus("ui");
Audio.StopBus("ambient", fadeOutSeconds: 1.0f);
float vol = Audio.GetBusVolume("sfx");
bool paused = Audio.IsBusPaused("ui");
Music with Crossfade and Loop Points¶
// Play music with a loop intro point
Audio.PlayMusic(_battleTheme, loops: -1, loopStartMs: 4000);
// Crossfade to a new track over 2 seconds
Audio.CrossfadeMusic(_bossTheme, duration: 2.0f);
// Stop with fade-out
Audio.StopMusic(fadeDuration: 1.5f);
// Real-time music control
Audio.PauseMusic();
Audio.ResumeMusic();
Audio.SeekMusic(positionMs: 30000);
Audio.SetMusicTrackVolume(0.8f);
Audio.SetMusicPitch(1.05f);
// Playback info
double pos = Audio.MusicPositionMs;
double dur = Audio.MusicDurationMs;
bool fading = Audio.IsMusicFadingOut;
Volume Hierarchy¶
Audio.MasterVolume = 0.9f; // Master gain
Audio.MusicVolume = 0.7f; // Applied to music tracks
Audio.SoundVolume = 1.0f; // Applied to sound effect tracks
// Final gain = MasterVolume × MusicVolume/SoundVolume × BusVolume × TrackVolume
Spatial Audio via ECS¶
Attach SoundEffectSourceComponent for automatic distance-based volume and stereo panning:
entity.AddComponent<SoundEffectSourceComponent>(s =>
{
s.SoundEffect = _footstepSound;
s.EnableSpatialAudio = true;
s.MinDistance = 50f; // Full volume within this radius
s.MaxDistance = 500f; // Silent beyond this radius
});
Track Limits and Priority¶
Audio.PlaySound(_sound, priority: 5); // Higher priority survives track eviction
int active = Audio.ActiveSoundTrackCount;
int max = Audio.MaxSoundTracks;
Post-Processing Effects¶
The GPU renderer now supports a post-processing pass. Add effects to the renderer pipeline from your scene:
protected override void OnLoadAsync(IEntityWorld world)
{
Renderer.PostProcessing.Add(new ChromaticAberrationEffect { Intensity = 0.005f });
Renderer.PostProcessing.Add(new VignetteEffect { Radius = 0.75f, Softness = 0.4f });
}
Breaking Changes¶
| Area | Before (v0.9.5) | After (v0.9.6) |
|---|---|---|
| Sound playback | PlaySound() returned channel int |
Returns track nint handle |
| Stop by channel | StopChannel(int) |
StopTrack(nint) |
| Pause by channel | PauseChannel(int) |
PauseTrack(nint) |
| Channel check | IsChannelPlaying(int) |
IsTrackAlive(nint) |
| Group control | No concept of buses | TagTrack / bus operations |
Migration¶
Replace all StopChannel, PauseChannel, and IsChannelPlaying call sites with the track-handle equivalents. Store the nint returned by PlaySound wherever you previously stored the channel int.
// Before
int channel = Audio.PlaySound(_sound);
Audio.StopChannel(channel);
// After
nint track = Audio.PlaySound(_sound);
Audio.StopTrack(track);