12

I'm trying to make a webpage in html5 which stores sample-data from a wav-file in an array. Is there any way to get the sample-data with javascript? I'm using a file-input to select the wav-file.

In the javascript I already added:

document.getElementById('fileinput').addEventListener('change', readFile, false);

but I have no idea what to do in readFile.

EDIT: I tried to get the file in an ArrayBuffer, pass it to the decodeAudioData method and get a typedArraybuffer out of it. This is my code:

var openFile = function(event) {
var input = event.target;
var audioContext = new AudioContext();

var reader = new FileReader();
reader.onload = function(){
var arrayBuffer = reader.result;
  console.log("arrayBuffer:");
  console.log(arrayBuffer);
  audioContext.decodeAudioData(arrayBuffer, decodedDone);

};
reader.readAsArrayBuffer(input.files[0]);
};
function decodedDone(decoded) {
var typedArray = new Uint32Array(decoded, 1, decoded.length);
  console.log("decoded");
  console.log(decoded);
  console.log("typedArray");
  console.log(typedArray);

for (i=0; i<10; i++)
{
    console.log(typedArray[i]);
}

}

The elements of typedArray are all 0. Is my way of creating the typedArray wrong or did I do something else wrong on?

EDIT: I finally got it. This is my code:

var openFile = function(event) {
var input = event.target;
var audioContext = new AudioContext();

var reader = new FileReader();
reader.onload = function(){
var arrayBuffer = reader.result;
  console.log("arrayBuffer:");
  console.log(arrayBuffer);
  audioContext.decodeAudioData(arrayBuffer, decodedDone);

};
reader.readAsArrayBuffer(input.files[0]);
};
function decodedDone(decoded) {

 var typedArray = new Float32Array(decoded.length);

typedArray=decoded.getChannelData(0);
console.log("typedArray:");
console.log(typedArray);

}

Thanks for the answers!

myName
  • 123
  • 1
  • 1
  • 5
  • So basically you want to get the dataURI from the file? – Slugge Mar 28 '15 at 13:46
  • I'm not sure so sure about that. I could be wrong since I haven't even heard of the term dataURI until now, but it seems to be a way to get data from elements in the webpage. When I use the eventlistener I can use the event to get some data from the wav-file (title, ...) but I can't seem to get the time domain data of the wav-file. I am looking for a way to get samplevalues to create something like an equalizer. Surely there are other ways to make an equalizer but I'm working with other people and they need to have the sampledata in an array(preferrably cut into arrays of a fixed size). – myName Mar 28 '15 at 14:24
  • So if i understand correctly you want to get the duration of the audio, you could load it in a audio tag and use js to get the duration from there, like so: http://codetheory.in/get-the-duration-of-an-audio-or-video-file-in-javascript/ – Slugge Mar 28 '15 at 14:28
  • I want more than just the duration, I want to get the timedomain-data in the wav-file and put this in an array where each element is the amplitude at a certain point in time. – myName Mar 28 '15 at 14:47
  • 1
    I highly doubt you will be able to do this with javascript, it would most likely require more advanced coding languages. Java, Python, C, or something similar – Slugge Mar 28 '15 at 14:49
  • dataURIs are inefficient, don't use them. There are blob URLs now. Also, the Web Audio API has a built-in equalizer :) – Touffy Mar 28 '15 at 15:50
  • The code I have works in chrome, but in firefox the arraybuffer is always empty. Does anyone have any idea why? – myName Apr 17 '15 at 14:40
  • Nevermind, it's because I used a wav-file. I suppose there is no way around firefox not supporting the reading of wav-data. – myName Apr 17 '15 at 15:12

3 Answers3

6

You'll need to learn a lot about Web APIs to accomplish that, but in the end it's quite simple.

  1. Get the file contents in an ArrayBuffer with the File API
  2. Pass it to the Web Audio API's decodeAudioData method.
  3. Get a typed ArrayBuffer with the raw samples you wanted.

Edit: If you want to implement an equalizer, you're wasting your time, there's a native equalizer node in the Audio API. Depending on the length of your wave file it might be better not to load it all in memory and instead to just create a source that reads from it and connect that source to an equalizer node.

Touffy
  • 6,309
  • 22
  • 28
  • Thanks, I'll try this out. And when I typed equalizer I was actually talking about some sort of visualizer. – myName Mar 28 '15 at 16:28
  • Well, there's also a native analyzer node in the API. You've got a ton of reading to do but I believe you'll find it an exciting read. – Touffy Mar 28 '15 at 16:39
  • I tried this but I'm not sure that I did it right. Is the variable that gets send to the callbackSucces function of decodeAudioData the decoded arraybuffer? Also, how do I create the TypedArray? – myName Mar 30 '15 at 12:21
  • Nevermind, I got it. The argument in callbackSuccess was an AudioBuffer. Thanks for the answer. – myName Mar 30 '15 at 14:18
0

Here's a simple code example to get a Float32Array from a wav audio file in JavaScript:

let audioData = await fetch("https://example.com/test.wav").then(r => r.arrayBuffer());

let audioCtx = new AudioContext({sampleRate:44100});

let decodedData = await audioCtx.decodeAudioData(audioData); // audio is resampled to the AudioContext's sampling rate

console.log(decodedData.length, decodedData.duration, decodedData.sampleRate, decodedData.numberOfChannels);

let float32Data = decodedData.getChannelData(0); // Float32Array for channel 0
joe
  • 3,752
  • 1
  • 32
  • 41
0

Wrapping the Joe's code with async function worked. Like this:

async function readAudio(url) {
  let audioData = await fetch(url).then(r => r.arrayBuffer());
  let audioCtx = new AudioContext({sampleRate:8000});
  // audio is resampled to the AudioContext's sampling rate
  let decodedData = await audioCtx.decodeAudioData(audioData);
  console.log(decodedData.length, decodedData.duration,
             decodedData.sampleRate, decodedData.numberOfChannels);
  let float32Data = decodedData.getChannelData(0); // Float32Array for channel 0
  processAudio(float32Data);  // PCM Float32 is between -1 to +1
}

readAudio("Something.wav");