0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

UIで音声波形を表示させたい!wavesurfer.js

0
Posted at

ねらい・対象・ゴール・TL;DR

ねらい: Webアプリで音声波形を表示したいエンジニアに、wavesurfer.jsの使い方を完全解説する

対象:

  • 音声プレイヤーUIを作りたいフロントエンドエンジニア
  • ポッドキャスト・音楽アプリを開発中の人
  • 音声編集ツールのプロトタイプを作りたい人

ゴール: wavesurfer.jsのインストールから実践的な活用まで理解する

TL;DR: wavesurfer.jsはWeb Audio API + HTML5 Canvasベースの音声波形可視化ライブラリ。npm install wavesurfer.jsしてWaveSurfer.create()するだけで動く。v7でTypeScript完全対応、Shadow DOMレンダリング、7つの公式プラグイン(Regions, Timeline, Spectrogram等)搭載。React/Vue連携も簡単。


はじめに:SoundCloudみたいな波形UIが欲しい

ポッドキャストアプリを作っている。音声ファイルを再生する機能は実装できた。

でも、なんか物足りない。

SoundCloudみたいな、あのカッコいい波形UIが欲しい。再生位置が視覚的にわかって、クリックでシークできるやつ。

「自分で実装するか...Web Audio APIで波形データ取得して、Canvasに描画して...」

待って。そんな車輪の再発明、する必要ある?

wavesurfer.jsを使おう。


wavesurfer.jsとは

"Wavesurfer.js is an interactive waveform rendering and audio playback library, perfect for web applications. It leverages modern web technologies to provide a robust and visually engaging audio experience."

— wavesurfer.js公式サイトより

和訳: wavesurfer.jsはインタラクティブな波形レンダリングと音声再生のライブラリで、Webアプリケーションに最適。モダンなWeb技術を活用し、堅牢で視覚的に魅力的なオーディオ体験を提供する。

基本情報

項目 内容
最新バージョン v7.x(2024年〜)
ライセンス BSD-3-Clause
言語 TypeScript(v7で完全書き直し)
依存関係 なし(ゼロ依存)
ブラウザ対応 Chrome, Firefox, Safari, Edge(Web Audio API対応ブラウザ)

何ができるのか

"With wavesurfer.js you can create anything from an HTML5 audio player to a sophisticated DJ application."

— SourceForge wavesurfer.js紹介ページより

和訳: wavesurfer.jsを使えば、シンプルなHTML5オーディオプレイヤーから本格的なDJアプリケーションまで、何でも作れる。

できること:

  • 音声ファイルの波形表示
  • 再生・一時停止・シーク
  • 波形の色・高さ・バーの幅などカスタマイズ
  • リージョン(区間)のマーキングとループ再生
  • タイムライン表示
  • スペクトログラム表示
  • マイクからの録音と波形表示
  • ズーム・ミニマップナビゲーション

できないこと(重要):

"Please don't expect wavesurfer to be able to cut, add effects, or process your audio in any way."

— wavesurfer.js GitHubより

和訳: wavesurferに音声のカット、エフェクト追加、その他の音声処理を期待しないでほしい。

wavesurfer.jsは「可視化」と「再生」に特化している。音声編集機能は別のライブラリが必要。


クイックスタート:5分で波形表示

インストール

npm install wavesurfer.js

最小構成コード

<!DOCTYPE html>
<html>
<head>
  <title>wavesurfer.js Demo</title>
</head>
<body>
  <div id="waveform"></div>
  <button id="playBtn">Play / Pause</button>

  <script type="module">
    import WaveSurfer from 'https://cdn.jsdelivr.net/npm/wavesurfer.js@7/dist/wavesurfer.esm.js'

    const wavesurfer = WaveSurfer.create({
      container: '#waveform',
      waveColor: '#4F4A85',
      progressColor: '#383351',
      url: '/path/to/audio.mp3',
    })

    document.getElementById('playBtn').addEventListener('click', () => {
      wavesurfer.playPause()
    })
  </script>
</body>
</html>

これだけ。たったこれだけで波形が表示される。

npmモジュールとして使う場合

import WaveSurfer from 'wavesurfer.js'

const wavesurfer = WaveSurfer.create({
  container: '#waveform',
  waveColor: '#4F4A85',
  progressColor: '#383351',
  url: '/audio.mp3',
})

TypeScript型定義も同梱されているので、@types/wavesurfer.jsのインストールは不要。


主要オプション解説

