Remotion LabRemotion Lab
音訊音訊視覺化

音訊視覺化

使用 Remotion 的 API 將音訊視覺化,建立音波圖、音樂視覺化效果等

Remotion 提供 API 用於音訊視覺化,例如建立音波圖或音樂視覺化效果。

@remotion/media-utils 套件提供讀取和處理音訊的輔助函式。使用 getAudioData() API 可以讀取音訊資料,使用 useAudioData() 輔助鉤子可以直接將音訊資料載入元件中。

柱狀視覺化

使用 visualizeAudio() API 可以取得目前幀的音頻頻譜。

柱狀視覺化非常適合用來呈現音樂效果。

BarVisualization.tsx
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>
  );
};

進階柱狀視覺化範例

以下是更完整的柱狀視覺化實作,使用絕對定位建立置中的頻譜展示:

AdvancedBarVisualization.tsx
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() 可以建立音訊波形視覺化效果。

WaveformVisualization.tsx
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 格式的檔案。

LargeAudioFile.tsx
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() 參數說明

參數類型必填說明
fpsnumber影片的每秒幀數
framenumber目前幀數
audioDataAudioDatauseAudioData() 取得的音訊資料
numberOfSamplesnumber回傳的頻率樣本數量(通常為 2 的次方)
smoothingTimeConstantnumber平滑常數,預設為 0.8
frequencyRange[number, number]要視覺化的頻率範圍

安裝 @remotion/media-utils

npm install @remotion/media-utils

或使用 yarn:

yarn add @remotion/media-utils

相關連結