QA@IT

JavaScriptでWavをMP3に変換する方法

7197 PV

wavデーターを動的に作成し、audioタグを動的に書き換えることで音を再生するプログラムを使用しています。
これをlibmp3lame.jsを用いてwavデーターをmp3データーに変換することで、IEでも音がでるようにしようと考えています。

speech-to-serverに含まれるencode.jsを同一ディレクトリに設置し、

var encoderWorker = new Worker('encoder.js');
encoderWorker.postMessage({ cmd: 'init', config: { samplerate: 44100, bitrate: 64 } });
encoderWorker.onmessage = function(e) {
    if (e.data.cmd == 'end') {
        encoderWorker.terminate();
        encoderWorker = null;
    }
};
encoderWorker.postMessage({ cmd: 'encode', buf: 任意のWavデーター(arraybuffer});

というように入れていますが、Uncaught RangeError: Invalid array buffer lengthというエラーが出てしまいます。
調べてみると、

var nread = Module.ccall('lame_encode_buffer_ieee_float', 'number', [ 'number', 'number', 'number', 'number', 'number', 'number' ], [ handle, inbuf_l, inbuf_r, channel_l.length, outbuf, BUFSIZE ]);

という部分でnreadが-1を出力しているため動かないようですが、どこに原因があるでしょうか?

回答

自己解決しました。
どうやら、Float32Arrayでデーターを渡さなければならなかったようです。
このFload32Arrayはオーディオデーターのやり取りでよく使われる形式らしく、それをArrayBufferやUint8Arrayで渡していたのが変換できなかった原因のようですね。

実働コード(IE11、Chrome、FireFoxで確認)
http://jsdo.it/Masashi.Yoshikawa/wav2mp3byJS/

編集 履歴 (0)
  • Float32Arrayで私の方でも音が鳴りました。 -

エラーがでるのはIE限定ですか?

現状任意のWavデーター(arraybuffer)にどういうデータを渡してるかわかりませんが、ChromeとSafariで 1秒くらいのWAVをUint8ArrayやCharCodeの配列でも渡して処理させることはできました(でもWAVEヘッダの有無にかかわらずノイズが酷いので変換はうまくいってないので、エラーは出ないで実行できましたというだけです)。

あと渡すサイズが大きいとバッファが足りなくてエラーになります(BUFSIZEを8192から変えれば通りはしましたけど直し方としてはイマイチですね)。

なお、

if (e.data.cmd == 'end') {

encoderWorker.postMessage({ cmd: 'finish' });

を発行しないと発生しません。

encodeだとe.data.cmd == 'data'が起きますね。

サンプルではWebSocketつかってストリーミングでやってるようですが、どういう単位で渡せばいいのかがちょっとわかりませんでした(そこまで見てません)。


追記

渡している形式が正しくなかったようです。
詳しくは
http://qa.atmarkit.co.jp/q/3337#answer_16178

編集 履歴 (1)

ありがとうございます。
指定の方法で変換されたと思われるデーターが出てきました。

調べてみたところ、バッファーサイズを変えるほかにemscriptenでコンパイル時にEMCC_OPTSに-s ALLOW_MEMORY_GROWTH=1を加える必要がありました。遅いのはASM_JS=1にすれば大丈夫そうなのはいいとして、ちょっと長いWavファイルでもすぐにバッファがあふれてしまうようでした。BUFFSIZEを1024000(!)ぐらいにしないとダメですね。

とりあえず、変換された形跡はあるし、IEでも再生できましたが、確かに雑音だらけで実用には程遠いようです。
ただ、空白部分はちゃんと空白になっているので型が怪しい気がします。
(ArrayBuffer(Uint8Array)型をそのままfloat型に割り当てている?)

編集 履歴 (1)
ウォッチ

この質問への回答やコメントをメールでお知らせします。