'Reactjs recorder-js download

I am trying to make a React app for recording voice samples and save them as wav files, I used recorder-js to make the record but I am still struggling to make the saving part as wav file, and I got the exporWAV is not a function everytime. If you've been there please help



Solution 1:[1]

Sample code is here

//create
var record_recorder;
record_recorder = new RecorderV2(input,{sampleRate:44100, numChannels:2});

//start
record_recorder.record();

//stop
record_recorder.stop();

//export
record_recorder.exportWAV(function(blob) {
      var url = URL.createObjectURL(blob);
      var li = document.createElement('div');
      var au = document.createElement('audio');
      var hf = document.createElement('a');
      var br = document.createElement('br');
      record_result_blob = blob;
      au.controls = true;
      au.src = url;
      hf.href = url;
      hf.download = 'record.wav';
      hf.innerHTML = hf.download;
      li.appendChild(au);
      li.appendChild(br);
      li.appendChild(hf);
      if (result)
          result(li);
});

See the example website: https://voice-recorder-online.com code: https://voice-recorder-online.com/js/index_editor.js

Solution 2:[2]

Here's How u can make waves depending on your voice frequency and record and save files in wav format.

(async() => {
    let leftchannel = [];
    let rightchannel = [];
    let recorder = null;
    let recording = false;
    let recordingLength = 0;
    let volume = null;
    let audioInput = null;
    let sampleRate = null;
    let AudioContext = window.AudioContext || window.webkitAudioContext;
    let context = null;
    let analyser = null;
    let canvas = document.querySelector("canvas");
    let canvasCtx = canvas.getContext("2d");
    let visualSelect = document.querySelector("#visSelect");
    let micSelect = document.querySelector("#micSelect");
    let stream = null;
    let tested = false;

    try {
      window.stream = stream = await getStream();
      console.log("Got stream");
    } catch (err) {
      alert("Issue getting mic", err);
    }

    const deviceInfos = await navigator.mediaDevices.enumerateDevices();

    var mics = [];
    for (let i = 0; i !== deviceInfos.length; ++i) {
      let deviceInfo = deviceInfos[i];
      if (deviceInfo.kind === "audioinput") {
        mics.push(deviceInfo);
        let label = deviceInfo.label || "Microphone " + mics.length;
        console.log("Mic ", label + " " + deviceInfo.deviceId);
        const option = document.createElement("option");
        option.value = deviceInfo.deviceId;
        option.text = label;
        micSelect.appendChild(option);
      }
    }

    function getStream(constraints) {
      if (!constraints) {
        constraints = {
          audio: true,
          video: false
        };
      }
      return navigator.mediaDevices.getUserMedia(constraints);
    }

    setUpRecording();

    function setUpRecording() {
      context = new AudioContext();
      sampleRate = context.sampleRate;

      // creates a gain node
      volume = context.createGain();

      // creates an audio node from teh microphone incoming stream
      audioInput = context.createMediaStreamSource(stream);

      // Create analyser
      analyser = context.createAnalyser();

      // connect audio input to the analyser
      audioInput.connect(analyser);

      // connect analyser to the volume control
      // analyser.connect(volume);

      let bufferSize = 2048;
      let recorder = context.createScriptProcessor(bufferSize, 2, 2);

      // we connect the volume control to the processor
      // volume.connect(recorder);

      analyser.connect(recorder);

      // finally connect the processor to the output
      recorder.connect(context.destination);

      recorder.onaudioprocess = function(e) {
        // Check
        if (!recording) return;
        // Do something with the data, i.e Convert this to WAV
        console.log("recording");
        let left = e.inputBuffer.getChannelData(0);
        let right = e.inputBuffer.getChannelData(1);
        if (!tested) {
          tested = true;
          // if this reduces to 0 we are not getting any sound
          if (!left.reduce((a, b) => a + b)) {
            alert("There seems to be an issue with your Mic");
            // clean up;
            stop();
            stream.getTracks().forEach(function(track) {
              track.stop();
            });
            context.close();
          }
        }
        // we clone the samples
        leftchannel.push(new Float32Array(left));
        rightchannel.push(new Float32Array(right));
        recordingLength += bufferSize;
      };
      visualize();
    }

    function mergeBuffers(channelBuffer, recordingLength) {
      let result = new Float32Array(recordingLength);
      let offset = 0;
      let lng = channelBuffer.length;
      for (let i = 0; i < lng; i++) {
        let buffer = channelBuffer[i];
        result.set(buffer, offset);
        offset += buffer.length;
      }
      return result;
    }

    function interleave(leftChannel, rightChannel) {
      let length = leftChannel.length + rightChannel.length;
      let result = new Float32Array(length);

      let inputIndex = 0;

      for (let index = 0; index < length;) {
        result[index++] = leftChannel[inputIndex];
        result[index++] = rightChannel[inputIndex];
        inputIndex++;
      }
      return result;
    }

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

    function start() {
      recording = true;
      document.querySelector("#msg").style.visibility = "visible";
      // reset the buffers for the new recording
      leftchannel.length = rightchannel.length = 0;
      recordingLength = 0;
      console.log("context: ", !!context);
      if (!context) setUpRecording();
    }

    function stop() {
      console.log("Stop");
      recording = false;
      document.querySelector("#msg").style.visibility = "hidden";

      // we flat the left and right channels down
      let leftBuffer = mergeBuffers(leftchannel, recordingLength);
      let rightBuffer = mergeBuffers(rightchannel, recordingLength);
      // we interleave both channels together
      let interleaved = interleave(leftBuffer, rightBuffer);

      ///////////// WAV Encode /////////////////
      // from http://typedarray.org/from-microphone-to-wav-with-getusermedia-and-web-audio/
      //

      // we create our wav file
      let buffer = new ArrayBuffer(44 + interleaved.length * 2);
      let view = new DataView(buffer);

      // RIFF chunk descriptor
      writeUTFBytes(view, 0, "RIFF");
      view.setUint32(4, 44 + interleaved.length * 2, true);
      writeUTFBytes(view, 8, "WAVE");
      // FMT sub-chunk
      writeUTFBytes(view, 12, "fmt ");
      view.setUint32(16, 16, true);
      view.setUint16(20, 1, true);
      // stereo (2 channels)
      view.setUint16(22, 2, true);
      view.setUint32(24, sampleRate, true);
      view.setUint32(28, sampleRate * 4, true);
      view.setUint16(32, 4, true);
      view.setUint16(34, 16, true);
      // data sub-chunk
      writeUTFBytes(view, 36, "data");
      view.setUint32(40, interleaved.length * 2, true);

      // write the PCM samples
      let lng = interleaved.length;
      let index = 44;
      let volume = 1;
      for (let i = 0; i < lng; i++) {
        view.setInt16(index, interleaved[i] * (0x7fff * volume), true);
        index += 2;
      }

      // our final binary blob
      const blob = new Blob([view], {
        type: "audio/wav"
      });

      const audioUrl = URL.createObjectURL(blob);
      console.log("BLOB ", blob);
      console.log("URL ", audioUrl);
      document.querySelector("#audio").setAttribute("src", audioUrl);
      const link = document.querySelector("#download");
      link.setAttribute("href", audioUrl);
      link.download = "output.wav";
    }

    // Visualizer function from
    // https://webaudiodemos.appspot.com/AudioRecorder/index.html
    //
    function visualize() {
      WIDTH = canvas.width;
      HEIGHT = canvas.height;
      CENTERX = canvas.width / 2;
      CENTERY = canvas.height / 2;

      let visualSetting = visualSelect.value;
      console.log(visualSetting);
      if (!analyser) return;

      if (visualSetting === "sinewave") {
        analyser.fftSize = 2048;
        var bufferLength = analyser.fftSize;
        console.log(bufferLength);
        var dataArray = new Uint8Array(bufferLength);

        canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);

        var draw = function() {
          drawVisual = requestAnimationFrame(draw);

          analyser.getByteTimeDomainData(dataArray);

          canvasCtx.fillStyle = "rgb(200, 200, 200)";
          canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);

          canvasCtx.lineWidth = 2;
          canvasCtx.strokeStyle = "rgb(0, 0, 0)";

          canvasCtx.beginPath();

          var sliceWidth = (WIDTH * 1.0) / bufferLength;
          var x = 0;

          for (var i = 0; i < bufferLength; i++) {
            var v = dataArray[i] / 128.0;
            var y = (v * HEIGHT) / 2;

            if (i === 0) {
              canvasCtx.moveTo(x, y);
            } else {
              canvasCtx.lineTo(x, y);
            }

            x += sliceWidth;
          }

          canvasCtx.lineTo(canvas.width, canvas.height / 2);
          canvasCtx.stroke();
        };

        draw();
      } else if (visualSetting == "frequencybars") {
        analyser.fftSize = 64;
        var bufferLengthAlt = analyser.frequencyBinCount;
        console.log(bufferLengthAlt);
        var dataArrayAlt = new Uint8Array(bufferLengthAlt);

        canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);

        var drawAlt = function() {
          drawVisual = requestAnimationFrame(drawAlt);

          analyser.getByteFrequencyData(dataArrayAlt);

          canvasCtx.fillStyle = "rgb(0, 0, 0)";
          canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);

          var barWidth = WIDTH / bufferLengthAlt;
          var barHeight;
          var x = 0;

          for (var i = 0; i < bufferLengthAlt; i++) {
            barHeight = dataArrayAlt[i];

            canvasCtx.fillStyle = "rgb(" + (barHeight + 100) + ",50,50)";
            canvasCtx.fillRect(
              x,
              HEIGHT - barHeight / 2,
              barWidth,
              barHeight / 2
            );

            x += barWidth + 1;
          }
        };

        drawAlt();
      } else if (visualSetting == "circle") {
        analyser.fftSize = 32;
        let bufferLength = analyser.frequencyBinCount;
        console.log(bufferLength);
        let dataArray = new Uint8Array(bufferLength);

        canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);

        let draw = () => {
          drawVisual = requestAnimationFrame(draw);

          analyser.getByteFrequencyData(dataArray);
          canvasCtx.fillStyle = "rgb(0, 0, 0)";
          canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);

          // let radius = dataArray.reduce((a,b) => a + b) / bufferLength;
          let radius = dataArray[2] / 2;
          if (radius < 20) radius = 20;
          if (radius > 100) radius = 100;
          // console.log('Radius ', radius)
          canvasCtx.beginPath();
          canvasCtx.arc(CENTERX, CENTERY, radius, 0, 2 * Math.PI, false);
          // canvasCtx.fillStyle = 'rgb(50,50,' + (radius+100) +')';
          // canvasCtx.fill();
          canvasCtx.lineWidth = 6;
          canvasCtx.strokeStyle = "rgb(50,50," + (radius + 100) + ")";
          canvasCtx.stroke();
        };
        draw();
      }
    }
#msg {
  visibility: hidden;
  color: red;
  font-weight: bold;
  font-size: 22px;
  font-family: Verdana;
}

button {
  padding: 5px 10px;
  border: 1px solid grey;
  font-size: 18px;
  background: white;
}

.audio-controls {
  display: flex;
  align-items: center;
  padding-top: 20px;
  justify-content: center;
}

.audio-controls button {
  margin: 0px 5px;
}

canvas {
  margin-top: 10px;
  background-color: black;
}

select {
  height: 25px;
  margin: 0px 5px;
}

a {
  margin-left: 20px;
}

.app {
  text-align: center;
  padding-top: 20px;
}
<div class="app">
  <select name="" id="micSelect"></select>

  <select id="visSelect">
    <option value="frequencybars">Bar</option>
    <option value="sinewave">Wave</option>
    <option value="circle">Circle</option>
  </select>

  <a id="download">Download</a>

  <div class="audio-controls">
    <button id="record">Record</button>
    <button id="stop">Stop</button>
    <audio id="audio" controls></audio>
  </div>

  <div id="msg">Recording...</div>
  <canvas width="500" height="300"></canvas>
  <div>

Live Demo: https://codepen.io/furki911/pen/jOYpvMx

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ashish Kamble
Solution 2 Ethan