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:
symbolsis a 1-D integer array.symbolsandunitshave the same length.- Every symbol id is in
[0, alphabet_size). - If
session_boundariesis 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)