chirp-sync
An acoustic slate for grouping and synchronizing multi-camera recordings. Roll every camera, play one short chirp, and recover the same take ID and precise acoustic sync point from every recording that heard it.
- Web generator: https://labtec901.github.io/chirp-sync/
- Python package: https://pypi.org/project/chirp-sync/
- Source: https://github.com/labtec901/chirp-sync
The acoustic payload is intentionally fixed: every chirp carries one random 40-bit take ID.
Installation
The CLI supports Python 3.10 and newer. Installing with pipx keeps command-line applications isolated:
pipx install chirp-sync
Installing with pip is also supported:
python -m pip install chirp-sync
FFmpeg must be available on PATH to scan
MP4, MOV, MP3, M4A, and other camera formats. A built-in WAV reader covers WAV
files. The microphone listener is optional:
python -m pip install "chirp-sync[mic]"
Typical workflow
- Open the web generator on a phone.
- Start every camera and audio recorder.
- Press Play chirp before the take.
- Scan the recordings afterward:
chirp-sync scan /path/to/recordings
Files with the same ID are grouped together and given offsets on a shared timeline. The chirp arrival is measured from each recording's own audio.
Prefix decoded IDs onto filenames
Preview the in-place rename first:
chirp-sync scan /path/to/recordings --prepend-id --dry-run
Then apply it:
chirp-sync scan /path/to/recordings --prepend-id
For example:
camera-a.mov -> ZY41WN7M_camera-a.mov
camera-b.mp4 -> ZY41WN7M_camera-b.mp4
Name collisions receive a numeric suffix, already-prefixed files are treated as complete, and recordings containing multiple take IDs are flagged for manual naming.
Export or organize a shoot
# Write every supported timeline/report format.
chirp-sync scan recordings --all-exports --outdir exports
# Copy files into take-ID folders.
chirp-sync scan recordings --organize sorted
# Preview moving instead of copying.
chirp-sync scan recordings --organize sorted --move --dry-run
Available exports are CSV, JSON, Final Cut Pro XML, and one CMX3600 EDL per take.
CLI reference
chirp-sync gen
Generate a WAV with a fresh random take ID. The balanced profile is the default.
chirp-sync gen
chirp-sync gen --take X4THAPJ9
chirp-sync gen --profile robust --repeats 2 -o stage.wav
Options control sample rate, peak level, lead-in, lead-out, repeat count, repeat gap, and PCM16 or float32 WAV output.
chirp-sync scan
Recursively scan files and directories, group matching IDs, calculate relative offsets, export timelines, organize copies, or prepend IDs in place.
chirp-sync scan PATH [PATH ...]
chirp-sync scan recordings --profile fast
chirp-sync scan recordings --json results.json
chirp-sync scan recordings --prepend-id --dry-run
Automatic profile detection is the scan default.
chirp-sync info
Inspect one recording in detail:
chirp-sync info recording.mov
The report includes media properties, take ID, chirp arrival time, profile, detection score, clarity, and direct-path strength.
chirp-sync listen
Record briefly from the desktop microphone and check that a chirp can be decoded in the room:
chirp-sync listen --seconds 20
Run chirp-sync COMMAND --help for every option.
Profiles
| Profile | SF | Symbol | Data symbols | Complete burst | Intended use |
|---|---|---|---|---|---|
fast |
7 | 32 ms | 24 | 1.088 s | Normal close-range use |
balanced (default) |
8 | 64 ms | 21 | 1.984 s | More range or reverberation |
robust |
9 | 128 ms | 19 | 3.712 s | Large, noisy, or echoing rooms |
The website adds 0.15 seconds of silence at each end. The CLI defaults to 0.25 seconds at each end. The table reports the encoded burst before that padding.
Encoding specification
The fixed frame is:
[ 8 unshifted up-chirps ][ 2 unshifted down-chirps ][ encoded ID symbols ]
preamble SFD protected data
The encoded block begins as exactly seven bytes:
[ five-byte unsigned take ID ][ two-byte CRC-16 ]
Integers and bit groups are most-significant-byte and most-significant-bit first unless stated otherwise.
- The displayed eight-character Crockford-base32 ID represents a 40-bit unsigned integer. The audio representation uses the five raw bytes.
- Append a big-endian CRC-16/CCITT-FALSE over those bytes. Parameters are
polynomial
0x1021, initial value0xffff, no reflection, and final XOR0x0000. - XOR all seven bytes with PN9 whitening using
x^9 + x^5 + 1, initial state0x1ff, and least-significant-bit-first mask output. The fixed mask isff e1 1d 9a ed 85 33. - Unpack MSB-first and encode the 56 bits with a zero-terminated,
constraint-length-7 convolutional code using octal generators
(171, 133, 165). Six zero tail bits terminate the trellis. The third parity output is omitted whenstep mod 3 == 2, producing 166 coded bits. - Zero-pad to a whole CSS symbol and apply the deterministic stride
interleaver. The padded length and stride are
(168, 103)for fast and balanced, and(171, 106)for robust. - Group into
SF-bit valuesvand Gray-map each CSS shift asg = v XOR (v >> 1).
Each data value selects a cyclic shift of a continuous-phase linear up-chirp in
the 1 to 5 kHz band. With N = 2^SF, bandwidth BW = 4000 Hz, and
Ts = N / BW, the instantaneous frequency is:
f(t) = 1000 + 4000 * ((t / Ts + g / N) mod 1), 0 <= t < Ts
The receiver finds the preamble, confirms the down-chirp delimiter, estimates the room's delay profile, obtains soft bit likelihoods from the CSS symbols, deinterleaves, runs a 64-state Viterbi decoder, removes whitening, and accepts the take ID only when its CRC passes.
Audio files and privacy
chirp-sync gen writes 48 kHz mono signed 16-bit PCM WAV by default and
normalizes the peak to -3 dBFS. --float32 selects 32-bit floating-point PCM.
The protocol supports recordings stored with common lossy camera codecs.
The web generator runs in the browser and stores its session log in browser storage.
Python API
from chirpsync import detect, generate
chirp = generate() # balanced profile by default
detections = detect(chirp.audio, chirp.sample_rate)
assert detections[0].take == chirp.payload.take
Development
git clone https://github.com/labtec901/chirp-sync.git
cd chirp-sync
python -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"
python -m pytest
ruff check .
python -m build
python -m twine check dist/*
Node.js is required for browser and Python encoder parity tests. FFmpeg is required for full media and codec simulation tests.
GitHub Actions tests Python 3.10 through 3.13, deploys webapp/ to GitHub Pages,
and publishes signed distributions to PyPI when a GitHub release is published.
PyPI publication uses trusted publishing rather than a long-lived API token.
License
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file chirp_sync-1.0.1.tar.gz.
File metadata
- Download URL: chirp_sync-1.0.1.tar.gz
- Upload date:
- Size: 63.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b7a3cf6bcefb89bf743035901c6fa9029a6c9e56c427ff3914f02258e2171bbe
|
|
| MD5 |
141a3e5b3ceb1715494b0c179b3c53ab
|
|
| BLAKE2b-256 |
892ef5f103a24a4ef45f2c8553eedf8d8fed0d1881aec1ccbeff3ee794731f05
|
Provenance
The following attestation bundles were made for chirp_sync-1.0.1.tar.gz:
Publisher:
publish.yml on labtec901/chirp-sync
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
chirp_sync-1.0.1.tar.gz -
Subject digest:
b7a3cf6bcefb89bf743035901c6fa9029a6c9e56c427ff3914f02258e2171bbe - Sigstore transparency entry: 2282453873
- Sigstore integration time:
-
Permalink:
labtec901/chirp-sync@283fd4c4cd50c5e55344c7d910d7bf65fc96fb8d -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/labtec901
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@283fd4c4cd50c5e55344c7d910d7bf65fc96fb8d -
Trigger Event:
release
-
Statement type:
File details
Details for the file chirp_sync-1.0.1-py3-none-any.whl.
File metadata
- Download URL: chirp_sync-1.0.1-py3-none-any.whl
- Upload date:
- Size: 39.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c26ef021f01e8abb9f3ce9a35b8bc5dc5c360fc01911ae833ed1e5e8f17ad0b3
|
|
| MD5 |
a6eb367fa099582ba1d3ecc990f28512
|
|
| BLAKE2b-256 |
c267675bffa5512f37845d3bb11cea80c9552a434e11b6f826e113a2ee8587ca
|
Provenance
The following attestation bundles were made for chirp_sync-1.0.1-py3-none-any.whl:
Publisher:
publish.yml on labtec901/chirp-sync
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
chirp_sync-1.0.1-py3-none-any.whl -
Subject digest:
c26ef021f01e8abb9f3ce9a35b8bc5dc5c360fc01911ae833ed1e5e8f17ad0b3 - Sigstore transparency entry: 2282453892
- Sigstore integration time:
-
Permalink:
labtec901/chirp-sync@283fd4c4cd50c5e55344c7d910d7bf65fc96fb8d -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/labtec901
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@283fd4c4cd50c5e55344c7d910d7bf65fc96fb8d -
Trigger Event:
release
-
Statement type: