GraphAudio.Kit 0.6.0

dotnet add package GraphAudio.Kit --version 0.6.0
                    
NuGet\Install-Package GraphAudio.Kit -Version 0.6.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="GraphAudio.Kit" Version="0.6.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="GraphAudio.Kit" Version="0.6.0" />
                    
Directory.Packages.props
<PackageReference Include="GraphAudio.Kit" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add GraphAudio.Kit --version 0.6.0
                    
#r "nuget: GraphAudio.Kit, 0.6.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package GraphAudio.Kit@0.6.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=GraphAudio.Kit&version=0.6.0
                    
Install as a Cake Addin
#tool nuget:?package=GraphAudio.Kit&version=0.6.0
                    
Install as a Cake Tool

GraphAudio.Kit

A high-level, game-focused audio library for .NET

Why GraphAudio.Kit?

  • Play sounds in one line after initial setup
  • 3D spatial audio that just works.
  • Flexible mixing with hierarchical audio buses.
  • Effect chains you can build and modify at runtime
  • Smart caching so you're not constantly reloading the same audio files

Installation

dotnet add package GraphAudio.Kit

Quick Start

Set up your audio engine once when your game starts:

using GraphAudio.Kit;
using GraphAudio.Kit.DataProviders;
using GraphAudio.Realtime;

// Create the engine that manages all your sounds
var context = new RealtimeAudioContext(
    sampleRate: 48000,
    channels: 2,
    bufferSize: 256
);
var engine = new AudioEngine(context);

// Tell it where to find your audio files
engine.DataProvider = new FileSystemDataProvider("path/to/your/audio/folder");

// Start the audio hardware
context.Start();

// That's it! Now you're ready to play sounds.

Keep the engine alive for the lifetime of your game. When you're done:

engine.Dispose();

Playing Your First Sound

Once you've done the setup above, playing a sound is dead simple:

// One-shot sounds (fire and forget)
engine.PlayOneShot("footstep.ogg");

// PlayOneShot also takes a setup callback, which you can use to set up the sounds properties before it plays and the engine owns it.

That's it! The sound plays, finishes, and cleans itself up automatically.

When You Need More Control

For sounds you want to control (music, ambience , etc.), create a Sound object:

// Load a sound into memory for instant playback
var sound = await engine.CreateBufferedSoundAsync("music.ogg");

// Control it like you'd expect
sound.Play();
sound.Pause();
sound.Stop();

sound.Gain = 0.5f;           // Volume (0.0 to 1.0)
sound.IsLooping = true;      // Loop it
sound.PlaybackRate = 1.2f;   // Speed it up 20%

// Jump to a specific time
sound.Seek(TimeSpan.FromSeconds(30));

Buffered vs Streaming Sounds

Buffered sounds load the entire audio file into memory. They're perfect for short, frequently-played sounds:

var click = await engine.CreateBufferedSoundAsync("click.ogg");

Streaming sounds read audio on-demand. Use these for long files like music.

var bgMusic = await engine.CreateStreamingSoundAsync("music/background.mp3");
bgMusic.IsLooping = true;
bgMusic.Play();

3D Spatial audio

The Simple Way: Position-Based

For detached sounds in your 3D world, just set their position:

var sound = await engine.CreateBufferedSoundAsync(
    "engine.ogg",
    mixState: SoundMixState.BinoralSpatialized  // Enable 3D audio for that sound.
);

sound.Position = new Vector3(10, 0, 5);  // World position
sound.IsLooping = true;
sound.Play();

// Update the listener (your player/camera) position
engine.SetListener(
    position: playerPosition,
    forward: playerForward,
    up: Vector3.UnitY
);

The sound will now pan with hrtf. Call engine.Update() in your game loop to keep everything in sync.

Spatial Anchors

If you have entities that play multiple sounds, Instead of manually updating every sound's position, you attach sounds to an anchor and update the anchor with your game entity's position:

// Create an anchor for your car entity
var carAnchor = new SpatialAnchor();

// Attach the engine sound to it
var engineSound = await engine.CreateBufferedSoundAsync(
    "car_engine.ogg",
    mixState: SoundMixState.BinoralSpatialized
);
engineSound.Anchor = carAnchor;
engineSound.IsLooping = true;
engineSound.Play();

// In your game update loop:
void Update()
{
    // Just update the anchor once and all attached sounds follow automatically!
    carAnchor.Position = carEntity.Transform.Position;

    // Update the engine (you must call this periodically)
    engine.Update();
}

You can even use position offsets if the sound source isn't exactly at the entity's center:

engineSound.Anchor = carAnchor;
engineSound.Position = new Vector3(0, -0.5f, 2);  // Offset from anchor

Advanced: distance Behavior

Control how sounds fade with distance:

sound.SetDistanceModel(
    model: SpatialPannerNode.DistanceModelType.Inverse,  // Realistic falloff
    refDistance: 1.0f,      // Distance where volume starts to decrease
    maxDistance: 50.0f,     // Distance where volume reaches minimum
    rolloffFactor: 1.0f     // How quickly volume decreases (higher = faster)
);

Advanced: Directional Sounds

Make sounds emit in a specific direction (like a megaphone or engine exhaust):

sound.Orientation = Vector3.UnitX;  // Sound points along X axis

sound.SetCone(
    innerAngle: 45f,    // Full volume within this angle
    outerAngle: 90f,    // Transition to outer volume
    outerGain: 0.3f     // Volume outside the cone (0.0 to 1.0)
);

Advanced: Occlusion & Transmission

Simulate sound passing through walls or obstacles:

// 0.0 = Open Air, 1.0 = Fully Blocked
sound.Occlusion = 1.0f;

// Occlusion must be > 0 for transmission to work.
sound.SetTransmission(
    low: 0.9f,
    mid: 0.9f,
    high: 0.8f
);

