I have a 3d space with different zones, each zone has its own sounds. My goal is to have smooth audio transitions when the user moves from one zone to another, basically doing cross-fades between the audio tracks.
Also I would like to handle gracefully the case when the user changes its mind and abruptly goes back to the zone just left, this means cancel the new audio transitions and revert back to the previous state gradually.
To do this I am using web audio api, in particular linearRampToValueAtTime and cancelScheduledValues to define the fades in/out functions:
const fadeIn = (sound, time = 4, gain = 1.0) => {
sound.gainNode.gain.cancelScheduledValues(sound.context.currentTime)
!sound.isPlaying && sound.play()
sound.gainNode.gain.linearRampToValueAtTime(gain, sound.context.currentTime + time)
}
const fadeOut = (sound, time = 4, gain = 0.0) => {
sound.gainNode.gain.cancelScheduledValues(sound.context.currentTime)
sound.gainNode.gain.linearRampToValueAtTime(gain, sound.context.currentTime + time)
}
I am testing this on just one sound, pressing key "I" triggers fadeIn and key "O" triggers fadeOut:
document.addEventListener("keyup", e => {
switch (e.keyCode) {
// I key
case 73:
fadeIn(mySound)
break
// O key
case 79:
fadeOut(mySound)
break
})
I got inconsistent results. Sometimes the audio fades correctly, other times it starts abruptly in the fadeIn or cut in the fadeOut. It seems like calling cancelScheduledValues when a transition has not been completed results in an erratic behaviour. I would like this to work smoothly even when triggering a fadeOut when a fadeIn has not completed yet and viceversa. I have also tried to defer a bit the linearRamps with setTimeout, something like
setTimeout(() => sound.gainNode.gain.linearRampToValueAtTime(gain, sound.context.currentTime + time), 0.1)
but got equally wrong results.
Am I using the api incorrectly? Any suggestion?
I think what's happening here is that, say, you're fading in and you haven't finished the ramp yet. Then you want a fade out, and cancel the events, including the unfinished fade-in ramp. Then that fade-in ramp is gone, and the timeline value reverts back to the value of the previous event.
So, as HankMoody suggests, use cancelAndHoldAtTime which is meant to handle this problem. But, AFAIK, only Chrome has this.
To be portable, I think what you want to do is compute where the ramp is at the time you want to cancel. Let's say the value is v. Then do
setValueAtTime(v, context.currentTime);
cancelScheduledValues(context.currentTime + eps);
where eps is some small value around 1/context.sampleRate or more.
Related
I'm developing a little roulette game like: https://csgofast.com/
My question is, the roulette animation used with transform & transition, works pretty well when I'm in the actual tab.
The problem is, when i move to another tab or miniminize, before the roullete starts, until i dont get back to the tab, it dosnt start scrolling / moving.
Is like the roullete animation is waiting until i get to the tab again, to start moving.
let intervalJackpot = setInterval(() => {
if (something == true) {
$("#slider").css('transform', 'translate3d(-7850px, 0px, 0px)');
$("#slider").css('transition', '15000ms cubic-bezier(0.32, 0.64, 0.45, 1)');
}
}, 500);
The code is in a setInterval, and that's the problem as i know.
The DB.roulleteSpin is just a simple code that comes from the Database.
How I could approach this situation? I will like to know the roulette starts moving and ends in the right place, no matters if I'm in the tab or not.
How i could approach this situation? Can someone show me an example? Thanks a lot.
I have 2 divs (left and right) and i want to scroll the left based on the right.
https://jsfiddle.net/3jdsazhg/2/
This works fine on desktop, but when i change to mobile, it's not smooth anymore...
This can be noticed very easily, by changing
_left.style.top = _content.scrollTop - (_content.scrollTop * ratioLeftRight) + 'px';
to
_left.style.top = _content.scrollTop + 'px';
Where it should act as a fixed positioned div
I would like to know the exact reason why this isn't smooth... I know that it's not the animation. Simple animation on the div is smooth, the issue comes up when it's based on scroll.
How can i make this animation smooth?
It's probably choppy because it's being fired ALOT when being scrolled, in fact i'm pretty sure IOS mobile pauses the javascript execution whilst the user is scrolling.
Instead I'd suggest using an interval, you could tweak the time between each interval to what feels good for your use-case.
Although it may seem intensive that it's firing this logic every X millisecond when using the scroll event you could be firing the event off hundreds of times per second, which is going to be far more intensive and noticeable to a user using a device with limit processing power.
(function () {
var interval = null,
//Currently set at 0.4 seconds, play with the code
//and change this value to see what works best for
//this use-case
time_between_interval = 400;
setInterval(scrollLogic, time_between_interval);
function scrollLogic () {
//The function body of what you're assigning
//to the scroll event.
}
//I have omitted clearing the interval but you would want to do that, perhaps on page change, or something.
//clearInterval(interval);
})();
I finally managed to think out a solution.
From my point of view, i'm guessing the mobile view fires the scroll event less often and because we are scrolling the wrapper, we first scroll the whole page and then scroll back with js the left part and because it's different from the desktop version, this issue becomes visible...
The solution was to change the left side to fixed position, and substract from the top instead of adding to it.
_left.style.top = -(_content.scrollTop * ratioLeftRight) + 'px';
When you are using requestAnimationFrame() for animation, the animation persists when you change browsers but not when you change tabs within your browser. The animation seems to pause.
For example, this animation.
http://pixijs.github.io/examples/index.html?s=basics&f=spritesheet.js&title=SpriteSheet%20Animation
Is there a way to make the animation persist even when you are in a different tab?
Your question isn't actually PIXI specific. It's about how the browser handles screen updates.
PIXI applications typically update each frame using the common Javascript function Window.requestAnimationFrame().
This function tends to pause when you switch tabs. From the docs:
The callback rate may be reduced to a lower rate when running in background tabs or in hidden <iframe>s in order to improve performance and battery life.
https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
So the short answer is no,
HOWEVER you can easily simulate it by keeping keep track of the time elapsed between updates, and move your animation forward accordingly.
In the PIXI example you provided, change the animate() function to this code below, and re-run it. Switch tabs, and when you switch back, you will see that the animation appears to continue as though you never switched tabs. Hope that helps! :)
var lastUpdate = new Date();
function animate() {
//Determine the amount of time since last frame update
var now = new Date();
var elapsed = now - lastUpdate;
lastUpdate = now;
//Update the rotation based on time elapsed
movie.rotation += elapsed/1000;
// render the stage container
renderer.render(stage);
requestAnimationFrame(animate);
}
How can I control the animation speed of a sprite using create JS?
When you press right and left, the sprite will run through the frames... I'd like to leave the fps at 60, but alter how fast the frames are looped through without altering the main game FPS rate.
See a demo here. Press right and left arrow to see.
I thought changing the bmp animation frequency property would do the trick...
bmpAnimation.frequency = 2;
But it did not work...
Or should I be using the jQuery animation?
Also, I noticed that each time I hit a random key, the animation plays 1 frame then goes back to first frame. Why is that?
Thanks!
1) The frequency is a property of the spriteSheet-animation, not the bitmapAnimation itself.
So you would have to set the freuqency in the SpriteSheetData itself(http://www.createjs.com/Docs/EaselJS/classes/SpriteSheet.html) or if you want to set it during runtime you could use:
bmpAnimation.spriteSheet.getAnimation("walk_right").frequency = 2;
Please also note that the frequency will be deprecated in the next version of EaselJS in favor of speed (bit this is in the NEXT version, so just something for you to keep in mind)
2) You are currently calling the gotoAndPlay() every frame (if walking), that means that every frame your animation will be set to the first frame of that animation, you could easily avoid this by using something like:
if ( dir == "right" and bmpAnimation.currentAnimation != "walk_right" ) {
bmpAnimation.gotoAndPlay("walk_right");
}
But a better way would be to only call that method ONCE when you start walking and then again when you stop walking.
I am working on a touch based JS application, I've studied Flex and Royal slider as examples. I noticed that both sliders acting similarly when getting touchmove event:
var started,touched ;
el.bind('touchstart',function(e){
started = Number(new Date()) ;
// Get pageX and pageY etc...
}) ;
el.bind('touchmove',function(e){
touched = Number(new Date()) ;
if (started-touched > 500) {
// Handle touch moves etc...
}
}) ;
My JS app works seamless without these, but why do they need to do this? Why they are waiting 500ms to get move datas?
I believe this is some kind of sensitivity setting. You only want to register a touch-move (drag) event if the user has been moving his or her finger across the device for at least 500ms (in this example).
This could be useful to differentiate between taps and drags. Otherwise, if the user would slightly move his/her finger when clicking, for example, a button, the app would also register a drag. As some controls accept both events, this could lead to erroneous behaviour.