Skip to content
Sign in

/api

Live · self-serve keys

Audio analysis as an API.

Most teams script ffmpeg for loudness checks, or ship audio to a cloud they don’t control. AudioLab puts loudness, voice quality, and signal analysis behind one key, and it can run right in the browser, so the audio never has to leave the user’s device.

One key, three labs Playground runs client-side EU-hosted API Loudness checked against EBU Tech 3341
Your first call
Your first call

From nothing to a real response in under two minutes. No account required to see the shape.

Endpoints
Endpoints

Each takes a multipart audio file, or a JSON body with a public url, and returns structured JSON. Full schemas live in the OpenAPI spec.

  • POST /v1/mixlab/analyze

    MixLab · loudness + dynamics

    Loudness (BS.1770-4), true-peak, loudness range, crest factor, stereo image, and a tonal-balance spectrum.

    Know if a track hits −14 LUFS, clips, or has a boomy low-end, before it ships.

    Request, response and errors

  • POST /v1/voicelab/qa

    VoiceLab · speech quality

    Speech quality: speech/silence ratio, pacing, signal-to-noise, energy in the pauses, sibilance, and clipping risk.

    Catch a noisy or clipped voice take automatically.

    Request, response and errors

  • POST /v1/signallab

    SignalLab · index + tags

    A metadata index: content type, tags, clipping/silence regions, brightness and dynamics buckets, file metadata.

    Tag and triage a whole library: what is it, is it clean, where is the silence.

    Request, response and errors

  • POST /v1/signallab/sample

    One sound from a sample library, not a recording: material and structure, plus the character vector for a single hit or tempo and loop QC for a phrase. Whatever could not be measured carries its reason.

    Request, response and errors

  • POST /v1/analyze/profile

    Measure against a named profile and get back only the lenses that question needs, keyed by stable lens id. Eleven profiles: basic (free), voice, master, provenance, dataset, environment, broadcast, loop, room (reverberation from a clap), chain (lost packets) and pitch (where a voice sits and how clean it is). Add series:true for the curves and per-block lanes.

    Request, response and errors

  • POST /v1/mixlab/check-target

    Pass or fail against a delivery target (Spotify, Apple Music, YouTube, podcast, EBU and others, or your own LUFS and true peak), with the delta per measure and, on a fail, an ffmpeg loudnorm command.

    Request, response and errors

  • POST /v1/mixlab/timeseries

    Short-term loudness about ten times a second, with its time-base, plus downsampled waveform peaks: for loudness charts and level meters.

    Request, response and errors

  • POST /v1/mixlab/spectrum

    FFT bins and seven band energies with the spectral descriptors (centroid, rolloff, flatness): for spectrum displays and tonal-balance diagnosis.

    Request, response and errors

  • POST /v1/voicelab/segments

    Voiced speech regions with start and end times and the level of each: when speech happens, not who is speaking. For auto-trim and chapters.

    Request, response and errors

  • POST /v1/batch

    Run any analysis route over up to 20 items in one call: URLs and/or uploaded objectPaths (local files). Each item is metered as one call; per-item ok/error in the response.

    Request, response and errors

  • GET /v1/usage

    Where your key stands this month: plan, calls and data used against the limits the API enforces, and your requests per minute. The same numbers as /account. Needs a key. Reading it is free and does not count as a call.

    Request, response and errors

See it on your own file

This is the API, running client-side. Drop a file, switch endpoints, and copy a request that returns the exact JSON you see. Your file is not uploaded; it stays in the browser.

api · playground · runs in your browser

