how can I reverse playback in web audio API but keep a forward version as well?
-
02-07-2021 - |
Вопрос
To my knowledge, the Web Audio API in google Chrome (v21) does not support the following:
source.playbackRate.value = -1;
I very much wish! I will be patient, but in the meantime, this post has a nice alternative solution. I have adopted it to try and reverse my own audio samples loaded from a loaded bufferlist, hoping that I can have both a forward and reversed version of each loaded buffer, like so:
function finishedLoading(bufferList) {
for (var it = 0; it < this.urlList.length; ++it) {
storedBuffer[it] = bufferList[it]; // assign bufferList to globals
storedBufferR[it] = bufferList[it];
// attempt to reverse storedBufferR only ...
Array.prototype.reverse.call( storedBufferR[it].getChannelData(0) );
Array.prototype.reverse.call( storedBufferR[it].getChannelData(1) );
}
}
The above function indeed reverses playback, however it reverses both 'storedbufferR' and 'storedbuffer' such that all buffers are reversed!
So here is where I get lost... I understand that Array.protoype affects all arrays, so I suppose I can see how 'storedBuffer' is affected by a reverse method on 'storedBufferR'. EDIT: the reverse method only affects the array in question
But is it possible to rewrite the above function to ensure array.protoype affects only the stored buffer I want reversed? If not, is there another way to go about storing both a forward and reversed version?
Решение
The comment about the two AudioBuffers sharing the same reference was on the right track, but the solution isn't to create a new AudioContext; rather, you just need to create a new AudioBuffer and clone the underlying Float32Arrays that hold the actual audio samples.
For example, this function would clone an AudioBuffer:
function cloneAudioBuffer(audioBuffer){
var channels = [],
numChannels = audioBuffer.numberOfChannels;
//clone the underlying Float32Arrays
for (var i = 0; i < numChannels; i++){
channels[i] = new Float32Array(audioBuffer.getChannelData(i));
}
//create the new AudioBuffer (assuming AudioContext variable is in scope)
var newBuffer = context.createBuffer(
audioBuffer.numberOfChannels,
audioBuffer.length,
audioBuffer.sampleRate
);
//copy the cloned arrays to the new AudioBuffer
for (var i = 0; i < numChannels; i++){
newBuffer.getChannelData(i).set(channels[i]);
}
return newBuffer;
}
Then, to modify the above...
function finishedLoading(bufferList) {
for (var it = 0; it < this.urlList.length; ++it) {
storedBuffer[it] = bufferList[it]; // assign bufferList to globals
storedBufferR[it] = cloneAudioBuffer(bufferList[it]);
// attempt to reverse storedBufferR only ...
Array.prototype.reverse.call( storedBufferR[it].getChannelData(0) );
Array.prototype.reverse.call( storedBufferR[it].getChannelData(1) );
}
}