はじめに
Web Audio APIで音声解析をしていると、解析値がちゃんと取れているか確認したくなります。
コンソールに出すだけでも確認できますが、ビジュアライザーを作るなら、画面上にメーターとして表示した方が分かりやすいです。
今回は React で、
- volume
- bass
- mids
- highs
を表示する簡単な音声メーターを作ります。
作るもの
以下のような値を受け取って、横棒のメーターとして表示します。
type AudioFeatures = {
volume: number
bass: number
mids: number
highs: number
}
値は 0〜1 の範囲を想定します。
<Meter label="volume" value={features.volume} />
<Meter label="bass" value={features.bass} />
<Meter label="mids" value={features.mids} />
<Meter label="highs" value={features.highs} />
Meterコンポーネント
まずはシンプルな Meter コンポーネントを作ります。
type MeterProps = {
label: string
value: number
}
export function Meter({ label, value }: MeterProps) {
const clampedValue = Math.max(0, Math.min(1, value))
return (
<div className="meter">
<div className="meter__header">
<span>{label}</span>
<span>{Math.round(clampedValue * 100)}%</span>
</div>
<div className="meter__track">
<div
className="meter__bar"
style={{ width: `${clampedValue * 100}%` }}
/>
</div>
</div>
)
}
値が 0〜1 の範囲を超える可能性もあるので、念のため clamp しています。
CSS
見た目は最小限にします。
.meter {
display: grid;
gap: 6px;
}
.meter__header {
display: flex;
justify-content: space-between;
font-size: 12px;
color: #666;
}
.meter__track {
height: 8px;
overflow: hidden;
border-radius: 999px;
background: rgba(0, 0, 0, 0.12);
}
.meter__bar {
height: 100%;
border-radius: inherit;
background: currentColor;
transition: width 80ms linear;
}
transition を少しだけ入れると、急な変化が少しなめらかに見えます。
ただし、音声解析値自体に smoothing をかけている場合は、CSS側の transition は短めでも十分です。
featuresをまとめて表示する
複数のメーターを並べるコンポーネントも作ります。
type AudioFeatures = {
volume: number
bass: number
mids: number
highs: number
}
type AudioMetersProps = {
features: AudioFeatures
}
export function AudioMeters({ features }: AudioMetersProps) {
return (
<div className="audio-meters">
<Meter label="volume" value={features.volume} />
<Meter label="bass" value={features.bass} />
<Meter label="mids" value={features.mids} />
<Meter label="highs" value={features.highs} />
</div>
)
}
CSSは以下のようにします。
.audio-meters {
display: grid;
gap: 12px;
}
毎フレーム更新しすぎない
音声解析値は requestAnimationFrame で毎フレーム更新されます。
ただ、メーター表示のために毎フレーム React state を更新すると、再レンダリングが多くなりすぎる場合があります。
そのため、UI用の値は少し間引いて更新するのが扱いやすいです。
const [featuresSnapshot, setFeaturesSnapshot] = useState<AudioFeatures>({
volume: 0,
bass: 0,
mids: 0,
highs: 0,
})
解析ループ内では、たとえば30fps程度に間引きます。
let lastUpdate = 0
function analyze(time: number) {
const nextFeatures = getAudioFeatures()
if (time - lastUpdate > 33) {
setFeaturesSnapshot(nextFeatures)
lastUpdate = time
}
requestAnimationFrame(analyze)
}
3D描画やCanvas描画では最新値が必要でも、UI表示は少し間引いても十分見えます。
メーターがあると調整しやすい
音声ビジュアライザーを作るとき、メーターがあるとかなり便利です。
たとえば、
- bassが強すぎる
- highsがほとんど反応していない
- volumeだけ常に高い
- smoothingを上げすぎて動きが鈍い
- sensitivityを上げすぎて常に振り切っている
といったことに気づきやすくなります。
ビジュアルだけ見ていると、何が原因で動きが不自然なのか分かりにくいことがあります。
メーターを置いておくと、解析値と見た目を対応させながら調整できます。
sensitivityの確認にも使える
音への反応を強くするために、sensitivityをかけることがあります。
const adjustedBass = clamp(bass * sensitivity, 0, 1)
このとき、メーターがあると、値がどれくらい増えているのか見えます。
もし常に100%に近いなら、sensitivityが強すぎます。
逆にほとんど動かないなら、感度が低すぎる可能性があります。
まとめ
Reactで音声メーターを作ると、Web Audio APIの解析値を視覚的に確認しやすくなります。
今回作ったのは、
- volume
- bass
- mids
- highs
を横棒で表示するシンプルなUIです。
音声ビジュアライザーでは、見た目の調整だけでなく、解析値そのものを見ることも重要です。
メーターを用意しておくと、感度やsmoothingの調整がかなりやりやすくなりました。