adc(...) — Audio Input as a Signal Source

adc() opens the live audio input and publishes what it hears on the control plane, so any cue in the score can be driven by the sound in the room. It is named after adc~ in Pd and Max, and behaves the way that name implies: it is where sound comes in, and its measurements are outlets you patch from.

adc()
synth(uid:s1, freq: follow(adc.pitch, 90, 2000))
scale(uid:box, sx: map(adc.amp, 0, 0.4, 0.5, 3))

Syntax

adc()
adc(uid:NAME)
adc(ch:l)
adc(ch:l, uid:left)
adc(off:1)

Parameters

param required description
uid ✖ Publish under this name instead of adc. Two mics with different uids are two independent sources.
ch ✖ Which channel to listen to: l/left/0, r/right/1, or mix (the default). Higher indices work on multi-input interfaces.
off ✖ off:1 stops. With a uid, stops only that one; on its own, releases the microphone entirely.

off:, not stop:. stop is a cue name in the grammar, so adc(stop:1) is read as the stop() cue and fails to parse.


Outlets

Ten measurements, published as <uid>.<channel>:

channel range what it carries
amp 0–1 RMS amplitude, smoothed — overall loudness
peak 0–1 Peak amplitude, unsmoothed
centroid 0–1 Spectral centroid — brightness
onset 0–1 Spikes to 1 on an attack, then decays
low 0–1 Low band, ~0–300 Hz
mid 0–1 Mid band, ~300–2000 Hz
high 0–1 High band, ~2000 Hz up
pitch Hz Detected pitch, 0 when there is no clear one
note 0–127 The same pitch as a MIDI note number (60 = middle C)
pitchConf 0–1 How much to trust pitch

Eight of these are already 0–1, so follow() is enough. pitch and note are not, which is what map() is for:

fade(uid:glow, opacity: follow(adc.centroid))
scale(uid:b, sx: map(adc.pitch, 80, 800, 0.4, 3))

It needs a gesture

Browsers refuse getUserMedia unless something the performer did led to it, so an adc() that fires from the playhead at load will usually be blocked. The reliable way in is a button:

button(label:"START LISTENING", trigger:adc())
button(label:"STOP", trigger:adc(off:1))

The failure is logged rather than thrown, so a score without permission still runs — anything bound to adc.* simply never moves. Once the input is open, firing adc() again does nothing, so it is safe to place one on every page of a multi-page score.


Stereo

ch: picks one channel. A pair is two cues with two uids:

adc(ch:l, uid:left)
adc(ch:r, uid:right)

scale(uid:lBox, sy: map(left.amp,  0, 0.35, 0.05, 1))
scale(uid:rBox, sy: map(right.amp, 0, 0.35, 0.05, 1))

Both taps share one input, so there is only ever one permission prompt however many channels a score listens to — and a second tap on an already-open stream costs nothing, needing no gesture of its own. Each keeps its own onset envelope and its own smoothed amplitude and pitch; they are independent sources, not two views of one.

The channel count is requested as ideal, never required, because a hard constraint would be refused outright by the mono microphone most people actually have. On a mono input, ch:r logs a warning and reads channel 0 rather than silently reporting nothing.


The mic object

adc() does not need a drawing, but it is usually better with one. The + button in the top bar creates a mic element — an adc() cue with a small microphone drawn on the score, with fields for uid, channel, size, colour and show/hide. See the DSL inspector.

The reason to place one is the connections view: a source with no element has nothing to anchor a cord to, so follow(adc.amp, …) draws as a dangling, unresolved connection. Give it a body and it becomes an object with ten outlets like any other. A hidden mic still listens and still has a position, so the cords still reach it.


Demo

See demo-adc — level and peak, the three bands, pitch and brightness, and a stereo pair as two independent sources. Press START LISTENING at B first; nothing moves until the input is open.

http://localhost:8001/?project=demo-adc


See Also

Tip: use ← → or ↑ ↓ to navigate the docs