Detect tempo (auto-BPM, experimental)
detect_tempoDetects tempo (BPM) from audio sources by analyzing beat onsets, and can automatically write the detected tempo to the global timeline for synchronization.
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 |