WaveSurfer.create()に渡せるオプションは豊富。よく使うものを紹介する。

見た目のカスタマイズ

const wavesurfer = WaveSurfer.create({
  container: '#waveform',        // 必須:波形を描画するDOM要素
  
  // 色の設定
  waveColor: '#4F4A85',          // 未再生部分の波形色
  progressColor: '#383351',      // 再生済み部分の波形色
  cursorColor: '#fff',           // カーソル(再生位置)の色
  cursorWidth: 2,                // カーソルの幅(px)
  
  // サイズの設定
  height: 128,                   // 波形の高さ(px)
  barWidth: 3,                   // バーの幅(px、0で連続波形)
  barGap: 1,                     // バー間の隙間(px)
  barRadius: 2,                  // バーの角丸(px)
  
  // レイアウト
  fillParent: true,              // 親要素の幅に合わせる
  minPxPerSec: 50,               // 1秒あたりの最小ピクセル数(ズーム)
})

動作のカスタマイズ

const wavesurfer = WaveSurfer.create({
  container: '#waveform',
  url: '/audio.mp3',
  
  // 再生設定
  autoplay: false,               // 読み込み完了後に自動再生
  interact: true,                // クリックでシーク可能か
  dragToSeek: true,              // ドラッグでシーク可能か
  
  // 表示設定
  normalize: true,               // 波形を正規化(最大音量で揃える)
  splitChannels: false,          // ステレオを別々に表示
  
  // スクロール設定
  autoScroll: true,              // 再生に合わせてスクロール
  autoCenter: true,              // 再生位置を中央に保つ
})

グラデーション波形

単色じゃ物足りない?グラデーションも使える。

const ctx = document.createElement('canvas').getContext('2d')
const gradient = ctx.createLinearGradient(0, 0, 0, 150)
gradient.addColorStop(0, '#ff0000')
gradient.addColorStop(0.5, '#ffff00')
gradient.addColorStop(1, '#00ff00')

const wavesurfer = WaveSurfer.create({
  container: '#waveform',
  waveColor: gradient,
  progressColor: '#383351',
  url: '/audio.mp3',
})

イベントハンドリング

wavesurferは様々なイベントを発火する。

const wavesurfer = WaveSurfer.create({
  container: '#waveform',
  url: '/audio.mp3',
})

// 読み込み完了
wavesurfer.on('ready', (duration) => {
  console.log(`読み込み完了!長さ: ${duration}秒`)
})

// 再生中(毎フレーム)
wavesurfer.on('audioprocess', (currentTime) => {
  console.log(`現在位置: ${currentTime}秒`)
})

// 再生開始
wavesurfer.on('play', () => {
  console.log('再生開始')
})

// 一時停止
wavesurfer.on('pause', () => {
  console.log('一時停止')
})

// 再生終了
wavesurfer.on('finish', () => {
  console.log('再生終了')
})

// シーク
wavesurfer.on('seeking', (currentTime) => {
  console.log(`シーク中: ${currentTime}秒`)
})

// クリック
wavesurfer.on('click', (relativeX) => {
  console.log(`クリック位置: ${relativeX * 100}%`)
})

// エラー
wavesurfer.on('error', (error) => {
  console.error('エラー発生:', error)
})

公式プラグイン7種 完全ガイド

wavesurfer.js v7には7つの公式プラグインがある。

"The 'official' plugins have been completely rewritten and enhanced"

— wavesurfer.js公式ドキュメントより

和訳: 公式プラグインは完全に書き直され、機能強化された。

プラグイン一覧

プラグイン 機能
Regions 音声の区間をマーキング、ドラッグで範囲調整
Timeline 波形下部に時間軸を表示
Minimap 全体俯瞰用のミニ波形
Envelope フェードイン/アウト、音量調整のUI
Record マイクから録音して波形表示
Spectrogram 周波数スペクトログラム表示
Hover ホバー位置に時間表示

Regions プラグイン

音声の特定区間をマーキングできる。ループ再生、区間削除UIなどに使える。

import WaveSurfer from 'wavesurfer.js'
import Regions from 'wavesurfer.js/dist/plugins/regions.esm.js'

const wavesurfer = WaveSurfer.create({
  container: '#waveform',
  url: '/audio.mp3',
})

// Regionsプラグインを登録
const regions = wavesurfer.registerPlugin(Regions.create())

