#!/usr/bin/env python3
"""Make doorbell.wav: a two-note "ding-dong" chime, synthesised (no licence issues).

Each note is a few decaying sine partials, like a struck metal bar.
Mono, 22.05 kHz, 16-bit, peak -3 dBFS (the Atom Echo's small speaker rattles near 0 dBFS).

Usage: python3 make-doorbell.py [out.wav]
"""
import math
import struct
import sys
import wave

RATE = 22050
LENGTH = 3.2  # seconds
NOTES = [(659.25, 0.0), (523.25, 0.75)]  # E5 "ding", then C5 "dong" 0.75 s later
# (multiple of the note, loudness, decay per second)
PARTIALS = [(1.0, 1.0, 2.5), (2.0, 0.6, 4.0), (3.0, 0.3, 6.0), (4.07, 0.2, 9.0)]
ATTACK = 0.004  # seconds; avoids a click at the start of each note
FADE = 0.3  # seconds of fade-out at the end
PEAK = 10 ** (-3 / 20)


def note(freq, t):
    if t < 0:
        return 0.0
    s = sum(a * math.sin(2 * math.pi * freq * m * t) * math.exp(-d * t) for m, a, d in PARTIALS)
    return s * min(1.0, t / ATTACK)


def main():
    out = sys.argv[1] if len(sys.argv) > 1 else "doorbell.wav"
    n = int(RATE * LENGTH)
    samples = []
    for i in range(n):
        t = i / RATE
        v = sum(note(f, t - start) for f, start in NOTES)
        v *= min(1.0, (LENGTH - t) / FADE)
        samples.append(v)
    scale = PEAK / max(abs(v) for v in samples)
    with wave.open(out, "wb") as w:
        w.setnchannels(1)
        w.setsampwidth(2)
        w.setframerate(RATE)
        w.writeframes(b"".join(struct.pack("<h", round(v * scale * 32767)) for v in samples))
    print(f"🟢 wrote {out} ({LENGTH} s, {RATE} Hz)")


if __name__ == "__main__":
    main()
