Detect tempo (auto-BPM, experimental)
detect_tempoDetects the tempo (BPM) of live audio or a file without manual tapping and optionally drives the global project tempo.
Instructions
EXPERIMENTAL automatic tempo (BPM) detection WITHOUT manual tapping. Detects beat onsets in live audio (kick band → RMS energy → moving-baseline threshold, reusing detect_onsets' primitive), measures the time between beats, and reduces the recent inter-onset intervals to a stable tempo (median → BPM = 60/interval) exposed as a bpm channel on a Null CHOP — bind a parameter to op('…/detect_tempo/bpm')['bpm']. Complements sync_external_clock (which is tap-tempo) and detect_onsets (which flags hits but derives no tempo). With drive_tempo on, it writes the detected BPM to the global tempo (op('/').time.tempo) so every Beat CHOP — create_tempo_sync, create_autopilot — follows the music automatically. Source defaults to a synthetic gated tone (device capture can hang TD on a macOS permission modal); also accepts a file, an existing CHOP, or the live device. Caveats: time-dependent (reads 0 on a paused timeline), can lock to half/double time, and must be tuned live per source (Threshold + Smoothing knobs).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| source | No | Audio source. Defaults to 'synthetic' (an internal gated tone at a known rate) because live device capture can hang TouchDesigner on a one-time macOS microphone-permission modal — same default rationale as extract_audio_features / detect_pitch. 'device' = live microphone/line in (creating it may pop that permission dialog — click Allow). 'file' = an audio file. 'existing' = reuse a CHOP you already have. | synthetic |
| file | No | Audio file path (source='file'). | |
| audio_in | No | Path of an existing audio CHOP to analyze (source='existing'). | |
| sensitivity | No | Onset-detection sensitivity 0..1. Higher = lower threshold = more beats registered (and a faster, twitchier lock); lower = only strong transients count. It maps to the excess-over-baseline threshold the kick band must clear (band-RMS magnitudes are tiny, so the usable window is small — tune live per source). | |
| min_bpm | No | Lower clamp on the reported tempo. Also rejects implausibly long gaps between beats (an interval longer than 60/min_bpm seconds is ignored, so a missed beat can't halve the tempo). | |
| max_bpm | No | Upper clamp on the reported tempo. Also rejects too-short intervals (a double-trigger shorter than 60/max_bpm seconds is ignored, so a stray transient can't double the tempo). | |
| drive_tempo | No | When true, the engine also writes the detected BPM to the project's global tempo (op('/').time.tempo), so every Beat CHOP downstream — create_tempo_sync, create_autopilot — follows the detected beat automatically (same write as sync_external_clock). | |
| expose_controls | No | Expose live 'Threshold' (onset sensitivity — lower fires on more beats) and 'Smoothing' (how many recent intervals the median locks over — higher = steadier, slower to react) knobs. | |
| name | No | Name for the generated system container. | detect_tempo |
| parent_path | No | Parent COMP path the generated system container (see `name`) is created inside. | /project1 |