3

I'm trying to convert a .wav file to a byte array string. I need to do this on the back-end targeting the file is becoming an issue.

        files.forEach(file => {
            let index = files.indexOf(file)
            let reader = new FileReader();
            reader.readAsArrayBuffer(file);
            console.log(reader.result);

            reader.onload = function (event) {
                let byteArray = new Uint8Array(reader.result);
                let FileName = file.name;
                let dataAsByteArrayString = byteArray.toString();
                var listHtml = $list.html();

The above code uses npm's filereader which says to target a file. I'm having difficulty doing this since this is not a front end drag and drop of the file.

my file that is generated is called "response.wav" how would I convert this file using JavaScript and node extensions? Thanks!

3
  • Into a byte array string? Commented Mar 4, 2018 at 1:30
  • Yes such as: DataAsByteArrayString':'82,73,70,70,255,255,255,255,87,65,86,69,102,109,116,32,16,0,0,0,1,0,1,0,34,86,0,0,68,172,0,0,2,0,16,0,76,73,83,84,26,0,0,0,73,78,70,79,73,83,70,84,14,0,0,0,76,97,118,102,53,55,46,55,49,46,49,48,48,0,100,9 Commented Mar 4, 2018 at 1:34
  • Are you trying to actually parse the WAV file, or do you just need to generically read a file? Commented Mar 4, 2018 at 1:43

2 Answers 2

2

I dont know if this will help but the last project I worked on we parsed a .wav file using the Node buffer API and wrote it using the Node file API. If you have more questions about the code I can direct you to the person that worked on this file the most. I hope it helps somewhat https://github.com/IntelliSound/intelliSound-Server/blob/development/lib/sound-data-parser.js

'use strict';

function ParsedWave(buffer) {
  
  const RIFF_HEADER_OFFSET = 0;
  const FILE_SIZE_OFFSET = 4;
  const RIFF_FORMAT_OFFSET = 8;
  const SUBCHUNK1_ID_OFFSET = 12;
  const AUDIO_FORMAT_OFFSET = 20;
  const NUMBER_OF_CHANNELS_OFFSET = 22;
  const SAMPLE_RATE_OFFSET = 24;
  const BITS_PER_SAMPLE_OFFSET = 34;
  const SUBCHUNK2_ID_OFFSET = 36;
  const SUBCHUNK2_SIZE_OFFSET = 40;
  const DATA_OFFSET = 44;
  
  this.buffer = buffer;
  this.riff = buffer.slice(RIFF_HEADER_OFFSET, RIFF_HEADER_OFFSET + 4).toString('utf8');
  this.fileSize = buffer.readUInt32LE(FILE_SIZE_OFFSET);
  this.riffType = buffer.slice(RIFF_FORMAT_OFFSET, RIFF_FORMAT_OFFSET + 4).toString('utf8');
  this.subChunk1Id = buffer.slice(SUBCHUNK1_ID_OFFSET, SUBCHUNK1_ID_OFFSET + 4).toString('utf8');
  this.audioFormat = buffer.readUInt16LE(AUDIO_FORMAT_OFFSET);
  this.numberOfChannels = buffer.readUInt16LE(NUMBER_OF_CHANNELS_OFFSET);
  this.sampleRate = buffer.readUInt32LE(SAMPLE_RATE_OFFSET);
  this.bitsPerSample = buffer.readUInt16LE(BITS_PER_SAMPLE_OFFSET);
  this.subChunk2Id = buffer.slice(SUBCHUNK2_ID_OFFSET, SUBCHUNK2_ID_OFFSET + 4).toString('utf8');
  this.subChunk2Size = buffer.readUInt32LE(SUBCHUNK2_SIZE_OFFSET);
  this.data = buffer.slice(DATA_OFFSET, this.subChunk2Size + DATA_OFFSET);
}

// Andrew - The bufferMapper function is going to accept a parsed wave-file and output
//          an array of values corresponding to the data subchunk in a format which can
//          be accepted as input to the neural network.

const bufferMapper = parsedWave => {
  
  const SIXTEEN_BIT_ZERO = 32768;
  const SIXTEEN_BIT_MAX = 65535;
  
  parsedWave.neuralArray = [];
  
  for (let i = 0; i < parsedWave.data.length; i += 2) {
    const sample = parsedWave.data.readInt16LE(i);
    const unsignedSample = sample + SIXTEEN_BIT_ZERO;
    const sigmoidSample = unsignedSample / SIXTEEN_BIT_MAX;
    parsedWave.neuralArray.push(sigmoidSample);
  }
  return parsedWave;
};

module.exports = data => {

  const parsedWaveFile = new ParsedWave(data);

  if (parsedWaveFile.riff !== 'RIFF') {
    throw new TypeError('incorrect file type, must be RIFF format');
  }

  if (parsedWaveFile.fileSize > 10000000) {
    throw new TypeError('file too large, please limit file size to less than 10MB');
  }

  if (parsedWaveFile.riffType !== 'WAVE') {
    throw new TypeError('file must be a WAVE');
  }

  if (parsedWaveFile.subChunk1Id !== 'fmt ') {
    throw new TypeError('the first subchunk must be fmt');
  }

  if (parsedWaveFile.audioFormat !== 1) {
    throw new TypeError('wave file must be uncompressed linear PCM');
  }

  if (parsedWaveFile.numberOfChannels > 2) {
    throw new TypeError('wave file must have 2 or less channels');
  }

  if (parsedWaveFile.sampleRate > 48000) {
    throw new TypeError('wave file must have sample rate of less than 48k');
  }

  if (parsedWaveFile.bitsPerSample !== 16) {
    throw new TypeError(`file's bit depth must be 16`);
  }

  if (parsedWaveFile.subChunk2Id !== 'data') {
    throw new TypeError('subchunk 2 must be data');
  }

  const neuralMappedWaveFile = bufferMapper(parsedWaveFile);

  return neuralMappedWaveFile;
};

Sign up to request clarification or add additional context in comments.

Comments

2

Using the included fs module, you can read in your wav file like so:

const fs = require('fs');
const path = './path/to/my.wav';

fs.readFile(path, (err, data) => {
    // Data is a Buffer object 

});

For documentation on working with a Node.JS Buffer see here. Now, if you were more interested in the file conversion portion, there are a couple of libraries out there. If you just need the conversion functionality, and not implementing yourself, node-fluent-ffmpeg may work for you. If you want to implement it yourself, this node-wav file may be a good reference (too much to paste here).

If you need to go from Buffer to ArrayBuffer, this SO shows some options.

1 Comment

Thank you! This helped a lot. I was able to go from buffer to arrayBuffer with with!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.