This playground runs the identical engine client-side, so the response below is exactly what the hosted API returns. Your file never leaves the browser. The hosted API is live with self-serve keys at audiolab.tools/v1/*.

Request
curl https://audiolab.tools/v1/mixlab/analyze \
  -H "Authorization: Bearer $AUDIOLAB_KEY" \
  -F file=@track.wav

Loudness, dynamics, spectrum

Response
Drop a file to see the responsematches public/openapi.yaml · /v1/mixlab/analyze
Response schema

Every endpoint, from the request to the answer field by field, with the status and the margin of each number, the errors it can give, and a box to try it with your own key. Generated from the OpenAPI contract, so it cannot drift from what the API sends. To try without uploading anything, use the playground above: it runs the engine in your browser.

POST /v1/mixlab/analyze Analyze loudness, dynamics, stereo, and spectrum 37 fields

Submit an audio file and get back the same JSON the in-browser MixLab analyzer renders. Every analysis returns inline; there is no async path. Files too long to decode are refused with 413 rather than queued.

Request

Send a public url (up to 150 MB), a small file as the multipart field file or as the raw body with an audio content type (about 4.5 MB), or an objectPath after a signed upload. A file you send is uploaded to the API: see /privacy for what is kept.

JSON field Type Notes
url string Public http(s) URL to the audio file (alternative to multipart upload).
objectPath string Path returned by /api/upload-url, for audio that has no public URL. Readable only by the key that uploaded it, and kept for about an hour so a follow-up question about the same file does not need a re-upload.
series boolean Send the curves as well: shortTermLufs, waveform and spectrum. Off by default since 22 September 2026, because they are ~98% of the payload and no answer needs them. Raw or multipart callers use ?series=true.
round boolean Round the numbers to what the measurement is worth: dB and LUFS to 2 decimals, seconds to 3, shares to 3, Hz to 1. Same keys, same types, only fewer decimals. Off by default: without it you get the full precision, exactly as before. Supported on mixlab/analyze, voicelab/qa, signallab and analyze/profile.
measureStatus boolean Add one extra key, measureStatus, with the status (validated, proxy, beta, withdrawn, planned), the basis, how it works (dsp, model, mixed) and, where known, the margin of every measure in the answer. Off by default: without it the answer has no extra key. Supported on mixlab/analyze, voicelab/qa, signallab and analyze/profile.

Example

curl https://audiolab.tools/v1/mixlab/analyze \
  -H "Authorization: Bearer $AUDIOLAB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://audiolab.tools/reference/is-original.mp3"}'

Response

MixLab analysis (mirrors the engine AnalysisResult type). The word next to a number says how far to trust it (the five statuses); a margin says how far it can be off. Add "measureStatus": true to the request to get the same status and margin inside the answer.

Field Type Status Notes
measureStatus MeasureStatus
durationSec* number Validated
sampleRate* integer Validated
channels* integer Validated
integratedLufs* number Validated Integrated loudness (LUFS), BS.1770-4. · ±0.1 LU
reportUrl string Shareable numbers-only report page for this analysis (https://audiolab.tools/r/<id>). Present on every metered analysis response.
shortTermLufsMax number Validated
loudnessRange number Validated LRA (LU). · ±1 LU
truePeakDb* number Validated True peak (dBTP). · +0.2 / -0.4 dB
peakDb number Validated
rmsDb number Validated
crestFactorDb number Validated
stereoWidth number Validated
stereoCorrelation number Validated
stereoBalanceDb number Validated RMS left minus right, dB. Positive is left louder. 0 on mono.
stereoLayout string Validated What kind of stereo file this is. dual-mono is two identical channels; one-sided is a dead channel. · mono | dual-mono | one-sided | stereo | silent
bassCorrelation number Validated Correlation below 120 Hz after a 4th-order low-pass. Null on mono or without energy there. Below 0 the low end cancels in mono.
momentaryLufsMax number Validated Loudest 400 ms window (EBU Tech 3341 M), LUFS. Ungated.
plrDb number Validated Peak to loudness ratio: true peak minus integrated, LU.
psrDb number Validated Peak to short-term ratio: true peak minus the loudest 3 s window, LU.
platformNormalisation object[] Validated Per platform: the gain it applies, the true peak after it, and whether that clears the ceiling. Read the peak AFTER the gain.
monoCompatible boolean Proxy
spectralCentroidHz number Validated
spectralRolloffHz number Validated
spectralFlatness number Validated
bandEnergy Band Validated
harshness.score number
harshness.label string Low | Medium | High
harshness.band string
muddiness.score number
muddiness.label string Low | Medium | High
spectrum.freqs number[]
spectrum.mags number[]
waveform number[] Validated Downsampled waveform peaks.
shortTermLufs number[] Validated Short-term loudness over time, at most 2000 points. Longer takes keep the PEAK per bucket, so a loud moment survives; seriesIntervalSec says how much time one point covers. Use /v1/mixlab/timeseries to choose the resolution yourself.
seriesIntervalSec number Seconds covered by one point of shortTermLufs.
fileName string

Errors

Every error carries a stable code and a docs_url: the cause, the fix and an example for each.

Try it with your key

This sends your URL or file to the EU-hosted API, so the audio leaves your device and counts as a call. The API keeps no audio: a direct request is decoded and discarded inside the request, and only numbers come back. Details on /privacy. To measure without uploading, use the playground above.

POST /v1/voicelab/qa Analyze speech quality 55 fields

Request

Send a public url (up to 150 MB), a small file as the multipart field file or as the raw body with an audio content type (about 4.5 MB), or an objectPath after a signed upload. A file you send is uploaded to the API: see /privacy for what is kept.

JSON field Type Notes
url string Public http(s) URL to the audio file (alternative to multipart upload).
objectPath string Path returned by /api/upload-url, for audio that has no public URL. Readable only by the key that uploaded it, and kept for about an hour so a follow-up question about the same file does not need a re-upload.
series boolean Send the curves as well: rmsEnvelope, voicedMask, segments and segmentalSnrPerSegmentDb. Off by default since 22 September 2026, because they are ~98% of the payload and no answer needs them. Raw or multipart callers use ?series=true.
round boolean Round the numbers to what the measurement is worth: dB and LUFS to 2 decimals, seconds to 3, shares to 3, Hz to 1. Same keys, same types, only fewer decimals. Off by default: without it you get the full precision, exactly as before. Supported on mixlab/analyze, voicelab/qa, signallab and analyze/profile.
measureStatus boolean Add one extra key, measureStatus, with the status (validated, proxy, beta, withdrawn, planned), the basis, how it works (dsp, model, mixed) and, where known, the margin of every measure in the answer. Off by default: without it the answer has no extra key. Supported on mixlab/analyze, voicelab/qa, signallab and analyze/profile.
speechDetector string Which speech detector finds the speech in the recording; it decides speechRatio, speechSec, silenceSec, longSilences, segments and the measures that read the pauses. v1 is the first detector and is the default until 15 January 2027; k2 lets a phrase run on into its soft word starts and endings (by at most 100 ms per side) and was better on new speakers in the tests (frame F1 from 0.88 to 0.94 on clean audio and noise at 20 and 10 dB; see the status of voice.speechRatio at https://audiolab.tools/lenses). The same keys and types in both, only the values differ: with k2 the speech ratio reads about 5 to 14 points higher, everything that reads the speech frames or the pauses moves with it, signalToNoiseDb is corrected below 16 dB and reads about 4 to 5 dB lower at 10 dB noise and below (closer to the true ratio), and a pause measure is null when no pause frame is left; brightness, sibilanceRisk, noiseFloorDb and peakDb do not move (details: https://audiolab.tools/docs/start/changes-and-deprecation). From 15 January 2027 the default becomes k2 and v1 stays selectable until at least 15 April 2027. Supported on voicelab/qa, voicelab/segments and analyze/profile. · v1 | k2

Example

curl https://audiolab.tools/v1/voicelab/qa \
  -H "Authorization: Bearer $AUDIOLAB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://audiolab.tools/samples/voice/speech-female-plain.mp3"}'

Response

VoiceLab speech-quality analysis (mirrors the engine VoiceAnalysis type). The word next to a number says how far to trust it (the five statuses); a margin says how far it can be off. Add "measureStatus": true to the request to get the same status and margin inside the answer.

Field Type Status Notes
measureStatus MeasureStatus
durationSec* number Validated
sampleRate* integer Validated
speechSec number Proxy
silenceSec number Proxy
speechRatio* number Proxy
segments VoiceSegment[] Proxy
estimatedSyllableRate number Proxy Speech bursts per second, counted from deep dips in the envelope. Not a syllable count.
speakingRateLabel string Proxy Slow | Normal | Fast | Variable
longSilences number Proxy
peakDb number Validated
averageSpeechRms number
averageSpeechRmsDb number Validated
noiseFloorDb number Validated
signalToNoiseDb number Validated ±6 dB
clipping.count integer
clipping.severity string None | Low | Medium | High
brightness number Proxy Mean spectral centre of every non-silent frame (pauses with noise included) over 2500 Hz, capped at 1.
activeKind string Proxy What the active material looks like, from the frame labels shared with the SignalLab timeline: voice, music or noise. Voice QA assumes speech input, so read every voice figure as a figure about the material rather than about a voice as soon as this is not "voice". Null when nothing rises above the silence gate. · voice | music | noise | mixed
activeVoiceShare number Proxy Share of active frames labelled voice, 0 to 1. Music with vocals genuinely sits in the middle. Null when nothing is active.
roomEchoScore number Withdrawn Energy left in the pauses after speech: the 60 to 420 ms tail after each phrase against the phrase itself. Noise OR reverb, and this number does not separate the two, so do not read it as a room verdict. Tested on 27 Sep 2026 against 24 measured room responses: it tracked the measured RT60 at Spearman 0.06 and a 1.71 s room scored below a 0.18 s booth, while it does rise with background noise. The field name is kept for compatibility with saved history and existing integrations. Null when no speech was found to read it from.
sibilanceRisk string Proxy Low | Medium | High
segmentalSnrDb number Validated SNR measured per phrase and averaged, dB.
segmentalSnrSpreadDb number Validated Spread of the per-phrase SNR, dB.
segmentalSnrPerSegmentDb number[] Validated
gapModulationRatio number Proxy 2 to 8 Hz share of the gap-envelope energy: speech rhythm where the target is silent.
gapModulationHighRatio number Proxy Share of the movement in the pauses between 8 and 16 Hz, from pauses of at least 1.4 s. Flat noise already reads about 0.5.
gapPeriodicity number Proxy Autocorrelation peak of the gap envelope at syllable lags.
gapLevelDb number Proxy Mean level of the gaps, dBFS.
humLevelDb number Validated Mains hum in the pauses, dB above the 30 to 600 Hz floor. Null when no 0.34 s window fits inside a pause.
humMainsHz integer Validated 50, 60, or null when the hum stays under 6 dB or was not measured. · 50 | 60
startsInSpeech boolean Validated The take opens mid-sound.
endsInSpeech boolean Validated The take is cut off at the end.
edgeStartDb number Validated Envelope level at the first frame, dBFS.
edgeEndDb number Validated Envelope level at the last frame, dBFS.
sceneBackground string Proxy What fills the speech pauses, read after the first 0.4 s of each: quiet, stationary (a machine), program (a second voice or music), unsteady (moves without cadence or pitch). Null under one second of pause. · quiet | stationary | program | unsteady
sceneProgramScore number Proxy 0 to 1: how strongly the pauses carry a program, from level movement times speech cadence or a moving pitch. Above 0.5 the label reads program.
sceneStationaryScore number Proxy 0 to 1: how still the pause floor stands in level and in spectral shape. Above 0.5 the label reads stationary.
sceneGapLowBandShare number Proxy Share of the pause power below 500 Hz.
sceneGapSpeechBandShare number Proxy Share of the pause power between 300 and 3400 Hz.
sceneGapStabilityDb number Proxy Standard deviation, dB, of the quieter half of the pause frames (20 ms each).
sceneGapHarmonicShare number Proxy Share of 40 ms pause frames with a clear, moving pitch between 70 and 400 Hz: a second voice or music. A fixed pitch is reported as sceneGapToneHz instead.
sceneGapToneHz number Proxy One steady tone filling the pauses (a fan, a transformer), Hz, or null.
sceneGapSpectralFlux number Proxy 0 to 1: how much the spectral shape of the pause floor changes between 0.4 s windows. Under 0.06 a machine, above 0.2 music or speech.
speechToBackgroundDb number Proxy Mean speech level minus the mean pause floor level, dB.
sceneIntelligibility string Proxy A proxy, not an STI: the weaker of the worst-tenth per-phrase SNR and speech over background (3 dB reads 0, 18 dB reads 1), reduced for clipping. Null under two measurable phrases. · clear | borderline | buried
sceneIntelligibilityScore number Proxy The intelligibility proxy as a number, 0 to 1.
worstPhraseSnrDb number Validated Tenth percentile of the per-phrase SNR, dB: what the weakest phrases measure against the noise beside them.
rmsEnvelope number[] Validated Level envelope, at most 2000 points. Longer takes are reduced by keeping the PEAK per bucket, so a short clip or a hot moment survives; seriesIntervalSec says how much time one point covers.
voicedMask boolean[] Proxy Speech present per envelope point, same length and interval as rmsEnvelope. A bucket reads true when any of its points did.
seriesIntervalSec number Seconds covered by one point of rmsEnvelope and voicedMask, so the series still maps onto the timeline after reduction.
totalSegments integer Speech segments the engine found, before any cap.
returnedSegments integer Segments in this response. Lower than totalSegments when truncated.
truncated boolean True when more than 500 segments were found and only the longest 500 are returned, with segmentalSnrPerSegmentDb kept in step.
fileName string

Errors

Every error carries a stable code and a docs_url: the cause, the fix and an example for each.

Try it with your key

This sends your URL or file to the EU-hosted API, so the audio leaves your device and counts as a call. The API keeps no audio: a direct request is decoded and discarded inside the request, and only numbers come back. Details on /privacy. To measure without uploading, use the playground above.

POST /v1/analyze/profile Measure against a named profile and get back only the lenses that question needs

One preset answers one question, keyed by stable lens id. Profiles: basic, voice, master, provenance, dataset, environment, broadcast, loop, room, chain, pitch. Only basic is free, the rest return 402. series:true adds curves and can reach ~2 MB: for your own code, not for a chat client.

Request

Send a public url (up to 150 MB), a small file as the multipart field file or as the raw body with an audio content type (about 4.5 MB), or an objectPath after a signed upload. A file you send is uploaded to the API: see /privacy for what is kept.

JSON field Type Notes
url string Public http(s) URL to the audio file.
objectPath string Path returned by /api/upload-url, for audio that has no public URL. Readable only by the key that uploaded it, and kept for about an hour so a follow-up question about the same file does not need a re-upload.
profile* string The preset. room: the reverberation time per octave band from one clap, balloon pop, impulse response or sweep (see roomSource); a recording that holds none of them is a 422 with the code room_not_measurable. chain: the gaps of digital silence inside the sound (lost packets). pitch: the pitch of a voice, how voiced the recording is and the harmonics-to-noise ratio. A measure that has not met its test yet (a beta that is not offered) is left out of the answer; the status of every measure is at https://audiolab.tools/lenses. · basic | voice | master | provenance | dataset | environment | broadcast | loop | room | chain | pitch
series boolean Include per-block lanes and curves alongside the single values.
round boolean Round the numbers to what the measurement is worth: dB and LUFS to 2 decimals, seconds to 3, shares to 3, Hz to 1. Same keys, same types, only fewer decimals. Off by default: without it you get the full precision, exactly as before. Supported on mixlab/analyze, voicelab/qa, signallab and analyze/profile.
measureStatus boolean Add one extra key, measureStatus, with the status (validated, proxy, beta, withdrawn, planned), the basis, how it works (dsp, model, mixed) and, where known, the margin of every measure in the answer. Off by default: without it the answer has no extra key. Supported on mixlab/analyze, voicelab/qa, signallab and analyze/profile.
contentModel string Which model gives the content type (voice, music, mixed, noise, unknown) and its confidence. v1 is the first model and is the default until 15 January 2027; v2 is the new one, much better on speech and music in the tests (see the status of signal.contentType at https://audiolab.tools/lenses). The same keys and types in both, only the values differ, and with v2 the evidence list contains model:v2. From 15 January 2027 the default becomes v2 and v1 stays selectable until at least 15 April 2027. Supported on signallab and analyze/profile. · v1 | v2
roomSource string For the room profile: how the recording was made. clap: one clap (the default; the bands from 500 Hz up); balloon: one balloon pop (the same bands); impulse: the file already is an impulse response (every octave band from 125 Hz); sweep: the file holds the exponential sweep of the engine as the room returned it (every octave band from 125 Hz). Supported on analyze/profile with the room profile. · clap | balloon | impulse | sweep
speechDetector string Which speech detector finds the speech in the recording; it decides speechRatio, speechSec, silenceSec, longSilences, segments and the measures that read the pauses. v1 is the first detector and is the default until 15 January 2027; k2 lets a phrase run on into its soft word starts and endings (by at most 100 ms per side) and was better on new speakers in the tests (frame F1 from 0.88 to 0.94 on clean audio and noise at 20 and 10 dB; see the status of voice.speechRatio at https://audiolab.tools/lenses). The same keys and types in both, only the values differ: with k2 the speech ratio reads about 5 to 14 points higher, everything that reads the speech frames or the pauses moves with it, signalToNoiseDb is corrected below 16 dB and reads about 4 to 5 dB lower at 10 dB noise and below (closer to the true ratio), and a pause measure is null when no pause frame is left; brightness, sibilanceRisk, noiseFloorDb and peakDb do not move (details: https://audiolab.tools/docs/start/changes-and-deprecation). From 15 January 2027 the default becomes k2 and v1 stays selectable until at least 15 April 2027. Supported on voicelab/qa, voicelab/segments and analyze/profile. · v1 | k2

Example

curl https://audiolab.tools/v1/analyze/profile \
  -H "Authorization: Bearer $AUDIOLAB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://audiolab.tools/reference/is-original.mp3", "profile": "basic"}'

Response

The answer is keyed by lens id and holds only the lenses the profile needs, each with its value, so there is no fixed field list. Every lens, its status and its margin is in the catalogue; the profile basic is free.

Errors

Every error carries a stable code and a docs_url: the cause, the fix and an example for each.

Try it with your key

This sends your URL or file to the EU-hosted API, so the audio leaves your device and counts as a call. The API keeps no audio: a direct request is decoded and discarded inside the request, and only numbers come back. Details on /privacy. To measure without uploading, use the playground above.

POST /v1/signallab Index an audio file (tags, content type, clipping/silence, metadata) 46 fields

Note: use /v1/signallab, not /v1/signallab/index. The hosting layer strips a trailing /index from any path, so the older form redirects and then 404s for clients that do not follow redirects.

Request

Send a public url (up to 150 MB), a small file as the multipart field file or as the raw body with an audio content type (about 4.5 MB), or an objectPath after a signed upload. A file you send is uploaded to the API: see /privacy for what is kept.

JSON field Type Notes
url string Public http(s) URL to the audio file (alternative to multipart upload).
objectPath string Path returned by /api/upload-url, for audio that has no public URL. Readable only by the key that uploaded it, and kept for about an hour so a follow-up question about the same file does not need a re-upload.
series boolean Send the curves as well: regions, energyEnvelope and centroidEnvelope. Off by default since 22 September 2026, because they are ~98% of the payload and no answer needs them. Raw or multipart callers use ?series=true.
round boolean Round the numbers to what the measurement is worth: dB and LUFS to 2 decimals, seconds to 3, shares to 3, Hz to 1. Same keys, same types, only fewer decimals. Off by default: without it you get the full precision, exactly as before. Supported on mixlab/analyze, voicelab/qa, signallab and analyze/profile.
measureStatus boolean Add one extra key, measureStatus, with the status (validated, proxy, beta, withdrawn, planned), the basis, how it works (dsp, model, mixed) and, where known, the margin of every measure in the answer. Off by default: without it the answer has no extra key. Supported on mixlab/analyze, voicelab/qa, signallab and analyze/profile.
contentModel string Which model gives the content type (voice, music, mixed, noise, unknown) and its confidence. v1 is the first model and is the default until 15 January 2027; v2 is the new one, much better on speech and music in the tests (see the status of signal.contentType at https://audiolab.tools/lenses). The same keys and types in both, only the values differ, and with v2 the evidence list contains model:v2. From 15 January 2027 the default becomes v2 and v1 stays selectable until at least 15 April 2027. Supported on signallab and analyze/profile. · v1 | v2

Example

curl https://audiolab.tools/v1/signallab \
  -H "Authorization: Bearer $AUDIOLAB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://audiolab.tools/reference/is-original.mp3"}'

Response

SignalLab indexer output (mirrors the engine SignalIndex type). The word next to a number says how far to trust it (the five statuses); a margin says how far it can be off. Add "measureStatus": true to the request to get the same status and margin inside the answer.

Field Type Status Notes
measureStatus MeasureStatus
fileName* string
fileSizeKb number Validated
format string Validated
durationSec* number Validated
sampleRate* integer Validated
channels* integer Validated
bitDepthGuess string Proxy A guess from the file type (16/24-bit guess for WAV, lossy for compressed formats). Not read from the samples.
peakDb number
rmsDb number
noiseFloorDb number
dcOffset number Validated
hasClipping boolean Validated
clippingRegions integer Validated
silenceRegions integer Validated
silenceTotalSec number Validated
contentTypeGuess* string Proxy voice | music | mixed | noise | silence | unknown
contentConfidence number Proxy
contentEvidence string[] Proxy The measurements that back the content type, as tags.
beatStability number Proxy Deprecated alias of tempo confidence; one release, then gone.
spectralFlatness number Validated Flatness of the opening 10 s, 0 tonal to 1 noise-like.
loopSeamRatio number Validated Wrap-around jump divided by the mean sample-to-sample step. Under 3 inaudible, above 10 a click. Null on files too short to judge.
edgeSilenceStartMs number Validated Milliseconds under -60 dBFS at the start.
edgeSilenceEndMs number Validated Milliseconds under -60 dBFS at the end.
inputSha256 string Validated SHA-256 of the submitted bytes, when supplied.
bandwidthHz number Validated Median per-block bandwidth over the non-silent blocks, Hz.
lossySource string Validated The wall a lossy encoder leaves, or unknown where two explanations collide (a 64 kbps wall and a sharp resample read the same). · lossless | lossy ~64k | lossy ~128k | lossy ~256k | unknown
effectiveBitDepth integer Validated Bits actually in use: 16 in a 24-bit container reads 16. Null under a thousand non-silent samples.
upsampledFromHz number Validated Likely original sample rate behind a resampler-shaped roll-off, or null.
bandwidthSplices integer Validated Bandwidth jumps of more than 3 kHz that hold for at least two seconds.
toneProminenceDb number Validated Most prominent tone against the masking noise in its critical band, dB (ISO 1996-2 annex C). Null on speech and under 0.17 s.
toneFrequencyHz number Validated
toneLabel string Validated Null where no tone was measured; see toneProminenceDb. · none | audible | prominent
thirdOctaveDb.centres number[]
thirdOctaveDb.db number[]
brightnessBucket string Proxy Dark | Balanced | Bright | Very bright
dynamicsBucket string Proxy Flat | Compressed | Modern | Dynamic
dominantBand string Proxy A rough band label from the zero-crossing rate. Not the band with the most energy.
monophonicProbability number Validated Left-right correlation, never below 0. Near 1 means mono in disguise. Not a probability.
regions TimelineRegion[] Proxy
totalRegions integer Regions the engine found, before any cap.
returnedRegions integer Regions in this response. Lower than totalRegions when truncated.
truncated boolean True when more than 500 regions were found and only the longest 500 are returned.
energyEnvelope number[] Validated
centroidEnvelope number[] Validated Zero-crossing rate per frame, a rough brightness trace. Not a spectral centre in Hz.
tags string[] Proxy

Errors

Every error carries a stable code and a docs_url: the cause, the fix and an example for each.

Try it with your key

This sends your URL or file to the EU-hosted API, so the audio leaves your device and counts as a call. The API keeps no audio: a direct request is decoded and discarded inside the request, and only numbers come back. Details on /privacy. To measure without uploading, use the playground above.

POST /v1/signallab/sample Describe a single sound from a sample library (material, character, loop) 41 fields

One SOUND, not a recording: a single one-shot from a sample library, for sorting and searching a pack. Use /v1/signallab for a take or an episode. A single hit returns the character vector with loop null; material with several onsets returns tempo and loop QC with character null.

Request

Send a public url (up to 150 MB), a small file as the multipart field file or as the raw body with an audio content type (about 4.5 MB), or an objectPath after a signed upload. A file you send is uploaded to the API: see /privacy for what is kept.

JSON field Type Notes
url string Public http(s) URL to the audio file (alternative to multipart upload).
objectPath string Path returned by /api/upload-url, for audio that has no public URL. Readable only by the key that uploaded it, and kept for about an hour so a follow-up question about the same file does not need a re-upload.

Example

curl https://audiolab.tools/v1/signallab/sample \
  -H "Authorization: Bearer $AUDIOLAB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://audiolab.tools/reference/cal-1k-sine.mp3"}'

Response

One sound from a sample library. character and loop are mutually exclusive: a single hit fills character, material with several onsets fills loop, and the other is null. The word next to a number says how far to trust it (the five statuses); a margin says how far it can be off. Add "measureStatus": true to the request to get the same status and margin inside the answer.

Field Type Status Notes
material.structure string silence = no energy; continuous = one sustained event; single-event = one hit; phrase = several onsets. · silence | continuous | single-event | phrase
material.durationClass string sample under 5 s, clip under 30 s, track under 15 min, long-form beyond that. · sample | clip | track | long-form
material.evidence string[] Plain sentences behind the call, such as "4 onsets" or "96% of windows above -40 dB".
material.onsetCount integer
material.attackStrength number Peak-to-surroundings ratio of the strongest onset, 0 to 1.
character.durationMs number
character.attackMs number Time from onset to peak.
character.decayT20Ms number Decay from a Schroeder curve, not from a short envelope: at low frequencies an envelope swings more within one period than the decay it is meant to measure.
character.decayFitR2 number Fit quality of that decay line, 0 to 1. Low means the number is not worth much.
character.decayRangeDb number
character.decayTruncated boolean True when the file ends before the sound does.
character.band.sub number
character.band.bass number
character.band.lowMid number
character.band.mid number
character.band.highMid number
character.band.presence number
character.band.air number
character.bodyTilt number Spectral tilt of the body, dB per octave.
character.bodyResonance number How peaked the body is: high means one resonance dominates.
character.clickRatio number Share of the energy in the first few milliseconds.
character.f0Hz number
character.note string Nearest note name for f0Hz, such as F1.
character.cents integer Deviation from that note, -50 to +50.
character.pitchDefiniteness number MPM clarity: 1.00 on a pure tone, 0.07 on white noise. Below the gate the pitch fields are omitted with a reason.
character.glideSt number Pitch change in semitones between two windows whose centres sit exactly 180 ms apart, so this is NOT the glide over the whole sound. A glide of 12 semitones spread over 1.5 s reads about 1.4 here. Sign follows direction: negative falls.
character.crestDb number
character.channelCorrelation number Null for mono input.
character.omitted object Per field that could not be measured, the reason why.
loop.durationSec number
loop.bpm number
loop.bars integer How many bars that tempo makes the file, at 4/4.
loop.tempoStrength number Strength of the winning tempo peak.
loop.candidateMargin number How far the winner sits above the runner-up. Near 0 means the tempo is a coin flip.
loop.bpmRaw number Before snapping to the octave and the grid.
loop.octaveCandidates object[] The same tempo at half and double time, since 120 and 60 fit the same file.
loop.seamRatio number Level jump at the loop seam relative to the material. 0 is seamless; high means it clicks when it wraps.
loop.edgeSilence.startMs number
loop.edgeSilence.endMs number
loop.omitted object
omitted object Top-level reasons, for whole blocks that could not be measured.

Errors

Every error carries a stable code and a docs_url: the cause, the fix and an example for each.

Try it with your key

This sends your URL or file to the EU-hosted API, so the audio leaves your device and counts as a call. The API keeps no audio: a direct request is decoded and discarded inside the request, and only numbers come back. Details on /privacy. To measure without uploading, use the playground above.

POST /v1/mixlab/check-target Check audio against a loudness target (Spotify, EBU, podcast, etc.) 18 fields

Run MixLab and verify against a delivery target. Returns pass/fail, per-metric deltas, issue messages, and an ffmpeg loudnorm command when it fails. Presets: spotify, apple-music, youtube, tidal, amazon-music, podcast, ebu-broadcast, atsc-broadcast. Use custom with lufs+tp.

Request

JSON field Type Notes
url string Public http(s) URL to the audio file.
objectPath string Path returned by /api/upload-url, for audio that has no public URL. Readable only by the key that uploaded it, and kept for about an hour so a follow-up question about the same file does not need a re-upload.
target* string Preset name or "custom".
lufs number Custom target LUFS (when target="custom").
tp number Custom target dBTP (when target="custom").

Example

curl https://audiolab.tools/v1/mixlab/check-target \
  -H "Authorization: Bearer $AUDIOLAB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://audiolab.tools/reference/is-original.mp3", "target": "spotify"}'

Response

Pass/fail verdict for a loudness target check, with concrete deltas and an ffmpeg loudnorm fix command. The word next to a number says how far to trust it (the five statuses); a margin says how far it can be off. Add "measureStatus": true to the request to get the same status and margin inside the answer.

Field Type Status Notes
pass* boolean True only if both LUFS within ±0.5 LU of target and true-peak ≤ target+0.5 dB.
target.lufs number Target integrated loudness (LUFS).
target.tp number Target maximum true-peak (dBTP).
target.label string Human-readable target name (e.g. "Spotify").
target.source string published: the platform documents the figure. measured: taken from outside measurements, so it can shift. · published | measured
target.sourceUrl string Where the platform publishes the figure. Present on published targets.
target.verifiedOn string Date the published figure was last checked at sourceUrl.
target.measurementCaveat string How the platform's own measurement differs from integrated loudness. Present only where it does (atsc-broadcast).
target.bron string Deprecated Dutch alias of source; removed after 2026-10-31. · published | measured
target.bewijs string Deprecated Dutch alias of sourceUrl; removed after 2026-10-31.
target.gecontroleerd string Deprecated Dutch alias of verifiedOn; removed after 2026-10-31.
target.meetVerschil string Deprecated Dutch alias of measurementCaveat; removed after 2026-10-31.
measurements.integratedLufs number
measurements.truePeakDb number
measurements.lufsDelta number measured - target.
measurements.tpDelta number measured - target.
issues* object[]
ffmpegFix string ffmpeg loudnorm one-liner to fix when failing; null when passing.

Errors

Every error carries a stable code and a docs_url: the cause, the fix and an example for each.

Try it with your key

This sends your URL or file to the EU-hosted API, so the audio leaves your device and counts as a call. The API keeps no audio: a direct request is decoded and discarded inside the request, and only numbers come back. Details on /privacy. To measure without uploading, use the playground above.

POST /v1/mixlab/timeseries Loudness and waveform over time (for graphing) 8 fields

Returns short-term LUFS samples (~10 Hz, EBU R128 3s window) with their time-base, plus downsampled waveform peaks. For loudness charts, level meters, waveform displays.

Request

JSON field Type Notes
url string
objectPath string Path returned by /api/upload-url, for audio that has no public URL. Readable only by the key that uploaded it, and kept for about an hour so a follow-up question about the same file does not need a re-upload.
waveformPoints integer Number of waveform peaks to return (downsampled). Default 200.

Example

curl https://audiolab.tools/v1/mixlab/timeseries \
  -H "Authorization: Bearer $AUDIOLAB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://audiolab.tools/reference/is-original.mp3"}'

Response

Loudness and waveform data over time, for graphing or visualization. The word next to a number says how far to trust it (the five statuses); a margin says how far it can be off. Add "measureStatus": true to the request to get the same status and margin inside the answer.

Field Type Status Notes
durationSec* number Validated
sampleRate integer Validated
loudnessOverTime* SeriesArray
waveformOverTime* SeriesArray
summary.integratedLufs number
summary.shortTermLufsMax number
summary.loudnessRange number
summary.truePeakDb number

Errors

Every error carries a stable code and a docs_url: the cause, the fix and an example for each.

Try it with your key

This sends your URL or file to the EU-hosted API, so the audio leaves your device and counts as a call. The API keeps no audio: a direct request is decoded and discarded inside the request, and only numbers come back. Details on /privacy. To measure without uploading, use the playground above.

POST /v1/mixlab/spectrum FFT spectrum bins + band energies 8 fields

Returns paired frequency/magnitude arrays plus 7-band energies and spectral descriptors (centroid, rolloff, flatness). For spectrum-analyzer UIs and tonal-balance diagnosis beyond the harshness/muddiness labels.

Request

JSON field Type Notes
url string
objectPath string Path returned by /api/upload-url, for audio that has no public URL. Readable only by the key that uploaded it, and kept for about an hour so a follow-up question about the same file does not need a re-upload.

Example

curl https://audiolab.tools/v1/mixlab/spectrum \
  -H "Authorization: Bearer $AUDIOLAB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://audiolab.tools/reference/is-original.mp3"}'

Response

FFT spectrum bins plus band energies and spectral descriptors. The word next to a number says how far to trust it (the five statuses); a margin says how far it can be off. Add "measureStatus": true to the request to get the same status and margin inside the answer.

Field Type Status Notes
sampleRate* integer Validated
spectralCentroidHz number Validated
spectralRolloffHz number Validated
spectralFlatness number Validated
bandEnergy* Band Validated
spectrum.freqs number[]
spectrum.mags number[]
spectrum.count integer

Errors

Every error carries a stable code and a docs_url: the cause, the fix and an example for each.

Try it with your key

This sends your URL or file to the EU-hosted API, so the audio leaves your device and counts as a call. The API keeps no audio: a direct request is decoded and discarded inside the request, and only numbers come back. Details on /privacy. To measure without uploading, use the playground above.

POST /v1/voicelab/segments Voiced speech segments with timestamps 6 fields

List voiced speech regions with start/end timestamps and per-segment RMS level. For auto-trim and chapter generation. RMS-based voice-activity detection: when speech happens, not who is speaking, and not where the speaker changes.

Request

JSON field Type Notes
url string
objectPath string Path returned by /api/upload-url, for audio that has no public URL. Readable only by the key that uploaded it, and kept for about an hour so a follow-up question about the same file does not need a re-upload.
speechDetector string Which speech detector finds the segments. v1 is the first detector and is the default until 15 January 2027; k2 lets a phrase run on into its soft word starts and endings (by at most 100 ms per side), so neighbouring segments sometimes merge into fewer, longer ones. The same keys and types in both, only the values differ. From 15 January 2027 the default becomes k2 and v1 stays selectable until at least 15 April 2027. Supported on voicelab/qa, voicelab/segments and analyze/profile. · v1 | k2

Example

curl https://audiolab.tools/v1/voicelab/segments \
  -H "Authorization: Bearer $AUDIOLAB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://audiolab.tools/samples/voice/speech-female-plain.mp3"}'

Response

Voiced regions with timestamps. For auto-trim and chapter generation. It finds where speech is, not who is speaking or where the speaker changes. The word next to a number says how far to trust it (the five statuses); a margin says how far it can be off. Add "measureStatus": true to the request to get the same status and margin inside the answer.

Field Type Status Notes
durationSec* number Validated
speechSec number Proxy
silenceSec number Proxy
speechRatio* number Proxy 0..1 fraction of audio that is voiced.
longSilences number Proxy Count of unusually long silences (e.g. potential dead air).
segments* SpeechSegment[] Proxy

Errors

Every error carries a stable code and a docs_url: the cause, the fix and an example for each.

Try it with your key

This sends your URL or file to the EU-hosted API, so the audio leaves your device and counts as a call. The API keeps no audio: a direct request is decoded and discarded inside the request, and only numbers come back. Details on /privacy. To measure without uploading, use the playground above.

POST /v1/batch Run one analysis route over up to 20 URLs in a single call 17 fields

One route over up to 20 sources in a single call: same engine, same metering as the single routes. Each item counts as one call plus its bytes, and a rate or quota stop ends the loop and is reported on the item where it fired. Provide urls and/or objectPaths, max 20 combined.

Request

JSON field Type Notes
urls string[] Public http(s) URLs to audio files.
objectPaths string[] Storage objects minted via /api/upload-url under this key's key/<keyHash>/ namespace, for local files with no public URL. Readable for about an hour, so a second question about the same file needs no re-upload, then swept.
endpoint string Which analysis route to run for every URL. · mixlab/analyze | mixlab/check-target | mixlab/timeseries | mixlab/spectrum | voicelab/qa | voicelab/segments | signallab | signallab/index
args object Optional route-specific extras (e.g. target, waveformPoints), applied to every URL.
name string Optional session name; stored on every item's event (meta.batch) so history can group the run.

Example

curl https://audiolab.tools/v1/batch \
  -H "Authorization: Bearer $AUDIOLAB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["https://audiolab.tools/reference/is-original.mp3", "https://audiolab.tools/reference/is-muddy.mp3"], "endpoint": "mixlab/analyze"}'

Response

The answer of /v1/batch. The word next to a number says how far to trust it (the five statuses); a margin says how far it can be off. Add "measureStatus": true to the request to get the same status and margin inside the answer.

Field Type Status Notes
endpoint* string The analysis route that ran.
count* integer Processed items; shorter than the request when a rate or quota stop fired.
batchId string Unique id for this run; every item's event carries it in meta.batch.
name string The session name, when provided.
summary.ok integer
summary.failed integer
summary.avgLufs number
summary.loudest.ref string
summary.loudest.lufs number
summary.quietest.ref string
summary.quietest.lufs number
summary.overTruePeakCount integer
summary.totalDurationSec number
summary.passed integer check-target only.
summary.passRate number check-target only, 0..1.
summary.headline string One-line human/agent-readable overview.
results* object[]

Errors

Every error carries a stable code and a docs_url: the cause, the fix and an example for each.

Try it with your key

This sends your URL or file to the EU-hosted API, so the audio leaves your device and counts as a call. The API keeps no audio: a direct request is decoded and discarded inside the request, and only numbers come back. Details on /privacy. To measure without uploading, use the playground above.

GET /v1/usage Where your key stands this month 11 fields

Your plan, the calls and data used this month against the limits the API enforces, and your requests per minute. The same numbers as /account. Needs a key. Reading it is free and does not count as a call; it is limited to 30 a minute.

Example

curl https://audiolab.tools/v1/usage \
  -H "Authorization: Bearer $AUDIOLAB_KEY"

Response

Where a key stands this month. The same numbers as /account. The word next to a number says how far to trust it (the five statuses); a margin says how far it can be off. Add "measureStatus": true to the request to get the same status and margin inside the answer.

Field Type Status Notes
plan* string The plan of the account. custom is a hand-issued key without a subscription. · free | plus | studio | enterprise | founder | custom
period.start* string First day of the month (UTC).
period.end* string Last day of the month (UTC).
period.resetsAt* string When the counters start again.
calls.used* integer Accepted requests this month, across all the keys of the account. A request that then fails still counts.
calls.limit* integer Calls allowed per month; null when there is no limit.
calls.remaining* integer limit minus used, never below 0; null when there is no limit.
data.usedBytes* integer Bytes of audio processed this month.
data.limitBytes* integer Bytes allowed per month; null when there is no limit.
data.remainingBytes* integer limitBytes minus usedBytes, never below 0; null when there is no limit.
requestsPerMinute* integer Requests per minute this key may make to the analysis routes.

Errors

  • 401 Invalid or revoked API key. /v1/batch and /v1/usage always need a key; the analysis routes also run without one, as a small keyless trial. invalid_api_key
  • 429 Too many requests this minute. See Retry-After. rate_limited
  • 500 Something went wrong on our side. The details are logged and never sent to you. storage_unavailable, analysis_error

Every error carries a stable code and a docs_url: the cause, the fix and an example for each.

Try it with your key

A GET without a body. It is free to call and does not count against your limits.

This asks the EU-hosted API where your key stands. No audio is involved.

Shared types Band · VoiceSegment · TimelineRegion · SeriesArray · SpeechSegment
Band
sub number
bass number
lowMid number
mid number
highMid number
presence number
air number
VoiceSegment
startSec number
endSec number
meanRms number
levelDb number Phrase level, dBFS.
clipFraction number Share of clipped samples in the phrase.
decayScore number Energy left in the pause after this phrase, relative to the phrase itself, 0 to 1. Noise or reverb, and this number does not separate the two, so it is not a reverberation measure. Same limit as roomEchoScore. Null when no usable pause follows the phrase.
tailDecayDbPerSec number Decay slope of the phrase tail, dB per second. Null when no usable tail.
flankFlatness number Background character on the phrase flanks, 0 tonal to 1 noise-like.
TimelineRegion
startSec number
endSec number
kind string voice | silence | music | noise | clipping
confidence number
SeriesArray
intervalSec number Seconds between samples.
count integer Number of samples.
samples number[]
unit string Unit of measurement (e.g. "LUFS", "peak (-1..1)").
SpeechSegment
startSec number
endSec number
durationSec number
meanRmsDb number Mean RMS of the segment in dBFS.

* required · generated from public/openapi.yaml, the lens registry and lib/code-samples.mjs

Keys and limits
Keys and limits

The hosted API uses a bearer key in the Authorization header, generated from your dashboard. Keys are self-serve and live, with a free tier of 1,000 calls and 2 GB a month, no card. The playground above still needs no key at all: it runs the engine in your browser and your audio never leaves the device.

Authorization: Bearer al_live_xxx

issued from the dashboard

Limits

What the API enforces today. These are ceilings, not quotas: see pricing for calls and data per month, and errors for what each failure means.

File sent directly in the request body150 MB
File via a signed upload URL, or read back by objectPath150 MB
Longest track for the analysis routes, at 48 kHz stereo. Lower sample rates and mono fit longer. The loudness routes (mixlab/*) do handle long files.~7.7 min
Items in one /v1/batch call20
Loudness, measured against the standard
Loudness, measured against the standard

Don’t take the loudness numbers on faith. Here is the engine run against the canonical EBU Tech 3341/3342 and ITU-R BS.1770-4 reference signals, checked against the standard’s own tolerances. The signals are the standard’s own, not ours; you can synthesise them and hold any meter to the same expected values. Every case we run is listed below, pass or fail, with the value the standard expects beside the value we measured.

5/5 compliance checks pass
EBU Tech 3341 / 3342 · ITU-R BS.1770-4 48 kHz · 2026-09-05

The cases cover loudness, loudness range and true peak against the EBU signals. Every other measure carries a status of its own: 94 validated against a standard or a known value, 56 proxies and 5 beta (no ground-truth test yet, which does not mean wrong). Scene, content type, intelligibility and speaking rate are proxies, and the room-echo score was withdrawn: it is not a reverb measure. Each measure, with what it was tested against and what it was not, is on the lenses page, how to read a status is in Read a response, and the OpenAPI document marks each response field with x-validation.

Every case, with the expected and the measured value 5 compliance · 2 extended
  • Integrated loudness 3341-1

    Stereo 1 kHz sine at −23 dBFS → −23.0 LUFS (absolute calibration)

    -22.99 LUFS
    target -23 · ±0.1 LU
    Pass
  • Integrated loudness 3341-2

    Stereo 1 kHz sine at −33 dBFS → −33.0 LUFS (linearity)

    -32.99 LUFS
    target -33 · ±0.1 LU
    Pass
  • Integrated loudness gate-abs

    Silence → −23 dBFS tone → silence: −70 LUFS absolute gate excludes silence → −23.0 LUFS

    -23.04 LUFS
    target -23 · ±0.1 LU
    Pass
  • Integrated loudness gate-rel

    −23 dBFS then −40 dBFS: −10 LU relative gate drops the quiet block → −23.0 LUFS

    -23.06 LUFS
    target -23 · ±0.1 LU
    Pass
  • True peak tp-997

    997 Hz sine at 0 dBFS → true peak 0.0 dBTP (BS.1770-4 true-peak)

    0 dBTP
    target 0 · +0.2 / −0.4 dB
    Pass

Extended observations

  • Loudness range 3342-1

    −20 dBFS and −30 dBFS blocks → loudness range ≈ 10 LU (EBU 3342)

    10 LU
    target 10 · ±1 LU
    Pass
  • True peak tp-isp

    12 kHz 0 dBFS, π/4 phase: samples sit at −3.0 dBFS, inter-sample peak detection (true peak should rise above sample peak)

    0.1 dBTP
    target 0 · +0.2 / −0.4 dB
    Pass

We measure what we claim. Per-task accuracy (scene, pitch, beat) and server-side research benchmarks aren’t claimed until the same kind of harness backs them.

Use it from an AI agent
Why this, not the usual options

The same job, three ways. The difference is who hosts the audio, how many tools you wire together, and who maintains it.

the old way

Scripting ffmpeg yourself

Free, but you build and babysit the pipeline. It only does loudness, there is no voice or signal layer, and it lives in your infra.

the old way

A cloud audio API

Capable, but every file is uploaded to a server you do not control, usually US-hosted, and most vendors do exactly one thing.

the smart path

AudioLab

One key for loudness, voice and signal, EU-hosted, with the loudness DSP checked against the EBU Tech 3341/3342 test cases and every case published on this page. The same engine also powers the in-browser labs, which analyse on your device without uploading your audio; those need no key at all.

Built for teams who ship audio

Podcast & post platforms

LUFS-QC every episode before publish, without uploading unreleased audio.

Voice-AI teams

Loudness and clarity QC on generated speech, right in your pipeline.

Plugin & audio-software devs

Embed analysis without building or hosting the DSP yourself.

Mastering & distribution

Show creators their loudness and dynamics before they submit.

Building on audio? Get a key.

The hosted API is live at audiolab.tools/v1/*. Self-serve keys with a free tier, live now. Add it to Claude or any agent in one page, or call the REST API directly. Building something bigger? Email partners@audiolab.tools.