Why are audio clicks/pops occurring when the position of a PannerNode is updated rapidly? - web-audio-api

I've been experimenting with the PannerNode for quite some time and in cases where I'm updating position of the panner repeatedly using either requestAnimationFrame() or setInterval(), I've noticed clicking/popping of audio.
Why is this happening and how can it be resolved?
I'd hoped that it would be fixed with the introduction of position as an AudioParam or I could circumvent the issue by using a ramp. I've tried setting the position with and without a ramp on Chrome Canary and the issue is still present.
You can hear it for yourself here: https://jsfiddle.net/txLke4fh/
Code snippet:
var ctx = new AudioContext();
var osc = ctx.createOscillator();
var panner = ctx.createPanner();
var temp = true;
osc.frequency.value = 220;
osc.connect(panner);
panner.panningModel = 'HRTF';
panner.setPosition(0, 0, 0);
panner.connect(ctx.destination);
osc.start(0);
osc.stop(ctx.currentTime + 10);
setInterval(function() {
if (temp) {
panner.setPosition(50, 0, 0);
temp = false;
} else {
panner.setPosition(-50, 0, 0);
temp = true;
}
}, 100);
EDIT: It can be observed on Chrome Canary too, with and without a linear ramp.
var ctx = new AudioContext();
var osc = ctx.createOscillator();
var panner = ctx.createPanner();
var temp = true;
osc.frequency.value = 220;
osc.connect(panner);
panner.panningModel = 'HRTF';
panner.positionX.value = 0;
panner.connect(ctx.destination);
osc.start(0);
osc.stop(ctx.currentTime + 10);
setInterval(function() {
if (temp) {
panner.positionX.linearRampToValueAtTime(50, ctx.currentTime + 0.01);
temp = false;
} else {
panner.positionX.linearRampToValueAtTime(-50, ctx.currentTime + 0.01);
temp = true;
}
}, 1000);

You're doing an instantaneous move from one position to another. I certainly would expect a click, depending on how where you moved.
If you have Chrome canary, you should be able to use automation (but don't use setPosition() which doesn't do automation). If you have an example of where it still clicks with automation, please post it; I'd like to see such an example.

Related

Continuous Line Rendering on ChartJS

