I working on a web app that shows a graph based on the microphone samples. I take the highest value of the vector return from getByteTimeDomainData each ~15ms and put it on a graph.
The problem is that in some phones (such as Xiaomi phones) I get fake microphone samples- it returns the same vector 10 times (~150ms), and only after that it samples the microphone again and returns a new vector for another 10 times.
Standart phones:
Highest values collected from 30 calls to getByteTimeDomainData:
230,237,237,236,236,220,220,232,232,218,218,214,214,217,217,227,227,222,222,224,224,222,222,216,216,202,202,223,223,205
Xiaomi phones:
Highest values collected from 30 calls to getByteTimeDomainData:
132,132,132,132,132,132,132,129,129,129,129,129,129,129,129,129,129,130,130,130,130,130,130,130,130,130,130,131,131,131
My question is- How can I improve it and get more samples in Xiaomi?
var start_amp = function () {
'use strict';
var soundAllowed = function (stream) {
window.persistAudioStream = stream;
var audioContext = new AudioContext();
var audioStream = audioContext.createMediaStreamSource(stream);
var analyser = audioContext.createAnalyser();
audioStream.connect(analyser);
analyser.smoothingTimeConstant = 0; // = 1 doesn't fix the samples problem
analyser.fftSize = 1024;
var frequencyArray = new Uint8Array(analyser.frequencyBinCount);
var doDraw = function () {
requestAnimationFrame(doDraw);
analyser.getByteTimeDomainData(frequencyArray);
var max = 0;
for (var i = 0; i < frequencyArray.length; i++) {
if (max < frequencyArray[i]) {
max = frequencyArray[i];
}
}
boardArray.push(max);
if (boardArray.length >= document.body.clientWidth * 0.7) {
boardArray.shift();
totalSamples += 1;
if (totalSamples == 60) {
totalSamples = 0;
}
}
draw(boardArray);
}
doDraw();
}
var soundNotAllowed = function (error) {
alert('Please check your microphone connectivity and allow this site to access it');
console.log(error);
}
navigator.getUserMedia({ audio: true }, soundAllowed, soundNotAllowed);
}
After some research, I found that creating another AudioContext and Analyser gives me different samples. Looks like there is some sample rate limit for each node.
So I created 3 AudioContext's and used the average of them:
var start_amp = function () {
'use strict';
var soundAllowed = function (stream) {
window.persistAudioStream = stream;
// Node 1
var audioContext = new AudioContext();
var audioStream = audioContext.createMediaStreamSource(stream);
var analyser = audioContext.createAnalyser();
audioStream.connect(analyser);
analyser.smoothingTimeConstant = 0; // = 1 doesn't fix the samples problem
analyser.fftSize = 1024;
// Node 2
var audioContext2 = new AudioContext();
var audioStream2 = audioContext2.createMediaStreamSource(stream);
var analyser2 = audioContext2.createAnalyser();
audioStream2.connect(analyser2);
analyser2.smoothingTimeConstant = 0; // = 1 doesn't fix the samples problem
analyser2.fftSize = 1024;
// Node 3
var audioContext3 = new AudioContext();
var audioStream3 = audioContext3.createMediaStreamSource(stream);
var analyser3 = audioContext3.createAnalyser();
audioStream3.connect(analyser3);
analyser3.smoothingTimeConstant = 0; // = 1 doesn't fix the samples problem
analyser3.fftSize = 1024;
var frequencyArray = new Uint8Array(analyser.frequencyBinCount);
var frequencyArray2 = new Uint8Array(analyser2.frequencyBinCount);
var frequencyArray3 = new Uint8Array(analyser3.frequencyBinCount);
var doDraw = function () {
requestAnimationFrame(doDraw);
analyser.getByteTimeDomainData(frequencyArray);
analyser2.getByteTimeDomainData(frequencyArray2);
analyser3.getByteTimeDomainData(frequencyArray3);
var max = 0;
for (var i = 0; i < frequencyArray.length; i++) {
if (max < frequencyArray[i]) {
max = frequencyArray[i];
}
}
var max2 = 0;
for (var i = 0; i < frequencyArray2.length; i++) {
if (max2 < frequencyArray2[i]) {
max2 = frequencyArray2[i];
}
}
var max3 = 0;
for (var i = 0; i < frequencyArray3.length; i++) {
if (max3 < frequencyArray3[i]) {
max3 = frequencyArray3[i];
}
}
boardArray.push((max + max2 + max3) / 3);
if (boardArray.length >= document.body.clientWidth * 0.7) {
boardArray.shift();
totalSamples += 1;
if (totalSamples == 60) {
totalSamples = 0;
}
}
draw(boardArray);
}
doDraw();
}
var soundNotAllowed = function (error) {
alert('Please check your microphone connectivity and allow this site to access it');
console.log(error);
}
navigator.getUserMedia({ audio: true }, soundAllowed, soundNotAllowed);
}
Related
Scenario: 4 players, each can have a pawn from 1 to 100.
I want to be able to efficiently check if Player 1's pawns collides with Player 2, 3, and 4.
Currently I have an aabbCheck, done first on Player 1's side where it checks against Player 2's pawns. Now I realized I have to do this for the rest of the players.
This is done in a NodeJS server. If a collision is detected, send a message to each players which in turn kills the pawn in question
// aabbCheck
var aabbCheck = function (aabb1, aabb2) {
if (aabb1.x + aabb1.w > aabb2.x &&
aabb1.x < aabb2.x + aabb2.w &&
aabb1.y + aabb1.h > aabb2.y &&
aabb1.y < aabb2.y + aabb2.h) {
return true;
}
return false;
};
// make the pawns move based on the angle the player targets
var marchPawn = function (pawn) {
var speed = 90;
pawn.aabb.x += speed * (Math.cos(pawn.angle) * (Date.now() - pawn.spawnTime) * 0.001);
pawn.aabb.y += speed * (Math.sin(pawn.angle) * (Date.now() - pawn.spawnTime) * 0.001);
pawn.spawnTime = Date.now();
};
// check if pawn collides with another entity
var checkPawnCollision = function (pawn, other) {
var aabb1 = {};
aabb1.x = pawn.aabb.x;
aabb1.y = pawn.aabb.y;
aabb1.w = pawn.aabb.w;
aabb1.h = pawn.aabb.h;
var aabb2 = {};
aabb2.x = other.aabb.x;
aabb2.y = other.aabb.y;
aabb2.w = other.aabb.w;
aabb2.h = other.aabb.h;
if (aabbCheck(aabb1, aabb2)) {
// console.log('pawn collides with other');
return true;
}
return false;
};
var playerPawn = {
player1: [],
player2: [],
player3: [],
player4: []
};
// Check if player 1 have pawns on the field
if (playerPawn.player1.length > 0) {
for (var i = 0; i < playerPawn.player1.length; i++) {
var pawn = playerPawn.player1[i];
if (pawn) {
// make the pawn move
marchPawn(pawn);
// Check if player 1 pawn collides with player 2 pawn
if (playerPawn.player2.length > 0) {
for (var j = 0; j < playerPawn.player2.length; j++) {
var p2pawn = playerPawn.player2[j];
if (p2pawn) {
if (checkPawnCollision(pawn, p2pawn)) {
// console.log('Pawn Collision');
playerPawn.player1.splice(i, 1);
playerPawn.player2.splice(j, 1);
}
}
}
}
}
}
}
// NOT YET DONE
// Check if player 2 have pawns on the field
if (playerPawn.player2.length > 0) {
for (var i = 0; i < playerPawn.player2.length; i++) {
var pawn = playerPawn.player2[i];
if (pawn) {
marchPawn(pawn);
}
}
}
// NOT YET DONE
// Check if player 3 have pawns on the field
if (playerPawn.player3.length > 0) {
for (var i = 0; i < playerPawn.player3.length; i++) {
var pawn = playerPawn.player3[i];
if (pawn) {
marchPawn(pawn);
}
}
}
// NOT YET DONE
// Check if player 4 have pawns on the field
if (playerPawn.player4.length > 0) {
for (var i = 0; i < playerPawn.player4.length; i++) {
var pawn = playerPawn.player4[i];
if (pawn) {
marchPawn(pawn);
}
}
}
I am making a tree with space-colonization algorithm in javascript. (with p5.js)
I followed the tutorial of https://www.youtube.com/watch?v=kKT0v3qhIQY&ab_channel=TheCodingTrain
or in C#
http://www.jgallant.com/procedurally-generating-trees-with-space-colonization-algorithm-in-xna/
I want to make a customized area (in this case a circle) where the leaves are generated randomly.
in Leaf.js I try to include some calculations of how the leaves get the random Coordinates within the circle.
So there is sketch.js , leaf.js, branch.js, tree.js
//leaf.js
function Leaf() {
function getChord(){
var r = 150;
var angle = random(0, 2 * PI);
var xChord = 2*r + sqrt(r) * cos(angle);
var yChord = r + sqrt(r) * sin(angle);
return (createVector(xChord, yChord));
}
this.pos = getChord();
this.reached = false;
// // var t = 2 * PI * random(0,1);
// // var r = sqrt(random(0,1));
// // var x = r * cos(t);
// // var y = r * sin(t);
// // this.pos = createVector(x, y);
// this.reached = false;
this.show = function() {
fill(58, 126, 34);
noStroke();
ellipse(this.pos.x, this.pos.y, 4, 4);
};
}
//branch.js
function Branch(parent, pos, dir) {
this.pos = pos;
this.parent = parent;
this.dir = dir;
this.origDir = this.dir.copy();
this.count = 0;
this.len = 3;
this.reset = function() {
this.dir = this.origDir.copy();
this.count = 0;
};
this.next = function() {
var nextDir = p5.Vector.mult(this.dir, this.len);
var nextPos = p5.Vector.add(this.pos, nextDir);
var nextBranch = new Branch(this, nextPos, this.dir.copy());
return nextBranch;
};
this.show = function() {
if (parent != null) {
stroke(151, 53, 48);
strokeWeight(1);
line(this.pos.x, this.pos.y, this.parent.pos.x, this.parent.pos.y);
}
};
}
And then in tree.js I push every leaf into leaves.
//tree.js
function Tree() {
this.leaves = [];
this.branches = [];
for (var i = 0; i < 1500; i++) {
this.leaves.push(new Leaf());
}
var pos = createVector(width / 2, height);
var dir = createVector(0, -1);
var root = new Branch(null, pos, dir);
this.branches.push(root);
var current = root;
var found = false;
while (!found) {
for (var i = 0; i < this.leaves.length; i++) {
var d = p5.Vector.dist(current.pos, this.leaves[i].pos);
if (d < max_dist) {
found = true;
}
}
if (!found) {
var branch = current.next();
current = branch;
this.branches.push(current);
}
}
this.grow = function() {
for (var i = 0; i < this.leaves.length; i++) {
var leaf = this.leaves[i];
var closestBranch = null;
var record = max_dist;
for (var j = 0; j < this.branches.length; j++) {
var branch = this.branches[j];
var d = p5.Vector.dist(leaf.pos, branch.pos);
if (d < min_dist) {
leaf.reached = true;
closestBranch = null;
break;
} else if (d < record) {
closestBranch = branch;
record = d;
}
}
if (closestBranch != null) {
var newDir = p5.Vector.sub(leaf.pos, closestBranch.pos);
newDir.normalize();
closestBranch.dir.add(newDir);
closestBranch.count++;
}
}
for (var i = this.leaves.length - 1; i >= 0; i--) {
if (this.leaves[i].reached) {
this.leaves.splice(i, 1);
}
}
for (var i = this.branches.length - 1; i >= 0; i--) {
var branch = this.branches[i];
if (branch.count > 0) {
branch.dir.div(branch.count + 1);
this.branches.push(branch.next());
branch.reset();
}
}
};
this.show = function() {
for (var i = 0; i < this.leaves.length; i++) {
this.leaves[i].show();
}
for (var i = 0; i < this.branches.length; i++) {
this.branches[i].show();
}
};
}
//sketch.js
var tree;
var max_dist = 30;
var min_dist = 10;
function setup() {
createCanvas(600, 600);
tree = new Tree();
}
function draw() {
background(111, 149, 231);
tree.show();
tree.grow();
}
Some how in the function getChord I think there is an infinite loop or having trouble getting the random value? Because it is not loading at all... It works when I change this.pos = getChord(); to this.pos = createVector(random(width),random(height-100);
Does anyone know how to solve this?
Or how to write codes to make an area of the circle where the leaves can be generated?
Thank you!
I'm doing a coding challenge from the coding train, and I'm trying to improve on his code. The idea is that the cars are driving around a race track. When I went back to check something, I noticed that I misspelled "activation: sigmoid", as in activation function. When I fixed it, the cars seemed to be driving in circles.
I'm a very new coder (as I am 12 years old), so many things in my code are broken, hard to understand, or just not finished. I'm also pretty new to stack overflow, so I might be breaking a lot of rules.
The link to download my project is here: https://1drv.ms/u/s!ApmY_SAko19ChzCKe5uNT7I9EZAX?e=YUg2ff
The misspelled words are at lines 29 and 34 in the nn.js file.
car.js
function pldistance(p1, p2, x, y) {
const num = abs((p2.y - p1.y) * x - (p2.x - p1.x) * y + p2.x * p1.y - p2.y * p1.x);
const den = p5.Vector.dist(p1, p2);
return num / den;
}
class Car {
constructor(brain, color = [random(255), random(255), random(255)]) {
this.colorGene = color;
this.dead = false;
this.finished = false;
this.fitness = 0;
this.rays = [];
this.wallRays = [];
this.degreeOfSight = degreeOfSight;
this.degreeOfRays = degreeOfSight / (numOfRays - 1);
if (this.degreeOfSight == 360) {
this.degreeOfRays = degreeOfSight / numOfRays;
}
this.pos = createVector(start.x, start.y);
this.vel = createVector();
this.acc = createVector();
this.sight = sight;
this.maxspeed = maxspeed;
this.maxforce = maxTurningSpeed;
this.currentGoal = 0;
this.timeTillDeadC = timeTillDead;
this.timeTillDead = this.timeTillDeadC;
this.goal;
this.rate = mutationRate;
if (degreeOfSight != 360) {
for (let a = -(this.degreeOfSight / 2); a <= this.degreeOfSight / 2; a += this.degreeOfRays) {
this.rays.push(new Ray(this.pos, radians(a)));
}
} else {
for (let a = -(this.degreeOfSight / 2); a < this.degreeOfSight / 2; a += this.degreeOfRays) {
this.rays.push(new Ray(this.pos, radians(a)));
}
}
for (let a = 0; a < 360; a += 45) {
this.wallRays.push(new Ray(this.pos, radians(a)));
}
if (brain) {
this.brain = brain.copy();
} else {
this.brain = new NeuralNetwork(this.rays.length + 2, 16, 2);
}
}
applyForce(force) {
this.acc.add(force);
}
update(x, y) {
this.timeTillDead--;
if (this.timeTillDead <= 0) {
this.dead = true;
}
if (!this.dead || this.finished) {
this.pos.add(this.vel);
this.vel.add(this.acc);
this.vel.limit(this.maxspeed);
this.acc.set(0, 0);
}
for (let i = 0; i < this.rays.length; i++) {
this.rays[i].rotate(this.vel.heading());
}
for (let i = 0; i < this.wallRays.length; i++) {
this.wallRays[i].rotate(this.vel.heading());
}
}
show(walls) {
push();
translate(this.pos.x, this.pos.y);
if (visualization) {
fill(this.colorGene[0], this.colorGene[1], this.colorGene[1]);
} else {
fill(0);
}
stroke(255);
const heading = this.vel.heading();
rotate(heading);
rectMode(CENTER);
rect(0, 0, 10, 5);
pop();
if (!this.dead) {
checkpoints[this.currentGoal].show();
}
for (let i = 0; i < this.rays.length; i++) {
let closest = null;
let record = this.sight;
for (let wall of walls) {
const pt = this.rays[i].cast(wall);
if (pt) {
const d = p5.Vector.dist(this.pos, pt);
if (d < record && d < this.sight) {
record = d;
closest = pt;
}
}
}
if (closest) {
if (showLines) {
ellipse(closest.x, closest.y, 4)
stroke(255, 100)
line(this.pos.x, this.pos.y, closest.x, closest.y);
}
}
}
}
check(checkpoints, walls) {
if (!this.dead) {
this.goal = checkpoints[this.currentGoal];
const d = pldistance(this.goal.a, this.goal.b, this.pos.x, this.pos.y);
if (d < 5) {
this.fitness++;
this.currentGoal++;
this.timeTillDead = this.timeTillDeadC;
if (this.currentGoal == checkpoints.length) {
this.finished = true;
this.fitness = this.fitness * 1.5;
if (endBarrier) {
this.dead = true;
} else {
this.currentGoal = 0;
}
}
}
}
for (let i = 0; i < this.wallRays.length; i++) {
let closest = null;
let record = this.sight;
for (let wall of walls) {
const pt = this.wallRays[i].cast(wall);
if (pt) {
const d = p5.Vector.dist(this.pos, pt);
if (d < record) {
record = d;
closest = pt;
}
}
}
if (record < 4) {
this.dead = true;
}
}
}
look(walls) {
const inputs = [];
for (let i = 0; i < this.wallRays.length; i++) {
let closest = null;
let record = this.sight;
for (let wall of walls) {
const pt = this.rays[i].cast(wall);
if (pt) {
const d = p5.Vector.dist(this.pos, pt);
if (d < record && d < this.sight) {
record = d;
closest = pt;
}
}
}
inputs[i] = map(record, 0, 50, 1, 0);
}
inputs.push(end.x);
inputs.push(end.y);
const output = this.brain.predict(inputs);
let angle = map(output[0], 0, 1, -PI, PI);
let speed = map(output[1], 0, 1, -this.maxspeed, this.maxspeed);
angle += this.vel.heading();
const steering = p5.Vector.fromAngle(angle);
steering.setMag(speed);
steering.limit(this.maxforce);
this.applyForce(steering);
}
mutateDemBabies() {
if (this.finished) {
this.rate = finishingMutationRate;
}
this.brain.mutate(this.rate);
let changeColor = this.brain.mutated();
if (changeColor) {
for (let color of this.colorGene) {
let r = map(random(20), 0, 20, -25, 25);
color += r;
}
}
this.rate = mutationRate;
}
dispose() {
this.brain.dispose();
}
}
nn.js
//<script src="https://cdn.jsdelivr.net/npm/#tensorflow/tfjs#1.1.0/dist/tf.min.js"></script>
class NeuralNetwork {
//this how many inputs, hidden, and output nodes there are. modelC is the brain that we want to copy to give to the new bird
constructor(inputNumber, hiddenNumber, outputNumber, modelC) {
if (modelC instanceof tf.Sequential) {
//this is the making a copy of the neural network
this.input_nodes = inputNumber;
this.hidden_nodes = hiddenNumber;
this.output_nodes = outputNumber;
this.model = modelC;
} else {
//this is the creating a random brain
this.input_nodes = inputNumber;
this.hidden_nodes = hiddenNumber;
this.output_nodes = outputNumber;
this.model = this.createBrain();
}
this.changeColor = false;
}
createBrain() {
//the model is the neural network
const model = tf.sequential();
//configuring the hidden layer
const hiddenLayer = tf.layers.dense({
units: this.hidden_nodes,
inputShape: [this.input_nodes],
activaation: "sigmoid"
});
//configuring the output layer
const outputLayer = tf.layers.dense({
units: this.output_nodes,
activaation: "sigmoid"
});
//adding the hidden layer to the model
model.add(hiddenLayer);
//adding the output layer to the model
model.add(outputLayer);
//returning the model
return model;
}
predict(inputs) {
//clearing the tensors after using them
//then returning the output
return tf.tidy(() => {
//creating a tensor with the inputs
const xs = tf.tensor2d([inputs]);
//running the inputs through the neural network
const ys = this.model.predict(xs);
//getting the raw numbers from the tensor object
const outputs = ys.dataSync();
//returning the outputs
return outputs;
});
}
copy() {
//clearing the tensors after using them
//then returning the output
return tf.tidy(() => {
//creating a new neural network
const modelCopy = this.createBrain();
//getting the weights from the old neural network
const weights = this.model.getWeights();
//setting the new weights
modelCopy.setWeights(weights);
//making a new network but this time with all the weights then returning it
return new NeuralNetwork(
this.input_nodes,
this.hidden_nodes,
this.output_nodes,
modelCopy
);
});
}
mutate(rate, colorGene) {
//clearing the tensors after using them
tf.tidy(() => {
this.changeColor = false;
//getting the weights so that we can change them later
const weights = this.model.getWeights();
//the variable that will be holding the mutated weights
const mutatedWeights = [];
for (let i = 0; i < weights.length; i++) {
//getting the shape of the current weights
let shape = weights[i].shape;
//making a copy of the raw numbers from the object tensor
//dataSync gets the numbers, but doesn't make a copy, so slice will make the copy
let values = weights[i].dataSync().slice();
for (let j = 0; j < values.length; j++) {
//if the random number is less than mutation rate the it runs the code
if (random(1) < rate) {
this.changeColor = true;
//mutating the value
//randomGaussianis returns a float from a series of numbers with a mean of 0
values[j] = values[j] + randomGaussian();
}
}
//holding the new value of each weight
mutatedWeights[i] = tf.tensor(values, shape);
}
//setting the mutated weights as the new weights
this.model.setWeights(mutatedWeights);
});
}
mutated() {
if (this.changeColor) {
this.changeColor = false;
return true;
} else {
this.changeColor = false;
return false;
}
}
dispose() {
//disposing the brain so that memory doesn't leak
this.model.dispose();
}
}
How do I change voice pitch without noise using web audio in JavaScript?
I tried the code below.
I got my voice with noisy and bit echo mixed.
I want a voice module which is like noiseless.
var pitchShifter = (function () {
var context, audioContext, pitchShifterProcessor, spectrumAudioAnalyser,
sonogramAudioAnalyser;
var validGranSizes = [256, 512, 1024, 2048, 4096, 8192],
grainSize = validGranSizes[1],
pitchRatio = 2.0,
overlapRatio = 0.50;
var filter, compressor;
hannWindow = function (length) {
var window = new Float32Array(length);
for (var i = 0; i < length; i++) {
window[i] = 0.5 * (1 - Math.cos(2 * Math.PI * i / (length - 1)));
}
return window;
};
linearInterpolation = function (a, b, t) {
return a + (b - a) * t;
};
initProcessor = function () {
if (navigator.getUserMedia) {
navigator.getUserMedia({
audio: true
},
function (stream) {
var convolver = audioContext.createConvolver();
compressor = audioContext.createDynamicsCompressor();
compressor.threshold.value = -50;
compressor.knee.value = 40;
compressor.ratio.value = 12;
compressor.reduction.value = -20;
compressor.attack.value = 0;
compressor.release.value = 0.25;
filter = audioContext.createBiquadFilter();
filter.Q.value = 8.30;
filter.frequency.value = 355;
filter.gain.value = 3.0;
filter.type = 'bandpass';
filter.connect(compressor);
compressor.connect(audioContext.destination);
filter.connect(audioContext.destination);
var microphone_stream = audioContext.createMediaStreamSource(
stream);
microphone_stream.connect(filter);
var source = audioContext.createBufferSource();
microphone_stream.connect(pitchShifterProcessor);
},
function (e) {
alert('Error capturing audio.');
}
);
}
if (pitchShifterProcessor) {
pitchShifterProcessor.disconnect();
}
if (audioContext.createScriptProcessor) {
pitchShifterProcessor = audioContext.createScriptProcessor(
grainSize, 1, 1);
} else if (audioContext.createJavaScriptNode) {
pitchShifterProcessor = audioContext.createJavaScriptNode(grainSize,
1, 1);
}
pitchShifterProcessor.buffer = new Float32Array(grainSize * 2);
pitchShifterProcessor.grainWindow = hannWindow(grainSize);
pitchShifterProcessor.onaudioprocess = function (event) {
var inputData = event.inputBuffer.getChannelData(0);
var outputData = event.outputBuffer.getChannelData(0);
for (i = 0; i < inputData.length; i++) {
// Apply the window to the input buffer
inputData[i] *= this.grainWindow[i];
// Shift half of the buffer
this.buffer[i] = this.buffer[i + grainSize];
// Empty the buffer tail
this.buffer[i + grainSize] = 0.0;
}
// Calculate the pitch shifted grain re-sampling and looping the input
var grainData = new Float32Array(grainSize * 2);
for (var i = 0, j = 0.0; i < grainSize; i++, j += pitchRatio) {
var index = Math.floor(j) % grainSize;
var a = inputData[index];
var b = inputData[(index + 1) % grainSize];
grainData[i] += linearInterpolation(a, b, j % 1.0) * this.grainWindow[
i];
}
// Copy the grain multiple times overlapping it
for (i = 0; i < grainSize; i += Math.round(grainSize * (1 -
overlapRatio))) {
for (j = 0; j <= grainSize; j++) {
this.buffer[i + j] += grainData[j];
}
}
// Output the first half of the buffer
for (i = 0; i < grainSize; i++) {
outputData[i] = this.buffer[i];
}
};
pitchShifterProcessor.connect(audioContext.destination);
};
return {
init: function () {
if ('AudioContext' in window) {
audioContext = new AudioContext();
} else {
alert('Your browser does not support the Web Audio API');
return;
}
initProcessor();
}
}
}());
window.requestAnimFrame = (function () {
return (window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
});
})();
window.addEventListener("DOMContentLoaded", pitchShifter.init, true);
You can use the PitchShifter in SoundTouchJS for this. I currently use this in my CDGPlayer for changing the 'key' for a user.
My game is an idle one where you click protons, neutrons, and electrons and when you have enough of some, you can build hydrogen and so forth. I kind of got my local variables to work but now I am having issues with the buying stage.
Basically hydrogen costs 1 proton and one electron, when you click on the button, it runs the function SetHydrogen(), when it does that, it is supposed to run based off of the variable HydrogenCost. I am not sure if any of this is feasible.
var protons = Number(localStorage.setItem("ProtonS", Pcount));
var neutrons = Number(localStorage.NeutronS);
var electrons = Number(localStorage.ElectronS);
var hydrogens = Number(localStorage.HydrogenS);
function SaveVariables(){
if (localStorage.getItem("ProtonS")){
localStorage.setItem("ProtonS", Pcount);
protons = Number(localStorage.ProtonS);
} else {
localStorage.ProtonS = Number(localStorage.ProtonS);
}
if (localStorage.NeutronS){
localStorage.NeutronS = neutrons;
neutrons = Number(localStorage.NeutronS);
} else {
neutrons = Number(localStorage.NeutronS);
}
if (localStorage.ElectronS){
localStorage.ElectronS = electrons;
electrons = Number(localStorage.ElectronS);
} else {
electrons = Number(localStorage.ElectronS);
}
if (localStorage.HydrogenS){
localStorage.HydrogenS = document.getElementByID("HydrogenTotal").innerHTML;
hydrogens = Number(localStorage.HydrogenS);
} else {
hydrogens = 0;
}
}
function LoadVariables(){
buying = 0;
CanUBuy = false;
protons = Number(localStorage.ProtonS);
neutrons = Number(localStorage.NeutronS);
electrons = Number(localStorage.ElectronS);
hydrogens = Number(localStorage.HydrogenS);
}
function update(){
protonTap.onmousedown = function() {protons = protons + 1};
neutronTap.onmousedown = function() {neutrons = neutrons + 1};
electronTap.onmousedown = function() {electrons = electrons + 1};
};
function draw(){
ProtonsTotal.value = protons.toFixed(0);
NeutronsTotal.value = neutrons.toFixed(0);
ElectronsTotal.value = electrons.toFixed(0);
console.log(hydrogens);
console.log(CanUBuy);
console.log(Pcount);
};
var mainloop = function() {update(), draw(), SaveVariables()};
var buying = 0;
function SetHydrogen(){
buying = 1;
HydrogenCost.buy;
if (CanUBuy = true){
HydrogenTotal.value ++;
buying = 0;
CanUBuy = false;
} else {
buying = 0;
}
}
function reset(){
CanUBuy = false;
protons = 0;
neutrons = 0;
electrons = 0;
hydrogens = 0;
buying = 0;
}
setInterval(mainloop, 16);
var CanUBuy = false;
var HydrogenCost = new buy(1,0,1);
function buy(ProtonCost, NeutronCost, ElectronCost){
if (buying = 1){
this.pCost = ProtonCost;
this.nCost = NeutronCost;
this.eCost = ElectronCost;
if (protons >= ProtonCost && neutrons >= NeutronCost && electrons >= ElectronCost) {
CanUBuy = true;
protons = protons - this.pCost;
neutrons = neutrons - this.nCost;
electrons = electrons - this.eCost;
} else{
CanUBuy = false;
alert("You don't have enough money");
}
} else if (buying = 0) {
buying = 0;
}
}
if(!localStorage.getItem('start')){
localStorage.setItem('start', Date.now());
}
var start = parseInt(localStorage.getItem('start'));
setInterval(function(){
ffs.value = ~~((Date.now() - start)/1e3);
}, 1e3);
At first, i think you should rethink your overall structure. You could shorten your code and make it reusable through OOP:
function stored(name,startvalue){
this.name=name;
this.value=+localStorage.getItem(name) || startvalue || 0;
}
stored.prototype={
change:function(by){
this.value+=by;
localStorage.setItem(this.name,this.value);
},
set:function(to){
this.value=to;
localStorage.setItem(this.name,this.value);
},
valueOf:function(){ return this.value;},
};
So you can do:
var neutrons=new stored("neutrons");
alert(+neutrons);//0, 5 on reload
neutrons.set(5);
alert(+neutrons);//5
Note the + to convert the stored object to its value.
A hydrogen function could look like this:
var protons=new stored("protons",10);
var electrons=new stored("electrons",10);
var hydrogens=new stored("hydrogens");
hydrogens.buy=function(){
if(+protons && +neutrons){
protons.change(-1);
neutrons.change(-1);
this.change(1);
}else{
alert("impossible. Sorry :(");
}
}
hydrogens.buy();//test
http://jsbin.com/pozinotida/1/edit?js