// 波形読み込み完了後にリージョンを追加
wavesurfer.on('ready', () => {
  // 10秒〜20秒の区間をマーク
  regions.addRegion({
    start: 10,
    end: 20,
    content: 'サビ',
    color: 'rgba(255, 0, 0, 0.3)',
    drag: true,      // ドラッグ移動可能
    resize: true,    // リサイズ可能
  })
  
  // マーカー(単一点)を追加
  regions.addRegion({
    start: 30,
    content: 'ここ重要',
    color: 'rgba(0, 255, 0, 0.5)',
  })
})

// リージョンクリック時のイベント
regions.on('region-clicked', (region, e) => {
  e.stopPropagation()
  region.play()  // そのリージョンだけ再生
})

Timeline プラグイン

波形の下に時間軸(目盛り)を表示する。

import WaveSurfer from 'wavesurfer.js'
import Timeline from 'wavesurfer.js/dist/plugins/timeline.esm.js'

const wavesurfer = WaveSurfer.create({
  container: '#waveform',
  url: '/audio.mp3',
  plugins: [
    Timeline.create({
      container: '#timeline',  // タイムライン用のコンテナ
      primaryLabelInterval: 10,  // 主目盛りの間隔(秒)
      secondaryLabelInterval: 5, // 副目盛りの間隔(秒)
      style: {
        fontSize: '12px',
        color: '#666',
      },
    }),
  ],
})
<div id="waveform"></div>
<div id="timeline"></div>

Minimap プラグイン

長い音声ファイル用。全体を俯瞰できるミニ波形を表示し、スクロールバーとして機能する。

import WaveSurfer from 'wavesurfer.js'
import Minimap from 'wavesurfer.js/dist/plugins/minimap.esm.js'

const wavesurfer = WaveSurfer.create({
  container: '#waveform',
  url: '/long-audio.mp3',
  minPxPerSec: 100,  // ズームイン状態
  plugins: [
    Minimap.create({
      container: '#minimap',
      height: 20,
      waveColor: '#ddd',
      progressColor: '#999',
    }),
  ],
})

Record プラグイン

マイクからの録音と波形表示。旧バージョンのMicrophoneプラグインの後継。

import WaveSurfer from 'wavesurfer.js'
import Record from 'wavesurfer.js/dist/plugins/record.esm.js'

const wavesurfer = WaveSurfer.create({
  container: '#waveform',
})

const record = wavesurfer.registerPlugin(Record.create())

// 録音開始
document.getElementById('recordBtn').addEventListener('click', async () => {
  // マイクへのアクセス許可を求める
  await record.startRecording()
})

// 録音停止
document.getElementById('stopBtn').addEventListener('click', async () => {
  const blob = await record.stopRecording()
  
  // 録音データをURLに変換して再生可能に
  const url = URL.createObjectURL(blob)
  wavesurfer.load(url)
})

// 録音中のイベント
record.on('record-progress', (time) => {
  console.log(`録音中: ${time}秒`)
})

Spectrogram プラグイン

FFT(高速フーリエ変換)を使った周波数スペクトログラムを表示。音声分析ツールに最適。

import WaveSurfer from 'wavesurfer.js'
import Spectrogram from 'wavesurfer.js/dist/plugins/spectrogram.esm.js'

const wavesurfer = WaveSurfer.create({
  container: '#waveform',
  url: '/audio.mp3',
  plugins: [
    Spectrogram.create({
      container: '#spectrogram',
      labels: true,           // 周波数ラベル表示
      height: 256,            // 高さ
      fftSamples: 512,        // FFTサンプル数
      frequencyMin: 0,        // 最小周波数
      frequencyMax: 12000,    // 最大周波数
    }),
  ],
})

Hover プラグイン

波形上にマウスを乗せると、その位置の時間を表示する。

import WaveSurfer from 'wavesurfer.js'
import Hover from 'wavesurfer.js/dist/plugins/hover.esm.js'

const wavesurfer = WaveSurfer.create({
  container: '#waveform',
  url: '/audio.mp3',
  plugins: [
    Hover.create({
      lineColor: '#ff0000',
      lineWidth: 2,
      labelBackground: '#555',
      labelColor: '#fff',
      labelSize: '12px',
    }),
  ],
})

Envelope プラグイン

フェードイン/フェードアウト、音量調整のGUIを提供。

import WaveSurfer from 'wavesurfer.js'
import Envelope from 'wavesurfer.js/dist/plugins/envelope.esm.js'

const wavesurfer = WaveSurfer.create({
  container: '#waveform',
  url: '/audio.mp3',
})

