Manually put pcm data into AudioBuffer

依然范特西╮ 提交于 2020-01-03 17:22:27

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!