Web Audio APIだけで音声編集アプリを作る:ブラウザ内処理の仕組みを実装レベルで解説
Web Audio APIだけで音声編集アプリを作る:ブラウザ内処理の仕組みを実装レベルで解説 音声ファイルをサーバにアップロードせず、ブラウザだけでカット・変換・音量調整ができるWebアプリがあります。これを支えているのが Web Audio API です。今回は「ブラウザ内で音声編集が完結する仕組み」を、実装レベルのコードとともに解説します。 1. decodeAudioData:ファイルを AudioBuf
Web Audio APIだけで音声編集アプリを作る:ブラウザ内処理の仕組みを実装レベルで解説
音声ファイルをサーバにアップロードせず、ブラウザだけでカット・変換・音量調整ができるWebアプリがあります。これを支えているのが Web Audio API です。今回は「ブラウザ内で音声編集が完結する仕組み」を、実装レベルのコードとともに解説します。
1. decodeAudioData:ファイルを AudioBuffer(32bit float PCM)に変換する
Web Audio API の入口は AudioContext と decodeAudioData です。MP3 や WAV といったファイルを、編集可能な PCM データ(AudioBuffer)にデコードします。
const ctx = new AudioContext();
const res = await fetch('voice.mp3');
const arrayBuffer = await res.arrayBuffer();
const audioBuffer = await ctx.decodeAudioData(arrayBuffer);
// audioBuffer.sampleRate → 44100 など
// audioBuffer.numberOfChannels → 1(モノラル)or 2(ステレオ)
// audioBuffer.getChannelData(0) → Float32Array(32bit float PCM、-1.0〜1.0)
AudioBuffer の中身は、チャンネルごとの Float32Array です。「編集する」とは、この配列を直接いじることに他なりません。入力フォーマットの差(MP3 / WAV / M4A など)は decodeAudioData が吸収してくれますが、対応コーデックはブラウザ依存です(例:Safari は OGG/Vorbis をデコードできません)。
2. 波形選択とトリミング:秒数をサンプル数に直すだけ
波形上で範囲を選んで切り出す処理は、考え方はシンプルです。秒数をサンプル数に変換し、配列を切り出すだけです。
function trim(buffer, startSec, endSec, ctx) {
const sr = buffer.sampleRate;
const start = Math.floor(startSec * sr);
const length = Math.floor((endSec - startSec) * sr);
const out = ctx.createBuffer(buffer.numberOfChannels, length, sr);
for (let ch = 0; ch < buffer.numberOfChannels; ch++) {
out.getChannelData(ch).set(
buffer.getChannelData(ch).subarray(start, start + length)
);
}
return out;
}
ミリ秒単位の精密な選択も同じ理屈です。波形の描画自体は getChannelData の値を間引いて canvas にプロットすれば実現できます。
3. 削除時の 4ms クロスフェード:つなぎ目の「プチッ」を消す
区間を削除して前後をつなぐと、波形の段差で「プチッ」というクリックノイズが発生します。これを防ぐ定番の手法が、つなぎ目にごく短いクロスフェードをかけることです。
function spliceWithCrossfade(head, tail, sampleRate) {
const fadeLen = Math.floor(sampleRate * 0.004); // 4ms
// head の末尾 fadeLen サンプルを、tail の先頭とミックスする
for (let ch = 0; ch < head.numberOfChannels; ch++) {
const h = head.getChannelData(ch);
const t = tail.getChannelData(ch);
for (let i = 0; i < fadeLen; i++) {
const k = i / fadeLen; // 0 → 1
const idx = h.length - fadeLen + i;
h[idx] = h[idx] * (1 - k) + t[i] * k;
}
}
// あとは head と tail.slice(fadeLen) を連結する
}
4ms という短さなら音の違和感はほぼなく、段差だけがきれいに消えます。
4. ピーク正規化:ピーク検出 → ゲイン計算
「全体の音量を、最大ピークが -1dBFS になるように揃える」処理です。手順は3ステップです。
- 全チャンネル・全サンプルを走査し、絶対値の最大(ピーク)を求める
- 目標値 ÷ ピーク でゲインを計算する(-1dBFS ≒ 0.891)
- 全サンプルにゲインを掛ける
function peakNormalize(buffer, targetDb = -1) {
let peak = 0;
for (let ch = 0; ch < buffer.numberOfChannels; ch++) {
const d = buffer.getChannelData(ch);
for (let i = 0; i < d.length; i++) {
const v = Math.abs(d[i]);
if (v > peak) peak = v;
}
}
const gain = Math.pow(10, targetDb / 20) / peak;
for (let ch = 0; ch < buffer.numberOfChannels; ch++) {
const d = buffer.getChannelData(ch);
for (let i = 0; i < d.length; i++) d[i] *= gain;
}
}
注意点として、すでに音割れしている(クリッピング済みの)素材はこの処理では直りません。正規化は「小さすぎる音を安全に持ち上げる」ための処理です。
5. エンコード:WAV 16bit 出力と lamejs による MP3 化
編集後の AudioBuffer は float32 のままではファイルに保存できません。WAV なら 16bit PCM に変換してヘッダを付けるだけです。
// Float32(-1.0〜1.0)→ Int16 への変換
function floatTo16BitPCM(view, offset, input) {
for (let i = 0; i < input.length; i++, offset += 2) {
const s = Math.max(-1, Math.min(1, input[i]));
view.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
}
}
MP3 はブラウザ標準 API ではエンコードできないため、LAME の JavaScript 移植版である lamejs を使います。ビットレートは 96〜320kbps の範囲で指定できます。
import { Mp3Encoder } from 'lamejs';
const encoder = new Mp3Encoder(2, 44100, 128); // ch, sampleRate, kbps
// Int16 化したサンプルをブロックごとに入力 → encoder.encodeBuffer()
// 最後に encoder.flush() で残りのデータを吐き出す
実測ではデスクトップ環境で約5倍速(1分の音声を約12秒でエンコード)程度の性能が出ます。すべてブラウザ内(メインスレッド〜Worker)で完結し、サーバ通信はゼロです。
6. ブラウザ差とメモリの現実
実装上ぶつかる壁は主に2つです。
-
コーデック差:
decodeAudioDataの対応形式はブラウザ依存です。MP3 / WAV はほぼ共通ですが、OGG は Safari 非対応、Opus の扱いにも差があります。対応入力形式の表は「実際にデコードできるか」の実測で作るのが確実です。 - メモリ:PCM は非圧縮なので重いのが現実です。44.1kHz ステレオで1時間分 = 44100 × 2ch × 4byte × 3600秒 ≒ 1.3GB。実用的な設計としては、400MB(約19分)を超えたあたりで警告を出すのが無難です。
7. プライバシー設計:ローカル処理 = アップロードなし
この方式の最大の利点は、音声データがユーザーの PC から一歩も出ないことです。サーバに送らないので通信の待ち時間がなく、サーバ側での保存・漏洩リスクも存在しません。「無料・登録不要」がビジネスとして成立するのも、サーバコストがほぼゼロだからです。
この仕組みをそのまま使った無料ツール例として、17NAS Online Audio Tools があります。登録不要・透かしなしで、ここで解説したトリミングやピーク正規化、MP3/WAV 変換などがブラウザ内だけで動きます。
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.