Trying to merge two buffers into one; I have been able to create the two buffers from the audio files and load and play them. Now I need to merge the two buffers into one buffer. How can they get merged?
context = new webkitAudioContext();
bufferLoader = new BufferLoader(
context,
[
'audio1.mp3',
'audio2.mp3',
],
finishedLoading
);
bufferLoader.load();
function finishedLoading(bufferList) {
// Create the two buffer sources and play them both together.
var source1 = context.createBufferSource();
var source2 = context.createBufferSource();
source1.buffer = bufferList[0];
source2.buffer = bufferList[1];
source1.connect(context.destination);
source2.connect(context.destination);
source1.start(0);
source2.start(0);
}
Now these sources are loaded separately and are played at the same time; but how do I merge these two sources into one buffer source? I do NOT want to append them, I want to overlay/merge them.
explanations and/or snippets would be great.
In audio, to mix two audio stream (here, buffers) into one, you can simply add each sample value together. Practically, here is we can do this, building on your snippet:
/* `buffers` is a javascript array containing all the buffers you want
* to mix. */
function mix(buffers) {
/* Get the maximum length and maximum number of channels accros all buffers, so we can
* allocate an AudioBuffer of the right size. */
var maxChannels = 0;
var maxDuration = 0;
for (var i = 0; i < buffers.length; i++) {
if (buffers[i].numberOfChannels > maxChannels) {
maxChannels = buffers[i].numberOfChannels;
}
if (buffers[i].duration > maxDuration) {
maxDuration = buffers[i].duration;
}
}
var out = context.createBuffer(maxChannels,
context.sampleRate * maxDuration,
context.sampleRate);
for (var j = 0; j < buffers.length; j++) {
for (var srcChannel = 0; srcChannel < buffers[j].numberOfChannels; srcChannel++) {
/* get the channel we will mix into */
var out = mixed.getChanneData(srcChannel);
/* Get the channel we want to mix in */
var in = buffers[i].getChanneData(srcChannel);
for (var i = 0; i < in.length; i++) {
out[i] += in[i];
}
}
}
return out;
}
Then, simply affect the return from this function to a new AudioBufferSourceNode.buffer
, and play it like usual.
A couple notes: my snippet assumes, for simplicity, that:
toMix[i]
value by a number lesser than 1.0 to make it quiter, greater than 1.0 to make it louder.Then again, the Web Audio API does all that for you, so I wonder why you need to do it yourself, but at least now you know how :-).
@Padenot is right but there is some typo in his code so it can't works if you copy/past it. Below you can find the same code with corrections so you can use it. Thanks for your help @Padenot ;)
function mix(buffers) {
var nbBuffer = buffers.length;// Get the number of buffer contained in the array buffers
var maxChannels = 0;// Get the maximum number of channels accros all buffers
var maxDuration = 0;// Get the maximum length
for (var i = 0; i < nbBuffer; i++) {
if (buffers[i].numberOfChannels > maxChannels) {
maxChannels = buffers[i].numberOfChannels;
}
if (buffers[i].duration > maxDuration) {
maxDuration = buffers[i].duration;
}
}
// Get the output buffer (which is an array of datas) with the right number of channels and size/duration
var mixed = context.createBuffer(maxChannels, context.sampleRate * maxDuration, context.sampleRate);
for (var j=0; j<nbBuffer; j++){
// For each channel contained in a buffer...
for (var srcChannel = 0; srcChannel < buffers[j].numberOfChannels; srcChannel++) {
var _out = mixed.getChannelData(srcChannel);// Get the channel we will mix into
var _in = buffers[j].getChannelData(srcChannel);// Get the channel we want to mix in
for (var i = 0; i < _in.length; i++) {
_out[i] += _in[i];// Calculate the new value for each index of the buffer array
}
}
}
return mixed;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With