ffmpegでPCM音源をWAVE形式に変換するときにハマったこと

 · 6 min read

こんにちは。
ffmpegでPCM音源を変換するときに、期待したとおりに変換されなくてハマったので備忘録を残します。

渡しの場合、音声を扱うプログラムも経験がなく、そもそもサンプリングレートとかの用語からして分からないという感じでした。
同じ悩みを抱える方がいればと思い備忘録を残します。

用語の説明

音声ファイルについての用語を調べてまとめて書こうと思ったのですが、
この記事とWikipedia読めばだいたい必要な情報は揃ってしまったので、ご紹介にとどめます。

サンプリングレート・ビット深度・ビットレートの意味と関係性

PCMってなに

PCMは音声波形を電子化したもので、「音」そのものと捉えるとしっくり来ました。

PCM(ぴーしーえむ)とは - コトバンク

PCMの基礎知識

PCMとWAVEファイルの違い

WAVE(.wav)ファイルはよく見る形式だと思うのでファイル自体の説明は割愛します。ここでは違いについてだけ。
.wavとPCMの大きな違いは、メタデータの有無です。

PCMはただの音声波形にすぎず、「サンプリングレート」や「ビットレート」などの情報がファイル自体に含まれていません。
一方WAVEファイルの中にはそれらのメタデータ+PCMが含まれています。
この差が何を起こすか、コードベースで説明します。

問題のコード

ffmpegをナマで扱うのはつらいので、fluent-ffmpegというnpmパッケージを利用させていただきました。
バイナリのパスの指定なども柔軟にできるので、Lambdaとかクセのあるランタイム下でも扱いやすいです。

で、以下が問題のあるコードです。
変換元の音声ファイルは16000Hz, Signed, 16bit, LPCMです。

const ffmpeg = require('fluent-ffmpeg')

const pcmPath = './demo' # pcm
const destPath = './demo.wav'

ffmpeg()
  .input(pcmPath)
  .inputFormat('s16be')
  .output(destPath)
  .run()

ffmpegは拡張子を見てinput, outputをよしなにしてくれるらしいと噂を聞いたので、シンプルに実装してみました。
s16beというのは、Signedで16bitでBig endianなPCMのフォーマットを指します。
変換した結果が、これです。

ffmpegNodejs
© 2012-2021 Leko