poor quality audio playback in javascript windows store app - javascript

I'm programming a Windows Store app using javascript and having trouble playing audio without poor quality. Usually when a sound plays it sounds as if it is skipping the first few hundred milliseconds of the sound (and sometimes more), resulting in clicks and sometimes almost no sound (because the sound files are short). I have 8 short files (27kb .mp3). The weirdest thing is that the volume of the playback also seems to randomly vary between a quiet and loud level. I'm using a Windows 8.1 tablet with a 1.6GHz processor.
//I declare like this:
var playList = new Array("chord1.mp3", "chord2.mp3", "chord3.mp3", "chord4.mp3", "chord5.mp3", "chord6.mp3", "chord7.mp3", "chord8.mp3" );
var playListIndex = 0;
var players = new Array();
//I initialise like this:
for (var i = 0; i < playList.length; i++) {
players[i] = new Audio();
players[i].src = playList[i];
}
//When it's time to play (listening for pointerdown events) I do this:
players[playListIndex].play();
//I have tried this but it just introduces latency without solving the problem
//new Audio(playList[playListIndex]).play();
//This happens after playing to make the sounds play sequentially.
//The problems occur even when there is no overlap of playback
playListIndex++;
if (playListIndex >= playList.length) {
playListIndex = 0;
}
There is almost nothing else going on in the app. Suggestions much appreciated.

Related

Web Audio Api precise looping in different browsers

So what I want is to have constant looping interchanging from different audio sources. For demo purpose I made a little puzzle game - you align numbers in order from 0 to 8 and depending on how you align them different loops are playing. I managed to get the result I want on Chrome Browser, but not on Safari or Firefox. I tried adding a different audio destination or multiple audio contexts but no matter what loop just stops after one iteration in Safari and other browsers except for Chrome.
Here is a link to the demo on code-pen Demo Puzzle with music
please turn down your sound as music might be a little too loud, I didn't master it. And here is basic code I have for Web Audio Api manipulation.
Thanks
*Also it does not work for mobile at all.
const AudioContext = window.AudioContext || window.webkitAudioContext;
var audioContext = new AudioContext();
const audio1 = document.getElementById("aud1");
const audio2 = document.getElementById("aud2");
const audio3 = document.getElementById("aud3");
const audio4 = document.getElementById("aud4");
var chosenTrack = audio2;
let gameStarted = false;
function startGame() {
document.getElementById("sHold").style.display = "none";
document.getElementById("container").style.display = "block";
gameStarted = true;
audioContext.resume();
audioContext = new AudioContext();
audio1.pause();
audio1.play();
audio1.currentTime = 0;
}
setInterval(function() {
if (gameStarted) {
//console.log(audioContext.currentTime );
if (audioContext.currentTime >= 6.4) {
audioContext = new AudioContext();
chosenTrack.pause();
chosenTrack.play();
chosenTrack.currentTime = 0;
}
}
}, 5);
Some thoughts:
You're not really using Web Audio this way, you're still using audio elements as the source which doesn't help if you want to be able to achieve precise timing. You should load them into AudioBuffers and play them using an AudioBufferSourceNode.
If you absolutely want to use audio elements (because the files you use are really massive and you want to stream them) you probably want to use the loop property on it although i doubt if that ends up being precise and gapless.
Never use setInterval to get a callback every frame, use requestAnimationFrame
Don't use setInterval OR requestAnimationFrame to be able to achieve precise audio looping, the javascript thread is not precise enough to do that AND can be held up when other things take a bit more time, too many enemies in screen for example. You should be scheduling ahead of time now and then: https://www.html5rocks.com/en/tutorials/audio/scheduling/
AudioBufferSourceNodes have a loop boolean property which will loop them as precise as possible
Do realise that different audio-decoders (so: different browsers) MIGHT decode audiofiles slightly differently: some may have a few more ms on the start for example. This might become an issue when using multiple looping AudioBufferSourceNodes, which may all be running out of sync after an x amount of time. I always reschedule something on the exact time needed instead of using the loop property.

ThreeJS switch video texture Performance

