Skip to main content

cluesurf-talk (Python)

The Python implementation of talk, a phonetic encoding. It reads and writes IPA, converts to and from tone (an ASCII notation), and turns either into integer codes for compact, one-token-per-sound tokenization.

The LIBRARY is called talk; the NOTATION it defines is called tone. This port is verified against the TypeScript reference on every one of Phoible's 3,422 phonemes: the tone spelling, the machine codes and the normalization all agree exactly.

Install

pip install cluesurf-talk

Usage

import talk

talk.ipa_to_talk("tʰa")        # 'th~a'
talk.talk_to_ipa("th~a")       # 'tʰa'
talk.readable("th~a")          # 'tʰa'   simplified, human-readable
talk.normalize_ipa("ʆ")        # 'ʃʲ'    folds the many ways IPA is written
talk.machine(text="th~a", type="tone", system="mesh")  # [20594, 7592]
talk.segment("th~a")           # Sounds, each a base plus its modifiers

API

function direction
ipa_to_talk(ipa) IPA to tone
talk_to_ipa(tone) tone to IPA
readable(tone) tone to the simplified reading form
normalize_ipa(ipa) IPA to the one form the parser reads
machine(text=, type=, system=) to integer codes
machine_text(text=, type=, system=) to fixed-width characters, for indexes
machine_bytes(text=, type=, system=) to fixed-width bytes
parse_ipa(ipa) IPA to bases with their modifiers
segment(tone) tone to Sounds
enumerate_sounds() every canonical sound

Encodings

Two NOTATIONS crossed with three TIERS, so six encodings. Which one you want follows from two questions: does it need to give the sound back exactly, and how much detail does it need to carry.

ipa is lossless, so what goes in comes back out. Use it wherever something downstream is compared to, displayed as, or exported as the original.

tone is deliberately coarser: O covers six IPA vowels, i$ covers ɨ, y and ʏ. That is what makes the space small enough to be a model's vocabulary, and it is why tone does not round-trip every distinction IPA can write.

tier holds tone ipa bytes
seed one atomic unit: a base, or a single mark 110 168 1
band a base plus its segmental marks 2,161 7,432,128 2 / 3
mesh a base plus everything, suprasegmentals included 25,426 166,167,936 2 / 4
from talk import machine, machine_bytes, byte_width, size_of

# Same call shape, all six encodings.
machine(text="tʰa", type="ipa", system="seed")    # [18, 104, 0]
machine(text="tʰa", type="ipa", system="mesh")    # [49710672, 0]
machine(text="th~a", type="tone", system="band")  # [1778, 683]
machine(text="th~a", type="tone", system="mesh")  # [20594, 7592]

machine_bytes(text="th~a", type="tone", system="mesh")  # 4 bytes
byte_width(type="ipa", system="mesh")   # 4
size_of(type="tone", system="mesh")     # 25584

For a single sound rather than a string, encode_unit and decode_unit take a Composition and the same type / system pair.

Codes are COMPUTED, never looked up. A table for ipa mesh would be over a gigabyte, so each code is a mixed-radix index: the base picks an offset and each axis contributes a digit whose radix is how many marks that axis offers that base. The only tables are the bases, the axes and a per-base offset, a few thousand integers, so the package ships no code registry.

Counting the space

from talk import count_space, count_attested, report_space

count_space(type="ipa", system="mesh", space="producible")  # 166167936
count_attested(phonemes=corpus, type="tone", system="mesh")
report_space(corpus)   # all eighteen numbers

Three counts matter and they differ by orders of magnitude. ATTESTED is what some documented language is recorded saying. PRODUCIBLE is what a human vocal tract can make. PERMITTED is what the notation can write, articulation ignored. A conlang tool wants the middle one, because a designed language draws from sounds nobody happens to use: only 2,161 of tone mesh's 25,426 producible sounds are attested anywhere.

Choosing a tier

The number that decides it is not vocabulary size but how often a tier MERGES two sounds some language contrasts. Across Phoible's 3,020 doculects, tone mesh still costs 29% of documented languages a distinction, because talk's base inventory is deliberately coarse and no tier setting recovers that. If a merged contrast would be a bug, use ipa.

How it works

Everything derives from two data files in code/talk/base/ and a double-array trie scan, with no runtime dependencies.

  • phones.json is the base inventory, one row per IPA symbol with its place, manner and voicing.
  • modifiers.json is the affixes, each with the axis it varies and the rule saying where it can attach.

Attachment rules are what keep the space honest. Aspiration needs a plosive or a fricative and refuses the glottal place, so is never generated. A nasal cannot take a nasal release.

Development

uv sync
uv run pytest        # 122 tests
uv run ruff check
python code/make/copy_base.py   # refresh the shared data

The shared data lives in the repo-root base/; copy_base.py copies what the runtime reads into this package. Edit the shared copy, not this one.

License

MIT

ClueSurf

Built by ClueSurf.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cluesurf_talk-3.0.0.tar.gz (34.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cluesurf_talk-3.0.0-py3-none-any.whl (40.4 kB view details)

Uploaded Python 3

File details

Details for the file cluesurf_talk-3.0.0.tar.gz.

File metadata

  • Download URL: cluesurf_talk-3.0.0.tar.gz
  • Upload date:
  • Size: 34.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for cluesurf_talk-3.0.0.tar.gz
Algorithm Hash digest
SHA256 e750a33d2f5b8fc7057e0c25bfd70e8779d88ba753d0075089902654ce98e269
MD5 75fb23eeffc36f9938c3460580a19acf
BLAKE2b-256 1ca574752ce15e5db4331e40487dfcc1c9f68be6098f50cdacba815d0c387ee1

See more details on using hashes here.

File details

Details for the file cluesurf_talk-3.0.0-py3-none-any.whl.

File metadata

  • Download URL: cluesurf_talk-3.0.0-py3-none-any.whl
  • Upload date:
  • Size: 40.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for cluesurf_talk-3.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 348643d953d107b03d88e3a825a8e86e58135f79f408cc8e3f7100f05d080d9b
MD5 f217c3ae83576bf16597dcc3bed2fd2c
BLAKE2b-256 914d3f5b3733b2d54e3dca979c985ed65255f982c43ad19dbf9a9c276e7e4060

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page