Principes clés
-
Architecture audio en couches - Chaque vidéo comporte trois couches audio : narration en haut (la plus forte), SFX au milieu (volume d'accentuation), et musique de fond à la base (la plus faible).
-
La narration détermine le timing - Générez la narration d'abord, mesurez sa durée, puis adaptez le timing des scènes. Ne forcez jamais la narration dans des durées de scènes arbitraires.
-
Baisser la musique pendant la parole - La musique de fond doit baisser de 50-60% quand la narration joue. Utilisez des transitions fluides (10-15 images) pour éviter les à-coups.
-
SFX comme accents, pas distractions - Gardez les SFX courts (moins de 0,5s), subtils en volume, et pertinents par rapport à l'action à l'écran.
-
Tester l'audio en contexte - Prévisualisez toujours le mélange complet avec toutes les couches ensemble. Écoutez la parole boueuse, les pics de volume, ou les silences morts.
Concepts fondamentaux
Architecture audio en 3 couches
| Couche | Rôle | Volume de base | Pendant la narration |
|---|---|---|---|
| Narration | Transmet l'information, détermine le rythme | 0,8-1,0 | N/A (couche supérieure) |
| SFX | Accentue les transitions et actions | 0,3-0,5 | 0,3-0,5 (inchangé) |
| Musique de fond | Établit la tonalité émotionnelle, remplit les silences | 0,3-0,5 | 0,15-0,25 (baissée) |
Modèle API ElevenLabs
ElevenLabs fournit du TTS neuronal via une API REST. Le flux principal :
- Choisissez une voix (prédéfinie ou clonée) - chacune a un
voice_id - Envoyez le texte + paramètres de voix à
/v1/text-to-speech/{voice_id} - Recevez des bytes audio bruts (mp3 par défaut)
- Écrivez dans un fichier et mesurez la durée pour le timing des scènes
Paramètres de voix :
| Paramètre | Plage | Bas | Haut | Recommandé |
|---|---|---|---|---|
| stability | 0-1 | Plus expressif, variable | Plus cohérent, monocorde | 0,4-0,6 |
| similarity_boost | 0-1 | Plus créatif | Plus proche de la voix originale | 0,6-0,8 |
| style | 0-1 | Livraison neutre | Style exagéré | 0,3-0,6 |
Concept du ducking audio
Le ducking audio réduit le volume de la musique de fond quand la narration commence et
le restaure quand la narration se termine. Dans Remotion, utilisez interpolate() :
Volume musique : 0,4 ---\ /--- 0,4
\ /
0,15 \__________/
début narration → fin
Les transitions doivent prendre 10-15 images (~0,3-0,5s à 30fps).
Synchronisation audio basée sur les images dans Remotion
useCurrentFrame()retourne le numéro d'image actuelinterpolate()mappe des plages d'images à des plages de valeurs (ex. volume)<Sequence from={frame}>place l'audio à une image spécifique<Audio volume={fn}>accepte un nombre statique ou une fonction par image
Convertissez les secondes en images : images = secondes * fps.
Tâches courantes
1. Configurer la clé API ElevenLabs et générer la narration
import fs from 'fs';
const ELEVENLABS_API_URL = 'https://api.elevenlabs.io/v1';
async function generateNarration(
text: string,
voiceId: string,
outputPath: string
): Promise<void> {
const response = await fetch(
`${ELEVENLABS_API_URL}/text-to-speech/${voiceId}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'xi-api-key': process.env.ELEVEN_LABS_API_KEY!,
},
body: JSON.stringify({
text,
model_id: 'eleven_multilingual_v2',
voice_settings: {
stability: 0.5,
similarity_boost: 0.75,
style: 0.5,
use_speaker_boost: true,
},
}),
}
);
if (!response.ok) {
const error = await response.text();
throw new Error(`ElevenLabs API error ${response.status}: ${error}`);
}
const buffer = Buffer.from(await response.arrayBuffer());
fs.writeFileSync(outputPath, buffer);
}
2. Sélectionner et configurer les paramètres de voix
Questions pour la sélection de voix : genre, tranche d'âge, accent, niveau d'énergie, chaleur.
interface VoiceSettings {
stability: number;
similarity_boost: number;
style: number;
use_speaker_boost: boolean;
}
const presets: Record<string, VoiceSettings> = {
explainer: { stability: 0.6, similarity_boost: 0.75, style: 0.4, use_speaker_boost: true },
promo: { stability: 0.3, similarity_boost: 0.7, style: 0.7, use_speaker_boost: true },
tutorial: { stability: 0.7, similarity_boost: 0.8, style: 0.2, use_speaker_boost: false },
};
3. Générer la narration par scène à partir d'un script
import { execSync } from 'child_process';
import path from 'path';
interface Scene { id: string; narrationText: string; }
interface SceneWithAudio extends Scene {
audioPath: string;
durationMs: number;
durationFrames: number;
}
function getAudioDurationMs(filePath: string): number {
const output = execSync(
`ffprobe -v error -show_entries format=duration -of csv=p=0 "${filePath}"`
).toString().trim();
return Math.round(parseFloat(output) * 1000);
}
async function generateSceneNarrations(
scenes: Scene[], voiceId: string, outputDir: string, fps: number
): Promise<SceneWithAudio[]> {
const results: SceneWithAudio[] = [];
for (const scene of scenes) {
const audioPath = path.join(outputDir, `${scene.id}.mp3`);
await generateNarration(scene.narrationText, voiceId, audioPath);
const durationMs = getAudioDurationMs(audioPath);
results.push({
...scene, audioPath, durationMs,
durationFrames: Math.ceil((durationMs / 1000) * fps),
});
}
return results;
}
4. Sourcer la musique de fond
Sources de musique libre de droits :
- Pixabay Audio : https://pixabay.com/music/ (gratuit, pas d'attribution)
- Freesound : https://freesound.org/ (CC0/CC-BY)
- YouTube Audio Library : téléchargez depuis YouTube Studio
- Fichiers locaux : placez dans
public/audio/pourstaticFile()de Remotion
5. Générer des SFX avec FFmpeg
# Son de clic - burst sinusoïdale courte
ffmpeg -f lavfi -i "sine=frequency=800:duration=0.05" \
-af "afade=t=out:st=0.02:d=0.03" click.wav
# Clavier tapé - burst de bruit filtré
ffmpeg -f lavfi -i "anoisesrc=d=0.08:c=white:a=0.3" \
-af "highpass=f=2000,lowpass=f=8000,afade=t=out:st=0.04:d=0.04" type.wav
# Whoosh - balayage fréquentiel
ffmpeg -f lavfi -i "sine=frequency=200:duration=0.4" \
-af "vibrato=f=8:d=0.5,afade=t=in:d=0.1,afade=t=out:st=0.2:d=0.2,lowpass=f=1000" \
whoosh.wav
# Ding/chime - synthèse de cloche
ffmpeg -f lavfi -i "sine=frequency=1200:duration=0.6" \
-af "afade=t=out:st=0.1:d=0.5,aecho=0.8:0.88:40:0.4" ding.wav
# Pop - impulsion
ffmpeg -f lavfi -i "sine=frequency=400:duration=0.08" \
-af "afade=t=out:st=0.02:d=0.06,lowpass=f=600" pop.wav
# Transition whoosh
ffmpeg -f lavfi -i "sine=frequency=300:duration=0.3" \
-af "vibrato=f=12:d=0.8,afade=t=in:d=0.05,afade=t=out:st=0.15:d=0.15,bandpass=f=500:w=400" \
swoosh.wav
6. Implémenter le ducking audio dans Remotion
import React from 'react';
import { Audio, useCurrentFrame, interpolate, Sequence } from 'remotion';
const AudioMixer: React.FC<{
narrationSrc: string;
musicSrc: string;
narrationStart: number;
narrationDuration: number;
}> = ({ narrationSrc, musicSrc, narrationStart, narrationDuration }) => {
const frame = useCurrentFrame();
const duckRampFrames = 10;
const musicVolume = interpolate(
frame,
[
narrationStart - duckRampFrames,
narrationStart,
narrationStart + narrationDuration,
narrationStart + narrationDuration + duckRampFrames,
],
[0.4, 0.15, 0.15, 0.4],
{ extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }
);
return (
<>
<Audio src={musicSrc} volume={musicVolume} />
<Sequence from={narrationStart} durationInFrames={narrationDuration}>
<Audio src={narrationSrc} volume={0.9} />
</Sequence>
</>
);
};
export default AudioMixer;
7. Mixer 3 couches audio dans une composition Remotion
import React from 'react';
import { Audio, Sequence, useCurrentFrame, interpolate } from 'remotion';
interface NarrationSegment { src: string; startFrame: number; durationFrames: number; }
interface SfxEvent { src: string; frame: number; }
const FullAudioMix: React.FC<{
narrations: NarrationSegment[];
sfxEvents: SfxEvent[];
musicSrc: string;
}> = ({ narrations, sfxEvents, musicSrc }) => {
const frame = useCurrentFrame();
const duckRamp = 10;
let musicVolume = 0.4;
for (const seg of narrations) {
const duck = interpolate(
frame,
[seg.startFrame - duckRamp, seg.startFrame,
seg.startFrame + seg.durationFrames, seg.startFrame + seg.durationFrames + duckRamp],
[1, 0.375, 0.375, 1],
{ extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }
);
musicVolume = musicVolume * duck;
}
return (
<>
<Audio src={musicSrc} volume={musicVolume} loop />
{sfxEvents.map((sfx, i) => (
<Sequence key={i} from={sfx.frame} durationInFrames={30}>
<Audio src={sfx.src} volume={0.4} />
</Sequence>
))}
{narrations.map((seg, i) => (
<Sequence key={i} from={seg.startFrame} durationInFrames={seg.durationFrames}>
<Audio src={seg.src} volume={0.9} />
</Sequence>
))}
</>
);
};
export default FullAudioMix;
8. Utiliser des fournisseurs TTS alternatifs
OpenAI TTS - bonne qualité, API simple, six voix intégrées :
import OpenAI from 'openai';
import fs from 'fs';
const openai = new OpenAI();
async function generateWithOpenAI(
text: string,
outputPath: string,
voice: 'alloy' | 'echo' | 'fable' | 'onyx' | 'nova' | 'shimmer' = 'alloy'
): Promise<void> {
const mp3 = await openai.audio.speech.create({
model: 'tts-1-hd',
voice,
input: text,
});
const buffer = Buffer.from(await mp3.arrayBuffer());
fs.writeFileSync(outputPath, buffer);
}
Edge TTS - gratuit, nombreuses voix, utilise le service TTS de Microsoft Edge :
pip install edge-tts
edge-tts --voice en-US-AriaNeural --text "Hello world" --write-media output.mp3
edge-tts --list-voices
Anti-patterns / erreurs courantes
| Erreur | Pourquoi c'est faux | Que faire à la place |
|---|---|---|
| Musique au même volume pendant la narration | La parole devient inintelligible | Implémenter le ducking audio - baisser la musique de 50-60% pendant la parole |
| Coder en dur la clé API ElevenLabs | La clé fuit dans le contrôle de version | Utiliser des variables d'environnement : process.env.ELEVEN_LABS_API_KEY |
| Utiliser TTS sans mesurer la durée | Timing de scène incorrect, narration coupée | Mesurer la durée audio avec ffprobe après la génération |
| SFX plus fort que la narration | Distrait du contenu | SFX à 0,3-0,5, narration à 0,8-1,0 |
| Pas de fade sur le début/fin de la musique | Le démarrage/arrêt abrupt semble un bug | Ajouter 0,5-1s de fade-in au démarrage et fade-out à la fin |
| Utiliser un modèle TTS de basse qualité | La voix robotique undermines la qualité | Utiliser eleven_multilingual_v2 ou tts-1-hd |
| Ignorer le format du fichier audio | Certains formats ajoutent du silence de remplissage | Utiliser MP3 pour la narration, WAV pour les SFX |
Pièges
-
Limites de débit ElevenLabs et quotas de caractères - Le tier gratuit a une limite de caractères mensuelle. Mettez en cache l'audio généré agressivement et ne régénérez que quand le texte change. Utilisez un hash du texte comme clé de cache.
-
Le remplissage du codeur MP3 ajoute du silence - Les fichiers MP3 ont souvent 20-50ms de silence au début. Taillez avec
ffmpeg -af silenceremove=1:0:-50dBou compensez le décalage dans le timing des images. -
Le volume Remotion Audio est par composant, pas global - Deux composants
<Audio>au volume 1,0 peuvent écrêter. Gardez le volume total sur les couches simultanées sous 1,0. -
Les SFX FFmpeg sonnent différemment selon les systèmes - Toujours spécifier
-ar 44100 -sample_fmt s16pour une sortie cohérente entre les machines. -
Cohérence de voix entre les scènes - ElevenLabs peut produire des tonalités différentes pour les mêmes paramètres avec du texte variable. Utilisez stability >= 0,5 pour la narration multi-scènes.
Références
Pour des patterns détaillés sur des sous-domaines audio spécifiques, consultez le fichier pertinent
du dossier references/ :
references/elevenlabs-api.md- patterns API ElevenLabs avancés incluant le clonage de voix, TTS streaming, API websocket, dictionnaires de prononciation, et gestion des quotasreferences/audio-mixing-patterns.md- patterns de mixage avancés incluant le ducking multi-segment, crossfades entre scènes, courbes d'automatisation de volume, et mastérisation du mix finalreferences/sfx-generation.md- génération complète de SFX avec FFmpeg incluant la synthèse complexe, le layering de multiples générateurs, et la construction d'une librairie de SFX réutilisable
Chargez un fichier references seulement si la tâche actuelle le nécessite - ils sont longs et consommeront du contexte.