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
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.
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.
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
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.
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.
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-coreis 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.
docs/getting-started.md
Godot APISoundGenerator, its playback, inputs, presets and events.docs/godot-api.md
Sound catalogEvery generator with its inputs and presets.docs/sound-catalog.md
RustUse the engine directly from your own Rust code.docs/rust.md
WebThe WebAssembly build that runs this page.docs/web.md
READMEThe overview, the project layout and how to contribute.README.md
Sound LabFind a sound, shape it by ear and copy its settings.lab.html