const envelope = wavesurfer.registerPlugin(
  Envelope.create({
    volume: 0.8,
    lineColor: 'rgba(255, 0, 0, 0.5)',
    lineWidth: 4,
    dragPointSize: 12,
    dragPointFill: 'rgba(255, 255, 255, 0.8)',
    dragPointStroke: 'rgba(255, 0, 0, 0.5)',
  })
)

// エンベロープポイントを追加
envelope.addPoint({ time: 0, volume: 0 })       // 開始: 音量0
envelope.addPoint({ time: 2, volume: 1 })       // 2秒: 最大音量
envelope.addPoint({ time: 10, volume: 1 })      // 10秒: 最大音量維持
envelope.addPoint({ time: 12, volume: 0 })      // 12秒: フェードアウト完了

Reactで使う

wavesurfer.jsには公式のReactパッケージがある。

インストール

npm install @wavesurfer/react wavesurfer.js

基本的な使い方

import WavesurferPlayer from '@wavesurfer/react'
import { useState, useCallback } from 'react'

function AudioPlayer({ url }) {
  const [wavesurfer, setWavesurfer] = useState(null)
  const [isPlaying, setIsPlaying] = useState(false)

  const onReady = useCallback((ws) => {
    setWavesurfer(ws)
    setIsPlaying(false)
  }, [])

  const onPlayPause = useCallback(() => {
    if (wavesurfer) {
      wavesurfer.playPause()
    }
  }, [wavesurfer])

  return (
    <div>
      <WavesurferPlayer
        height={100}
        waveColor="#4F4A85"
        progressColor="#383351"
        url={url}
        onReady={onReady}
        onPlay={() => setIsPlaying(true)}
        onPause={() => setIsPlaying(false)}
      />
      <button onClick={onPlayPause}>
        {isPlaying ? '⏸️ Pause' : '▶️ Play'}
      </button>
    </div>
  )
}

export default AudioPlayer

"All of the familiar wavesurfer options become React props. You can subscribe to various wavesurfer events also via props. Just prepend an event name with on, e.g. ready -> onReady."

— @wavesurfer/react npmページより

和訳: wavesurferのオプションがすべてReactのpropsになる。イベントもprops経由で購読でき、イベント名の前にonをつけるだけ(例: ready → onReady)。

useWavesurfer フック

コンポーネント形式ではなくフックを使いたい場合:

import { useRef, useState, useCallback } from 'react'
import { useWavesurfer } from '@wavesurfer/react'

function AudioPlayer({ url }) {
  const containerRef = useRef(null)
  
  const { wavesurfer, isReady, isPlaying, currentTime } = useWavesurfer({
    container: containerRef,
    url: url,
    waveColor: 'purple',
    height: 100,
  })

  const onPlayPause = useCallback(() => {
    wavesurfer && wavesurfer.playPause()
  }, [wavesurfer])

  return (
    <div>
      <div ref={containerRef} />
      <p>現在時間: {currentTime.toFixed(1)}</p>
      <button onClick={onPlayPause} disabled={!isReady}>
        {isPlaying ? 'Pause' : 'Play'}
      </button>
    </div>
  )
}

プラグインの使用(React)

プラグインを使う場合、useMemoで配列をメモ化する必要がある。

"Important: The plugins array must be memoized using useMemo or defined outside the component."

— @wavesurfer/react npmページより

和訳: 重要: plugins配列はuseMemoでメモ化するか、コンポーネント外で定義する必要がある。

import { useMemo } from 'react'
import WavesurferPlayer from '@wavesurfer/react'
import Timeline from 'wavesurfer.js/dist/plugins/timeline.esm.js'
import Regions from 'wavesurfer.js/dist/plugins/regions.esm.js'

function AudioPlayerWithPlugins({ url }) {
  // プラグイン配列をメモ化(重要!)
  const plugins = useMemo(() => [
    Timeline.create({ container: '#timeline' }),
    Regions.create(),
  ], [])

  return (
    <div>
      <WavesurferPlayer
        height={100}
        waveColor="violet"
        url={url}
        plugins={plugins}
      />
      <div id="timeline" />
    </div>
  )
}

Vue 3で使う

Vue用には@meersagor/wavesurfer-vueというサードパーティパッケージがある。

インストール

npm install @meersagor/wavesurfer-vue wavesurfer.js

基本的な使い方

<script setup lang="ts">
import { ref } from 'vue'
import { useWaveSurfer } from '@meersagor/wavesurfer-vue'

