elevenlabs について
ElevenLabs APIで音声を生成・処理するツールキットスキルです。音声合成、文字起こし、ボイスクローン、効果音、音楽に加え、Remotionのシーンにナレーションを同期する方法を扱います。
主な機能
- 01複数モデルで音声を生成
- 02Scribeで音声を文字起こし
- 03インスタントボイスクローンを作成
- 04効果音と音楽を生成
- 05Remotion用にシーン音声を調整
活用シーン
- 01ナレーション付き動画シーンの制作
- 02音声の文字起こしと単語タイミングの調整
- 03音声サンプルからのボイスクローン作成
- 04効果音やバックグラウンド音楽の生成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ digitalsamba/ claude-code-video-toolkit --skill elevenlabsインストール後、Claude Code で/elevenlabsを入力して読み込まれたか確認します。
同梱ファイルreference.md
詳細
ElevenLabs の音声生成
.env に ELEVENLABS_API_KEY が必要です。
テキスト読み上げ
from elevenlabs.client import ElevenLabs
from elevenlabs import save, VoiceSettings
import os
client = ElevenLabs(api_key=os.getenv("ELEVENLABS_API_KEY"))
audio = client.text_to_speech.convert(
text="Welcome to my video!",
voice_id="JBFqnCBsd6RMkjVDRZzb",
model_id="eleven_multilingual_v2",
voice_settings=VoiceSettings(
stability=0.5,
similarity_boost=0.75,
style=0.5,
speed=1.0
)
)
save(audio, "voiceover.mp3")
モデル
| モデル | 品質 | SSML サポート | 備考 |
|---|---|---|---|
eleven_multilingual_v2 | 一貫性が最も高い | なし | 安定しており、本番環境で使用可能です。29 言語に対応しています。ツールキットのデフォルトです。スタイルと速度を指定できます |
eleven_v4 | 表現力が最も高い | なし(オーディオタグ、IPA) | 最新モデル(2026-09-28 リリース)です。90 以上の言語に対応し、音声のクローン精度が最も高いモデルです。安定性と類似度のみ指定でき、スタイルと速度は指定できません |
eleven_flash_v2_5 | 良好 | <break>、<phoneme> | 最速かつ最も低価格です。一時停止タグと発音タグに対応しています |
eleven_v3 | 表現力が高い | なし | 前世代のモデルです。v4 を推奨します |
選択方法: 信頼性と速度・スタイルの調整を重視する場合は multilingual_v2、最大限の表現力とクローン音声を重視する場合は v4(複数のテイクを試してください)、SSML の制御を重視する場合は flash を選択します。
非推奨: eleven_turbo_v2_5 → eleven_flash_v2_5 を使用してください(品質は同じで、レイテンシが低くなります。非推奨モデルを参照)。ツールキットでは引き続き --model eleven_turbo_v2_5 を受け付けますが、1 行の警告を表示して eleven_flash_v2_5 を送信します。
Eleven v4
2026-09-28 リリース(変更履歴、モデルページ)。ElevenLabs がコンテンツ制作と長尺音声向けに推奨しているとおり、ツールキットは 1 つの入力(ナレーターの音声)で Text to Dialogue API を呼び出して v4 を利用します。
from elevenlabs import DialogueInput
audio = client.text_to_dialogue.convert(
inputs=[DialogueInput(text="[warm] Welcome to my video!", voice_id="JBFqnCBsd6RMkjVDRZzb")],
model_id="eleven_v4",
settings={"stability": 0.5, "similarity": 0.75}, # the only two settings v4 takes
)
save(audio, "voiceover.mp3")
uv run tools/voiceover.py --model eleven_v4 ...(およびredub.py --model eleven_v4)を実行すると、この処理が行われます。--style/--speedは無視されることを 1 回だけ警告し、テキストが 1 リクエストあたり約 2,000 文字を超える場合は、信頼性の高い対話の上限に合わせて文の区切りで分割します。--speedの代わりに--max-wpmで話すペースを調整してください。client.text_to_dialogue.convert_with_timestamps(...)は、TTS のconvert_with_timestampsと同じ文字アライメントを返すため、redub.py --syncは v4 でも動作し、同じ安定性と類似度を送信します。settingsは辞書として渡してください。2.69 より前の SDK バージョンでは、安定性のみを含むモデルとして型付けされます。API は 2026-09-28 以降、そこで指定されたsimilarityを読み取ります(範囲外の値は 422 エラーになります)。Text to Dialogue にはelevenlabs>=2.21が必要です。- オーディオタグ(
[whispering]、[warm]、[sigh])と句読点を使って直接音声を生成します。v4 はタグを効果音として読み上げることもあるため、声を明確に表すタグを記述してください。 eleven_v4_turboはリアルタイム向けのバリアントで、Text to Dialogue WebSocket 経由でのみ利用できます。オフラインのレンダリングでは低レイテンシのメリットがないため、ツールキットでは使用しません。
スタイル別の音声設定
| スタイル | stability | similarity | style | speed |
|---|---|---|---|---|
| 自然/プロフェッショナル | 0.75-0.85 | 0.9 | 0.0-0.1 | 1.0 |
| 会話調 | 0.5-0.6 | 0.85 | 0.3-0.4 | 0.9-1.0 |
| 活気のある YouTuber 風 | 0.3-0.5 | 0.75 | 0.5-0.7 | 1.0-1.1 |
セクション間の一時停止
flash モデルの場合: SSML の break タグをインラインで使用します。
...end of section. <break time="1.5s" /> Start of next...
1 回の break は最大 3 秒です。break が多すぎると、速度に不自然な乱れが生じることがあります。
multilingual_v2/v3/v4 の場合: SSML はサポートされていません。次の方法があります。
- 段落の区切り(空行)を入れると、自然な約 0.3~0.5 秒の間ができます
- v3/v4:
[long pause]などのオーディオタグを使います - ffmpeg で後処理し、音声を分割して無音を挿入します
警告: ...(省略記号)は確実な一時停止の方法ではありません。単語や音として発音されることがあります。一時停止の手段として省略記号を使用しないでください。
発音の制御
発音表記(すべてのモデル): 発音させたいとおりに単語を記述します。
Janus→Jan-usnginx→engine-x- ハイフン、大文字、アポストロフィを使って発音を誘導します
SSML の phoneme タグ(flash のみ):
<phoneme alphabet="ipa" ph="ˈdʒeɪnəs">Janus</phoneme>
v4 の IPA: タグは不要です。単語の代わりに IPA をスラッシュで囲み、二重引用符で括ります。
The term "/ˌbaɪoʊˈkemɪstri/" refers to the study of chemical processes.
反復ワークフロー
- 生成 → 聴く → 発音やペースの問題を特定する
- 調整する:発音を表す綴り、ブレークタグ、音声設定
- 再生成する。ポーズの精度が不十分な場合は、TTS エンジンを無理に調整するのではなく、ffmpeg で後処理時に無音を追加します。
音声テキスト変換(Scribe)
with open("voiceover.mp3", "rb") as f:
result = client.speech_to_text.convert(file=f, model_id="scribe_v2", tag_audio_events=False)
words = [w for w in result.words if w.type == "word"] # .text, .start, .end (seconds)
scribe_v2 は現行バージョンであり、ツールキットのデフォルトです。scribe_v1 は非推奨で、削除予定日は 2026-07-09 と告知されています(変更履歴)。ただし、現在も応答するため、--stt-model scribe_v1(redub)と --model scribe_v1(align_captions)は警告を表示したうえで実行されます。2025 年に公開された scribe_v1 のプレビュー版である scribe_v1_experimental は、警告とともに受け付けられ、scribe_v2 として送信されます。ツールキットでは、redub.py(文字起こしと --sync による単語のタイミング調整)および align_captions.py で Scribe を使用します。
音声クローン
インスタント音声クローン
with open("sample.mp3", "rb") as f:
voice = client.voices.ivc.create(
name="My Voice",
files=[f],
remove_background_noise=True
)
print(f"Voice ID: {voice.voice_id}")
client.voices.clone()ではなく、client.voices.ivc.create()を使用します- パスではなく、ファイルハンドルをバイナリモード(
"rb")で渡します - まず m4a を変換します:
ffmpeg -i input.m4a -codec:a libmp3lame -qscale:a 2 output.mp3 - 複数のサンプル(2~3 個のクリップ)を使うと精度が向上します
- 音声 ID を保存して再利用します
プロフェッショナル音声クローン: Creator プラン以上が必要で、音声は 30 分以上必要です。reference.md を参照してください。
効果音
1 回の生成につき最大 22 秒です。
result = client.text_to_sound_effects.convert(
text="Thunder rumbling followed by heavy rain",
duration_seconds=10,
prompt_influence=0.3
)
with open("thunder.mp3", "wb") as f:
for chunk in result:
f.write(chunk)
プロンプトのヒント: 具体的に指定します — 「木の床板の上を、ゆっくりと意図的に歩く重い足音。きしむ音も含める」
音楽生成
10 秒から 5 分までです。.generate() ではなく、client.music.compose() を使用します。
result = client.music.compose(
prompt="Upbeat indie rock, catchy guitar riff, energetic drums, travel vlog",
music_length_ms=60000,
force_instrumental=True
)
with open("music.mp3", "wb") as f:
for chunk in result:
f.write(chunk)
プロンプトの構成: ジャンル、ムード、楽器、テンポ、用途を指定します。BGM には「ボーカルなし」を追加するか、force_instrumental=True を使用します。
Remotion との統合
完全なワークフロー:スクリプトから同期されたシーンまで
VOICEOVER-SCRIPT.md → voiceover.py → public/audio/ → Remotion composition
↓ ↓ ↓ ↓
Scene narration Generate MP3 Audio files <Audio> component
with durations per scene with timing synced to scenes
ステップ 1:シーンごとの音声を生成する
ツールキットのナレーションツールを使って、各シーンの音声を生成します:
# Generate voiceover files for each scene
uv run tools/voiceover.py --scene-dir public/audio/scenes --json
# Output:
# public/audio/scenes/
# ├── scene-01-title.mp3
# ├── scene-02-problem.mp3
# ├── scene-03-solution.mp3
# └── manifest.json (durations for each file)
manifest.json にはタイミング情報が含まれています:
{
"scenes": [
{ "file": "scene-01-title.mp3", "duration": 4.2 },
{ "file": "scene-02-problem.mp3", "duration": 12.8 },
{ "file": "scene-03-solution.mp3", "duration": 15.3 }
],
"totalDuration": 32.3
}
ステップ 2:Remotion のコンポジションで音声を使用する
// src/Composition.tsx
import { Audio, staticFile, Series, useVideoConfig } from 'remotion';
// Import scene components
import { TitleSlide } from './scenes/TitleSlide';
import { ProblemSlide } from './scenes/ProblemSlide';
import { SolutionSlide } from './scenes/SolutionSlide';
// Scene durations (from manifest.json, converted to frames at 30fps)
const SCENE_DURATIONS = {
title: Math.ceil(4.2 * 30), // 126 frames
problem: Math.ceil(12.8 * 30), // 384 frames
solution: Math.ceil(15.3 * 30), // 459 frames
};
export const MainComposition: React.FC = () => {
return (
<>
{/* Scene sequence */}
<Series>
<Series.Sequence durationInFrames={SCENE_DURATIONS.title}>
<TitleSlide />
</Series.Sequence>
<Series.Sequence durationInFrames={SCENE_DURATIONS.problem}>
<ProblemSlide />
</Series.Sequence>
<Series.Sequence durationInFrames={SCENE_DURATIONS.solution}>
<SolutionSlide />
</Series.Sequence>
</Series>
{/* Audio track - plays continuously across all scenes */}
<Audio src={staticFile('audio/voiceover.mp3')} volume={1} />
{/* Optional: Background music at lower volume */}
<Audio src={staticFile('audio/music.mp3')} volume={0.15} />
</>
);
};
ステップ 3:シーンごとの音声(別の方法)
より細かく制御するには、各シーンに個別に音声を追加します:
// src/scenes/ProblemSlide.tsx
import { Audio, staticFile, useCurrentFrame } from 'remotion';
export const ProblemSlide: React.FC = () => {
const frame = useCurrentFrame();
return (
<div style={{ /* slide styles */ }}>
<h1>The Problem</h1>
{/* Scene content */}
{/* Audio starts when this scene starts (frame 0 of this sequence) */}
<Audio src={staticFile('audio/scenes/scene-02-problem.mp3')} />
</div>
);
};
ナレーションに映像を同期する
シーンの長さは、逆算するのではなく、音声から計算します:
// src/config/timing.ts
import manifest from '../../public/audio/scenes/manifest.json';
const FPS = 30;
// Convert audio durations to frame counts
export const sceneDurations = manifest.scenes.reduce((acc, scene) => {
const name = scene.file.replace(/^scene-\d+-/, '').replace('.mp3', '');
acc[name] = Math.ceil(scene.duration * FPS);
return acc;
}, {} as Record<string, number>);
// Usage in composition:
// <Series.Sequence durationInFrames={sceneDurations.title}>
音声のタイミングパターン
import { Audio, Sequence, interpolate, useCurrentFrame } from 'remotion';
// Fade in audio
export const FadeInAudio: React.FC<{ src: string; fadeFrames?: number }> = ({
src,
fadeFrames = 30
}) => {
const frame = useCurrentFrame();
const volume = interpolate(frame, [0, fadeFrames], [0, 1], {
extrapolateRight: 'clamp',
});
return <Audio src={src} volume={volume} />;
};
// Delayed audio start
export const DelayedAudio: React.FC<{ src: string; delayFrames: number }> = ({
src,
delayFrames
}) => (
<Sequence from={delayFrames}>
<Audio src={src} />
</Sequence>
);
// Usage:
// <FadeInAudio src={staticFile('audio/music.mp3')} fadeFrames={60} />
// <DelayedAudio src={staticFile('audio/sfx/whoosh.mp3')} delayFrames={45} />
ナレーションとデモ動画の同期
シーンにナレーションとデモ動画の両方がある場合:
import { Audio, OffthreadVideo, staticFile, useVideoConfig } from 'remotion';
export const DemoScene: React.FC = () => {
const { durationInFrames, fps } = useVideoConfig();
// Calculate playback rate to fit demo into voiceover duration
const demoDuration = 45; // seconds (original demo length)
const sceneDuration = durationInFrames / fps; // seconds (from voiceover)
const playbackRate = demoDuration / sceneDuration;
return (
<>
<OffthreadVideo
src={staticFile('demos/feature-demo.mp4')}
playbackRate={playbackRate}
/>
<Audio src={staticFile('audio/scenes/scene-04-demo.mp3')} />
</>
);
};
エラー処理
import { Audio, staticFile, delayRender, continueRender } from 'remotion';
import { useEffect, useState } from 'react';
export const SafeAudio: React.FC<{ src: string }> = ({ src }) => {
const [handle] = useState(() => delayRender());
const [audioReady, setAudioReady] = useState(false);
useEffect(() => {
const audio = new window.Audio(src);
audio.oncanplaythrough = () => {
setAudioReady(true);
continueRender(handle);
};
audio.onerror = () => {
console.error(`Failed to load audio: ${src}`);
continueRender(handle); // Continue without audio rather than hang
};
}, [src, handle]);
if (!audioReady) return null;
return <Audio src={src} />;
};
ツールキットコマンド:/generate-voiceover
/generate-voiceover コマンドでワークフロー全体を処理できます:
/generate-voiceover
1. Reads VOICEOVER-SCRIPT.md
2. Extracts narration for each scene
3. Generates audio via ElevenLabs API
4. Saves to public/audio/scenes/
5. Creates manifest.json with durations
6. Updates project.json with timing info
人気の音声
- George:
JBFqnCBsd6RMkjVDRZzb(温かみのあるナレーター) - Rachel:
21m00Tcm4TlvDq8ikWAM(聞き取りやすい女性の声) - Adam:
pNInz6obpgDQGcFmaJgB(プロフェッショナルな男性の声)
すべてを一覧表示するには:client.voices.get_all()
API の全ドキュメントについては、reference.md を参照してください。