nodes/audio.pyΒΆ

Part of Tower Defence.

 1"""Procedural audio: built on the engine's AudioSynth API.
 2
 3Replaces the upstream's bundled shot.wav (no licence grant) with a
 4sound generated at load time. The sweep keeps a small amount of
 5bespoke numpy because AudioSynth oscillators have constant frequency
 6(same pattern as the other ports).
 7"""
 8
 9from __future__ import annotations
10
11import math
12
13import numpy as np
14
15from simvx.core import AudioClip
16
17SAMPLE_RATE = 44100
18NCHANNELS = 2
19
20
21def make_shot() -> AudioClip:
22    """Turret shot: filtered noise crack over a fast downward thump."""
23    n = int(SAMPLE_RATE * 0.16)
24    rng = np.random.default_rng(3)
25    noise = rng.uniform(-1, 1, n).astype(np.float32) * 0.35
26    noise *= np.exp(np.linspace(0.0, -9.0, n, dtype=np.float32))  # sharp decay
27    freq = np.linspace(220, 70, n)
28    thump = np.sin(2 * math.pi * np.cumsum(freq) / SAMPLE_RATE).astype(np.float32) * 0.30
29    thump *= np.exp(np.linspace(0.0, -6.0, n, dtype=np.float32))
30    mono = noise + thump
31    out = np.empty(mono.size * NCHANNELS, dtype=np.float32)
32    out[0::NCHANNELS] = mono
33    out[1::NCHANNELS] = mono
34    return AudioClip.from_pcm(out, sample_rate=SAMPLE_RATE, channels=NCHANNELS, name="shot")
35
36
37__all__ = ["make_shot"]