Skip to content
Sign in

/docs · SignalLab · Intro

A useful tag schema for audio archives

What to put in your audio metadata so downstream tools can actually use it.

Updated May 11, 2026


Most audio archives die from the same problem: bad metadata. Files are uploaded with final_v2_FINAL.wav and a vague folder name, and a year later nobody can find anything.

A tag schema that survives is one with a few firm rules and a lot of forgiveness on everything else. Here’s the schema SignalLab emits for every indexed file, and why each tag earns its place.

The core tags

Every tag follows the pattern namespace:value so downstream tools can filter and group cleanly.

content:*

The big one. voice, music, mixed, noise, or silence. This is the tag your editor needs first, before anything else. If a file is content:silence, nothing downstream needs to look at it.

noise means steady background noise (hum, hiss, air conditioning, a crowd), not every sound that is neither speech nor music. mixed means that part of the file reads as speech and part as music; it does not detect speech over music. The content type is a proxy. The website, and the API with contentModel: "v2", use the new model: on 600 real excerpts plus three environments it had never seen it found 197 of 200 speech and 190 of 200 music excerpts and 40 of 90 steady-noise ones (street traffic and the metro mostly read unknown). The first model, which the API returns until 15 January 2027, did much worse: it recognised noise in only 3 of 200 and took a lot of music and noise for speech. Use the content type as a hint for triage, not as a result. The numbers are under signal.contentType on the Lenses page.

sample-rate:*, channels:*

Technical facts, useful for filtering (“show me only the 48 kHz stereo voiceovers”) and for routing files to the right pipeline. Note the indexer does not emit a container format or a bit depth: it works on decoded audio, so by the time it runs those are properties of the decode, not of the signal.

brightness:*, dynamics:*

Spectral and dynamic character buckets: dark/balanced/bright/very-bright and flat/compressed/modern/dynamic. These are useful for search and for downstream processing decisions. A voiceover tagged brightness:very-bright probably needs a de-esser.

issue:*

The most actionable family. issue:clipping, issue:noisy, issue:dc-offset, issue:lots-of-silence. These map directly to QA workflows: “fail any file with issue:clipping at ingest” is a one-line rule.

hint:*

Softer signals. hint:has-headroom, hint:loud, hint:mono-content-in-stereo. These are for tools that want context but shouldn’t fail on them.

What the schema deliberately doesn’t include

  • Mood tags (happy, melancholic, etc.). These are unreliable from signal alone and lock you into a controlled vocabulary that ages badly.
  • Genre tags. Same problem, worse. Genre classification is a user-facing job, not a metadata-layer one.
  • Speaker identity. Personally identifying. Should be opt-in and live in a separate namespace.
  • Free-form descriptions. Lovely for humans, terrible for downstream automation.

The discipline is: only tag what can be reliably computed and reliably consumed. The rest belongs in a human-curated layer or in the user-facing app, not in the schema.

A worked example

For a 12-minute podcast interview at 48k/16-bit stereo:

content:voice
brightness:balanced
dynamics:modern
sample-rate:48000
channels:stereo
hint:has-headroom

Six tags on a clean file. A file with problems picks up issue:* as well (issue:clipping, issue:dc-offset, issue:noisy, issue:lots-of-silence), and the other hint:* values are hint:loud and hint:mono-content-in-stereo. Seven namespaces in total: content, brightness, dynamics, sample-rate, channels, issue, hint. Every one can be queried, every one can be filtered on, every one was computed automatically. The numbers you might expect as tags (duration, peak, RMS, noise floor, the content-type confidence) come back as fields on the result, not as tags, because ranges do not filter well as strings. No “interview”, no “Alex_and_Sara_episode_42”, no “great episode but room sounds off”. Those belong in your CMS.

Why this matters

Audio is a wretched format to grep through. The only reason an audio archive scales past a few thousand files is the metadata layer. A schema like this is the thing that lets a downstream editor say: “Show me every voice-content file under five minutes, no clipping, brightness balanced, recorded since March.” Without that, you’re asking someone to listen.

Next in SignalLab docs

Streaming clipping detection at scale →

How to detect clipping in audio at ingest time without decoding the whole file.

More in SignalLab docs