Naar inhoud
Inloggen

/docs · General · Practical

Voice-agent- en TTS-vendors vergelijken, en gespreksaudio controleren

Drie API-aanroepen, tien getallen, en hoe ver je elk getal kunt vertrouwen: een gids voor QA-teams die voice-agent-, text-to-speech- of voice-isolation-vendors vergelijken.

Bijgewerkt 15 okt 2026


Voor wie dit is

Je hebt opnames van twee of meer voice-agent-, text-to-speech- of voice-isolation-vendors, of van één vendor in de tijd, en je wilt ze met getallen vergelijken: hoe luid, hoe ruisig, of er iets clipt, hoe breed de band is, hoeveel pauzes.

Het is voor teams die daarbovenop hun eigen pass- en failregels instellen. Het is niet bedoeld om te beoordelen hoe natuurlijk een stem klinkt, en het leest de woorden niet. Zie wat AudioLab niet doet.

Wat je krijgt

Per opname ongeveer tien getallen. Elk heeft een status die zegt hoe ver je het kunt vertrouwen (vraag measureStatus aan en het antwoord draagt hem), en, waar we het weten, een marge die zegt hoe ver het ernaast kan zitten. We geven je startbereiken. De beslissing om een opname te laten slagen of falen blijft bij jou.

Liever geen code schrijven? De werkbank vergelijkt twee sets opnames in je browser: log in op /account, open het tabblad Voice en zet in de batch “Compare two sets” aan. Je krijgt dezelfde tien getallen met dezelfde statussen, en marges waar we die hebben gemeten, je audio wordt niet geüpload, en het rapport exporteert als één HTML-bestand.

Voordat je begint

  1. Haal een sleutel. Hij is gratis en vraagt geen kaart: log in op /account en genereer er een. De gratis tier is 1.000 aanroepen per maand, 2 GB per maand en 60 verzoeken per minuut. De tien getallen kosten drie aanroepen per opname, en het bestand telt per aanroep mee voor je maanddata, dus drie keer.
  2. Gebruik bij elke vendor dezelfde zinnen. Een verschil tussen vendors betekent alleen iets op dezelfde tekst, bij dezelfde achtergrondruis.
  3. Stuur de audio zoals je gebruikers haar horen. Dezelfde samplerate en codec als in productie. Een vendor die als studio-WAV prima klinkt, kan er na de telefoonlijn anders uitzien.
  4. Vraag de extra’s aan. Voeg "round": true en "measureStatus": true toe aan het verzoek. Beide staan standaard uit, dus er verandert niets in een bestaande integratie. round geeft minder decimalen (46,7 in plaats van 46,69999999999999). measureStatus voegt één sleutel toe met de status van elke maat en, waar we het weten, zijn marge. Met een ruw bestand als body zet je de twee opties in plaats daarvan in de querystring: ?round=true&measureStatus=true.

De drie aanroepen

Eén opname vraagt drie POST-verzoeken met dezelfde body: mixlab/analyze voor loudness, voicelab/qa voor de stem en de achtergrond, en signallab voor de bandbreedte. Stuur een publieke URL (tot 150 MB), of een klein bestand als ruwe body (ongeveer 4,5 MB). Voor een lokaal bestand van meer dan 4,5 MB upload je het eerst via een signed URL en stuur je zijn objectPath, zoals beschreven in de OpenAPI-spec.

curl
export AUDIOLAB_KEY=al_live_...
BODY='{"url":"https://example.com/vendor-a/sentence-01.wav","round":true,"measureStatus":true}'

for route in mixlab/analyze voicelab/qa signallab; do
  curl -s "https://audiolab.tools/v1/$route" \
    -H "Authorization: Bearer $AUDIOLAB_KEY" \
    -H "Content-Type: application/json" \
    -d "$BODY" > "vendor-a_sentence-01_${route//\//_}.json"
done
Python

Het pakket audiolabtools heeft de tien getallen als één aanroep, met de status en de marge van elk:

pip install audiolabtools
from audiolabtools import AudioLab

numbers = AudioLab().ten_numbers("https://example.com/vendor-a/sentence-01.wav")
for field, m in numbers.items():
    print(field, m.value, m.unit, m.status, m.margin)

