音訊視覺化
使用 Remotion 的 API 將音訊視覺化,建立音波圖、音樂視覺化效果等
Remotion 提供 API 用於音訊視覺化,例如建立音波圖或音樂視覺化效果。
@remotion/media-utils 套件提供讀取和處理音訊的輔助函式。使用 getAudioData() API 可以讀取音訊資料,使用 useAudioData() 輔助鉤子可以直接將音訊資料載入元件中。
柱狀視覺化
使用 visualizeAudio() API 可以取得目前幀的音頻頻譜。
柱狀視覺化非常適合用來呈現音樂效果。
import {useAudioData, visualizeAudio} from '@remotion/media-utils';
import {Html5Audio, staticFile, useCurrentFrame, useVideoConfig} from 'remotion';
const music = staticFile('music.mp3');
export const MyComponent: React.FC = () => {
const frame = useCurrentFrame();
const {width, height, fps} = useVideoConfig();
const audioData = useAudioData(music);
if (!audioData) {
return null;
}
const visualization = visualizeAudio({
fps,
frame,
audioData,
numberOfSamples: 16,
}); // [0.22, 0.1, 0.01, 0.01, 0.01, 0.02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
// 為每個頻率渲染一個柱狀條,振幅越高柱狀條越長
return (
<div>
<Html5Audio src={music} />
{visualization.map((v, i) => {
return (
<div
key={i}
style={{width: 1000 * v, height: 15, backgroundColor: 'blue'}}
/>
);
})}
</div>
);
};進階柱狀視覺化範例
以下是更完整的柱狀視覺化實作,使用絕對定位建立置中的頻譜展示:
import {useAudioData, visualizeAudio} from '@remotion/media-utils';
import {AbsoluteFill, Audio, staticFile, useCurrentFrame, useVideoConfig} from 'remotion';
const music = staticFile('music.mp3');
export const AudioBars: React.FC = () => {
const frame = useCurrentFrame();
const {width, height, fps} = useVideoConfig();
const audioData = useAudioData(music);
if (!audioData) {
return null;
}
const numberOfBars = 64;
const visualization = visualizeAudio({
fps,
frame,
audioData,
numberOfSamples: numberOfBars,
});
const barWidth = width / numberOfBars;
return (
<AbsoluteFill style={{backgroundColor: '#000', display: 'flex', alignItems: 'flex-end'}}>
<Audio src={music} />
{visualization.map((amplitude, i) => (
<div
key={i}
style={{
width: barWidth - 2,
height: amplitude * height,
backgroundColor: `hsl(${(i / numberOfBars) * 360}, 100%, 60%)`,
marginRight: 2,
}}
/>
))}
</AbsoluteFill>
);
};波形視覺化
使用 visualizeAudioWaveform() 可以建立音訊波形視覺化效果。
import {visualizeAudioWaveform, useAudioData} from '@remotion/media-utils';
import {AbsoluteFill, Audio, staticFile, useCurrentFrame, useVideoConfig} from 'remotion';
const music = staticFile('music.wav'); // 波形視覺化需要 .wav 格式
export const WaveformViz: React.FC = () => {
const frame = useCurrentFrame();
const {fps, width, height} = useVideoConfig();
const audioData = useAudioData(music);
if (!audioData) {
return null;
}
const waveform = visualizeAudioWaveform({
fps,
frame,
audioData,
numberOfSamples: 100,
windowInSeconds: 1 / fps,
});
const centerY = height / 2;
const amplitude = height * 0.4;
// 使用 SVG 繪製波形
const points = waveform.map((v, i) => {
const x = (i / waveform.length) * width;
const y = centerY + v * amplitude;
return `${x},${y}`;
}).join(' ');
return (
<AbsoluteFill style={{backgroundColor: '#111'}}>
<Audio src={music} />
<svg width={width} height={height}>
<polyline
points={points}
fill="none"
stroke="#00ff88"
strokeWidth={2}
/>
</svg>
</AbsoluteFill>
);
};處理大型音訊檔案
useAudioData() 會將整個音訊檔案載入記憶體中。對於小型檔案這沒有問題,但對於大型檔案可能會很慢並消耗大量記憶體。
使用 useWindowedAudioData() 只載入目前幀附近的音訊片段。這個 API 的限制是只適用於 .wav 格式的檔案。
import {useWindowedAudioData, visualizeAudio} from '@remotion/media-utils';
import {AbsoluteFill, Audio, staticFile, useCurrentFrame, useVideoConfig} from 'remotion';
const largeAudioFile = staticFile('large-music.wav');
export const LargeAudioVisualization: React.FC = () => {
const frame = useCurrentFrame();
const {fps} = useVideoConfig();
// 使用視窗化音訊資料,效能更佳
const audioData = useWindowedAudioData({
src: largeAudioFile,
frame,
fps,
windowInSeconds: 3, // 只載入前後 3 秒的音訊
});
if (!audioData) {
return null;
}
const visualization = visualizeAudio({
fps,
frame,
audioData,
numberOfSamples: 32,
});
return (
<AbsoluteFill>
<Audio src={largeAudioFile} />
<div style={{display: 'flex', alignItems: 'flex-end', height: '100%'}}>
{visualization.map((v, i) => (
<div
key={i}
style={{
flex: 1,
height: `${v * 100}%`,
backgroundColor: 'purple',
margin: 1,
}}
/>
))}
</div>
</AbsoluteFill>
);
};visualizeAudio() 參數說明
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
fps | number | 是 | 影片的每秒幀數 |
frame | number | 是 | 目前幀數 |
audioData | AudioData | 是 | 由 useAudioData() 取得的音訊資料 |
numberOfSamples | number | 是 | 回傳的頻率樣本數量(通常為 2 的次方) |
smoothingTimeConstant | number | 否 | 平滑常數,預設為 0.8 |
frequencyRange | [number, number] | 否 | 要視覺化的頻率範圍 |
安裝 @remotion/media-utils
npm install @remotion/media-utils或使用 yarn:
yarn add @remotion/media-utils