web worker and asynchronous operation - javascript

I am learning web worker and right now I am going through the problem of using await inside the onmessage. How can i do this?
import { Copc, Key } from "copc";
var nodePages, pages, receivedData;
async function load() {
let filename = "https://s3.amazonaws.com/data.entwine.io/millsite.copc.laz";
const copc = await Copc.create(filename);
let scale = copc.header.scale[0];
let [x_min, y_min, z_min, x_max, y_max, z_max] = copc.info.cube;
let width = Math.abs(x_max - x_min);
let center_x = (x_min + x_max) / 2;
let center_y = (y_min + y_max) / 2;
let center_z = (z_min + z_max) / 2;
receivedData = await Copc.loadHierarchyPage(
filename,
copc.info.rootHierarchyPage
);
nodePages = receivedData.nodes;
pages = receivedData.pages;
postMessage(200);
}
onmessage = function (message) {
let index = message.data;
let myRoot = nodePages[keyCountMap[m]];
const view = await Copc.loadPointDataView(filename, copc, myRoot);
};
and again there is another issue, the loadPointDataView function is asynchronous, how can i implement this in my webworker?
Any help please
This is my original code that i want to parallelize:
let filename = "https://s3.amazonaws.com/data.entwine.io/millsite.copc.laz";
const copc = await Copc.create(filename);
scale = copc.header.scale[0];
const { nodes: nodePages, pages: pages } = await Copc.loadHierarchyPage(
filename,
copc.info.rootHierarchyPage
);
for (let m = 0; m < keyCountMap.length; m += 2) {
let myRoot = nodePages[keyCountMap[m]];
const view = await Copc.loadPointDataView(filename, copc, myRoot);
let getters = ["X", "Y", "Z", "Intensity"].map(view.getter);
let chunkCount = 20;
let totalCalled = 0;
let innerPromises = [];
for (let j = 0; j < keyCountMap[m + 1]; j += chunkCount) {
readPoints(index + j, getters)
}
}
const readPoints = async (id, getters) => {
return new Promise((resolve, reject) => {
let returnPoint = getXyzi(id, getters);
positions.push(
returnPoint[0] - x_min - 0.5 * width,
returnPoint[1] - y_min - 0.5 * width,
returnPoint[2] - z_min - 0.5 * width
);
const vx = (returnPoint[3] / 65535) * 255;
color.setRGB(vx, vx, vx);
colors.push(color.r, color.g, color.b);
});
};
function getXyzi(index, getters) {
return getters.map((get) => get(index));
}

Related

javascript promises does not work as expected while image combining