Het leest de sleutel uit AUDIOLAB_KEY, doet de drie aanroepen hieronder met round en measureStatus aan, en werpt per foutcode een exception (DataQuotaExceeded, RateLimited, enzovoort, elk met code en docs_url). De README van het pakket heeft de rest. Zonder het pakket kan hetzelfde met requests:

import os, requests

KEY = os.environ["AUDIOLAB_KEY"]

def analyze(route, url):
    r = requests.post(
        f"https://audiolab.tools/v1/{route}",
        headers={"Authorization": f"Bearer {KEY}"},
        json={"url": url, "round": True, "measureStatus": True},
        timeout=120,
    )
    if not r.ok:
        # error.code zegt wat er gebeurde, zie https://audiolab.tools/docs/errors
        raise RuntimeError(r.json()["error"]["code"] + ": " + r.json()["error"]["message"])
    return r.json()

def ten_numbers(url):
    mix, voice, sig = (analyze(r, url) for r in ("mixlab/analyze", "voicelab/qa", "signallab"))
    return {
        "integratedLufs": mix["integratedLufs"],
        "truePeakDb": mix["truePeakDb"],
        "peakDb": mix["peakDb"],
        "speechLevelDb": voice["averageSpeechRmsDb"],
        "noiseFloorDb": voice["noiseFloorDb"],
        "signalToNoiseDb": voice["signalToNoiseDb"],
        "clipping": voice["clipping"]["severity"],
        "speechRatio": voice["speechRatio"],
        "longSilences": voice["longSilences"],
        "bandwidthHz": sig["bandwidthHz"],
    }
TypeScript
const KEY = process.env.AUDIOLAB_KEY!;

