ai-lab.org
PitchFlip

PitchFlip ができるまで — soundtouchjs でブラウザ完結のボイスチェンジャーを作る

soundtouchjs (SoundTouch / SimpleFilter / WebAudioBufferSource) を CDN side-load して、 音声のピッチ (±24半音) とテンポ (0.5〜2.0倍) を独立に変更し WAV エンコードして書き出すボイスチェンジャーの設計記録。

·decision改善·stage公開中

PitchFlip ができるまで — soundtouchjs でブラウザ完結のボイスチェンジャーを作る

PitchFlip は、 声のピッチとテンポを アップロード不要・サインアップ不要・無料・ブラウザだけで 変えられる Webサービスです。 soundtouchjs を CDN side-load して WebAudio API で動かす構成。 メディア処理ラボ 13本柱に続く 14本目、 新カテゴリ 「音声加工」 を追加しました。

なぜこの形にしたか

「ボイスチェンジャー ブラウザ」「声 加工 無料」 の検索需要は SNS / YouTuber / 言語学習で日常的に強い。 既存サービスは ほぼ全部 スマホアプリ DL 必須 / サーバーアップロード前提。 soundtouchjs は SoundTouch (C++) の純 JS ポートで、 ピッチとテンポを独立に制御できる。 ブラウザ完結で出す素地が揃っています。

visual direction

シンセウェーブ・ネオン (deep purple + hot magenta + cyan)。 既存 13本柱と完全別軸の neon dark warm。

実装の見どころ

1. CDN side-load + Turbopack バイパス

soundtouchjs は ESM 構文だが dist/soundtouch.js を main にしている。 Next.js Turbopack の chunk loader を介すと過去踏んだのと同じクラッシュを発火させ得るので、 最初から CDN ESM の dynamic import で side-load:

const mod = await import(
  "https://cdn.jsdelivr.net/npm/soundtouchjs@0.3.0/dist/soundtouch.js"
)
const { SoundTouch, SimpleFilter, WebAudioBufferSource } = mod

2. ピッチ + テンポを独立に変える

audio.playbackRate = 1.5 系のナイーブな実装はピッチとテンポを同時に変えてしまう。 SoundTouch は WSOLA 系のアルゴリズムで、 ピッチを変えずにテンポだけ または テンポを変えずにピッチだけ が変えられる:

const st = new SoundTouch()
st.pitch = Math.pow(2, semitones / 12)  // 1.0 = 原音, 2.0 = 1オクターブ上
st.tempo = tempoFactor                  // 1.0 = 原速, 1.5 = 50%速い

3. Offline レンダリング + WAV エンコード

ファイル全体を offline 処理して WAV で書き出す経路を v1 では採用。 リアルタイムプレビューより 「変えた音声を SNS / 動画編集に貼りたい」 動線優先:

const blockSize = 4096
const sampleBuffer = new Float32Array(blockSize * 2)
const outSamples: number[] = []
while (true) {
  const extracted = filter.extract(sampleBuffer, blockSize)
  if (extracted === 0) break
  for (let i = 0; i < extracted; i++) outSamples.push(sampleBuffer[i * 2])
  if (outSamples.length % (blockSize * 16) === 0) {
    await new Promise((r) => setTimeout(r, 0)) // UI yield
  }
}

WAV は 44byte の RIFF/WAVE ヘッダ + 16-bit PCM mono で素朴に組みます。

4. プリセット 6本

SNS で需要の高い 6パターンをプリセット化:

  • そのまま / チップ (+7st) / ダーク (-6st) / モンスター (-12st, 0.85x) / lofi (-2st, 0.8x) / 高速 (1.5x, ピッチ維持)

5. マイク録音

getUserMedia + MediaRecorder でブラウザ内録音 → 即加工 → DL。 メタデータも残らない。

6. SEO §7.1

  • 主用語: 「ボイスチェンジャー」「声 加工 ブラウザ」「ピッチ変更 オンライン」
  • 補助: 「soundtouchjs」「WebAudio」「アップロード不要」「無料」

7. §8.5.2 invariants

result panel に data-output-bytes / data-mime / data-output-sec / data-input-sec を出し、 e2e で mime === audio/wav / outputSec > 0 / outputBytes > 4096 を assert。

苦労したところ

  • soundtouchjs の TS 型なし — 必要なクラスのシグネチャだけ手書きで定義
  • mono 強制 — ステレオはタイミングが微妙にズレ得るので v1 は down-mix mono に
  • 長尺ファイル — 1分以上の音声でも UI が固まらないようブロック毎に setTimeout(0) yield

今後の拡張

  • ステレオ対応 / mp3 / opus 出力
  • 共有 URL (?pitch=&tempo=)
  • リアルタイム preview
  • voice-scribe との Process Chain (加工 → 文字起こし)
  • リバーブ / EQ プリセット

ラボの 14本柱

voice-scribe / clip-cast / bg-snap / text-pluck / pdf-anvil / pixel-lift / pic-flip / mind-cell / beam-drop / word-warp / exif-peel / ascii-bake / py-pad / pitch-flip

カテゴリ 8つ目 「音声加工」 を追加。

[ ./next_action ]

読んだら、 PitchFlip を実際に動かす。

この開発ログは PitchFlip をどう作ったかの記録です。 読み終わったらそのままサービス本体へ戻って、 実物で価値を確かめてください。

[ ./related_logs ]

関連する開発ログ

all logs →
FateNum

FateNum ができるまで — 占い・診断 thesis 1本目を 数秘術 で開く

計算ツール 連続 2本 (coin-stack / roof-fund) のあと、 §3.1 Thesis Audit に従って別 thesis 「占い・診断」 へ振り直し。 ピタゴラス式数秘術を純 JS で実装、 zodiac wheel + serif display で過去 16本柱と全く別の visual を組んだ設計記録。

read log →
RoofFund

RoofFund ができるまで — 住宅ローン シミュレーターを建築立面図で見せる

コインスタックの直後に置く 計算ツール 2本目。 元利均等 / 元金均等 / 繰上げ返済 (期間短縮型) を純 JS で実装し、 残高推移を建築立面図風 SVG で描く設計記録。 §6.1 Visual Audit の最初の適用例。

read log →
CoinStack

CoinStack ができるまで — NISA / iDeCo シミュレーターで thesis を多様化する

14本柱が on-device ML に偏った反省から、 §3.1 Thesis Audit で別軸を採用。 NISA/iDeCo/つみたて投資 の複利 FV + 節税試算を純 JS で実装した設計記録。

read log →
PyPad

PyPad ができるまで — Pyodide でブラウザ完結の Python REPL を作る

Pyodide (CPython を WebAssembly にコンパイルしたランタイム) を CDN side-load して、 入力したコードがブラウザの外に出ない Python REPL を構築した設計記録。

read log →
ASCIIBake

ASCIIBake ができるまで — Canvas だけで画像を文字に焼く軽量ピース

Canvas API の createImageBitmap → drawImage → getImageData だけで画像の明暗を読み、 文字ランプにマップする アスキーアート生成ツールの設計記録。 ML / WASM / モデル不要、 純 JS で 12本目を埋めた話。

read log →
ExifPeel

ExifPeel ができるまで — ブラウザだけで画像のEXIFを確認・剥離する設計

exifr (EXIF パーサ) と piexifjs (JPEG EXIF 操作) と Canvas API をブラウザ内で動かし、 GPS / 撮影機種 / 編集ソフト履歴を覗いて剥がすツールの設計記録。 JPEG ロスレス strip と PNG/WebP の Canvas 再エンコード戦略、 GPS 警告 UI まで解説します。

read log →