I am successfully recording audio, storing it, and reloading it into Audio
object for playback in the browser.
However, I would like to be able to record new audio and "splice" it into the original recording at a certain time offset, completely replacing that portion of the original recording onward from that offset. For instance, suppose I recorded 10 seconds of audio from the microphone, and subsequently, I wished to "record over" the last 5 seconds of that audio with 8 seconds of totally new audio, ending up with a new bufferArray that I could persist. I've spent some hours researching this and still am pretty vague on how to do it. If anybody has any suggestions, I'd be appreciative.
The closest examples I could find involved getting two buffers and attempting to concatenate them, as in this fiddle. However, I'm having some difficulties relating this fiddle to my code and what I need to do. Certain posts mention I need to know the sample rate, create new buffers with that same sample rate, and copy data from two buffers into the new buffer. But there are precious few working examples on this technique, and I'm heavily scratching my head trying to figure this out from just the MDN docs.
Here's the code I have working now.
const saveRecordedAudio = (e) => {
console.log("Audio data available", e.data);
const reader = new FileReader();
reader.addEventListener("loadend", function() {
// reader.result contains the contents of blob as a typed array
let bufferArray = reader.result;
// From: https://stackoverflow.com/questions/9267899/arraybuffer-to-base64-encoded-string
let base64String = btoa([].reduce.call(new Uint8Array(bufferArray),function(p,c){return p+String.fromCharCode(c)},''));
// persist base64-encoded audio data on filesystem here.
storeRecordedAudio(base64String); // defined elsewhere and not shown here for brevity's sake
});
reader.readAsArrayBuffer(e.data);
const audioUrl = window.URL.createObjectURL(e.data);
// Put the recorded audio data into the browser for playback.
// From: http://stackoverflow.com/questions/33755524/how-to-load-audio-completely-before-playing (first answer)
const audioObj = new Audio (audioUrl);
audioObj.load();
};
const recordAudio = () => {
navigator.getUserMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
if (navigator.getUserMedia) {
navigator.getUserMedia (
{ // constraints - only audio needed for this app
audio: true
},
// Success callback
function(stream) {
const mediaRecorder = new MediaRecorder(stream);
mediaRecorder.ondataavailable = audio.saveRecordedAudio;
}),
// fail callback
function(err) {
console.log('Could not record.');
}
);
}
};
// I've already fetched a previously recorded audio buffer encoded as
// a base64 string, so place it into an Audio object for playback
const setRecordedAudio => (b64string) => {
const labeledAudio = 'data:video/webm;base64,' + b64String;
const audioObj = new Audio(labeledAudio);
audioObj.load();
};