1

I am building a web app which allows users to listen to a loop of instrumental music and then record vocals on top. This is all working using Recorder.js however there are a few problems:

  • There is latency with recording, so this needs to be set by the user before pressing record.
  • The exported loop is not always the same length as the sample rate might not match the time needed exactly

However since then I went back to the drawing board and asked: What's best for the user?. This gave me a new set of requirements:

  • Backing loop plays continuously in the background
  • Recording starts and stops whenever the user chooses
  • Recording then plays back in sync with loop (the dead time between loops is automatically filled with blank audio)
  • User can slide an offset slider to adjust for small timing issues with latency
  • User can select which portion of the recording to save (same length as original backing loop)

Here's a diagram of how that would look:

enter image description here

Logic I have so far:

// backing loop
a.startTime = 5
a.duration = 10
a.loop = true

// recording
b.startTime = 22.5
b.duration = 15
b.loop = false

// fill blank space + loop
fill = a.duration - (b.duration % a.duration) // 5
c = b.buffers + (fill * blankBuffers)
c.startTime = (context.currentTime - a.startTime) % a.duration
c.duration = 20
c.loop = true

// user corrects timing offset
c.startTime = ((context.currentTime - a.startTime) % a.duration) - offset

// user choose favourite loop
? this is where I start to lose the plot!

Here is an example of chopping the buffers sent from Recorder.js:

// shorten the length of buffers
start = context.sampleRate * 2; // start at 2 seconds
end = context.sampleRate * 3; // end at 3 seconds
buffers.push(buffers.subarray(start, end));

And more example code from the previous versions i've been working on: https://github.com/mattdiamond/Recorderjs/issues/105

Any help in working out how to slice the buffers for the exported loop or improving this logic would be greatly appreciated!

UPDATE

Using this example I was able to find out how to insert blank space into the recording:

http://mdn.github.io/audio-buffer/

I've now managed to almost replicate the functionality I need, however the white noise seems off. Is there a miscalculation somewhere?

http://kmturley.github.io/Recorderjs/loop.html

Kim T
  • 3,668
  • 28
  • 58

1 Answers1

0

I managed to solve this by writing the following logic

diff = track2.startTime - track1.startTime
before = Math.round((diff % track1.duration) * 44100)
after = Math.round((track1.duration - ((diff + track2.duration) % track1.duration)) * 44100)
newAudio = [before data] + [recording data] + [after data]

and in javascript code it looks like this:

var i = 0,
    channel = 0,
    channelTotal = 2,
    num = 0,
    vocalsRecording = this.createBuffer(vocalsBuffers, channelTotal),
    diff = this.recorder.startTime - backingInstance.startTime + (offset / 1000),
    before = Math.round((diff % backingInstance.buffer.duration) * this.context.sampleRate),
    after = Math.round((backingInstance.buffer.duration - ((diff + vocalsRecording.duration) % backingInstance.buffer.duration)) * this.context.sampleRate),
    audioBuffer = this.context.createBuffer(channelTotal, before + vocalsBuffers[0].length + after, this.context.sampleRate),
    buffer = null;

// loop through the audio left, right channels
for (channel = 0; channel < channelTotal; channel += 1) {
    buffer = audioBuffer.getChannelData(channel);
    // fill the empty space before the recording
    for (i = 0; i < before; i += 1) {
        buffer[num] = 0;
        num += 1;
    }
    // add the recording data
    for (i = 0; i < vocalsBuffers[channel].length; i += 1) {
        buffer[num] = vocalsBuffers[channel][i];
        num += 1;
    }
    // fill the empty space at the end of the recording
    for (i = 0; i < after; i += 1) {
        buffer[num] = 0;
        num += 1;
    }
}
// now return the new audio which should be the exact same length
return audioBuffer;

You can view a full working example here:

http://kmturley.github.io/Recorderjs/loop.html

Kim T
  • 3,668
  • 28
  • 58