Node.jsでのWAVEエンコード&保存

#はじめに
クライアント側ではなくサーバ側でgetUserMediaを保存したい！

サンプルソースはこちら
https://github.com/sinkunvv/qiita-samples/tree/master/Nodejs-wav

今回の実装で使用したライブラリは以下の通り

```json:package.json

{
  "name": "wav-encode",
  "version": "1.0.0",
  "dependencies": {
    "express": "^3.3.8",
    "socket.io": "^2.1.0",
    "wav-encoder": "^1.3.0"
  }
}
```

#1.　getUserMediaを使用して音声データを取得する
まずはクライアント側の実装例
録音ボタン等にrecord()を紐づけてgetUserMediaで音声データを取得する

```javascript:client.js

let buffer = 2048;
let context;
let processor;
let input;
let globalStream;
var audioData = [];
const property = {
    audio: true,
    video: false
};

function record() {
    context = new AudioContext();
    processor = context.createScriptProcessor(buffer, 1, 1);
    processor.connect(context.destination);
    context.resume();

    var recording = function(stream) {
        globalStream = stream;
        input = context.createMediaStreamSource(stream);
        input.connect(processor);
        processor.onaudioprocess = function(audio) {
            audioStream(audio);
        };
    };
    navigator.mediaDevices.getUserMedia(property).then(recording);
}

function audioStream(audio) {
    var input = audio.inputBuffer.getChannelData(0);
    var bufferData = new Float32Array(buffer);

    for (var i = 0; i < buffer; i++) {
        bufferData[i] = input[i];
    }
    audioData.push(bufferData);
}
```

# 2. サーバに音声データを送信する
今回はストリーミングで音声認識をする必要があったためsocket.ioを使用していた。
bufferデータを送ることができれば他の方法を使用しても良いはず。（未確認）

```javascript:client.js
function stop() {
    startButton.disabled = false;
    stopButton.disabled = true;
    socket.emit('stop', audioData);
    let track = globalStream.getTracks()[0];
    track.stop();
    audioData = [];
    input.disconnect(processor);
    processor.disconnect(context.destination);
    context.close().then(function() {
        input = null;
        processor = null;
        context = null;
        startButton.disabled = false;
    });
}
```
録音停止したタイミングで蓄積した音声データを送る。

# 3.Node.jsで音声データを受け取り、WAVにエンコードする
socket.ioでstopイベントを受け取ったらそのデータをexportWAVに送る

```javascript:server.js
    // 録音終了
    socket.on('stop', function(data) {
        exportWAV(data, sampleRateHertz);
        console.log('stop record');
    });
```

```javascript:server.js

const WavEncoder = require('wav-encoder');
const fs = require('fs');

// jsonの要素数
function Objlen(data) {
    return Object.keys(data).length;
}

// 
function exportWAV(data, sampleRate) {
    var mergeBuffers = function(data) {
        var sampleLength = 0;
        for(var i = 0; i < data.length; i++) {
            sampleLength += Objlen(data[i]);
        }

        var samples = new Float32Array(sampleLength);
        var sampleIndex = 0;

        for(var i = 0; i < data.length; i++) {
            for(var j = 0; j < Objlen(data[i]); j++) {
                samples[sampleIndex] = data[i][j]
                sampleIndex++;
            }
        }
        return samples;
    };

    var audioData = {
            sampleRate: 44100,
            channelData: [mergeBuffers(data)]
        };

    WavEncoder.encode(audioData).then((buffer) => {
        fs.writeFile('demo.wav', Buffer.from(buffer), function(e) {
            if (e) {
                console.log(e)
            } else {
                console.log("Success")
            }
        });
    });
}
```

#終わり
音声認識での機械学習用にデータを収集したかったが
クライアント側でwavに変換してダウンロードする的なのは多くまとめられていたけれど
サーバ側で保存するが中々見つからなかったのでまとめてみた。
wav-encoderには助けられた...


誰かの足がかりになればと。


#参考サイト
[getUserMediaで録音したデータをWAVファイルとして保存する - Qiita](https://qiita.com/HirokiTanaka/items/56f80844f9a32020ee3b)
[Media Capture and Streams と Web Audio API で実現する録画・録音・ WAVファイルの生成 | CYOKODOG](http://www.cyokodog.net/blog/media-capture-and-streams-web-audio-api/)
[javascript - Node.js can´t create Blobs? - Stack Overflow](https://stackoverflow.com/questions/14653349/node-js-can%C2%B4t-create-blobs)