HTML5 Web Audio API porting from javax.sound and distortion

I have a requirement to generate audio on the fly (generating from wav or mp3 files is not an option). Fortunately, the new WebAudio API (FF4 and Chrome 13) provides this functionality.

I have Java code that I port to Javascript that looks like this:

byte[] buffer = new byte[]{ 56, -27, 88, -29, 88, -29, 88, -29 ............ }; AudioFormat af = new AudioFormat(44100, 16, 1, true, false); SourceDataLine sdl = AudioSystem.getSourceDataLine(af); sdl.open(af, 1470 * 4); //create 4 frame audio buffer sdl.start(); sdl.write(buffer, 0, buffer.length); 

I am trying to get this to work with the web audio API, but it is extremely distorted. Here is the code I use in JS:

 var buffer = [ 56, -27, 88, -29, 88, -29, 88, -29 ............ ]; var ctx = new webkitAudioContext(); var src = ctx.createBufferSource(); src.buffer = ctx.createBuffer(1, buffer.length, 44100); src.buffer.getChannelData(0).set(buffer); src.connect(ctx.destination); src.looping = false; src.noteOn(0); 

Here is the .java file that I am testing with: http://gwt-nes-port.googlecode.com/svn/wiki/webAudioTests/Main.java

And here is the .js file that I am testing with: http://gwt-nes-port.googlecode.com/svn/wiki/webAudioTests/Main.js

Any clues about the differences between how javax.sound and Web Audio work, and what causes distortion in my JS code?

+2
source share
2 answers

Thanks to the very useful Google Chrome team, I figured this out. Here's what they said:

Hi, Brad, it looks like the sample data is outside of the actual range. For this API, full-scale floating-point PCM audio data should be between -1.0 โ†’ +1.0

Perhaps your data values โ€‹โ€‹are 16 bits (-32768 โ†’ +32767).

Therefore, when I create my byte array, I need to make sure that everything is represented as decimal. So instead:

 byte[] buffer = new byte[]{ 56, -27, 88, -29, 88, ............ }; 

I really needed something like:

 byte[] buffer = new byte[]{ 0.023, -0.1, 0.125, -0.045, ............ }; 

So, in my code, I just added some logic to convert 16-bit scaled values โ€‹โ€‹to the appropriate range, for example:

 for(var i=0;i<buffer.length;i++) { var b = buffer[i]; b = (b>0)?b/32767:b/-32768; buffer[i] = b; } 

The sound is now represented as decimal and no longer sounds like a distorted heavy metal song.

+4
source

You can do this without the web audio API, since you have sample data. Create a WAV file on the fly and use type arrays.

Slide 23: http://davidflanagan.com/Talks/jsconf11/BytesAndBlobs.html

0
source

All Articles