Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
62
Help us understand the problem. What is going on with this article?
@HirokiTanaka

getUserMediaで録音したデータをWAVファイルとして保存する

More than 5 years have passed since last update.

1. 録音する

以下のように作った関数 startRecording を呼ぶと
変数 audioData に録音した音声データが取得できます。

        var localMediaStream = null;
        var localScriptProcessor = null;
        audioData = []; // 録音データ

        var onAudioProcess = function(e) {
          var input = e.inputBuffer.getChannelData(0);
          var bufferData = new Float32Array(bufferSize);
          for (var i = 0; i < bufferSize; i++) {
            bufferData[i] = input[i];
          }

          audioData.push(bufferData);
        };
        var startRecording = function() {
          navigator.getUserMedia(
            { audio: true },
            function(stream) {
              localMediaStream = stream;
              var scriptProcessor = audioContext.createScriptProcessor(bufferSize, 1, 1);
              localScriptProcessor = scriptProcessor;
              var mediastreamsource = audioContext.createMediaStreamSource(stream);
              mediastreamsource.connect(scriptProcessor);
              scriptProcessor.onaudioprocess = onAudioProcess;
              scriptProcessor.connect(audioContext.destination);
            },
            function(e) {
              console.log(e);
            }
          );
        };

2. WAVファイルに変換する

以下のように作った関数 exportWAV に 1 で作成した audioData を引数にわたして呼び出すと
WAVファイルを作成して、その url を返却してくれます。

        var exportWAV = function(audioData) {

          var encodeWAV = function(samples, sampleRate) {
            var buffer = new ArrayBuffer(44 + samples.length * 2);
            var view = new DataView(buffer);

            var writeString = function(view, offset, string) {
              for (var i = 0; i < string.length; i++){
                view.setUint8(offset + i, string.charCodeAt(i));
              }
            };

            var floatTo16BitPCM = function(output, offset, input) {
              for (var i = 0; i < input.length; i++, offset += 2){
                var s = Math.max(-1, Math.min(1, input[i]));
                output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
              }
            };

            writeString(view, 0, 'RIFF');  // RIFFヘッダ
            view.setUint32(4, 32 + samples.length * 2, true); // これ以降のファイルサイズ
            writeString(view, 8, 'WAVE'); // WAVEヘッダ
            writeString(view, 12, 'fmt '); // fmtチャンク
            view.setUint32(16, 16, true); // fmtチャンクのバイト数
            view.setUint16(20, 1, true); // フォーマットID
            view.setUint16(22, 1, true); // チャンネル数
            view.setUint32(24, sampleRate, true); // サンプリングレート
            view.setUint32(28, sampleRate * 2, true); // データ速度
            view.setUint16(32, 2, true); // ブロックサイズ
            view.setUint16(34, 16, true); // サンプルあたりのビット数
            writeString(view, 36, 'data'); // dataチャンク
            view.setUint32(40, samples.length * 2, true); // 波形データのバイト数
            floatTo16BitPCM(view, 44, samples); // 波形データ

            return view;
          };

          var mergeBuffers = function(audioData) {
            var sampleLength = 0;
            for (var i = 0; i < audioData.length; i++) {
              sampleLength += audioData[i].length;
            }
            var samples = new Float32Array(sampleLength);
            var sampleIdx = 0;
            for (var i = 0; i < audioData.length; i++) {
              for (var j = 0; j < audioData[i].length; j++) {
                samples[sampleIdx] = audioData[i][j];
                sampleIdx++;
              }
            }
            return samples;
          };

          var dataview = encodeWAV(mergeBuffers(audioData), audioContext.sampleRate);
          var audioBlob = new Blob([dataview], { type: 'audio/wav' });

          var myURL = window.URL || window.webkitURL;
          var url = myURL.createObjectURL(audioBlob);
          return url;
        };

参考サイト

62
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
HirokiTanaka
<フリーのソフトウェアエンジニア > <Web系の仕事がメイン(Node/C#/Java/PHP)> <携帯ネイティブアプリ(iOS/Android)などもつくっている> <最近の活動(ReactJSとAngularJSでアプリをつくっている)>

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
62
Help us understand the problem. What is going on with this article?