I wanted to show a vertical line that follows my mouse on my chartjs canvas and the following codes does what I one except one thing, it will stop updating once the tooltips fades out (when there is no data intersects with my cursor). I know it has something to do with rendering but I do not know how and what variable I have to manipulate with.
I can force the animation playing non-stop by setting my animation as timed loop but I don't think this is a proper solution. This will also consume more resources since I need only my lines to be updating constantly not the whole graph.
The function is implemented with inline plugin.
Please have a look, thank you!
let canvas = document.getElementById('myChart')
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
};
}
let mousePosX;
canvas.addEventListener('mousemove', function(evt) {
var mousePos = getMousePos(canvas, evt);
mousePosX = mousePos.x;
}, false);
const config = {
type: 'scatter',
plugins: [
{
afterDraw(chart) {
let x = mousePosX;
let yAxis = chart.scales.y;
let ctx = chart.ctx;
ctx.save();
ctx.beginPath();
ctx.moveTo(x, yAxis.top);
ctx.lineTo(x, yAxis.bottom);
ctx.lineWidth = 1;
ctx.strokeStyle = 'rgba(0, 0, 255, 0.4)';
ctx.stroke();
ctx.restore();
},
}
],
.....

How target a movieClip in animate cc in this drag drop code

is there a way to modify this code for animate cc to make object in the stage and interact with it ?
it is a bit of pain to make drag and drop in createjs for animate cc
there is nothing in the web that describe how to do it for animate cc or flash cc even the documentation has nothing to tell about drag and drop in the canvas
//Stage
var stage = new createjs.Stage("demoCanvas");
//VARIABLES
//Drag Object Size
dragRadius = 40;
//Destination Size
destHeight = 100;
destWidth = 100;
//Circle Creation
var label = new createjs.Text("DRAG ME", "14px Lato", "#fff");
label.textAlign="center";
label.y -= 7;
var circle = new createjs.Shape();
circle.graphics.setStrokeStyle(2).beginStroke("black")
.beginFill("red").drawCircle(0,0, dragRadius);
//Drag Object Creation
//Placed inside a container to hold both label and shape
var dragger = new createjs.Container();
dragger.x = dragger.y = 100;
dragger.addChild(circle, label);
dragger.setBounds(100, 100, dragRadius*2, dragRadius*2);
//DragRadius * 2 because 2*r = width of the bounding box
var label2 = new createjs.Text("HERE", "bold 14px Lato", "#000");
label2.textAlign = "center";
label2.x += 50;
label2.y += 40;
var box = new createjs.Shape();
box.graphics.setStrokeStyle(2).beginStroke("black").rect(0, 0, destHeight, destWidth);
var destination = new createjs.Container();
destination.x = 350;
destination.y = 50;
destination.setBounds(350, 50, destHeight, destWidth);
destination.addChild(label2, box);
//DRAG FUNCTIONALITY =====================
dragger.on("pressmove", function(evt){
evt.currentTarget.x = evt.stageX;
evt.currentTarget.y = evt.stageY;
stage.update(); //much smoother because it refreshes the screen every pixel movement instead of the FPS set on the Ticker
if(intersect(evt.currentTarget, destination)){
evt.currentTarget.alpha=0.2;
box.graphics.clear();
box.graphics.setStrokeStyle(3)
.beginStroke("#0066A4")
.rect(0, 0, destHeight, destWidth);
}else{
evt.currentTarget.alpha=1;
box.graphics.clear(); box.graphics.setStrokeStyle(2).beginStroke("black").rect(0, 0, destHeight, destWidth);
}
});
//Mouse UP and SNAP====================
dragger.on("pressup", function(evt) {
if(intersect(evt.currentTarget, destination)){
dragger.x = destination.x + destWidth/2;
dragger.y = destination.y + destHeight/2;
dragger.alpha = 1;
box.graphics.clear();
box.graphics.setStrokeStyle(2).beginStroke("black").rect(0, 0, destHeight, destWidth);
stage.update(evt);
}
});
//Tests if two objects are intersecting
//Sees if obj1 passes through the first and last line of its
//bounding box in the x and y sectors
//Utilizes globalToLocal to get the x and y of obj1 in relation
//to obj2
//PRE: Must have bounds set for each object
//Post: Returns true or false
function intersect(obj1, obj2){
var objBounds1 = obj1.getBounds().clone();
var objBounds2 = obj2.getBounds().clone();
var pt = obj1.globalToLocal(objBounds2.x, objBounds2.y);
var h1 = -(objBounds1.height / 2 + objBounds2.height);
var h2 = objBounds2.width / 2;
var w1 = -(objBounds1.width / 2 + objBounds2.width);
var w2 = objBounds2.width / 2;
if(pt.x > w2 || pt.x < w1) return false;
if(pt.y > h2 || pt.y < h1) return false;
return true;
}
//Adds the object into stage
stage.addChild(destination, dragger);
stage.mouseMoveOutside = true;
stage.update();
thanks
I am not exactly sure what you are asking. The demo you showed works fine (looks like it came from this codepen), and it is not clear what you are trying to add. This demo was made directly in code, not with Animate CC - which is really good for building assets, animations, and display list structure, but you should write application code around what gets exported.
There are plenty of documentation and examples online for Drag and Drop, in the EaselJS GitHub, and EaselJS docs:
DragAndDrop demo in GitHub
Live demo on EaselJS demos page
Documentation on pressMove
Tutorial on Mouse Events which includes Drag and Drop
I recommend narrowing down what you are trying to do, show what code or approaches you have tried so far, and posting specific questions here.
Lastly, here is the first part of an ongoing series for working with Animate CC: http://blog.gskinner.com/archives/2015/04/introduction-to-the-flash-cc-html5-canvas-document.html
Cheers.

Using leapmotion to control Unity3d interface

I understand that I can use leapmotion in game with Unity3D.
What I can't see any information on, is if I can use it to actual interact with assets, models etc as I build the game. For example revolving a game object around the x axis or zooming in or out of the view.
Is this possible?
Yes, it is possible, but requires some scripts that nobody has written yet (ASFAIK). Here is a VERY rough example that I worked up today since I've been curious about this question, too.
All it does is move, scale, and rotate a selected game object -- it doesn't try to do this in a good way -- it is a proof of concept only. To make it work you would have to do a sensible conversion of Leap coordinates and rotations to Unity values. To try it, put this script in a folder called "Editor", select a game object in the scene view and hold a key down while moving your hand above your Leap. As I said, none of these movements really work to edit an object, but you can see that it is possible with some sensible logic.
#CustomEditor (Transform)
class RotationHandleJS extends Editor {
var controller = new Leap.Controller();
var position;
var localScale;
var localRotation;
var active = false;
function OnSceneGUI () {
e = Event.current;
switch (e.type) {
case EventType.KeyDown:
position = target.transform.position;
localScale = target.transform.localScale;
localRotation = target.transform.localRotation;
active = true;
Debug.Log("editing");
break;
case EventType.KeyUp:
active = false;
target.transform.position = position;
target.transform.localScale = localScale;
EditorUtility.SetDirty (target);
break;
}
if(active){
frame = controller.Frame();
ten = controller.Frame(10);
scale = frame.ScaleFactor(ten);
translate = frame.Translation(ten);
target.transform.localScale = localScale + new Vector3(scale, scale, scale);
target.transform.position = position + new Vector3(translate.x, translate.y, translate.z);
leapRot = frame.RotationMatrix(ten);
quats = convertRotation(leapRot);
target.transform.localRotation = quats;
}
}
var LEAP_UP = new Leap.Vector(0, 1, 0);
var LEAP_FORWARD = new Leap.Vector(0, 0, -1);
var LEAP_ORIGIN = new Leap.Vector(0, 0, 0);
function convertRotation(matrix:Leap.Matrix) {
var up = matrix.TransformDirection(LEAP_UP);
var forward = matrix.TransformDirection(LEAP_FORWARD);
return Quaternion.LookRotation(new Vector3(forward.x, forward.y,forward.z), new Vector3(up.x, up.y, up.z));
}
}

event processing in dojo surface

I have a surface where i draw some kind of dynamic image based on the data from my backend, on click of a certain area, i want different data to be published. but my following code always takes last data drawn to publish.
function renderICD() {
var totalx=1200;
var totaly=1000;
var xOffset = 150;
var yOffset = 20;
surface = dojox.gfx.createSurface("icdTab",totalx+2,totaly+2);
var grid = surface.createGroup();
var step = 1;
var xyHolder = {};
var group = grid.createGroup();
for(var ii=0;ii<2;ii++)
{
var x = (step-1) * (75+85);
step++;
var group = grid.createGroup();
group.createRect({x:xOffset+x+33, y:yOffset+20+90, width: 10, height: 10}).setFill([255, 255, 255, 0.9])
.setStroke({color:'black' , width:2});
dojo.connect(group.getEventSource(),"onclick",function(e) {
var internal = ii;
alert("publishing "+internal);
//shape was clicked, now do something!
});
grid.createText({x:xOffset+x+33, y:yOffset+20+80, text:ii,align:"middle"})
.setFill('red')
.setFont({size: '10px',weight: "bold"});
}
}
As i understand, only 1 instance of function written to handle event is present, but what i am trying to handle is 2 different events.
How can i achieve this?
Snapshot of surface with 2 rects, when i click on both rects, i get '2' in my alert.
JavaScript has functional scope, not block scope, so you only have one ii variable, which is always equal to "2" by the time you click on a rect. There are many ways to fix this, example below :
function renderICD() {
var totalx=1200;
var totaly=1000;
var xOffset = 150;
var yOffset = 20;
surface = dojox.gfx.createSurface("icdTab",totalx+2,totaly+2);
var grid = surface.createGroup();
var step = 1;
var xyHolder = {};
var group = grid.createGroup();
dojo.forEach([0,1], function(item, ii) {
var x = (step-1) * (75+85);
step++;
var group = grid.createGroup();
group.createRect({x:xOffset+x+33, y:yOffset+20+90, width: 10, height: 10}).setFill([255, 255, 255, 0.9])
.setStroke({color:'black' , width:2});
dojo.connect(group.getEventSource(),"onclick",function(e) {
var internal = ii;
alert("publishing "+internal);
//shape was clicked, now do something!
});
grid.createText({x:xOffset+x+33, y:yOffset+20+80, text:ii,align:"middle"})
.setFill('red')
.setFont({size: '10px',weight: "bold"});
});
}

Strange mouse event position problem

I have a function which returns mouse event positions.
// returns the xy point where the mouse event was occured.
function getXY(ev){
var xypoint = new Point();
if (ev.layerX || ev.layerY) { // Firefox
xypoint.x = ev.layerX;
xypoint.y = ev.layerY;
} else if (ev.offsetX || ev.offsetX == 0) { // Opera
xypoint.x = ev.offsetX;
xypoint.y = ev.offsetY;
}
return xypoint;
}
I am capturing mouse events to perform drawings on html5 canvas. Sometimes I am getting -ve values for xypoint. When I debug the application using firebug I am getting really strange behavior. for example if I put my break point at the 4th line of this function with condition (xypoint.x<0 || xypoint.y<0), it stops at the break point and I can see that layer.x, layer.y was positive and correct. But xypoint.x or xypoint.y is negative. If I reassign the values using firbug console I am getting correct values in xypoint. Can anyone explain me what is happening.
The above works fine if I move mouse with normal speed. If I am moving mouse at very rapid speed I am getting this behavior.
Thanks
Handling mouse position was an absolute pain with Canvas. You have to make a ton of adjustments. I use this, which has a few minor errors, but works even with the drag-and-drop divs I use in my app:
getCurrentMousePosition = function(e) {
// Take mouse position, subtract element position to get relative position.
if (document.layers) {
xMousePos = e.pageX;
yMousePos = e.pageY;
xMousePosMax = window.innerWidth+window.pageXOffset;
yMousePosMax = window.innerHeight+window.pageYOffset;
} else if (document.all) {
xMousePos = window.event.x+document.body.scrollLeft;
yMousePos = window.event.y+document.body.scrollTop;
xMousePosMax = document.body.clientWidth+document.body.scrollLeft;
yMousePosMax = document.body.clientHeight+document.body.scrollTop;
} else if (document.getElementById) {
xMousePos = e.pageX;
yMousePos = e.pageY;
xMousePosMax = window.innerWidth+window.pageXOffset;
yMousePosMax = window.innerHeight+window.pageYOffset;
}
elPos = getElementPosition(document.getElementById("cvs"));
xMousePos = xMousePos - elPos.left;
yMousePos = yMousePos - elPos.top;
return {x: xMousePos, y: yMousePos};
}
getElementPosition = function(el) {
var _x = 0,
_y = 0;
if(document.body.style.marginLeft == "" && document.body.style.marginRight == "" ) {
_x += (window.innerWidth - document.body.offsetWidth) / 2;
}
if(el.offsetParent != null) while(1) {
_x += el.offsetLeft;
_y += el.offsetTop;
if(!el.offsetParent) break;
el = el.offsetParent;
} else if(el.x || el.y) {
if(el.x) _x = el.x;
if(el.y) _y = el.y;
}
return { top: _y, left: _x };
}
Moral of the story? You need to figure in the offset of the canvas to have proper results. You're capturing the XY from the event, which has an offset that's not being captured in relation to the window's XY. Make sense?