Tutorial 4 — Build a symbol stream

Combine cluster labels and units into a SymbolStream — the data structure every downstream sequence primitive consumes.

Construct

from decipher import SymbolStream, split_sessions

sessions = split_sessions(units, gap_s=10.0)   # split where the inter-unit gap exceeds 10 s

stream = SymbolStream(
    symbols=result.labels_assigned,
    alphabet_size=result.n_clusters,
    units=units,
    source_sr=src.sr,
    session_boundaries=sessions,
    name="payne_excerpt",
)

print(len(stream), "symbols across", len(stream.session_boundaries), "sessions")

The constructor validates that:

  • symbols is a 1-D integer array.
  • symbols and units have the same length.
  • Every symbol id is in [0, alphabet_size).
  • If session_boundaries is non-empty, the intervals cover [0, N) exactly once.

Sessions

split_sessions(units, gap_s) returns half-open (start, end) intervals — adjacent units are in the same session iff units[i].start_s - units[i-1].end_s ≤ gap_s. Use sessions when shuffle-based nulls (e.g. for mutual information) should preserve within-session structure.

Round-trip from any symbol

The contract is that stream.symbols[i] indexes stream.units[i], whose source_samples is playable.

from decipher import write_wav

i = 42
write_wav("symbol_42.wav",
          stream.units[i].source_samples,
          stream.units[i].sr)

Next

Entropy and mutual information →