Remotion Audioコンポーネント完全ガイド:BGM・ナレーション・効果音の実装
Remotion Audioコンポーネント完全ガイド:BGM・ナレーション・効果音の実装
映像と音声が組み合わさって、初めて「動画」が完成します。Remotionで作ったビジュアルアニメーションにBGMを乗せ、ナレーションと同期させ、効果音を特定のフレームに合わせる——これらをすべて、Reactの宣言的なモデルで実現するのが <Audio> コンポーネントです。
このガイドでは、staticFile とURLによるオーディオ読み込み、数値と関数どちらでも設定できる volume、startFrom/endAt によるトリミング、<Loop> を使ったループ、複数トラックのレイヤリング、対応フォーマット、そして最も多いトラブルである「音声がずれる」問題の原因と対処法まで体系的に解説します。
<Audio> コンポーネントの基本
<Audio> は remotion パッケージから直接インポートします。追加のインストールは不要です。
import { Audio } from 'remotion';
最もシンプルな使い方は、オーディオファイルを指定してコンポジションの開始から再生するだけです。
import { Audio, staticFile } from 'remotion';
export const MyComposition: React.FC = () => {
return (
<>
<Audio src={staticFile('bgm.mp3')} />
{/* その他のビジュアルコンポーネント */}
</>
);
};
<Audio> は不可視です——DOM要素を一切描画しません。JSXのどこに置いてもビジュアル上の影響はなく、音声の動作のみを管理します。
src プロップ:staticFile と URL の使い分け
staticFile(推奨)
staticFile() は、Remotionプロジェクトにバンドルされているオーディオファイルを参照する推奨の方法です。ファイルをプロジェクトの public/ ディレクトリに配置し、ファイル名を引数に渡します。
your-project/
public/
bgm.mp3
narration.mp3
sfx-pop.wav
src/
Root.tsx
MyComposition.tsx
<Audio src={staticFile('bgm.mp3')} />
<Audio src={staticFile('narration.mp3')} />
public/ 内のファイルは開発プレビュー中に提供され、レンダリング時にも正しくバンドルされます。外部サービスへの依存がないため、本番レンダリングに最も安定した方法です。
リモートURL
HTTPSのURLを直接渡すこともできます。
<Audio src="https://example.com/audio/bgm.mp3" />
開発時には問題なく動作しますが、レンダリング時にRemotionがURLをフェッチするため、ネットワークアクセスが必要で、URLが安定している必要があります。本番レンダリングには staticFile の使用を推奨します。
動的な src(inputProps との組み合わせ)
src は単なるプロップなので、動的に設定できます。
interface Props {
audioFile: string;
}
export const DynamicAudioComp: React.FC<Props> = ({ audioFile }) => {
return <Audio src={staticFile(audioFile)} />;
};
ユーザーがオーディオトラックを選択できるテンプレートシステムに特に便利です。
volume プロップ:固定と動的
固定ボリューム
0(無音)から 1(最大音量)の間の数値を渡します。
<Audio src={staticFile('bgm.mp3')} volume={0.4} />
この設定はオーディオ全体に対して一定の音量を適用します。
動的ボリューム(フレーム単位のキーフレーミング)
volume プロップは関数 (frame: number) => number も受け付けます。この関数はレンダリングされる各フレームで呼び出され、フェードイン・フェードアウト・ダッキングなど、あらゆる音量形状を実現できます。
import { Audio, staticFile, interpolate } from 'remotion';
export const FadeInAudio: React.FC = () => {
return (
<Audio
src={staticFile('bgm.mp3')}
volume={(frame) =>
interpolate(frame, [0, 30], [0, 0.5], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
})
}
/>
);
};
最初の30フレーム(30fpsで1秒)かけて音量が0から0.5にフェードインします。extrapolateRight: 'clamp' でフレーム30以降も0.5を維持します。
フェードアウト(終了直前)
150フレームのコンポジションの最後2秒でフェードアウトする例:
<Audio
src={staticFile('bgm.mp3')}
volume={(frame) =>
interpolate(frame, [120, 150], [0.5, 0], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
})
}
/>
オーディオダッキング(ナレーション中のBGM音量を下げる)
放送・映像制作の定番テクニックです。ナレーションが入る区間だけBGMを下げ、ナレーション後に戻します。
{/* ナレーションはフレーム30〜120に配置 */}
<Audio
src={staticFile('bgm.mp3')}
volume={(frame) =>
interpolate(
frame,
[25, 30, 120, 130],
[0.6, 0.15, 0.15, 0.6],
{ extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }
)
}
/>
<Audio src={staticFile('narration.mp3')} startFrom={30} />
4つのキーポイント [25, 30, 120, 130] が、滑らかなランプダウン→15%でのサステイン→ランプアップを生成します。
startFrom と endAt でオーディオをトリミングする
startFrom
オーディオファイルのどのフレームから再生を開始するかを指定します。ファイルの先頭をカットします。値はコンポジションの fps 基準のフレーム数です(ミリ秒ではありません)。
// 最初の1秒をスキップ(30fps)
<Audio src={staticFile('bgm.mp3')} startFrom={30} />
音楽トラックに数秒の無音イントロがある場合や、特定の拍から再生を開始したい場合に使います。
endAt
オーディオの再生を停止するフレームを指定します。ファイルの末尾をカットします。
// 最初の3秒だけ再生(フレーム0〜90)
<Audio src={staticFile('bgm.mp3')} endAt={90} />
両方を組み合わせる
// ファイルの2秒目から5秒目を抽出して再生
<Audio
src={staticFile('bgm.mp3')}
startFrom={60} // 2秒(2 × 30fps)から開始
endAt={150} // 5秒(5 × 30fps)で終了
/>
これでオーディオファイルの中間から3秒分のセグメントを切り取れます。特定のフレーズや音楽フレーズだけを使いたいときに最適です。
<Sequence> と組み合わせてタイミングを制御する
コンポジション内の特定の時点からオーディオを開始するには(ファイルのトリミングではなく)、<Audio> を <Sequence> で囲みます。
{/* コンポジションのフレーム60(2秒後)から効果音を再生 */}
<Sequence from={60}>
<Audio src={staticFile('sfx-pop.wav')} />
</Sequence>
<Audio> に startFrom を指定すると、それはシーケンスの開始からの相対値ではなく、コンポジションのグローバルフレームからの相対値になります。<Sequence from> と startFrom の役割の違いを明確にしておくことが重要です。
<Loop> でオーディオをループする
<Loop> コンポーネントは指定した回数または無制限に内容を繰り返します。<Audio> を <Loop> で囲むことでリピート再生を実現します。
import { Loop, Audio, staticFile } from 'remotion';
export const LoopingBgm: React.FC = () => {
return (
// 6秒(180フレーム)のトラックを10回ループ
<Loop durationInFrames={180} times={10}>
<Audio src={staticFile('loop-bgm.mp3')} />
</Loop>
);
};
times を省略するとコンポジションの長さいっぱいループします。
<Loop durationInFrames={180}>
<Audio src={staticFile('loop-bgm.mp3')} />
</Loop>
<Loop> の durationInFrames はオーディオファイルの実際の長さと一致させる必要があります。短すぎると音声が途切れ、長すぎると次のループ前に無音区間ができます。シームレスループ用に設計されたオーディオファイル(終端が先頭に自然につながる)を使うのがベストです。
複数のオーディオトラックをレイヤリングする
<Audio> コンポーネントは必要なだけ同時に描画できます。最終レンダリングで自動的にミックスされます。
export const FullMixComposition: React.FC = () => {
return (
<>
{/* BGM — 控えめな音量 */}
<Audio src={staticFile('bgm.mp3')} volume={0.3} />
{/* ナレーション — フルボリューム、1秒後から */}
<Sequence from={30}>
<Audio src={staticFile('narration.mp3')} volume={1} />
</Sequence>
{/* 特定の瞬間の効果音 */}
<Sequence from={90}>
<Audio src={staticFile('sfx-ding.wav')} volume={0.8} />
</Sequence>
{/* ビジュアルレイヤー */}
<MySlides />
</>
);
};
専用のミキサーコンポーネントは不要です。ミキシングはプレビュー時にはブラウザのオーディオエンジンが、レンダリング時には音声処理パイプラインが自動的に行います。クリッピングを避けるため、合計音量が 1.0 を超えないよう注意してください。
muted プロップ
muted={true} を渡すと、コンポーネントツリーからオーディオを削除せずに無音にできます。開発中に一時的に無効化したい場合や、プレイヤー埋め込みでミュート状態をユーザー設定から制御する場合に便利です。
<Audio src={staticFile('bgm.mp3')} volume={0.4} muted={isMuted} />
対応オーディオフォーマット
RemotionのレンダリングにはChromiumベースのヘッドレスブラウザを使用します。Chromiumがサポートするフォーマットが対応フォーマットです。
| フォーマット | 拡張子 | 備考 |
|---|---|---|
| MP3 | .mp3 | 最も互換性が高い。BGM・ナレーションに推奨。 |
| WAV | .wav | 非圧縮。ファイルサイズは大きいが劣化なし。短い効果音に最適。 |
| AAC | .aac / .m4a | MP3より小さいファイルサイズで高品質。 |
| OGG Vorbis | .ogg | オープンフォーマット。Chromiumで完全サポート。 |
| FLAC | .flac | ロスレス。大きなファイルサイズ。ローカルレンダリングには可。 |
| WebM Audio | .webm | サポートされているが使用頻度は低い。 |
推奨: BGMとナレーションには .mp3(128〜320kbps、幅広い互換性)。短い効果音にはタイミングの正確さが求められるため .wav を推奨。
注意: ギャップレスループヘッダーなどのフォーマット固有の機能は、予期せぬ動作をする場合があります。ループはRemotio Studio のプレビューで必ず手動確認してからレンダリングしてください。
<Audio> と <OffthreadVideo> の使い分け
<OffthreadVideo> はRemotionで動画ファイルを埋め込むためのコンポーネントです。フレームレートの問題を避けるためにビデオをオフスレッドでレンダリングし、音声トラックも含めて処理します。
動画ファイルの音声を使いたい場合は <OffthreadVideo> を使います——ビジュアルフレームと音声を両方処理します。同じファイルに <Audio> を追加する必要はありません。
// 正しい: 動画ファイルには OffthreadVideo を使う
<OffthreadVideo src={staticFile('intro-clip.mp4')} volume={0.8} />
// 避けること: 同じ動画ファイルに Audio を別途追加すると音声が2重になる
<Audio> はスタンドアロンのオーディオファイル(BGM、ナレーション、効果音)専用です。
音声ズレ問題の原因と対処法
音声ズレ——プレビューでは正常なのにレンダリング済み動画では音声とビジュアルがずれる——はRemotionプロジェクトで最も多いオーディオトラブルです。主な原因と対処法を整理します。
原因1:フレームレートの不一致
コンポジションの設定とタイミング計算で使うfpsが異なると、オーディオが絶対時間的に間違った位置に配置されます。
対処法: フレームのオフセット計算には必ず useVideoConfig().fps を使い、ハードコードしない。
const { fps } = useVideoConfig();
const voiceoverStart = fps * 2; // 常に2秒後
<Sequence from={voiceoverStart}>
<Audio src={staticFile('narration.mp3')} />
</Sequence>
原因2:可変ビットレート(VBR)のMP3ファイル
VBR MP3ファイルは長尺になるとデコーダーの内部時間推定が実際のサンプル位置からズレていき、同期ドリフトを引き起こします。これはChromiumの既知の制限です。
対処法: 使用前にCBR(固定ビットレート)に変換する。
ffmpeg -i input.mp3 -codec:a libmp3lame -b:a 192k -ar 44100 output-cbr.mp3
WAVファイルはPCMなので本質的にCBRであり、この問題は発生しません。
原因3:コンポジションより長いオーディオファイル
<Audio> のファイルがコンポジションの durationInFrames より長く、endAt を指定していない場合、オーディオはコンポジションの終端でカットされます。フェードアウトを意図している場合は、volume コールバックで明示的に実装してください。
原因4:<Sequence> 内での <Audio> の配置と startFrom の混同
<Audio> を <Sequence> の中に配置した場合、最終動画でのオーディオ開始時間は「シーケンスの from 値」と「startFrom のオフセット」の合計です。「<Sequence from> はコンポジション内のどの時点から開始するか」「startFrom はオーディオファイルのどの位置から再生するか」——この2つの役割を混同しないよう注意してください。
原因5:プレイヤー埋め込みで pauseWhenBuffering を使わない
<Player> コンポーネントでオーディオのバッファリングが必要な場合、ビジュアルは先行するのに音声が遅れる現象が起きることがあります。pauseWhenBuffering プロップをプレイヤーに渡すことで防止できます。
<Player
component={MyComposition}
durationInFrames={300}
fps={30}
compositionWidth={1920}
compositionHeight={1080}
pauseWhenBuffering
acknowledgeRemotionLicense
/>
実践例:ナレーション付き動画の完成形
import {
Audio,
staticFile,
Sequence,
Loop,
interpolate,
useVideoConfig,
} from 'remotion';
import { MySlide } from './MySlide';
export const NarrationVideo: React.FC = () => {
const { durationInFrames, fps } = useVideoConfig();
return (
<>
{/* BGM: 4秒ループ、フェードイン・アウト付き */}
<Loop durationInFrames={fps * 4}>
<Audio
src={staticFile('bgm-loop.mp3')}
volume={(frame) => {
const fadeIn = interpolate(frame, [0, fps], [0, 0.25], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
const fadeOut = interpolate(
frame,
[durationInFrames - fps, durationInFrames],
[0.25, 0],
{ extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }
);
return Math.min(fadeIn, 0.25) * (frame > durationInFrames - fps ? fadeOut / 0.25 : 1);
}}
/>
</Loop>
{/* ナレーション: 1秒後からフルボリューム */}
<Sequence from={fps}>
<Audio src={staticFile('narration.mp3')} volume={1} />
</Sequence>
{/* ビジュアルスライド */}
<Sequence from={0} durationInFrames={fps * 5}>
<MySlide title="はじめに" />
</Sequence>
<Sequence from={fps * 5} durationInFrames={fps * 5}>
<MySlide title="メインポイント" />
</Sequence>
</>
);
};
よくある質問(FAQ)
Q: コンポジション開始より前から音声を再生できますか?
できません。<Audio> はフレーム0以降でしか音声を再生できません。オーディオファイルの先頭をスキップしたい場合は、startFrom プロップを使ってファイル内の再生位置を進めてください。負のフレームに音声を配置することはできません。
Q: オーディオファイルがコンポジションより短い場合どうなりますか?
音声は再生されて停止します。自動ループはしません。繰り返したい場合は <Loop> を明示的に使ってください。
Q: RemotionはMP3とWAVのどちらを推奨していますか?
BGMとナレーションには .mp3(CBRエンコード済み)を推奨します。短い効果音ではタイミングの精度が重要なため .wav が安定しています。いずれの場合も、使用前に必ずRemotio Studio プレビューで動作を確認してください。
Q: 音声をビジュアルイベントのフレームと同期させるにはどうすればいいですか?
ビジュアルイベントが発生するフレームを計算し、<Audio>(またはそれを囲む <Sequence>)をそのフレームに配置します。イベントがスプリングアニメーションで駆動されている場合、measureSpring() を使ってアニメーションが収束するフレームを正確に計算できます。
Q: BGMと複数のナレーション・効果音をミックスするとき、音量の合計が1.0を超えると何が起きますか?
クリッピング(音が割れる)が発生します。各トラックの音量を調整して、同時に最大音量が重なるタイミングでも合計が 1.0 を超えないよう設計してください。
Q: 音声の波形をコンポジション内でビジュアライズできますか?
Remotionには波形表示の組み込み機能はありません。ただし、FFmpegやWeb Audio APIを使って事前にオーディオファイルから振幅データを抽出し、JSONとして保存、コンポジションにインポートして視覚要素にマッピングする手法は実装可能です。
Q: <Audio> コンポーネントを使うとき、ファイルは毎フレーム読み込まれますか?
いいえ。オーディオファイルは一度デコードされてメモリにキャッシュされ、フレームごとに再読み込みされることはありません。src に staticFile() を使っていれば、パフォーマンスの問題は通常発生しません。
まとめ
<Audio> コンポーネントはRemotionでプログラマブル動画に音声を追加するための、シンプルで宣言的なインターフェースです。要点を整理します。
- バンドル済みファイルには
staticFile('filename.mp3')を使い、public/に配置する volumeは数値(固定)と関数(frame) => number(動的)の両方を受け付けるstartFromとendAtはオーディオファイルのどの部分を使うかを指定(フレーム単位)、<Sequence from>でコンポジション内での配置タイミングを制御する<Loop durationInFrames={...}>で繰り返し再生を実現する- 複数の
<Audio>を重ねてBGM・ナレーション・効果音をミックスする——自動的にミックスダウンされる - 長尺コンテンツでの音声ズレを防ぐため、CBRエンコードのMP3を使う
プロフェッショナルな音声構成を持つRemotionテンプレートは RenderComp で公開中 →
RenderCompのライブラリには、BGMのフェードイン・ナレーション同期スロット・効果音プレースホルダーを含む、プロが設計した音声レイヤー構成のテンプレートが揃っています。自分のオーディオファイルを差し替えるだけで、音声タイミングをゼロから構築することなく完成度の高い動画が作れます。