Hi,
I'm mapping a video texture onto a sphere in ThreeJs. I dynamically changing the source of the video on click to display different videos.
The Code runs and switches the source, but it takes different times on different devices to update. It's kind of a lag. The source is switched and then it takes X-Milliseconds to update to the new video. During that time, the old video keeps playing. So I guess it might be some kind of video memory thing?
The lags are like this:
Desktop PC Chrome - instant exchange
Macbook Pro 13 Chrome - 0.2 seconds lag
Nexus 5 Chrome - 0.5 seconds lag
Iphone 7 Safari - 1 second lag
I'm preloading all videos with preloadJS, but this still didn't change anything. Using smaller videos on mobile (implemented in the example) also didn't help.
Basically I'm doing this:
this.video = document.createElement('video');
this.video.setAttribute('playsinline', '');
this.video.muted = true;
this.video.loop = true;
this.video.src = 'img/Room1Mobile.mp4';
this.video.crossOrigin = '';
this.video.play();
this.videoTexture = new THREE.Texture(this.video);
this.videoTexture.minFilter = THREE.LinearFilter;
this.videoTexture.magFilter = THREE.LinearFilter;
this.videoTexture.format = THREE.RGBFormat;
this.sphereMat.side = THREE.BackSide;
this.sphereMat.transparent = true;
this.sphereMat.opacity = 1;
this.cube = new THREE.Mesh(this.cubeGeometry, this.sphereMat);
this.cube.name = "videoGlobe";
this.scene.add(this.cube)
Later I then switch the source like this:
this.video.src = "img/Room2.mp4";
this.video.load();
this.video.play();
I understand, the problem is quite difficult to debug, but still hope someone could give me a tip :)
Here's a full demo.

How can I get an event when an audio file reaches a certain point?

I am experimenting with interactive audio applications in HTML, and I would like to be able to seamlessly start playing one audio file just as another audio file reaches a particular playback location; for example, if audio file A is playing, then I would like to receive an event when it reaches 16 seconds in exactly.
I have tried using audio.play(); setTimeout(myCallback, 16000); for this, but I am finding it to be incredibly unstable in some browsers (Safari especially, particularly when the window is in the background), and will sometimes fire slightly early, and other times fire very late. This remains the case even if I explicitly stop, rewind, and .load() the upcoming audio segment when scheduling the callback.
My current (simple) looper that simply toggles between two players every 16 seconds is below:
audio = []
for (var i = 0; i < 2; i++) {
audio[i] = new Audio("mew" + i + ".mp3");
}
var which = 0;
var pump = function() {
audio[which].play();
which = (which + 1) % audio.length;
window.setTimeout(pump, 16000);
}
audio[which].addEventListener('canplaythrough', function() {
pump();
});
for (i in audio) {
audio[i].load();
}
Also, note that while in this case I could use setInterval(), that will not always be the case (and anyway, setInterval() suffers from the same stability problem).

Loading many Audio files in Javascript Windows Store App

I'm having difficulty playing Audio in a Windows store app. I'm using JavaScript. The code is below.
When I try to play a sound from the array of over 200 sounds (average size 15KB), it sounds like a Cylon, from Battlestar Galactica, is attacking my app. If I wait long enough it's OK, or if the array of sounds is less then it obviously loads faster too.
Is there an event or some way to determine when the app is ready to play all sounds? Or a better approach?
var play = new Array("over", "200", "sounds", "in", "this", "list", "that", "average", "15KB");
for (var i = 0; i< play.length; ++i){
tmpAudio = new Audio("/sound/" + words[i] + ".mp3");
play[i] = tmpAudio;
}
something.onClick = function () {
play[soundPos].play();
}
Well, the thing is I believe in the for loop, what you are mainly doing is loading all of the sound files into memory (too much caching) first which as expected will slow things down.
I would suggest a few changes:
1- Use [] for array creation
2- Cache a var arrayLength = play.length and use it in the loop instead of i < play.length as this will be checked for every element.
3- In fact I suggest you remove the loop and do a just when needed (onclick) loading of the audio file (put some loading image or canvas in there for user friendliness).
For this you might need to re-write some of your code let's say
var play = { sound1: urlWord, sound2: urlWord, sound3: urlWord,......};
Although not array (arrays are weirdly implemented in JS interpreters)
you might loop on it as in the following link:
stackoverflow link on iterating over objects mainly for in
in the onclick:
something.onClick = function () {
//if the below works or else just use a temp var
new Audio("/sound/" + play[soundPos] + ".mp3").play();
}

unload a sound in AIR, system memory getting full

I'm building an AIR application which loads and plays mp3's from a users computer, I'm using the code pretty much straight out the book to do this:
function startTrack()
{
if (isStarted == 0)
{
theSound = new air.Sound();
urlReq = new air.URLRequest(...dynamicaly generated extension);
theSound.load(urlReq);
soundHandle = theSound.play();
isStarted = 1;
}
else
{
soundHandle.stop();
soundHandle = null;
theSound = null;
urlReq = null;
isStarted = 0;
startTrack();
}
}
There are a series of links on the page of the app which play different mp3's, when you click on one it passes the path of the sound to urlReq and plays it. When you click on a second sound it stops the first playing and plays the next one. What I thought would happen is the old sound would be destroyed by call theSound = null etc but it just seems to stop the sound play the new sound and keep the old one loaded so you eventually run out of system memory after lots of tracks have been started and kept loaded.
So if anyone knows how to unload a sound or how to generally dump things from the system memory the app is using it would be much appreciated.
Thanks all
Will
You call air.System.gc() after deleting all the related elements.

Categories

Resources