Gemini-3.8-flash-tts Trailing Static / Scratch Noise Artifact at Sentence & Turn Boundaries

When generating text-to-speech using gemini-3.8-flash-tts via the Python SDK or REST API, the raw audio response returned in part.inline_data.data contains an audible ~50–150ms trailing static / scratch noise burst at the end of generated speech turns.

This issue occurs across single-sentence prompts and multi-turn dialogues, affecting voices such as Veda, Rami, Puck, and Kore. While playback within the Google AI Studio Web UI (https://aistudio.google.com/generate-speech) sounds clean (due to client-side WebAudio player post-processing and noise gating), direct consumption of raw API audio bytes yields noticeable scratch artifacts at speech boundaries.


Empirical Observations & Analysis

  1. Waveform Energy Spike: Inspection of the 24kHz PCM signal shows that after speech energy naturally decays (RMS < 0.002), the final 50–150ms of the returned buffer contains an abrupt high-amplitude noise burst (Peak up to 0.571 / RMS up to 0.122).

  2. Step-Discontinuity Pop: Concatenating raw turns or padding with silence creates an instantaneous voltage drop from ~0.57V to 0.0V, producing a sharp step impulse (“scratch / TV signal loss” sound) at every transition.

  3. Web UI vs SDK API Difference: The AI Studio web UI post-processes audio buffers using a WebAudio noise gate mask, whereas the raw API endpoint sends un-masked decoder tail frames. import os
    import base64
    import numpy as np
    import soundfile as sf
    from google import genai
    from google.genai import types

    client = genai.Client(api_key=os.getenv(“GEMINI_API_KEY”))

    1. Request speech from gemini-3.8-flash-tts

    response = client.models.generate_content(
    model=“gemini-3.8-flash-tts”,
    contents=“Happy weekend, everyone! Welcome to Future Human Daily.”,
    config=types.GenerateContentConfig(
    response_modalities=[“AUDIO”],
    speech_config=types.SpeechConfig(
    voice_config=types.VoiceConfig(
    prebuilt_voice_config=types.PrebuiltVoiceConfig(voice_name=“Veda”)
    )
    )
    )
    )

    2. Extract raw audio bytes

    part = response.candidates[0].content.parts[0]
    raw_bytes = part.inline_data.data
    if isinstance(raw_bytes, str):
    raw_bytes = base64.b64decode(raw_bytes)

    pcm_samples = np.frombuffer(raw_bytes, dtype=np.int16).astype(np.float32) / 32768.0

    3. Inspect final 100ms (2400 samples)

    tail_samples = pcm_samples[-2400:]
    print(f"Tail Peak Amplitude: {np.max(np.abs(tail_samples)):.4f}“)
    print(f"Tail RMS Energy: {np.sqrt(np.mean(tail_samples**2)):.4f}”)

    4. Save raw output to file

    sf.write(“gemini_3.8_tail_artifact_test.wav”, pcm_samples, 24000)

Hello @vipin_patney

Unary requests to gemini-3.8-flash-tts return a complete WAV file (audio/wav), not raw PCM. The file has a header at the start and a metadata block at the end. np.frombuffer() on the whole buffer reads those non-audio bytes as samples, and that causes the noise at the end of each clip.

Please try the below steps:

  • If you only need a file, write part.inline_data.data directly to a .wav file.
  • If you need the samples (for example to join turns or add silence), read them with a WAV reader:
import io, wave
import numpy as np

part = response.candidates[0].content.parts[0]
with wave.open(io.BytesIO(part.inline_data.data)) as w:
    pcm = np.frombuffer(w.readframes(w.getnframes()), dtype=np.int16).astype(np.float32) / 32768.0

  • If you call the REST API and want headerless PCM, set generationConfig.responseFormat.audio.mimeType to AUDIO_L16. See Audio output formats.

If you still hear noise inside a clip (for example between sentences) after reading the audio this way, please share the generated file and the approximate timestamp.