Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Play and mix audio in Godot 4.x: AudioStreamPlayer (2D/3D variants), audio buses with volume/mute and effects, music vs SFX routing, db/linear volume, and precise sync-to-beat playback timing. Use when playing sounds or music in a Godot project, routing AudioStreamPlayer nodes to buses, adjusting bus volume via AudioServer, or syncing gameplay to the beat.
.claude/skills/gamedev-skills-godot-audio/SKILL.md| Model | Eval pass | Runs |
|---|---|---|
| gemini-3.6-flashlowest | 98% | 52 |
| gemini-3.1-pro-preview | 100% | 1 |
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 17% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 62% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 205% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 208% | 0% |
| case-05 | ✓→✓ | = Same ✓ | 56% | 0% |
Play SFX and music, route them through buses, control volume in decibels, and time gameplay to the beat. Targets Godot 4.7.
adjusting volume/mute from code, adding bus effects (reverb, compressor), positional 3D audio, or syncing events to music.
When not to use: engine-agnostic audio design (adaptive music structure, mixing philosophy, ducking patterns) → audio-design; importing/encoding assets outside Godot.
AudioStreamPlayer — non-positional (music, UI, global SFX).AudioStreamPlayer2D / AudioStreamPlayer3D — positional; volume/pan from distance.AudioStream to stream (.ogg for music/loops, .wav for short SFX)and play(). Set autoplay for music that starts with the scene.
bus to a named bus (e.g. "Music", "SFX").Define buses in the Audio panel (bottom dock); each can have volume, mute, solo, and effects.
0 dB = unchanged,-80 dB ≈ silent. Convert with linear_to_db/db_to_linear.
AudioServer by bus index.gdscript@onready var sfx: AudioStreamPlayer = $Sfx # stream assigned in the editor func play_jump() -> void: sfx.pitch_scale = randf_range(0.95, 1.05) # slight variation avoids fatigue sfx.play() # For many overlapping copies, use an AudioStreamPlayer with an # AudioStreamPolyphonic stream, or spawn short-lived players and free on `finished`.
gdscriptfunc set_music_volume(linear_0_to_1: float) -> void: var bus := AudioServer.get_bus_index("Music") # Convert a 0..1 slider to decibels; clamp avoids -inf at 0. AudioServer.set_bus_volume_db(bus, linear_to_db(maxf(linear_0_to_1, 0.0001))) func toggle_sfx(muted: bool) -> void: AudioServer.set_bus_mute(AudioServer.get_bus_index("SFX"), muted)
gdscript@onready var a: AudioStreamPlayer = $MusicA @onready var b: AudioStreamPlayer = $MusicB func crossfade_to(stream: AudioStream, secs := 1.5) -> void: b.stream = stream b.volume_db = -40.0 b.play() var tw := create_tween().set_parallel(true) tw.tween_property(a, "volume_db", -40.0, secs) # fade out current tw.tween_property(b, "volume_db", 0.0, secs) # fade in next tw.chain().tween_callback(a.stop) var tmp := a; a = b; b = tmp # swap roles
gdscript@onready var music: AudioStreamPlayer = $Music func get_playback_time() -> float: # Add time since the last audio mix, subtract output latency, for sub-frame accuracy. var t := music.get_playback_position() + AudioServer.get_time_since_last_mix() return t - AudioServer.get_output_latency()
volume_db/set_bus_volume_db are decibels. Settingvolume_db = 0.5 is nearly full volume, not half. Map sliders with linear_to_db.
linear_to_db(0.0) is -inf. Clamp the linear value to a small minimum (e.g.0.0001) before converting, or special-case 0 → mute.
get_bus_index("Muisc") returns -1; calls then erroror no-op. Match the exact bus name from the Audio panel.
AudioStreamPolyphonic, or AudioStreamPlayer per-shot freed on finished.
.ogg import has aLoop option; AudioStreamWAV has loop_mode).
get_playback_position() alone is jittery — it updates per audio mix,not per frame; add get_time_since_last_mix() and subtract get_output_latency().
AudioListener3D/Camera3D to hear it, or max_distance/attenuation too tight, or wrong bus muted.
.tres), adding effects (reverb/compressor/EQ) and side-chainducking, AudioStreamPolyphonic/AudioStreamInteractive, microphone capture, and procedural audio with AudioStreamGenerator, read references/buses-and-effects.md.
audio-design — engine-agnostic adaptive music, mixing, and ducking practice.godot-animation — syncing animation/Tween to get_playback_position().godot-ui-control — volume sliders wired to AudioServer.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 12,874 | 7,832 | -39% | 1 | 1 | 0% | 2,649 | 3,110 | +17% | 0 | 0 | — |
case-02 | pass→pass | 10,356 | 9,291 | -10% | 1 | 1 | 0% | 1,932 | 3,135 | +62% | 0 | 0 | — |
case-03 | pass→pass | 3,857 | 3,404 | -12% | 1 | 1 | 0% | 723 | 2,204 | +205% | 0 | 0 | — |
case-04 | pass→pass | 3,896 | 3,737 | -4% | 1 | 1 | 0% | 698 | 2,151 | +208% | 0 | 0 | — |
case-05 | pass→pass | 8,328 | 4,640 | -44% | 1 | 1 | 0% | 1,471 | 2,296 | +56% | 0 | 0 | — |
case-06 | pass→pass | 7,349 | 5,925 | -19% | 1 | 1 | 0% | 1,419 | 2,587 | +82% | 0 | 0 | — |
case-07 | pass→pass | 11,394 | 6,645 | -42% | 1 | 1 | 0% | 2,163 | 2,739 | +27% | 0 | 0 | — |
case-08 | pass→pass | 10,218 | 7,341 | -28% | 1 | 1 | 0% | 2,134 | 3,046 | +43% | 0 | 0 | — |
case-09 | pass→pass | 14,666 | 7,359 | -50% | 1 | 1 | 0% | 2,710 | 3,043 | +12% | 0 | 0 | — |
case-10 | pass→pass | 5,023 | 4,578 | -9% | 1 | 1 | 0% | 920 | 2,331 | +153% | 0 | 0 | — |
case-11 | pass→pass | 7,961 | 4,916 | -38% | 1 | 1 | 0% | 1,429 | 2,285 | +60% | 0 | 0 | — |
case-12 | pass→pass | 11,929 | 7,954 | -33% | 1 | 1 | 0% | 2,208 | 2,948 | +34% | 0 | 0 | — |
case-13 | pass→pass | 3,371 | 2,751 | -18% | 1 | 1 | 0% | 665 | 1,977 | +197% | 0 | 0 | — |
case-14 | pass→pass | 7,719 | 4,070 | -47% | 1 | 1 | 0% | 1,439 | 2,273 | +58% | 0 | 0 | — |
case-15 | pass→pass | 3,382 | 2,466 | -27% | 1 | 1 | 0% | 511 | 1,903 | +272% | 0 | 0 | — |
case-16 | pass→pass | 6,004 | 5,892 | -2% | 1 | 1 | 0% | 1,206 | 2,667 | +121% | 0 | 0 | — |
case-17 | pass→pass | 5,141 | 2,610 | -49% | 1 | 1 | 0% | 912 | 1,950 | +114% | 0 | 0 | — |
case-18 | pass→pass | 6,981 | 4,449 | -36% | 1 | 1 | 0% | 1,417 | 2,410 | +70% | 0 | 0 | — |
case-19 | pass→pass | 7,057 | 3,683 | -48% | 1 | 1 | 0% | 1,489 | 2,214 | +49% | 0 | 0 | — |
case-20 | pass→pass | 16,392 | 14,541 | -11% | 1 | 1 | 0% | 2,505 | 3,800 | +52% | 0 | 0 | — |
case-21 | pass→pass | 3,636 | 3,815 | +5% | 1 | 1 | 0% | 702 | 2,210 | +215% | 0 | 0 | — |
case-22 | pass→pass | 12,828 | 11,835 | -8% | 1 | 1 | 0% | 2,046 | 3,404 | +66% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +5 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 8/2/2026 | +5% |
Other measured skills in the registry, with their headline benchmark lift.