Web Audio APIでOfflineAudioContextを作るときの長さの指定、どうしよう
OfflineAudioContextのコンストラクタ
Web Audio APIのOfflineAudioContextを作るとき、
コンストラクタで長さを指定しますよね。length。
- これが十分な長さより短いと作成した音声が短くなってしまい、
- 長すぎると最後の方に音が出力されないゾーンが出来てしまう。
const offlineCtx = new OfflineAudioContext(numberOfChannels, length, sampleRate);
けれど、いつもいつも事前に適切な長さが分かることばかりではない。
特に、Web Audio APIで音声を加工するのであれば。
例えば、playbackRateを低くしたりすると、音声が長くなってしまいますよね。
(加工後の音声の秒数でも分かれば計算で出せるけど、
音声を加工するにはOfflineAudioContextを作る必要があって、
音声を加工する前にlengthの指定が必要なんですね)
どうしよう
これで良いのか分からないけど、
自分の対応はこうしてみた。
- でっかく作って (短いと加工した音声が入らなくなるのだから当然だ)
- 余分な部分を切り詰めよう
あ、これ、今更だけど、オフラインに音声ファイルを出力するケースを想定した考えかもしれない。
長いOfflineAudioContextを作る
これは簡単ですね。
lengthの数値を大きくすれば良い。
const offlineCtx = new OfflineAudioContext(numberOfChannels, length, sampleRate);
切り詰める
音声が入っている場所までの長さを調べる。
ああ、そうだ。このコードは最終的にWAVファイルの出力を想定しているので、
データのサイズが偶数である必要があって、長さを計測する際、少し調整が入っているよ。
function correctFrameCount(audioBuffer: AudioBuffer): number { let max = 0; for (let i = 0; i < audioBuffer.numberOfChannels; i++) { const buffer: Float32Array = audioBuffer.getChannelData(i); const count = correctBufferLength(buffer); if (max < count) { max = count; } } return max; } function correctBufferLength(buffer: Float32Array): number { let pos = 0; for (let i = buffer.length - 1; i >= 0; i--) { if (buffer[i] !== 0x00) { pos = i; break; } } if (pos % 2 != 0) { pos += 1; } return pos; }
そして、測った長さにAudioBufferを切り詰める。
function buildCorrectAudioBuffer(audioBuffer: AudioBuffer): any { const frameCount = correctFrameCount(audioBuffer); const nAudioBuffer = new AudioBuffer({ numberOfChannels: audioBuffer.numberOfChannels, length: frameCount, sampleRate: audioBuffer.sampleRate, }); for (let i = 0; i < audioBuffer.numberOfChannels; i++) { const buffer = audioBuffer.getChannelData(i); const trimmed = buffer.slice(0, frameCount); nAudioBuffer.copyToChannel(trimmed, i, 0); } return nAudioBuffer; }
const newAudioBuf = buildCorrectAudioBuffer(audioBuf);
おわり
おわり。