hv-sign / example.py
zeechimp's picture
Create example.py
5a44508 verified
Raw History Blame Contribute Delete
3.15 kB
"""Minimal usage example for hv-sign.
If you have FSDD, ESC-50, or another corpus locally, edit the paths.
Otherwise this file synthesizes a small corpus and runs the full suite.
"""
import math
import os
import wave
from array import array
from hv_sign import HVSign
OUTDIR = "./hv_sign_example"
def _write_wav(path: str, samples, sr: int = 16000) -> None:
ints = array(
"h",
(max(-32768, min(32767, int(x * 32767))) for x in samples),
)
with wave.open(path, "wb") as w:
w.setnchannels(1)
w.setsampwidth(2)
w.setframerate(sr)
w.writeframes(ints.tobytes())
def _beeps(freqs, dur_ms, gap_ms, sr=16000):
out = []
for f in freqs:
n = int(sr * dur_ms / 1000)
for i in range(n):
t = i / sr
env = math.sin(math.pi * i / n) ** 0.5
out.append(0.5 * env * math.sin(2 * math.pi * f * t))
out.extend([0.0] * int(sr * gap_ms / 1000))
return out
def _chirp(f0, f1, dur_ms, sr=16000):
n = int(sr * dur_ms / 1000)
dur_s = dur_ms / 1000.0
out = []
for i in range(n):
t = i / sr
phase = 2 * math.pi * (f0 * t + 0.5 * (f1 - f0) * t * t / dur_s)
env = math.sin(math.pi * i / n)
out.append(0.5 * env * math.sin(phase))
return out
def main() -> None:
os.makedirs(OUTDIR, exist_ok=True)
# Synthesize a small corpus
corpus = {
"beeps_low": _beeps([220, 220, 220], 150, 100),
"beeps_high": _beeps([880, 660, 440], 120, 90),
"chirp_up": _chirp(200, 2000, 800),
"mix_a": _beeps([220, 330, 440, 220, 550], 100, 80),
"mix_b": _beeps([150, 900, 300, 1500, 200], 120, 70),
}
for name, sig in corpus.items():
_write_wav(os.path.join(OUTDIR, f"{name}.wav"), sig)
model = HVSign()
# Single file
first = os.path.join(OUTDIR, "beeps_low.wav")
report = model.score_file(first)
print("=" * 60)
print("Single-file report")
print("=" * 60)
print(model.render_file(report))
print()
print("=" * 60)
print("Numeric summary")
print("=" * 60)
print(f" events : {len(report.events)}")
print(f" unique fix : {len(set(report.fixed_score))}")
print(f" fixed score : {report.fixed_score}")
print()
# Corpus
print("=" * 60)
print("Corpus report")
print("=" * 60)
corpus_report = model.score_directory(OUTDIR)
print(model.render_corpus(corpus_report))
print()
if corpus_report.discovered:
d = corpus_report.discovered
print("=" * 60)
print("Discovered alphabet summary")
print("=" * 60)
print(f" k : {d.k}")
print(f" silhouette : {d.silhouette:.4f}")
print()
# Decay
print("=" * 60)
print("Symbolic decay")
print("=" * 60)
decay = model.decay_analysis(first)
print(model.render_decay(decay))
print()
print("=" * 60)
print("Numeric summary")
print("=" * 60)
print(f" symbolic SNR : {decay.symbolic_snr}")
print(f" note : {decay.note}")
print()
if __name__ == "__main__":
main()