/docs · General · Practical
Is my audio upsampled?
One call per file and one field to read: bandLimit.upsampled says yes, no or cannot-say, with the reason in plain words. What to do with each answer, how often each came out in our tests, and what it cannot see.
Updated Nov 10, 2026
Who this is for
You build or buy speech for a dataset that should be wideband, and you want to know which files only look that way. The sample rate in a header says how a file is stored, not what is in it: a telephone call stored at 16 or 48 kHz still stops near 4 kHz.
This page gives you one call, one field to read, and what to do with each answer. You do not need to know how the engine decides: the limits are in the answer itself.
1. Call it
Add bandLimit to a request to the signal analysis. For one local file with curl:
curl -s "https://audiolab.tools/v1/signallab?bandLimit=true" \
-H "Authorization: Bearer $AUDIOLAB_KEY" \
-F file=@recording.wav
For a file at a public URL, send JSON instead:
curl -s https://audiolab.tools/v1/signallab \
-H "Authorization: Bearer $AUDIOLAB_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/recording.wav", "bandLimit": true}'
With the Python client (pip install audiolabtools), one file, then a folder 20 files at a time into a CSV:
import csv
from pathlib import Path
from audiolabtools import AudioLab
lab = AudioLab() # reads AUDIOLAB_KEY
band = lab.signal("recording.wav", bandLimit=True)["bandLimit"]
print(band["upsampled"], band["reason"])
files = sorted(str(p) for p in Path("recordings").glob("*.wav"))
with open("upsampled.csv", "w", newline="", encoding="utf-8") as f:
out = csv.writer(f)
out.writerow(["file", "upsampled", "ratio", "reason"])
for i in range(0, len(files), 20):
chunk = files[i : i + 20]
answer = lab.batch(chunk, endpoint="signallab", bandLimit=True)
for name, r in zip(chunk, answer["results"]):
b = (r.get("data") or {}).get("bandLimit") or {}
out.writerow([name, b.get("upsampled", "error"), b.get("ratio"),
b.get("reason", r.get("error"))])
In an AI assistant with the AudioLab MCP server (version 0.5.1 or later), index_signal takes bandLimit: true, and so does analyze_batch with endpoint: "signallab/index", for 20 files at a time. Ask it, for example: “Which of these recordings were upsampled?”
Every file is one call and is uploaded to the API, hosted in the EU; only numbers come back. For a large folder, the dataset audit has a full script that paces itself, can sample, and picks up where it stopped.
2. Read one field
Read bandLimit.upsampled. It is yes, no or cannot-say. Next to it, bandLimit.reason says the same in plain words, with the bandwidth and the sample rate: copy it into your report as it is. This is the answer for a recording we brought down to 8 kHz and back up to 16 kHz:
{
"bandLimit": {
"upsampled": "yes",
"status": "validated",
"reason": "The band stops at 4.3 kHz in a 16 kHz file: the audio was probably at 8 kHz or less, as in a telephone call, before it was stored at this rate. In study UP-1, 0.1 to 1.8% of untouched recordings read the same way.",
"basis": [
{
"check": "telephone-origin (UP-1)",
"status": "validated",
"result": "fires"
},
{
"check": "band-limit ratio (UP-2)",
"status": "proxy",
"result": "band-limited",
"ratio": 0.537
}
],
"bandwidthHz": 4296.9,
"sampleRate": 16000,
"ratio": 0.537,
"verdict": "band-limited",
"reasonCode": "ratio-below-L"
}
}
status is validated only for a yes. basis lists each condition the answer rests on, with its own status, so you can see why. You do not need it to act.
3. What to do with each answer
upsampled | What it means | What to do |
|---|---|---|
yes | The band stops under 5 kHz in a file of 16 kHz or more, for at least 2 seconds: the audio was probably at 8 kHz or less, as in a telephone call, before it was stored at this rate. Status validated (study UP-1). | Do not use it as native wideband. |
no | The band reaches half the sample rate: no sign of upsampling. Status proxy (study UP-2). | Nothing to do. |
cannot-say | Everything else: a band that stops early without the telephone pattern, a band between 80 and 90 percent of half the sample rate, a file under 2 seconds, a tonal spectrum, or silence. The reason says which. | Set it aside. If your dataset may only hold native wideband, leave it out or listen to it. If you need a number to filter on, bandLimit.ratio is the bandwidth over half the sample rate. |
Why a band that only stops early is not a yes: a narrow source looks the same. In study UP-2, a LibriSpeech speaker recorded at its own rate read as band-limited, and so would a microphone or a filter that cuts the top.
4. How often each answer came out in our tests
We read the recordings of both studies again with the decision, on 10 November 2026. The two rules were fixed before those studies ran, and how they combine into one answer was fixed before this reading, so this is a description of how the three answers fall, not a new test. The UP-1 recordings were read twice, at their own rate and decoded at 48 kHz, so the counts are readings, not files.
| Kind of recording | Readings | yes | no | cannot-say |
|---|---|---|---|---|
| Through an 8 kHz telephone codec and back to 16 or 48 kHz (UP-1: G.711, AMR, GSM) | 4,692 | 4,608 (98.2%) | 0 | 84 (1.8%) |
| Through a telephone codec (UP-2: AMR, G.711, GSM) | 90 | 90 (100%) | 0 | 0 |
| Upsampled from 4 kHz | 450 | 443 (98.4%) | 0 | 7 (1.6%) |
| Upsampled from 8 kHz | 450 | 436 (96.9%) | 0 | 14 (3.1%) |
| Upsampled from 11.025 kHz | 450 | 1 (0.2%) | 0 | 449 (99.8%) |
| Upsampled from 16 kHz to 44.1 or 48 kHz | 3,428 | 5 (0.1%) | 0 | 3,423 (99.9%) |
| FLEURS speech at its own 16 kHz | 1,082 | 14 (1.3%) | 1,032 (95.4%) | 36 (3.3%) |
| LibriSpeech speech at its own 16 kHz | 150 | 0 | 141 (94.0%) | 9 (6.0%) |
| Speech cut off at 6 kHz, at its own 16 kHz | 782 | 17 (2.2%) | 1 (0.1%) | 764 (97.7%) |
| Speech through a lossy codec (MP3 32 to 128 kbit/s, AAC 48, Opus 16) | 300 | 0 | 130 (43.3%) | 170 (56.7%) |
What that means for you:
- No upsampled reading got a
no: 0 of 9,560. yesfinds the telephone pattern and upsampling from 4 or 8 kHz. Upsampling from 11.025 kHz or more comes outcannot-say, almost neveryes. So readcannot-sayas “look at this”, not as “probably fine”.- On speech at its own rate, a
yeswas wrong for 14 of 1,082 FLEURS readings (1.3%) and none of the 150 LibriSpeech readings. Speech cut off at 6 kHz readyesin 17 of 782 (2.2%).
What it cannot see
- Real telephone lines, VoIP codecs (Opus, G.722) and Bluetooth headsets. UP-1 used telephone codecs we ran ourselves.
- Native 44.1 and 48 kHz recordings: how often they would read
cannot-sayis not measured. A 44.1 kHz source stored at 48 kHz readsno; the rule cannot see that step. - An upsampler that makes up high frequencies of its own, such as a model that restores the band, reads
no. - It names no source rate, apart from the telephone origin.
The two studies, with their pre-registration and results, are on the studies page. What the band limit was tested on is also on its page.
Next in General docs
Read a response: what each field means and how far to trust it →
A real answer from the API, field by field: what it says, its status and margin, and what you may and may not conclude from it.
More in General docs
- Practical
Compare voice-agent and TTS vendors, and check conversational audio
Three API calls, ten numbers, and how far to trust each one: a guide for QA teams comparing voice-agent, text-to-speech or voice-isolation vendors.
- Practical
Check audio quality in CI: fail a build when a file breaks your rules
A short Python script and a GitHub workflow that measure each audio file with the AudioLab API, compare the numbers with limits you set, and fail the build with a message that says why.
- Practical
Audit a dataset of conversations: where the audio really comes from
Measure a folder of call, voice-agent or text-to-speech recordings for upsampling, a lossy source, splices, mono in disguise, clipping and bit depth, 20 files at a time, and know when the audio is uploaded and when it is not.
- Intro
What AudioLab does not do
The limits of the analysis, stated plainly: it does not transcribe, predict recognition errors, score naturalness, identify speakers or measure latency, and its background hints are guesses.
- Intro
Changes and deprecation: what changes, when, and how you find out
The promise behind /v1, what counts as a change that needs notice, how we announce it, and what is deprecated today.