saumwacht-godot/tools/generate_audio.py
Martin Stickelbroeck c2b447610c Baseline: Saumwacht 0.15.0 (Phase 20A) vor dem Umbau zu Champions of Luneraria
Unveränderter Ausgangsstand inklusive Masterprompt und Konzeptbildern
unter assets/. .godot/ und docs/screenshots/ bleiben laut .gitignore
unversioniert; letztere sind unter ../backups gesichert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 20:00:36 +02:00

46 lines
2.2 KiB
Python

"""Original synthesized SFX. No samples or third-party audio. Reproducible PCM."""
from pathlib import Path
import math, random, struct, wave, json
ROOT = Path(__file__).resolve().parents[1]
OUT = ROOT / 'assets/audio'
RATE = 24000
def create(name, duration, tones=(), noise=0.0, decay=8, sweep=0.0):
rng = random.Random(name)
values = []
low = 0.0
for i in range(round(RATE * duration)):
t = i / RATE
env = min(1, t/.006) * min(1, (duration-t)/.035) * math.exp(-decay*t/duration)
low = .72*low + .28*rng.uniform(-1,1)
sample = noise * low
for hz, weight, delay in tones:
tt = max(0,t-delay)
if t >= delay:
sample += weight * math.sin(2*math.pi*(hz*tt+sweep*tt*tt)) * math.exp(-2*tt/duration)
values.append(sample*env)
peak = max(abs(x) for x in values) or 1
pcm = b''.join(struct.pack('<h', round(x/peak*.55*32767)) for x in values)
with wave.open(str(OUT / (name+'.wav')), 'wb') as f:
f.setnchannels(1); f.setsampwidth(2); f.setframerate(RATE); f.writeframes(pcm)
return {'id':name,'seconds':duration,'peak':.55,'sample_rate':RATE}
OUT.mkdir(parents=True, exist_ok=True)
specs = [
('place',.22,[(330,.5,0),(660,.3,.025)],.4,4,0),
('error',.20,[(135,.7,0)],.05,2,-80),
('stone',.24,[(92,.7,0),(181,.25,0)],1.6,6,-30),
('bolt',.22,[(540,.4,0),(1120,.2,0)],.8,5,-1200),
('mortar',.50,[(62,.6,0),(120,.25,0)],2.0,4,-25),
('ember',.24,[(390,.3,0),(780,.2,.04)],1.2,4,-240),
('ability',.65,[(330,.4,0),(440,.3,.08),(660,.25,.15)],.2,2,35),
('wave',.90,[(164.8,.5,0),(220,.3,.10),(329.6,.4,.20)],.1,2,0),
('boss',1.25,[(73.4,.6,0),(110,.4,.15),(146.8,.4,.28)],.4,1.6,0),
('settle',.65,[(392,.5,0),(523.25,.35,.12),(659.25,.3,.24)],.03,1.5,0),
('leak',.55,[(82.4,.65,0),(123.5,.3,.07)],.8,2,-28),
('victory',1.8,[(261.63,.4,0),(329.63,.3,.12),(392,.3,.24),(523.25,.4,.48)],.015,1.4,0),
('defeat',1.4,[(196,.45,0),(146.83,.4,.22),(98,.5,.42)],.02,1.5,0),
]
records = [create(*spec) for spec in specs]
(OUT/'manifest.json').write_text(json.dumps({'origin':'Original procedural synthesis; tools/generate_audio.py', 'clips':records}, indent=2)+'\n')
print(f'Generated {len(records)} original PCM effects.')