Audio Buses

Buses let you group and control the gain and effects on multiple sounds at once. Think a music bus, a UI bus, gameplay bus, etc.

var musicBus = engine.GetBus("music");

// Attach sounds to buses
var bgMusic = await engine.CreateStreamingSoundAsync("music.mp3", bus: musicBus);
// Control the entire bus
musicBus.Gain = 0.5f;   // All music plays at 50% volume
music.Muted = true;    // Silence all music instantly

// Smooth volume changes
musicBus.Fade(target: 0.2f, duration: 2.0);  // Fade to 20% over 2 seconds

Hierarchical Buses

You can create bus hierarchies using forward slashes:

var playerSfx = engine.GetBus("sfx/player");
var enemySfx = engine.GetBus("sfx/enemy");
var uiSfx = engine.GetBus("sfx/ui");

// Adjusting the parent affects all children
var sfxBus = engine.GetBus("sfx");
sfxBus.Gain = 0.5f;  // All sfx/* buses now play at 50% of their individual volume

All buses eventually connect to the master bus:

engine.MasterBus.Gain = 0.8f;  // Global volume control

Advanced: Effect Chains

Effect chains let you add high-level effects to individual sounds or entire buses. Effects process in the order you add them.

You can use high-level effects like ReverbEffect:

var reverb = new ReverbEffect(engine);
await reverb.SetImpulseResponseAsync("irs/hall.wav");
reverb.Wet.Value = 0.5f;

soundOrBus.Effects.Add(reverb);

Or you can wrap standard GraphAudio nodes using NodeEffect:

var lowpass = new BiQuadFilterNode(engine.Context);
lowpass.Type = BiQuadFilterNode.FilterType.LowPass;
lowpass.Frequency.Value = 800;

sound.Effects.Add(new NodeEffect(engine, lowpass));

The EffectChain takes ownership of the effects. When you remove an effect or dispose the chain, the effects (and their underlying nodes) are automatically disposed.

soundOrBus.Effects.Remove(reverb);
soundOrBus.Effects.Clear();

soundOrBus.Effects.Insert(0, newReverb);

Advanced: creating Custom Effects

You are encouraged to create your own reusable effects by subclassing Effect. An effect is simply a mini-graph with an input and an output. This allows you to encapsulate complex DSP graphs (like a multi-tap delay or a specific filter chain) into a single, easy-to-use package.

To implement a custom effect, you need to:

  1. Inherit from Effect: Pass the AudioEngine to the base constructor.
  2. Define Input/Output: Expose the entry and exit nodes of your internal graph via the Input and Output properties.
  3. Manage Resources: Override OnDispose to clean up any nodes you created.

Here is an example custom effect:

public class BoostEffect : Effect
{
    private readonly GainNode _gain;

    public override AudioNode Input => _gain;
    public override AudioNode Output => _gain;

    public BoostEffect(AudioEngine engine, float amount) : base(engine)
    {
        _gain = new GainNode(engine.Context);
        _gain.Gain.Value = amount;
    }

    protected override void OnDispose()
    {
        _gain.Dispose();
    }
}

Preloading for Performance

If you know you'll need certain sounds soon, preload them to avoid slowdowns:

// Load multiple sounds in parallel
await engine.PreloadBuffersAsync(new[]
{
    "footstep_1.ogg",
    "footstep_2.ogg",
    "footstep_3.ogg",
    "jump.ogg"
});

// Now they'll play instantly when needed
engine.PlayOneShot("footstep_1.ogg", setup: sound => sound.Anchor = playerAnchor);  // No load time!

Fade In/Out

Sounds and buses both support smooth volume transitions:

// Fade in when playing
sound.Play(fadeInDuration: 1.5);  // Fade in over 1.5 seconds

// Fade out before stopping
await sound.Stop(fadeOutDuration: 2.0);  // Fade out over 2 seconds, then stop

// Bus fades affect all sounds on the bus
musicBus.Fade(target: 0.0f, duration: 3.0);  // Fade out all music

Advanced: Spatial Blend Controllers

Spatial blend controllers let you customize how sounds transition between 2D and 3D audio based on distance. By default, sounds are fully 3D, but you might want close sounds to feel more "direct":

using GraphAudio.Kit.SpatialBlendControllers;

// Make close sounds more direct (easier to hear), far sounds fully spatial
var controller = new LinearSpatialBlendController(
    minDistance: 0f,
    maxDistance: 10f,
    minBlend: 0.3f,   // 30% spatial when close
    maxBlend: 1.0f    // 100% spatial when far
);

sound.SpatialBlendController = controller;

You can also set a default controller for all new sounds:

Sound.DefaultSpatialBlendController = controller;

Best Practices

  1. Call engine.Update() every frame in your game loop. It handles spatial audio updates and cleans up finished one-shot sounds.

  2. Use PlayOneShot for short effects that fire and forget. Use explicit Sound objects when you need long-term control.

  3. Attach sounds to SpatialAnchor objects rather than updating positions manually. It's cleaner and more efficient.

  4. Organize with buses from the start. Even if you don't need per-category volume or effects now, you will later.

  5. Preload frequently-used sounds

  6. Use streaming for long audio (music, ambience, cutscenes...). Use buffered sounds for everything else.

  7. Dispose sounds you're done with if you hold a reference.

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.6.0 90 1/20/2026
0.5.4 90 1/1/2026
0.5.3 88 1/1/2026
0.5.2 315 11/21/2025
0.5.1 402 11/20/2025
0.4.1 412 11/20/2025
0.4.0 401 11/19/2025
0.3.4 338 11/17/2025
0.3.3 293 11/16/2025
0.3.2 288 11/16/2025
0.3.1 240 11/16/2025