"""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()