Procedural audio for Godot 4

Game sound without sound files.

Brusverk synthesizes footsteps, wildlife, weather, music and engines while your game runs, driven by the game's own state. No recordings, and never the same twice.

  • 150+ sound generators
  • open source Rust
  • MIT or Apache-2.0
A jungle platformer in Godot 4. Every sound in it, from the vine and the crocodile to the music, is computed live by Brusverk.

Hear it live.

These sounds are computed in this tab by the same engine, compiled to WebAssembly. Each picture is the sound's spectrogram; press play and it is computed again from its inputs. Nothing is downloaded but the engine.

Open the Sound Lab

Play any sound with its inputs on sliders, tune its parameters and copy them into Godot.

Browse every sound

Your game already knows how it should sound.

In Godot a generator is an AudioStream, so players, buses, 3D position and effects work as they do for a sample. The difference is that it listens to the game.

  • Game state in, sound outHand the generator what your game already computes: speed, the ground underfoot, time of day, how close the danger is.
  • Continuous inputsInputs run from 0 to 1 and can change every frame. The sound follows smoothly instead of cutting between clips.
  • Endless variationNothing is a loop. No two footsteps, coins or bird songs come out the same, so the tenth one is not the first one again.
  • Named parametersEvery sound has presets and named parameters in the Godot inspector. Tune by ear in the Sound Lab and paste the JSON back.
player.gdGDScript
extends CharacterBody2D

func _ready() -> void:
    # A continuous sound: footsteps that follow the player
    var steps := SoundGenerator.create("footstep")
    steps.set_preset("Close up")
    $Steps.stream = steps        # any AudioStreamPlayer, 2D or 3D
    $Steps.play()
    # An event sound: plays once per play()
    $Coin.stream = SoundGenerator.create("treasure")

func _physics_process(_delta: float) -> void:
    var moving := is_on_floor() and absf(velocity.x) > 10.0
    var pb := $Steps.get_stream_playback() as SoundGeneratorPlayback
    pb.set_inputs({
        "pace": 0.45 if moving else 0.0,  # steps by itself
        "speed": absf(velocity.x) / 400.0,
        "surface": 0.1,                  # 0.1 is grass
    })

func collect_coin() -> void:
    $Coin.play()  # `finished` fires when it has rung out
The inputs and the sound: a heavy truck
Loading the engine…
10 kHz1 kHz100 Hz
throttlerpm
The two lines at the bottom are all the game supplies. The picture above them is the sound that comes out.

Missing a sound? Write it as a text file.

A model file is a graph of nodes (noise, filters, resonators, delays, a reverb) plus formulas that turn the inputs into control signals. It loads while the game runs and shows its parameters in the Godot inspector, like a built-in generator.

This is campfire.toml, the file behind the campfire demo above.

Edit it in the Sound Lab
models/campfire.tomlTOML
The file appears here once the engine has loaded.

Get started.

There are no prebuilt binaries yet: you build the Godot extension from source with Rust and cargo, which takes a minute or two. It is tested with Godot 4.7 on macOS; Linux and Windows build from the same source but have not been tested yet.

TerminalRust stable
git clone https://github.com/joakimeriksson/brusverk
cd brusverk
cargo build -p brusverk-godot --release

Then point a .gdextension file at the library in target/release. The getting-started guide walks through it.

  • Real-time safe. No allocation, locks or blocking on the audio thread; parameter changes arrive over lock-free queues.
  • Not only Godot. brusverk-core is plain Rust with no engine dependency, and the WebAssembly build has a C interface.
  • Checked by ear and by eye. Realistic sounds are tuned against real recordings, and every sound is reviewed by spectrogram for dropouts, clipping and ringing.