I have a requirement to generate audio on the fly (generating from wav or mp3 files is not an option). Luckily the new WebAudio API (FF4 and Chrome 13) provides this functionality.
I have some Java code i'm porting 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'm trying to get this working with the Web Audio API, but it is extremely distorted. Here is the code i'm using 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 a .java file that i'm testing with: http://gwt-nes-port.googlecode.com/svn/wiki/webAudioTests/Main.java
And here is the .js file that i'm testing with: http://gwt-nes-port.googlecode.com/svn/wiki/webAudioTests/Main.js
Any tips on the differences between how javax.sound and Web Audio work, and what is causing the distortion in my JS code?
Thanks to the very helpful Google Chrome team, I figured this one out. Here is what they said:
Hi Brad, it looks like your sample-data is outside of the valid range. For this API, the full-scale floating-point PCM audio data should be within the range -1.0 -> +1.0
Perhaps your data values are 16bit scaled (-32768 -> +32767).
So when I create my byte array, I need to make sure everything is represented as a decimal. So instead of this:
byte[] buffer = new byte[]{ 56, -27, 88, -29, 88, ............ };
I really needed something that looked like this:
byte[] buffer = new byte[]{ 0.023, -0.1, 0.125, -0.045, ............ };
So in my code I just added some logic to convert the 16bit scaled values to the appropriate range like this:
for(var i=0;i<buffer.length;i++) {
var b = buffer[i];
b = (b>0)?b/32767:b/-32768;
buffer[i] = b;
}
Now the audio is represented as a decimal and no longer sounds like a distorted heavy metal song.
You can do this without the Web Audio API since you have the sample data. Generate a .wav file on the fly and use type arrays.
Slide 23: http://davidflanagan.com/Talks/jsconf11/BytesAndBlobs.html
精彩评论