#!/usr/bin/env python3 """Generate crisp, pleasant retro/modern sound effects as 16-bit 44.1kHz mono WAVs.""" import math import struct import wave from pathlib import Path SAMPLE_RATE = 44100 OUT_DIR = Path(__file__).resolve().parent.parent / "assets" / "audio" OUT_DIR.mkdir(parents=True, exist_ok=True) def write_wav(filename: str, samples: list[float]): path = OUT_DIR / filename with wave.open(str(path), "w") as wav: wav.setnchannels(1) wav.setsampwidth(2) wav.setframerate(SAMPLE_RATE) raw = bytearray() for s in samples: val = max(-1.0, min(1.0, s)) ival = int(val * 32767) raw.extend(struct.pack(" E6).""" duration = 0.35 n = int(SAMPLE_RATE * duration) samples = [] t_split = 0.08 for i in range(n): t = i / SAMPLE_RATE if t < t_split: freq = 987.77 # B5 env = min(1.0, t / 0.005) else: freq = 1318.51 # E6 t_sub = t - t_split env = math.exp(-9.0 * t_sub) # Add a light sparkle harmonic s = (math.sin(2 * math.pi * freq * t) + 0.25 * math.sin(4 * math.pi * freq * t)) * env samples.append(s * 0.8) write_wav("coin.wav", samples) def gen_click(): """Short crisp mechanical button click.""" duration = 0.05 n = int(SAMPLE_RATE * duration) samples = [] for i in range(n): t = i / SAMPLE_RATE env = math.exp(-80.0 * t) freq = 1200.0 - 800.0 * (t / duration) s = math.sin(2 * math.pi * freq * t) * env samples.append(s * 0.7) write_wav("click.wav", samples) def gen_chime(): """Pleasant 3-note ascending arpeggio (C6, E6, G6).""" duration = 0.8 n = int(SAMPLE_RATE * duration) notes = [1046.5, 1318.5, 1567.98] # C6, E6, G6 step = 0.12 samples = [] for i in range(n): t = i / SAMPLE_RATE s_total = 0.0 for idx, freq in enumerate(notes): t_start = idx * step if t >= t_start: t_note = t - t_start env = math.exp(-6.0 * t_note) s_total += math.sin(2 * math.pi * freq * t_note) * env * 0.35 samples.append(s_total) write_wav("chime.wav", samples) def gen_fanfare(): """Triumphant short fanfare jingle (C5, G5, C6).""" duration = 1.0 n = int(SAMPLE_RATE * duration) notes = [(0.0, 0.15, 523.25), (0.15, 0.30, 783.99), (0.30, 0.95, 1046.5)] samples = [] for i in range(n): t = i / SAMPLE_RATE s_total = 0.0 for t_start, t_end, freq in notes: if t >= t_start: t_rel = t - t_start env = math.exp(-4.0 * t_rel) if t >= t_end - 0.05 else min(1.0, t_rel / 0.01) s_total += (math.sin(2 * math.pi * freq * t_rel) + 0.2 * math.sin(4 * math.pi * freq * t_rel)) * env * 0.4 samples.append(s_total) write_wav("fanfare.wav", samples) def gen_door_open(): """Low wooden mechanical slide/creak.""" duration = 0.6 n = int(SAMPLE_RATE * duration) samples = [] for i in range(n): t = i / SAMPLE_RATE env = math.sin(math.pi * (t / duration)) ** 0.5 freq = 160.0 + 80.0 * math.sin(30.0 * t) s = math.sin(2 * math.pi * freq * t) * env * 0.6 samples.append(s) write_wav("door_open.wav", samples) if __name__ == "__main__": gen_bell() gen_coin() gen_click() gen_chime() gen_fanfare() gen_door_open()