const containerRef = ref<HTMLElement | null>(null)

const options = {
  height: 48,
  waveColor: '#4F4A85',
  progressColor: '#383351',
  barWidth: 3,
  barGap: 2,
  barRadius: 4,
}

const { waveSurfer, currentTime, totalDuration, isPlaying } = useWaveSurfer({
  containerRef,
  options,
  url: '/audio.mp3',
})

const formatTime = (seconds: number): string => {
  const mins = Math.floor(seconds / 60)
  const secs = Math.floor(seconds % 60)
  return `${mins}:${secs.toString().padStart(2, '0')}`
}
</script>

<template>
  <div>
    <div ref="containerRef"></div>
    <div class="controls">
      <button @click="waveSurfer?.playPause()">
        {{ isPlaying ? '⏸️ Pause' : '▶️ Play' }}
      </button>
      <span>{{ formatTime(currentTime) }} / {{ formatTime(totalDuration) }}</span>
    </div>
  </div>
</template>

よくあるトラブルと解決策

CORSエラー

"Wavesurfer fetches audio from the URL you specify in order to decode it. Make sure this URL allows fetching data from your domain."

— wavesurfer.js公式FAQより

和訳: wavesurferは指定されたURLから音声をフェッチしてデコードする。そのURLがあなたのドメインからのデータ取得を許可していることを確認せよ。

症状:

Access to fetch at 'https://example.com/audio.mp3' from origin 'http://localhost:3000' 
has been blocked by CORS policy

解決策:

  1. 同一ドメインに音声ファイルを配置する
  2. 音声ファイルを提供するサーバーでAccess-Control-Allow-Originヘッダーを設定する
  3. 開発時はプロキシを使う

大きなファイルでメモリ不足

"Since wavesurfer decodes audio entirely in the browser using Web Audio, large clips may fail to decode due to memory constraints. We recommend using pre-decoded peaks for large files."

— wavesurfer.js公式FAQより

和訳: wavesurferはWeb Audioを使ってブラウザ内で音声を完全にデコードするため、大きなファイルはメモリ制約により失敗する可能性がある。大きなファイルには事前デコード済みのpeaksデータの使用を推奨。

解決策: BBCのaudiowaveformツールで事前にpeaksデータを生成する。

# audiowaveformをインストール(macOS)
brew install audiowaveform

# peaksデータを生成
audiowaveform -i audio.mp3 -o peaks.json --pixels-per-second 20
// 事前生成したpeaksを使用
const wavesurfer = WaveSurfer.create({
  container: '#waveform',
  url: '/audio.mp3',
  peaks: [[0.1, 0.2, 0.3, ...]],  // 事前生成したデータ
  duration: 180,  // 音声の長さ(秒)
})

VBRファイルで波形がズレる

"If you're using a VBR (variable bit rate) audio file, there might be a mismatch between the audio and the waveform. This can be fixed by converting your file to CBR (constant bit rate)."

— wavesurfer.js公式FAQより

和訳: VBR(可変ビットレート)音声ファイルを使用している場合、音声と波形がずれる可能性がある。ファイルをCBR(固定ビットレート)に変換することで修正できる。

# ffmpegでCBRに変換
ffmpeg -i input.mp3 -b:a 192k output.mp3

Reactで波形が複数表示される

useEffectのクリーンアップでwavesurferを破棄し忘れると、再レンダリングのたびに波形が増える。

useEffect(() => {
  const ws = WaveSurfer.create({
    container: waveformRef.current,
    url: '/audio.mp3',
  })
  
  // クリーンアップ関数でdestroy()を呼ぶ
  return () => ws.destroy()
}, [])

実践例:ポッドキャストプレイヤー

学んだことを活かして、実用的なプレイヤーを作ってみよう。

<!DOCTYPE html>
<html>
<head>
  <title>Podcast Player</title>
  <style>
    .player-container {
      max-width: 800px;
      margin: 0 auto;
      padding: 20px;
      font-family: sans-serif;
    }
    #waveform {
      margin: 20px 0;
    }
    .controls {
      display: flex;
      align-items: center;
      gap: 15px;
    }
    .controls button {
      padding: 10px 20px;
      font-size: 16px;
      cursor: pointer;
    }
    .time {
      font-family: monospace;
      font-size: 14px;
    }
    .speed-control {
      margin-left: auto;
    }
  </style>
