Skip to main content

chirp-sync

CI PyPI Python License: MIT

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.

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

  1. Open the web generator on a phone.
  2. Start every camera and audio recorder.
  3. Press Play chirp before the take.
  4. 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.

  1. The displayed eight-character Crockford-base32 ID represents a 40-bit unsigned integer. The audio representation uses the five raw bytes.
  2. Append a big-endian CRC-16/CCITT-FALSE over those bytes. Parameters are polynomial 0x1021, initial value 0xffff, no reflection, and final XOR 0x0000.
  3. XOR all seven bytes with PN9 whitening using x^9 + x^5 + 1, initial state 0x1ff, and least-significant-bit-first mask output. The fixed mask is ff e1 1d 9a ed 85 33.
  4. 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 when step mod 3 == 2, producing 166 coded bits.
  5. 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.
  6. Group into SF-bit values v and Gray-map each CSS shift as g = 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

MIT

Download files

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

Source Distribution

chirp_sync-1.0.1.tar.gz (63.7 kB view details)

Uploaded Source

Built Distribution

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

chirp_sync-1.0.1-py3-none-any.whl (39.3 kB view details)

Uploaded Python 3

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

Hashes for chirp_sync-1.0.1.tar.gz
Algorithm Hash digest
SHA256 b7a3cf6bcefb89bf743035901c6fa9029a6c9e56c427ff3914f02258e2171bbe
MD5 141a3e5b3ceb1715494b0c179b3c53ab
BLAKE2b-256 892ef5f103a24a4ef45f2c8553eedf8d8fed0d1881aec1ccbeff3ee794731f05

See more details on using hashes here.

Provenance

The following attestation bundles were made for chirp_sync-1.0.1.tar.gz:

Publisher: publish.yml on labtec901/chirp-sync

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for chirp_sync-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c26ef021f01e8abb9f3ce9a35b8bc5dc5c360fc01911ae833ed1e5e8f17ad0b3
MD5 a6eb367fa099582ba1d3ecc990f28512
BLAKE2b-256 c267675bffa5512f37845d3bb11cea80c9552a434e11b6f826e113a2ee8587ca

See more details on using hashes here.

Provenance

The following attestation bundles were made for chirp_sync-1.0.1-py3-none-any.whl:

Publisher: publish.yml on labtec901/chirp-sync

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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