below is my javascript code which i use for combining 64 images to generate a panorama image. but when i load it first time it gives me broken image however at seconds or third time it gives me right image.
In Below combine function do all image combine process,
combinedArray contains all urls of images.
function combine(imgSources, width, height, right, left) {
return Promise.all(imgSources.map(function (url) {
return new Promise(function (resolve) {
let img = new Image();
img.crossOrigin = `anonymous`;
img.src = url;
img.onload = function () {resolve(img);};
});
})).then(function (images) {
let canvas = document.createElement(`canvas`);
canvas.width = width;
canvas.height = height;
// draw images to the canvas
let ctx = canvas.getContext(`2d`);
for (let i = 0; i < imgSources.length; i++) {
ctx.drawImage(images[i], right * i, left * i);
}
// return the resulting image in base64 form
return canvas.toDataURL(`image/jpeg`);
});
}
function generateParonama(angle = 10) {
let url=`https://cdn.yourvrtours.com/000679.fcf5f084b8794573a6789774f9bfcbaf.1122/A4CDD7C7-3F58-435A-9A5B-9522078DE10B/optimized/Point_7537F461-3868-4EFB-9B82-3A1E3CF81955/3/`;
let mainImage;
let allSides = [`f`, `r`, `b`, `l`];
let allImages = [];
let combinedArray = [];
let ind = 0;
// generates array for all 64 images
function genareteArray() {
for (let index = 0; index < allSides.length; index++) {
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
let t = `${url + allSides[index] + j + '_' + i}.jpg`;
combinedArray.push(t);
}
}
}
}
// arrange array at given angle
function reArrangeArray() {
let position = 0 / 22.5;
let array2 = [];
if (position <= 8) {
position = (position + 8) * 4;
array2 = combinedArray.slice(position, 64);
combinedArray.splice(position)
combinedArray = array2.concat(combinedArray)
}
else {
position = (position - 8) * 4;
array2 = combinedArray.slice(0, position);
combinedArray.push(array2)
}
}
genareteArray();
reArrangeArray();
allSides.map((side, i) => {
return new Promise((res) => {
for (let index = 0; index < 4; index++) {
combine(
[
combinedArray[0 + ind],
combinedArray[1 + ind],
combinedArray[2 + ind],
combinedArray[3 + ind],
], 512, 2048, 0, 512)
.then(function (result) {
// result will be a column of 512 box
allImages.push(result);
if (allImages.length > 15) {
combine(allImages, 8192, 2048, 512, 0).then((r) => {
var img = new Image();
img.src = r;
document.body.appendChild(img);
});
}
});
ind = ind + 4;
}
});
});
}
generateParonama(10);
img{
max-width:600px;
}
Can you try this -
function combine(imgSources, width, height, right, left) {
return Promise.all(imgSources.map(function (url) {
return new Promise(function (resolve) {
let img = new Image();
img.crossOrigin = `anonymous`;
img.src = url;
img.onload = function () { resolve(img); };
});
})).then(function (images) {
let canvas = document.createElement(`canvas`);
canvas.width = width;
canvas.height = height;
// draw images to the canvas
let ctx = canvas.getContext(`2d`);
for (let i = 0; i < imgSources.length; i++) {
ctx.drawImage(images[i], right * i, left * i);
}
// return the resulting image in base64 form
return canvas.toDataURL(`image/jpeg`);
});
}
async function generateParonama(angle = 10) {
let url = `https://cdn.yourvrtours.com/000679.fcf5f084b8794573a6789774f9bfcbaf.1122/A4CDD7C7-3F58-435A-9A5B-9522078DE10B/optimized/Point_7537F461-3868-4EFB-9B82-3A1E3CF81955/3/`;
let mainImage;
let allSides = [`f`, `r`, `b`, `l`];
let allImages = [];
let combinedArray = [];
let ind = 0;
// generates array for all 64 images
function genareteArray() {
for (let index = 0; index < allSides.length; index++) {
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
let t = `${url + allSides[index] + j + '_' + i}.jpg`;
combinedArray.push(t);
}
}
}
}
// arrange array at given angle
function reArrangeArray() {
let position = 0 / 22.5;
let array2 = [];
if (position <= 8) {
position = (position + 8) * 4;
array2 = combinedArray.slice(position, 64);
combinedArray.splice(position)
combinedArray = array2.concat(combinedArray)
}
else {
position = (position - 8) * 4;
array2 = combinedArray.slice(0, position);
combinedArray.push(array2)
}
}
genareteArray();
reArrangeArray();
console.log(combinedArray);
for (let i = 0; i < allSides.length; i++) {
const side = allSides[i];
for (let index = 0; index < 4; index++) {
var result = await combine(
[
combinedArray[0 + ind],
combinedArray[1 + ind],
combinedArray[2 + ind],
combinedArray[3 + ind],
], 512, 2048, 0, 512);
// result will be a column of 512 box
allImages.push(result);
if (allImages.length > 15) {
var r = await combine(allImages, 8192, 2048, 512, 0);
var img = new Image();
img.src = r;
document.body.appendChild(img);
}
ind = ind + 4;
}
}
}
generateParonama(10);
It is not the most efficient way of using promises. I only used async-await feature to make sure image components are getting loaded in sequence.
As an example this solution might be made more efficient by using Promise.All API (you can it by altering my code)

Having problem in doing operations on values after asynchronous calls

