Scenario:
- Audio starts playing from 0:00. At exactly 0:05, the track skips forwards to 0:30.
- The track immediately starts playing at 0:30, and at exactly 0:35, the track skips backwards to 0:05 and plays the rest of the audio file
Summary: Play: 0:00 to 0.05, Skip: 0:05 to 0:30, Play: 0:30 to 0:35, Skip: 0:35 to 0:05, Play: 0.05 to END
The real problem comes when there is the need for a immediate and seamless skip. For example, setTimeout
is very inaccurate and drifts meaning it cannot be used in this case.
I have tried to use the Web Audio API to accomplish this, but I'm still unable to get an immediate transition. I'm currently scheduling segments of a loaded song using AudioBufferSourceNode.start(when, offset, duration);
, initially passing in (0 [when], 0 [offset], 0:05 [duration])
for the example above. After this, I'm still using setTimeout
to call the same function to run just short of 0:30 and scheduling something like (0 [when] + 0:05 [previous duration], 0:30 [offset], 0:05 [duration])
.
Example of this
var AudioContext = window.AudioContext || window.webkitAudioContext,
audioCtx = new AudioContext();
var skipQueue = [0, 5, 30, 35, 5];
// getSong(); // load in the preview song (https://audiojungle.net/item/inspiring/9325839?s_rank=1)
playSound(0, 0);
function getSong() {
console.log("Loading song...");
request = new XMLHttpRequest();
// request.open('GET', "https://preview.s3.envato.com/files/230851789/preview.mp3?response-content-disposition=attachment%3Bfilename%3D20382637_uplifting-cinematic-epic_by_jwaldenmusic_preview.mp3&Expires=1501966849&Signature=HUMfPw3b4ap13cyrc0ZrNNumb0s4AXr7eKHezyIR-rU845u65oQpxjmZDl8AUZU7cR1KuQGV4TLkQ~egPt5hCiw7SUBRApXw3nnrRdtf~M6PXbNqVYhrhfNq4Y~MgvZdd1NEetv2rCjhirLw4OIhkiC2xH2jvbN6mggnhNnw8ZemBzDH3stCVDTEPGuRgUJrwLwsgBHmy5D2Ef0It~oN8LGG~O~LFB5MGHHmRSjejhjnrfSngWNF9SPI3qn7hOE6WDvcEbNe2vBm5TvEx2OTSlYQc1472rrkGDcxzOHGu9jLEizL-sSiV61uVAp5wqKxd2xNBcsUn3EXXnjMIAmUIQ__&Key-Pair-Id=APKAIEEC7ZU2JC6FKENA", true); // free preview from envato
request.responseType = "arraybuffer";
request.onload = function() {
var audioData = request.response;
audioCtx.decodeAudioData(audioData, function(buffer) {
audioBuffer = buffer;
console.log("Ready to play!");
playSong()
}, function(e) {
"Error with decoding audio data" + e.err
});
}
request.send();
}
function playSound(previousPlay, nextPlay) {
// source = audioCtx.createBufferSource();
// source.buffer = audioBuffer;
// source.connect(audioCtx.destination);
skipQueue.shift();
var duration = Math.abs(skipQueue[0] - previousPlay);
// source.start(nextPlay, previousPlay, duration);
console.log("Running: source.start(" + nextPlay + ", " + previousPlay + ", " + duration + ")");
console.log("Current Time: " + previousPlay);
console.log("Next Play in: " + duration + " (Skipping from " + skipQueue[0] + " to " + skipQueue[1] + ")");
if (skipQueue.length > 1) {
setTimeout(function() {
playSound(skipQueue[0], nextPlay + duration);
}, 1000 * duration - 50); // take 50ms off for drift that'll be corrected in scheduling
}
}
<strong>Expected:</strong><br />
Play: 0:00 to 0.05, Skip: 0:05 to 0:30, Play: 0:30 to 0:35, Skip: 0:35 to 0:05, Play: 0.05 to END
I can't get this simplified down example 100% working, but you can see what my attempt is in the console. I've also commented out code since StackOverflow doesn't support AJAX.
I'm open to using any other API or method that you have in mind!