async function analyze(route: string, url: string) {
  const r = await fetch(`https://audiolab.tools/v1/${route}`, {
    method: 'POST',
    headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({ url, round: true, measureStatus: true }),
  });
  const body = await r.json();
  // Bij een fout zegt body.error.code wat er gebeurde: https://audiolab.tools/docs/errors
  if (!r.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
  return body;
}

export async function tenNumbers(url: string) {
  const [mix, voice, sig] = await Promise.all(['mixlab/analyze', 'voicelab/qa', 'signallab'].map((r) => analyze(r, url)));
  return {
    integratedLufs: mix.integratedLufs, truePeakDb: mix.truePeakDb, peakDb: mix.peakDb,
    speechLevelDb: voice.averageSpeechRmsDb, noiseFloorDb: voice.noiseFloorDb, signalToNoiseDb: voice.signalToNoiseDb,
    clipping: voice.clipping.severity, speechRatio: voice.speechRatio, longSilences: voice.longSilences,
    bandwidthHz: sig.bandwidthHz,
  };
}
MCP (Claude en andere agents)

Verbind de AudioLab-server zoals getoond op /connect, en vraag dan:

Use analyze_loudness, analyze_voice and index_signal on these three URLs. Give me a table with integrated loudness, true peak, peak, speech level, noise floor, signal-to-noise, clipping, speech ratio, long silences and bandwidth for each. Tell me which of these are validated and which are proxies.

De MCP-tools geven dezelfde getallen terug. Ze voegen de status niet toe aan elk resultaat; elke toolbeschrijving noemt zijn gevalideerde maten en zijn proxy’s (de voice-tool zegt ook dat het veld voor pauze-energie geen galmmaat is), en deze pagina zegt het per veld.

De tien getallen

Getal Status Marge
integratedLufs Gevalideerd ±0,1 LU
truePeakDb Gevalideerd +0,2 / -0,4 dB
peakDb Gevalideerd geen opgegeven
averageSpeechRmsDb Gevalideerd geen opgegeven
noiseFloorDb Gevalideerd geen opgegeven
signalToNoiseDb Gevalideerd ±6 dB
clipping Gevalideerd geen opgegeven
speechRatio Proxy geen opgegeven
longSilences Proxy geen opgegeven
bandwidthHz Gevalideerd geen opgegeven
  1. integratedLufs POST /v1/mixlab/analyze · LUFS Gevalideerd

    Hoe luid de hele opname is.

    Een niveau, geen kwaliteit. Vergelijk vendors op dezelfde zinnen. Voor gespreksaudio bestaat geen standaarddoel (broadcast gebruikt -23, podcasts -16).

    Gangbaar bereik: geen. Wordt bepaald door je eigen gain staging, niet door de vendor. Vergelijk vendors in plaats daarvan op hetzelfde niveau.
    Marge
    ±0,1 LU. De tolerantie van EBU Tech 3341, gehaald door de loudness-benchmark bij elke build.

    Getoetst tegen, en wat het niet is: loudness.integrated

  2. truePeakDb POST /v1/mixlab/analyze · dBTP Gevalideerd

    Het hoogste niveau dat het signaal bereikt bij het afspelen, ook tussen de samples in.

    Informatie voor gespreksaudio, geen slagen of falen. Boven 0 betekent dat een decoder of encoder verderop in de keten het kan clippen.

    Gangbaar bereik: geen. Wordt bepaald door je eigen gain staging, niet door de vendor. Vergelijk vendors in plaats daarvan op hetzelfde niveau.
    Marge
    +0,2 / -0,4 dB. De tolerantie voor een true-peakmeter in ITU-R BS.1770, gehaald door de loudness-benchmark bij elke build.

    Getoetst tegen, en wat het niet is: loudness.truePeak

  3. peakDb POST /v1/mixlab/analyze · dBFS Gevalideerd

    Het hoogste enkele sample.

    0 is full scale. Binnen 1 dB van 0: kijk naar clipping.

    Gangbaar bereik: geen. Wordt bepaald door je eigen gain staging, niet door de vendor. Vergelijk vendors in plaats daarvan op hetzelfde niveau.

    Getoetst tegen, en wat het niet is: level.peak

  4. averageSpeechRmsDb POST /v1/voicelab/qa · dBFS Gevalideerd

    Hoe luid de stem is terwijl ze spreekt.

    Alleen over de spraak gemeten, in dBFS, dus niet op dezelfde schaal als LUFS. Vergelijk vendors op dezelfde tekst.

    Gangbaar bereik: geen. Wordt bepaald door je eigen gain staging, niet door de vendor. Vergelijk vendors in plaats daarvan op hetzelfde niveau.

    Getoetst tegen, en wat het niet is: voice.speechLevel

  5. noiseFloorDb POST /v1/voicelab/qa · dBFS Gevalideerd

    Het niveau van het stilste tiende van de opname: de achtergrond.

    Lager is schoner. Bij echte ruis zit het 1 tot 8 dB onder het gemiddelde niveau van die ruis, omdat het de stilste momenten leest. Synthetische stemmen hebben vaak digitale stilte tussen de woorden: de engine leest dan zijn ondergrens, -120. Het hangt af van hoe luid het bestand is: vergelijk vendors op hetzelfde spraakniveau, of gebruik de signaal-ruisverhouding, die daar niet van afhangt.

    Synthetische stem, schoon
    -120 tot -65,4
    Menselijke stem, schoon
    -56,1 tot -54,2
    Menselijke stem, ruis 10 dB eronder
    -38,8 tot -37
    Synthetische stem, telefoonband
    -120 tot -76,1

    Getoetst tegen, en wat het niet is: voice.noiseFloor

  6. signalToNoiseDb POST /v1/voicelab/qa · dB Gevalideerd

    Hoe ver de stem boven die achtergrond uitsteekt.

    Een schatting. Binnen 6 dB als de werkelijke verhouding 10 tot 30 dB is bij stabiele ruis. Onder 10 dB leest het te hoog. Boven ongeveer 50 dB zegt het alleen dat de pauzes heel stil zijn, vaak digitale stilte: vergelijk daar geen getallen.

    Synthetische stem, schoon
    46,8 tot 101,3
    Menselijke stem, schoon
    26,6 tot 29,5
    Menselijke stem, ruis 10 dB eronder
    11,9 tot 13,8
    Synthetische stem, telefoonband
    55,4 tot 99,5
    Marge
    ±6 dB. Geldt voor voorgelezen spraak met een stabiele achtergrondruis bij een werkelijke verhouding van 10 tot 30 dB (90 procent van de gevallen). Onder 10 dB leest het te hoog, met 3 dB of meer. Met de K2-detector geldt het vanaf 5 dB voor een stadsplein en voor straatverkeer, en gepoold over keuken, woonkamer, gang en kantine (90e percentiel 4,4 dB bij 5 dB); bij 10 dB is de gepoolde waarde over die vier 6,25 dB en haalt een metro 7,3 dB; bij 0 dB leest het nog steeds ongeveer 6 dB te hoog.

    Getoetst tegen, en wat het niet is: voice.snr

  7. clipping POST /v1/voicelab/qa · ernst Gevalideerd

    Of samples tegen het plafond aan kwamen en zijn afgevlakt.

    None, Low, Medium of High, met het aantal. Bij elke schone opname die we maten was het None. Repareer dit eerst: niets anders vergelijkt goed op een geclipte opname.

    Synthetische stem, schoon
    None 48 van 48
    Menselijke stem, schoon
    None 40 van 40
    Menselijke stem, ruis 10 dB eronder
    None 40 van 40
    Synthetische stem, telefoonband
    None 48 van 48

    Getoetst tegen, en wat het niet is: voice.clipping

  8. speechRatio POST /v1/voicelab/qa · aandeel Proxy

    Het aandeel van de opname waarin de stem luid genoeg is om als spraak te tellen.

    Leest ongeveer 12 punten te laag op schone spraak: zachte woordbegins en -einden tellen als pauze. Gebruik het om vendors op dezelfde tekst te vergelijken, niet als een werkelijk aandeel.

    Synthetische stem, schoon
    0,63 tot 0,72
    Menselijke stem, schoon
    0,54 tot 0,73
    Menselijke stem, ruis 10 dB eronder
    0,36 tot 0,58
    Synthetische stem, telefoonband
    0,57 tot 0,68

    Getoetst tegen, en wat het niet is: voice.speechRatio

  9. longSilences POST /v1/voicelab/qa · aantal Proxy

    Hoeveel pauzes langer dan 1,5 seconde er tussen stukken spraak zitten.

    Dode lucht. Exact bij 7 of 8 van de 10 schone opnames, en binnen één bij bijna alle. Ruis maakt het minder betrouwbaar.

    Gangbaar bereik: geen. Het hangt af van je tekst: een enkele zin heeft er geen, een script met pauzes heeft er meerdere. Tel ze bij elke vendor op dezelfde zinnen.

    Getoetst tegen, en wat het niet is: voice.longSilences

  10. bandwidthHz POST /v1/signallab · Hz Gevalideerd

    De hoogste frequentie die nog echte inhoud draagt.

    Ongeveer 4.000 is een telefoonlijn. Breedbandstem reikt tot ongeveer 8.000, en een opname met 44,1 of 48 kHz samplefrequentie kan meer laten zien. Een daling als de achtergrond ruisig is kan betekenen dat de vendor hoge tonen wegsnijdt om het te verbergen.

    Synthetische stem, schoon
    8.000
    Menselijke stem, schoon
    8.000
    Menselijke stem, ruis 10 dB eronder
    8.000
    Synthetische stem, telefoonband
    4.100 tot 4.200

    Getoetst tegen, en wat het niet is: provenance.bandwidthHz

De bereiken lopen van het 5e tot het 95e percentiel van wat de engine mat: 48 synthetische Nederlandse stemmen, 40 Engelse opnames van voorgelezen spraak met een heel stille ruisvloer, dezelfde opnames met woonkamerruis die 10 dB onder de stem is bijgemengd, en de synthetische stemmen door een telefoonband. Ze laten zien wat je kunt verwachten, niet wat goed is.

De bereiken zijn wat we maten op schone en op ruisige opnames. Het zijn startpunten, geen normen. Voor je eigen limieten, zie de laatste stap hieronder.

Zo lees je ze

  1. Kijk eerst naar clipping. Als het niet None is, repareer dan de audio. Niets anders vergelijkt goed op een geclipte opname.
  2. Behandel true peak als informatie. Er is geen standaardplafond voor gespreksaudio. Onze eigen broadcast- en streamingpresets gebruiken -1 of -2 dBTP, en ze bestaan voor levering, niet voor een voice-agent. Als je pipeline de audio opnieuw codeert, kijk dan naar de piek op het punt waar ze opnieuw wordt gecodeerd.
  3. Lees ruis met twee getallen. De ruisvloer zegt hoe stil de achtergrond is. De signaal-ruisverhouding zegt hoe ver de stem erboven uitsteekt. Als ze het oneens zijn, kijk dan eerst naar de ruisvloer: dat is de eenvoudigere meting. Ze leest het stilste tiende van de opname, dus bij echte ruis zit ze 1 tot 8 dB onder het gemiddelde niveau van die ruis.
  4. Kijk naar de bandbreedte naast de ruis. Een vendor wiens bandbreedte daalt als de achtergrond ruisig is, snijdt misschien de hoge frequenties weg om de ruis te verbergen. Dat is een afweging om te zien, niet noodzakelijk een fout.
  5. Gebruik de proxy’s om te vergelijken, niet om feiten vast te stellen. Spraakratio en lange stiltes zijn proxy’s: ze vertellen betrouwbaar welke vendor op dezelfde tekst meer pauzes laat, maar de spraakratio is niet het ware aandeel spraak.
  6. Lees een verschil kleiner dan de marge niet als resultaat. De marge zegt hoe ver één getal van de waarheid kan zitten. We hebben niet gemeten hoe goed het verschil tussen twee getallen standhoudt. Als twee vendors 3 dB uit elkaar liggen op signaal-ruisverhouding en de marge is 6 dB, behandel het dan als een aanwijzing en luister naar de opnames.
  7. Stel je eigen limieten in op basis van je eigen goede opnames. Neem twintig opnames die je goed vindt. Gebruik hun 5e en 95e percentiel als je bereik, en houd de startbereiken hierboven als controle op de meting zelf.
  8. Vergelijk vendors over veel zinnen, niet over één. Gebruik bij elke vendor dezelfde zinnen. Kijk voor elk getal naar de mediaan en de spreiding over de zinnen, en naar hoeveel zinnen dezelfde kant op gaan als je twee vendors naast elkaar legt. We hebben niet gemeten hoe goed het verschil tussen twee vendors standhoudt, dus een verschil dat in maar een paar zinnen zichtbaar is, is een aanwijzing.

Wat het niet kan

  • Het transcribeert niet, en het voorspelt geen transcriptiefouten uit audiokwaliteit. In onze eigen toets van 1.248 transcripties voorspelde de signaal-ruisverhouding geen herkenningsfouten.
  • Het zegt niet of een stem natuurlijk of robotachtig klinkt, en het onderscheidt stemmen niet.
  • Het meet geen latency, onderbrekingen of beurtwisseling.
  • De achtergrondaanwijzingen (sceneBackground en de andere scene-velden) zijn heuristieken op de pauzes, geen herkenning van wat de ruis veroorzaakt.

De volledige lijst staat op wat AudioLab niet doet.

Privacy en limieten

  • Je audio wordt niet bewaard. Ze wordt in het geheugen geanalyseerd in Frankfurt. Een gecomprimeerd bestand (MP3, FLAC, M4A) gaat via een tijdelijk bestand dat direct na het decoderen wordt verwijderd. Een bestand dat je via de signed-upload-route uploadt, wordt binnen het uur verwijderd. Wij bewaren de getallen en, als je dat toestaat, de bestandsnaam. Zie /privacy.
  • Limieten. Gratis: 1.000 aanroepen en 2 GB per maand, 60 verzoeken per minuut. Plus: 10.000 aanroepen, 20 GB, 120 per minuut. Een bestand mag 150 MB zijn als je een publieke URL of een objectPath stuurt. Elk geaccepteerd verzoek telt mee, ook als het daarna faalt. Een fout zegt wat je moet doen: /docs/errors.
  • Waar je staat. GET /v1/usage met je sleutel geeft het abonnement, de deze maand gebruikte aanroepen en data tegen de limieten, en de verzoeken per minuut terug: dezelfde getallen als /account. Het lezen is gratis en telt niet als aanroep. Controleer het voor een grote batch in plaats van het uit een 402 te ontdekken.
  • Vragen over een getal. Schrijf naar support@audiolab.tools met de veldnaam en het bestand, en we zeggen wat we weten.

Hierna

Volgende in General docs

Audiokwaliteit controleren in CI: laat een build falen als een bestand je regels breekt →

Een kort Python-script en een GitHub-workflow die elk audiobestand met de AudioLab-API meten, de getallen vergelijken met limieten die je zelf instelt, en de build laten falen met een bericht dat zegt waarom.

More in General docs