问题
So I've pulled the channel data out of an AudioBuffer
and sent it via transferable object to a web worker to do some processing on it, and now I want to put it back in. Do I really have to copy it back in like this?
var myData = new Float32Array(audioBuf.length);
var chanData = audioBuf.getChannelData(0);
for ( var n = 0; n < chanData.length; n++ ) {
chanData[n] = myData[n];
}
I'm really hoping there is some way to just change out the ArrayBuffer
each of the AudioBuffer
channels reference. Something like...
audioBuf.channel[0].buffer = myData.buffer;
...would be wonderfully simple and effective, but seemingly does not exist. Is there any way at all like this to change the reference and avoid copying the data?
EDIT: With a little further investigation, I see the problem of using the web audio API with transferable objects is even more annoying. When you transfer the array buffers to the worker, the underlying array buffers of the AudioBuffer
are cleared, I believe making even a copy operation through the Float32Array
returned by getChannelData
impossible. The only way I can see to accomplish what I want right now is to abandon the original AudioBuffer
, create an entirely new AudioBuffer
and then copy my data into it. Really??
回答1:
We recently added two new methods on AudioBuffer, from which use copyFromChannel could be useful to you. It does what it says on the tin (put an ArrayBuffer in a channel of an AudioBuffer), maybe saving a copy in the process (the reasons and condition to avoid the copy are explained here).
I believe it's only implemented in Firefox for the moment, but I haven't checked.
回答2:
I struggled with this all day, so I figured I should share my solution.
var PCM = [0,1,2,3,4,5,6,7,8,9,8,7,6,5,4,3,2,1];
var room = new window.AudioContext();
var sampleRate = 44100;
var channels = 1;
var audioBuffer = room.createBuffer(channels, 0, sampleRate);
var channelObject = audioBuffer.getChannelData(0);
var audioBufferDataArray = channelObject.data;
// actual code to set the data
audioBuffer.length = PCM.length; // optional
for(var i=0; i<PCM.length; i++){
audioBufferDataArray[i] = PCM[i];
}
回答3:
A few things:
1) There's a pretty low-cost method for copying data from one typed array to another that doesn't require you to go through the headache of looping.
var copy = new Float32Array(orig.length);
copy.set(orig);
2) The issue of your AudioBuffer getting cleared is just part of the spec for transferable objects with web workers (https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers#Passing_data_by_transferring_ownership_(transferable_objects)). That's the only way they can guarantee thread safety. If two threads had access to the same object at the same time, they could both mutate it, and you'd end up with all kinds of craziness.
I'm not totally sure why you're so annoyed at the prospect of creating a new AudioBuffer
and copying data into it. You can do that in 2 lines for a mono buffer. 3 lines for stereo. You've already done way more work than that by setting up all the boilerplate necessary to get a web worker up and running.
Anyway, if you could give some more specifics about your application and what it's doing, I'd be happy to make some recommendations.
回答4:
You were so close! The method you want is AudioBuffer.copyToChannel()
.
This will copy your Float32Array
to an audio buffer node like so :
var myData = new Float32Array(audioBuf.length);
//copy mydata to first channel
audioBuf.copyToChannel( myData , 0 , 0 );
Deep in the docs:
https://developer.mozilla.org/en-US/docs/Web/API/AudioBuffer/copyToChannel
Hope this helps
来源:https://stackoverflow.com/questions/21957824/manually-put-pcm-data-into-audiobuffer