• #Vue3
  • #Nuxt
  • #Web Audio API
  • #Canvas
  • #ステレオ
  • #コンポーネント移植
開発mdx-playgroundメモ

ステレオサウンドテストページをVue 3/Nuxtで実装

React JSXで書いていたステレオテストページを、Vue 3 / Nuxt対応に変換した作業ログ。

背景

もともとstereo-test.jsxというReact向けのプロトタイプがあり、ヘッドホンの左右チャンネルに別々の音を流して分離を確認するページだった。これをNuxtのページとして正式に組み込みたかった。

主な変換ポイントは以下の通り。

  • JSXの構文をVueの<template>に書き換え
  • useState / useRefref()に置き換え
  • useEffectのクリーンアップをonUnmountedに対応
  • Canvas描画コンポーネントを別ファイルに切り出し

StereoWaveCanvasコンポーネント

波形アニメーションを描画するCanvasコンポーネントをStereoWaveCanvas.vueとして新規作成した。Nuxtのauto-import機能で、components/に置くだけでページ側から<StereoWaveCanvas />で使える。

コンポーネントのpropsは2つだけ。

const props = defineProps({
  isActive: { type: Boolean, default: false },
  color: { type: String, default: '#fff' },
})

isActiveがfalseのときは薄い水平線を描画し、trueになるとrequestAnimationFrameでサイン波のアニメーションが始まる。watchでpropsの変化を検知してアニメーションの開始/停止を切り替える仕組み。

描画のポイントは、複数の周波数のサイン波を重ね合わせて「それっぽい」波形にしているところ。

const a = Math.sin(t * Math.PI) * (h * 0.35) *
  (0.6 + 0.25 * Math.sin(phase + t * 9) + 0.15 * Math.sin(phase * 1.4 + t * 14))

実際の音声波形ではなく、あくまで視覚的なフィードバック用の装飾アニメーション。


stereo-test.vue テストページ

メインのテストページでは、左右チャンネルそれぞれに音源を割り当てて再生する。

音源の種類

Web Audio APIのAudioBufferを直接生成している。外部ファイルは使わず、全てコード内で波形を計算する方式。

音源内容
440Hz ToneA音のサイン波(ビブラート付き)
523Hz ToneC音 + 倍音
Click120BPMのメトロノーム
Pink Noiseフィルタードノイズ
Sweep200Hz - 2000Hzのスイープ
MelodyC-E-Gのアルペジオ

ステレオパンニングの実装

StereoPannerNodeで左右の振り分けを制御する。L/RそれぞれにGainNode -> StereoPannerNodeのチェーンを作り、モード切替でpan.valuegain.valueを操作する。

const lP = ctx.createStereoPanner(); lP.pan.value = -1  // 左
const rP = ctx.createStereoPanner(); rP.pan.value = 1   // 右
lG.connect(lP).connect(ctx.destination)
rG.connect(rP).connect(ctx.destination)

4つのモード(L/R Split, Mix, Left only, Right only)とバランススライダーの組み合わせで、再生中に動的にパンニングを変更できる。


index.vueへの導線追加

トップページの「テスト・デモ」セクションに「サウンド」カテゴリを新設し、ステレオテストへのナビカードを追加した。

<h3 class="demo-category-label">サウンド</h3>
<div class="nav-cards demo-cards">
  <NuxtLink to="/stereo-test" class="nav-card demo-card">
    ...ステレオ出し分けテスト...
  </NuxtLink>
</div>

今後サウンド関連のデモページが増えたときに、このカテゴリにぶら下げていける構成。


Chrome DevTools MCPでの動作確認

実装後の確認にChrome DevTools MCPを使った。確認できたのは以下。

  • ページが正常にレンダリングされること
  • 左右のサンプル選択UIが表示されていること
  • 再生中に波形アニメーションとパルスドットが表示されること
  • モード切替やバランススライダーのUI表示

音声の左右分離は実際にヘッドホンをつけて耳で確認する必要があり、MCPだけでは音の出力までは検証できない。UIの表示崩れや要素の欠落がないことの確認に使った。


元JSXファイルの削除

Vue移植が完了したため、元のstereo-test.jsxを削除して整理した。Nuxtのページとしてpages/stereo-test.vueが正式な置き場所になる。


振り返り

React -> Vueの変換で手間がかかるのは、JSXのインライン条件分岐(三項演算子の連鎖)をv-if / v-forに書き直すところ。逆に、Vueの<style scoped>でスタイルを閉じ込められるのはありがたい。

Web Audio APIでバッファを直接生成する方式は、音声ファイルの管理が不要でデプロイが楽。ただし音源の種類を増やすとgenerateBuffer関数が肥大化するので、音源定義を別ファイルに切り出す余地はある。