</head>
<body>
  <div class="player-container">
    <h2>Podcast Player</h2>
    <div id="waveform"></div>
    <div id="timeline"></div>
    
    <div class="controls">
      <button id="playBtn">▶️ Play</button>
      <button id="backBtn">⏪ -10s</button>
      <button id="forwardBtn">⏩ +10s</button>
      <span class="time">
        <span id="currentTime">0:00</span> / <span id="duration">0:00</span>
      </span>
      <div class="speed-control">
        <label>Speed: </label>
        <select id="speedSelect">
          <option value="0.5">0.5x</option>
          <option value="0.75">0.75x</option>
          <option value="1" selected>1x</option>
          <option value="1.25">1.25x</option>
          <option value="1.5">1.5x</option>
          <option value="2">2x</option>
        </select>
      </div>
    </div>
  </div>

  <script type="module">
    import WaveSurfer from 'https://cdn.jsdelivr.net/npm/wavesurfer.js@7/dist/wavesurfer.esm.js'
    import Timeline from 'https://cdn.jsdelivr.net/npm/wavesurfer.js@7/dist/plugins/timeline.esm.js'
    import Hover from 'https://cdn.jsdelivr.net/npm/wavesurfer.js@7/dist/plugins/hover.esm.js'

    const formatTime = (seconds) => {
      const mins = Math.floor(seconds / 60)
      const secs = Math.floor(seconds % 60)
      return `${mins}:${secs.toString().padStart(2, '0')}`
    }

    const wavesurfer = WaveSurfer.create({
      container: '#waveform',
      waveColor: '#4F4A85',
      progressColor: '#383351',
      cursorColor: '#fff',
      cursorWidth: 2,
      barWidth: 3,
      barGap: 1,
      barRadius: 2,
      height: 80,
      url: '/path/to/podcast.mp3',
      plugins: [
        Timeline.create({
          container: '#timeline',
          primaryLabelInterval: 60,
          secondaryLabelInterval: 30,
          style: { fontSize: '11px', color: '#888' },
        }),
        Hover.create({
          lineColor: '#ff0000',
          labelBackground: '#333',
          labelColor: '#fff',
        }),
      ],
    })

    // 要素取得
    const playBtn = document.getElementById('playBtn')
    const backBtn = document.getElementById('backBtn')
    const forwardBtn = document.getElementById('forwardBtn')
    const currentTimeEl = document.getElementById('currentTime')
    const durationEl = document.getElementById('duration')
    const speedSelect = document.getElementById('speedSelect')

    // イベントハンドラ
    wavesurfer.on('ready', (duration) => {
      durationEl.textContent = formatTime(duration)
    })

    wavesurfer.on('audioprocess', (time) => {
      currentTimeEl.textContent = formatTime(time)
    })

    wavesurfer.on('play', () => {
      playBtn.textContent = '⏸️ Pause'
    })

    wavesurfer.on('pause', () => {
      playBtn.textContent = '▶️ Play'
    })

    // コントロール
    playBtn.addEventListener('click', () => wavesurfer.playPause())
    backBtn.addEventListener('click', () => wavesurfer.skip(-10))
    forwardBtn.addEventListener('click', () => wavesurfer.skip(10))
    speedSelect.addEventListener('change', (e) => {
      wavesurfer.setPlaybackRate(parseFloat(e.target.value))
    })

    // キーボードショートカット
    document.addEventListener('keydown', (e) => {
      if (e.code === 'Space') {
        e.preventDefault()
        wavesurfer.playPause()
      } else if (e.code === 'ArrowLeft') {
        wavesurfer.skip(-10)
      } else if (e.code === 'ArrowRight') {
        wavesurfer.skip(10)
      }
    })
  </script>
</body>
</html>

まとめ:音声UI開発の強い味方

wavesurfer.jsは、Web上で音声波形を扱うならまず検討すべきライブラリだ。

強み:

  • ゼロ依存で軽量
  • TypeScript完全対応
  • 豊富なカスタマイズオプション
  • 7つの公式プラグイン
  • React/Vue連携が容易
  • アクティブにメンテナンスされている

弱み:

  • 大きなファイルはメモリに注意
  • 音声編集機能はない(あくまで可視化・再生のみ)
  • ストリーミング再生は限定的

SoundCloudライクなUIを作りたいなら、wavesurfer.jsは最短ルートだ。

5分で波形表示、30分でフル機能プレイヤー。

音声アプリ開発、始めてみよう。


参考リンク


この記事が役に立ったら、ぜひフォローといいねをお願いします。wavesurfer.jsで作ったものがあればコメントで教えてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?