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
-
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). -
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.
-
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 typesclient = 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)