Here i'm calculation two values color and number after calculation i'm updating the values but this is not working
gameSchema.methods.computeBets = async function(){
const game = this;
const greenMultiplier = 2;
const voiletMultiplier = 4.5;
const redMultiplier = 2;
try {
const { gameType } = game;
let model = Schema;
gameType === 'Fast Parity' ? model = FastParity : model = SlowParity;
const gameDetails = await model.findOne({ gameId: game._id });
const { allPlayerBettedBetId } = gameDetails;
let color = {};
let number = {};
await Promise.all(allPlayerBettedBetId.map(async(bet) => {
const betdetails = await UserBet.findById(bet._id);
const { colorBettedOn, numberBettedOn,amountBetted,betType} = betdetails;
// console.log(colorBettedOn, numberBettedOn, amountBetted);
if(betType==='color')
color[colorBettedOn] = color[colorBettedOn] ? color[colorBettedOn] + amountBetted : amountBetted;
if(betType==='number')
number[numberBettedOn] = number[numberBettedOn] ? number[numberBettedOn] + amountBetted : amountBetted;
}));
console.log(color, number);
color.forEach(item => {
if (item.green)
item.green *= greenMultiplier;
if (item.red)
item.red *= redMultiplier;
if (item.voilet)
item.voilet *= voiletMultiplier;
});
let colorCombination = {
"green": color.green,
"green/voilet": color.green+(color.voilet/2),
"red/voilet": color.red+(color.voilet/2),
"red": color.red
};
number.forEach(item => {
item.value *= 2;
})
console.log(number,colorCombination)
return { number, colorCombination };
after await Promise.all console.log(number,color) is working but when i'm updating the values they are not working.I'm not good at async function as i don't have much exprience in that.what mistake i'm doing in the forEach functions

Accessing mobile IP Camera using react

I want to access my mobile ip camera instead of using webcam. I tried to set the ip address in the ref attribute but it doesn't show anything I also try to set the localhost address to ref but it still doesn't show anything. This code is for gun detection it works only in web cam mode I want to use the mobile IP Camera instead of webcam. I am using my mobile camera as an IP camera and want to access that specific camera but everytime it shows me the webcam of my laptop. I tried to set the value of this.video.current.srcObject to the ip of my camera and also try to assign it the localhost address but it still doesn't work.
import React from 'react'
import * as tf from '#tensorflow/tfjs'
import './styles.css'
const LABELS = '/model/labels.json'
const MODEL = '/model/tensorflowjs_model.pb'
const WEIGHTS_URL = '/model/weights_manifest.json'
var obj;
const TFWrapper = model => {
const calculateMaxScores = (scores, numBoxes, numClasses) => {
const maxes = []
const classes = []
for (let i = 0; i < numBoxes; i++) {
let max = Number.MIN_VALUE
let index = -1
for (let j = 0; j < numClasses; j++) {
if (scores[i * numClasses + j] > max) {
max = scores[i * numClasses + j]
index = j
}
}
maxes[i] = max
classes[i] = index
}
return [maxes, classes]
}
const buildDetectedObjects = (width,height,boxes,scores,indexes,classes) => {
const count = indexes.length
const objects = []
for (let i = 0; i < count; i++) {
const bbox = []
for (let j = 0; j < 4; j++) {
bbox[j] = boxes[indexes[i] * 4 + j]
}
const minY = bbox[0] * height
const minX = bbox[1] * width
const maxY = bbox[2] * height
const maxX = bbox[3] * width
bbox[0] = minX
bbox[1] = minY
bbox[2] = maxX - minX
bbox[3] = maxY - minY
objects.push({
bbox: bbox,
class: classes[indexes[i]],
score: scores[indexes[i]]
})
}
return objects
}
const detect = input => {
const batched = tf.tidy(() => {
const img = tf.fromPixels(input)
// Reshape to a single-element batch so we can pass it to executeAsync
return img.expandDims(0)
})
const height = batched.shape[1]
const width = batched.shape[2]
return model.executeAsync(batched).then(result => {
const scores = result[0].dataSync()
const boxes = result[1].dataSync()
// clean the webgl tensors
batched.dispose()
tf.dispose(result)
const [maxScores, classes] = calculateMaxScores(
scores,
result[0].shape[1],
result[0].shape[2]
)
const indexTensor = tf.tidy(() => {
const boxes2 = tf.tensor2d(boxes, [
result[1].shape[1],
result[1].shape[3]
])
return tf.image.nonMaxSuppression(
boxes2,
maxScores,
20, // maxNumBoxes
0.1,
0.5
)
})
const indexes = indexTensor.dataSync()
indexTensor.dispose()
return buildDetectedObjects(width,height,boxes,maxScores,indexes,classes)
})
}
return {
detect: detect
}
}
class Detection extends React.Component {
videoRef = React.createRef()
canvasRef = React.createRef()
gunDetected = false
componentDidMount() {
if (navigator.mediaDevices) {
const webCamPromise = navigator.mediaDevices
.getUserMedia({
audio: false,
video: {
facingMode: 'user'
}
})
.then(stream => {
window.stream = stream
this.videoRef.current.srcObject = stream
return new Promise((resolve, _) => {
this.videoRef.current.onloadedmetadata = () => {
resolve()
}
})
})
const modelPromise = tf.loadFrozenModel(MODEL, WEIGHTS_URL)
const labelsPromise = fetch(LABELS).then(data => data.json())
Promise.all([modelPromise, labelsPromise, webCamPromise])
.then(values => {
const [model, labels] = values
this.detectFrame(this.videoRef.current, model, labels)
})
.catch(error => {
console.error(error)
})
}
}
setRef = webcam => {
this.webcam = webcam;
};
detectFrame = (video, model, labels) => {
TFWrapper(model)
.detect(video)
.then(predictions => {
this.renderPredictions(predictions, labels)
requestAnimationFrame(() => {
this.detectFrame(video, model, labels)
})
})
}
renderPredictions = (predictions, labels) => {
const ctx = this.canvasRef.current.getContext('2d')
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
// Font options.
const font = '20px sans-serif'
ctx.font = font
ctx.textBaseline = 'top'
predictions.forEach(prediction => {
const x = prediction.bbox[0]
const y = prediction.bbox[1]
const width = prediction.bbox[2]
const height = prediction.bbox[3]
const label = labels[parseInt(prediction.class)]
obj=label;
console.log(obj) //returning GUN
//Bounding Box Styling s
ctx.strokeStyle = '#FF0000'
ctx.lineWidth = 5
ctx.strokeRect(x, y, width, height)
//Label Background Styling
ctx.fillStyle = '#FF0000'
const textWidth = ctx.measureText(label).width
const textHeight = parseInt(font, 0)
ctx.fillRect(x, y, textWidth, textHeight)
})
predictions.forEach(prediction => {
const x = prediction.bbox[0]
const y = prediction.bbox[1]
const label = labels[parseInt(prediction.class)]
// Draw the text last to ensure it's on top.
ctx.fillStyle = '#000000'
ctx.fillText(label, x, y)
})
}
render() {
return (
<div>
<video
className="size"
autoPlay
playsInline
muted
ref={this.videoRef}
width="800"
height="500"
/>
<canvas
className="size"
ref={this.canvasRef}
width="800"
height="500"
/>
</div>
)
}
}
export default Detection;

How to fix similar predictions in tenserflow.js

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 to change voice pitch without noise using web audio javascript?

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.

Categories

Resources