I'm new to both languages, and I'm trying to convert this program I found on github and edited, to p5.js so I can include it in a webpage. I tried following guides and replacing void() with function(), int i with var i etc.. but there seems to be something wrong. The first code is the original .pde and the second one is my attempt at converting it. Many thanks!
final int STAGE_WIDTH = 1200;
final int STAGE_HEIGHT = 950;
final int NB_PARTICLES = 60000;
final float MAX_PARTICLE_SPEED = 5;
final int MIN_LIFE_TIME = 20;
final int MAX_LIFE_TIME = 80;
final String IMAGE_PATH = "starrynight.jpg";
myVector tabParticles[];
float particleSize = 1.2;
PImage myImage;
int imageW;
int imageH;
color myPixels[];
FlowField ff;
GUI gui;
void setup()
{
size(1200, 950, P3D);
background(0);
initializeImage();
initializeParticles();
ff = new FlowField(5);
gui = new GUI(this);
gui.setup();
}
void initializeImage()
{
myImage = loadImage(IMAGE_PATH);
imageW = myImage.width;
imageH = myImage.height;
myPixels = new color[imageW * imageH];
myImage.loadPixels();
myPixels = myImage.pixels;
image(myImage, 0, 0);
}
void setParticle(int i) {
tabParticles[i] = new myVector((int)random(imageW), (int)random(imageH));
tabParticles[i].prevX = tabParticles[i].x;
tabParticles[i].prevY = tabParticles[i].y;
tabParticles[i].count = (int)random(MIN_LIFE_TIME, MAX_LIFE_TIME);
tabParticles[i].myColor = myPixels[(int)(tabParticles[i].y)*imageW + (int)(tabParticles[i].x)];
}
void initializeParticles()
{
tabParticles = new myVector[NB_PARTICLES];
for (int i = 0; i < NB_PARTICLES; i++)
{
setParticle(i);
}
}
void draw()
{
ff.setRadius(gui.getR());
ff.setForce(gui.getF());
particleSize = gui.getS();
float vx;
float vy;
PVector v;
for (int i = 0; i < NB_PARTICLES; i++)
{
tabParticles[i].prevX = tabParticles[i].x;
tabParticles[i].prevY = tabParticles[i].y;
v = ff.lookup(tabParticles[i].x, tabParticles[i].y);
vx = v.x;
vy = v.y;
vx = constrain(vx, -MAX_PARTICLE_SPEED, MAX_PARTICLE_SPEED);
vy = constrain(vy, -MAX_PARTICLE_SPEED, MAX_PARTICLE_SPEED);
tabParticles[i].x += vx;
tabParticles[i].y += vy;
tabParticles[i].count--;
if ((tabParticles[i].x < 0) || (tabParticles[i].x > imageW-1) ||
(tabParticles[i].y < 0) || (tabParticles[i].y > imageH-1) ||
tabParticles[i].count < 0) {
setParticle(i);
}
strokeWeight(1.5*particleSize);
stroke(tabParticles[i].myColor, 250);
line(tabParticles[i].prevX, tabParticles[i].prevY, tabParticles[i].x, tabParticles[i].y);
}
ff.updateField();
}
void mouseDragged() {
if(mouseX>950 && mouseY>830) return;
ff.onMouseDrag();
}
void keyPressed() {
//if (key =='s' || key == 'S') {
// ff.saveField();
//}
}
class myVector extends PVector
{
myVector (float p_x, float p_y) {
super(p_x, p_y);
}
float prevX;
float prevY;
int count;
color myColor;
}
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
class FlowField {
PVector[][] field;
PVector[][] tempField;
int cols, rows;
int resolution;
int affectRadius;
float force;
File file = new File(dataPath("field.txt"));
FlowField(int r) {
resolution = r;
cols = 1200 / resolution;
rows = 950 / resolution;
field = new PVector[cols][rows];
tempField = new PVector[cols][rows];
init();
affectRadius = 3;
force = 1;
}
void setRadius(int r) {
affectRadius = r;
}
void setForce(float f) {
force = f;
}
void init() {
try {
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
tempField[i][j] = new PVector(0, 0);
}
}
readField();
}
catch(Exception e) {
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
field[i][j] = new PVector(0, 0);
}
}
}
}
PVector lookup(float x, float y) {
int column = int(constrain(x/resolution, 0, cols-1));
int row = int(constrain(y/resolution, 0, rows-1));
return PVector.add(field[column][row],tempField[column][row]);
}
void drawBrush() {
pushStyle();
noFill();
stroke(255, 255, 255);
ellipse(mouseX, mouseY, affectRadius*10, affectRadius*10);
popStyle();
}
void drawField(float x, float y, PVector v) {
int column = int(constrain(x/resolution, 0, cols-1));
int row = int(constrain(y/resolution, 0, rows-1));
for (int i=-affectRadius; i<=affectRadius; i++) {
for (int j=-affectRadius; j<=affectRadius; j++) {
if (i*i+j*j<affectRadius*affectRadius) {
try {
tempField[column+i][row+j].add(v).mult(0.9);
}
catch(Exception e) {
}
}
}
}
}
void updateField(){
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
tempField[i][j].mult(0.992);
}
}
}
void onMouseDrag() {
PVector direc = new PVector(mouseX-pmouseX, mouseY-pmouseY).normalize();
drawField(pmouseX, pmouseY, direc.mult(force));
}
void saveField() {
try {
FileWriter out = new FileWriter(file);
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
out.write(field[i][j].x+","+field[i][j].y+"\t");
}
out.write("\r\n");
}
out.close();
}
catch(Exception e) {
}
}
void readField() throws IOException {
try {
BufferedReader in = new BufferedReader(new FileReader(file));
String line;
for (int i = 0; (line = in.readLine()) != null; i++) {
String[] temp = line.split("\t");
for (int j=0; j<temp.length; j++) {
String[] xy = temp[j].split(",");
float x = Float.parseFloat(xy[0]);
float y = Float.parseFloat(xy[1]);
field[i][j] = new PVector(x, y);
}
}
in.close();
}
catch(Exception e) {
throw new IOException("no field.txt");
}
}
}
import controlP5.*;
class GUI {
ControlP5 cp5;
Slider sliderR;
Slider sliderF;
Slider sliderS;
GUI(PApplet thePApplet){
cp5 = new ControlP5(thePApplet);
}
void setup(){
cp5.setColorBackground(0x141414);
sliderR = cp5.addSlider("Radius")
.setPosition(980,890)
.setRange(1,20)
.setValue(12).setSize(150,25);
sliderF = cp5.addSlider("Force")
.setPosition(980,918)
.setRange(0.1,0.5)
.setValue(0.3).setSize(150,25);
sliderS = cp5.addSlider("Particle Size")
.setPosition(980,862)
.setRange(0.8,2)
.setValue(1.5).setSize(150,25);
}
int getR(){
return int(sliderR.getValue());
}
float getF(){
return sliderF.getValue();
}
float getS(){
return sliderS.getValue();
}
}
final var STAGE_WIDTH = 1200;
final var STAGE_HEIGHT = 950;
final var NB_PARTICLES = 60000;
final let MAX_PARTICLE_SPEED = 5;
final var MIN_LIFE_TIME = 20;
final var MAX_LIFE_TIME = 80;
final let IMAGE_PATH = "starrynight.jpg";
myVector tabParticles[];
let particleSize = 1.2;
PImage myImage;
var imageW;
var imageH;
color myPixels[];
FlowField ff;
GUI gui;
function setup()
{
var canvas = createCanvas(1200, 950, P3D);
canvas.parent('canvasForHTML');
background(0);
initializeImage();
initializeParticles();
ff = new FlowField(5);
gui = new GUI(this);
gui.setup();
}
function preload() { img = loadImage('data/starrynight.jpg');
}
function initializeImage()
{ imageW = myImage.width;
imageH = myImage.height;
myPixels = new color[imageW * imageH];
myImage.loadPixels();
myPixels = myImage.pixels;
image(myImage, 0, 0);
}
function setParticle(var i) {
tabParticles[i] = new myVector((var)random(imageW), (var)random(imageH));
tabParticles[i].prevX = tabParticles[i].x;
tabParticles[i].prevY = tabParticles[i].y;
tabParticles[i].count = (var)random(MIN_LIFE_TIME, MAX_LIFE_TIME);
tabParticles[i].myColor = myPixels[(var)(tabParticles[i].y)*imageW + (var)(tabParticles[i].x)];
}
function initializeParticles()
{
tabParticles = new myVector[NB_PARTICLES];
for (var i = 0; i < NB_PARTICLES; i++)
{
setParticle(i);
}
}
function draw()
{
ff.setRadius(gui.getR());
ff.setForce(gui.getF());
particleSize = gui.getS();
let vx;
let vy;
PVector v;
for (var i = 0; i < NB_PARTICLES; i++)
{
tabParticles[i].prevX = tabParticles[i].x;
tabParticles[i].prevY = tabParticles[i].y;
v = ff.lookup(tabParticles[i].x, tabParticles[i].y);
vx = v.x;
vy = v.y;
vx = constrain(vx, -MAX_PARTICLE_SPEED, MAX_PARTICLE_SPEED);
vy = constrain(vy, -MAX_PARTICLE_SPEED, MAX_PARTICLE_SPEED);
tabParticles[i].x += vx;
tabParticles[i].y += vy;
tabParticles[i].count--;
if ((tabParticles[i].x < 0) || (tabParticles[i].x > imageW-1) ||
(tabParticles[i].y < 0) || (tabParticles[i].y > imageH-1) ||
tabParticles[i].count < 0) {
setParticle(i);
}
strokeWeight(1.5*particleSize);
stroke(tabParticles[i].myColor, 250);
line(tabParticles[i].prevX, tabParticles[i].prevY, tabParticles[i].x, tabParticles[i].y);
}
ff.updateField();
}
function mouseDragged() {
if(mouseX>950 && mouseY>830) return;
ff.onMouseDrag();
}
function keyPressed() {
//if (key =='s' || key == 'S') {
// ff.saveField();
//}
}
class myVector extends PVector
{
myVector (let p_x, let p_y) {
super(p_x, p_y);
}
let prevX;
let prevY;
var count;
color myColor;
}
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
class FlowField {
PVector[][] field;
PVector[][] tempField;
var cols, rows;
var resolution;
var affectRadius;
let force;
File file = new File(dataPath("field.txt"));
FlowField(var r) {
resolution = r;
cols = 1200 / resolution;
rows = 950 / resolution;
field = new PVector[cols][rows];
tempField = new PVector[cols][rows];
init();
affectRadius = 3;
force = 1;
}
function setRadius(var r) {
affectRadius = r;
}
function setForce(let f) {
force = f;
}
function init() {
try {
for (var i=0; i<cols; i++) {
for (var j=0; j<rows; j++) {
tempField[i][j] = new PVector(0, 0);
}
}
readField();
}
catch(Exception e) {
for (var i=0; i<cols; i++) {
for (var j=0; j<rows; j++) {
field[i][j] = new PVector(0, 0);
}
}
}
}
PVector lookup(let x, let y) {
var column = var(constrain(x/resolution, 0, cols-1));
var row = var(constrain(y/resolution, 0, rows-1));
return PVector.add(field[column][row],tempField[column][row]);
}
function drawBrush() {
pushStyle();
noFill();
stroke(255, 255, 255);
ellipse(mouseX, mouseY, affectRadius*10, affectRadius*10);
popStyle();
}
function drawField(let x, let y, PVector v) {
var column = var(constrain(x/resolution, 0, cols-1));
var row = var(constrain(y/resolution, 0, rows-1));
for (var i=-affectRadius; i<=affectRadius; i++) {
for (var j=-affectRadius; j<=affectRadius; j++) {
if (i*i+j*j<affectRadius*affectRadius) {
try {
tempField[column+i][row+j].add(v).mult(0.9);
}
catch(Exception e) {
}
}
}
}
}
function updateField(){
for (var i=0; i<cols; i++) {
for (var j=0; j<rows; j++) {
tempField[i][j].mult(0.992);
}
}
}
function onMouseDrag() {
PVector direc = new PVector(mouseX-pmouseX, mouseY-pmouseY).normalize();
drawField(pmouseX, pmouseY, direc.mult(force));
}
function saveField() {
try {
FileWriter out = new FileWriter(file);
for (var i=0; i<cols; i++) {
for (var j=0; j<rows; j++) {
out.write(field[i][j].x+","+field[i][j].y+"\t");
}
out.write("\r\n");
}
out.close();
}
catch(Exception e) {
}
}
function readField() throws IOException {
try {
BufferedReader in = new BufferedReader(new FileReader(file));
let line;
for (var i = 0; (line = in.readLine()) != null; i++) {
let[] temp = line.split("\t");
for (var j=0; j<temp.length; j++) {
let[] xy = temp[j].split(",");
let x = let.parselet(xy[0]);
let y = let.parselet(xy[1]);
field[i][j] = new PVector(x, y);
}
}
in.close();
}
catch(Exception e) {
throw new IOException("no field.txt");
}
}
}
import controlP5.*;
class GUI {
ControlP5 cp5;
Slider sliderR;
Slider sliderF;
Slider sliderS;
GUI(PApplet thePApplet){
cp5 = new ControlP5(thePApplet);
}
function setup(){
cp5.setColorBackground(0x141414);
sliderR = cp5.addSlider("Radius")
.setPosition(980,890)
.setRange(1,20)
.setValue(12).setSize(150,25);
sliderF = cp5.addSlider("Force")
.setPosition(980,918)
.setRange(0.1,0.5)
.setValue(0.3).setSize(150,25);
sliderS = cp5.addSlider("Particle Size")
.setPosition(980,862)
.setRange(0.8,2)
.setValue(1.5).setSize(150,25);
}
var getR(){
return var(sliderR.getValue());
}
let getF(){
return sliderF.getValue();
}
let getS(){
return sliderS.getValue();
}
}
I felt like doing nothing this evening, so here you go:
Also, I recommend getting the "Better Comments" extension/plugin for your code editor of choice, since I used those here a lot
const STAGE_WIDTH = 1200;
const STAGE_HEIGHT = 950;
const NB_PARTICLES = 60000;
const MAX_PARTICLE_SPEED = 5;
const MIN_LIFE_TIME = 20;
const MAX_LIFE_TIME = 80;
const IMAGE_PATH = "starrynight.jpg";
let tabParticles = [];
let particleSize = 1.2;
let myImage;
let imageW;
let imageH;
let myPixels = [];
let ff;
let gui;
function setup()
{
size(1200, 950, WEBGL);
background(0);
initializeImage();
initializeParticles();
ff = new FlowField(5);
// ! CHANGE THIS AND ALL OF THE OTHER GUI STUFF THAT COME AFTER IT!
// gui = new GUI(this);
// gui.setup();
}
function initializeImage()
{
myImage = loadImage(IMAGE_PATH);
imageW = myImage.width;
imageH = myImage.height;
myPixels = new color[imageW * imageH]; // ? dunno
// myImage.loadPixels();
// myPixels = myImage.pixels;
image(myImage, 0, 0);
}
function setParticle(i) {
tabParticles[i] = new myVector(random(imageW), random(imageH));
tabParticles[i].prevX = tabParticles[i].x;
tabParticles[i].prevY = tabParticles[i].y;
tabParticles[i].count = random(MIN_LIFE_TIME, MAX_LIFE_TIME);
tabParticles[i].myColor = myPixels[(int)(tabParticles[i].y)*imageW + (int)(tabParticles[i].x)];
}
function initializeParticles()
{
// tabParticles = new myVector[NB_PARTICLES];
for(let i = 0; i < NB_PARTICLES; i ++)
tabParticles.push(new myVector())
for (let i = 0; i < NB_PARTICLES; i++)
{
setParticle(i);
}
}
function draw()
{
ff.setRadius(gui.getR());
ff.setForce(gui.getF());
particleSize = gui.getS();
let vx;
let vy;
let v;
for (let i = 0; i < NB_PARTICLES; i++)
{
tabParticles[i].prevX = tabParticles[i].x;
tabParticles[i].prevY = tabParticles[i].y;
v = ff.lookup(tabParticles[i].x, tabParticles[i].y);
vx = v.x;
vy = v.y;
vx = constrain(vx, -MAX_PARTICLE_SPEED, MAX_PARTICLE_SPEED);
vy = constrain(vy, -MAX_PARTICLE_SPEED, MAX_PARTICLE_SPEED);
tabParticles[i].x += vx;
tabParticles[i].y += vy;
tabParticles[i].count--;
if ((tabParticles[i].x < 0) || (tabParticles[i].x > imageW-1) ||
(tabParticles[i].y < 0) || (tabParticles[i].y > imageH-1) ||
tabParticles[i].count < 0) {
setParticle(i);
}
strokeWeight(1.5*particleSize);
stroke(tabParticles[i].myColor, 250);
line(tabParticles[i].prevX, tabParticles[i].prevY, tabParticles[i].x, tabParticles[i].y);
}
ff.updateField();
}
function mouseDragged() {
if(mouseX>950 && mouseY>830) return;
ff.onMouseDrag();
}
function keyPressed() {
//if (key =='s' || key == 'S') {
// ff.saveField();
//}
}
class myVector extends PVector
{
constructor (p_x, p_y) {
super(p_x, p_y);
this.prevX
this.prevY
this.count
this.myColor
}
}
class FlowField {
constructor(r) {
this.field; // PVector[][]
this.tempField; // PVector[][]
this.cols; this.rows; // int
this.resolution; // int
this.affectRadius; // int
this.force; // float
this.file = new File(dataPath("field.txt")); // File
// ! You'll need to have a preload loadStrings(filepath) or fetch(filename).then(blob => blob.text()).then(text => ... )
// ! can't be bothered to do this right now
throw "Ult1: change this!!! also delete this line (just incase: ~129th line)"
resolution = r;
cols = 1200 / resolution;
rows = 950 / resolution;
field = new PVector[cols][rows];
tempField = new PVector[cols][rows];
init();
affectRadius = 3;
force = 1;
}
setRadius(r) {
affectRadius = r;
}
setForce(f) {
force = f;
}
// FROM HERE ON I CONVERTED IT WHILE HALF ASLEEP (11pm)
init() {
try {
for (let i=0; i<cols; i++) {
for (let j=0; j<rows; j++) {
tempField[i][j] = createVector()
}
}
readField();
}
catch(e) {
for (let i=0; i<cols; i++) {
for (let j=0; j<rows; j++) {
field[i][j] = createVector()
}
}
}
}
lookup(x, y) {
let column = int(constrain(x/resolution, 0, cols-1));
let row = int(constrain(y/resolution, 0, rows-1));
return p5.Vector.add(field[column][row],tempField[column][row]);
}
drawBrush() {
pushStyle();
noFill();
stroke(255, 255, 255);
ellipse(mouseX, mouseY, affectRadius*10, affectRadius*10);
popStyle();
}
drawField(x, y, v) {
let column = int(constrain(x/resolution, 0, cols-1));
let row = int(constrain(y/resolution, 0, rows-1));
for (let i=-affectRadius; i<=affectRadius; i++) {
for (let j=-affectRadius; j<=affectRadius; j++) {
if (i*i+j*j<affectRadius*affectRadius) {
try {
tempField[column+i][row+j].add(v).mult(0.9);
}
catch(e) {
}
}
}
}
}
updateField(){
for (let i=0; i<cols; i++) {
for (let j=0; j<rows; j++) {
tempField[i][j].mult(0.992);
}
}
}
onMouseDrag() {
let direc = createVector(mouseX-pmouseX, mouseY-pmouseY).normalize()
drawField(pmouseX, pmouseY, direc.mult(force));
}
saveField() {
try {
// FileWriter out = new FileWriter(file);
throw "FileWriter doesn't exist in Javascript, line: 215"
// ! this doesn't exist! in javascript, I don't remember how to do this, but you can just search it on Google
for (let i=0; i<cols; i++) {
for (let j=0; j<rows; j++) {
out.write(field[i][j].x+","+field[i][j].y+"\t");
}
out.write("\r\n");
}
out.close();
}
catch(e) {
}
}
readField() {
throw "once again, BufferedReader is just not a thing, but it's for file reading, so you can just loadString(\"file\") or fetch... line: 230"
try {
let _in = new BufferedReader(new FileReader(file));
let line;
for (let i = 0; (line = _in.readLine()) != null; i++) {
let temp = line.split("\t");
for (let j=0; j<temp.length; j++) {
let xy = temp[j].split(",");
let x = Float.parseFloat(xy[0]);
let y = Float.parseFloat(xy[1]);
field[i][j] = createVector(x, y);
}
}
_in.close();
}
catch(e) {
throw new IOException("no field.txt");
}
}
}
// I think you should just do this with html to be honest
// copy this into your body (below the <script src="sketch.js"></script>, or above it):
/*
<div id="GUI">
<label for="Radius">Radius</label>
<input type="range" name="Radius" id="slider-radius" min="1" max="20" step="0.5" value="10">
<br>
<label for="Force">Force</label>
<input type="range" name="Force" id="slider-force" min="0.1" max="0.5" step="0.01" value="0.3">
<br>
<label for="Particle-size">Particle size</label>
<input type="range" name="Particle-size" id="slider-particle-size" min="0.8" max="2" step="0.05" value="1.5">
</div>
<style>
html, body {
background-color: #141414;
}
label {
color: #ccc;
}
</style>
*/
// color: #ccc is the same as text-color = #CCCCCC in some other language, maybe...
class GUI {
constructor(){
throw "don't declare the GUI class, instead do GUI.getR(), GUI.getF() ... line: 288, you should be able to see line # in your console"
}
static getR(){
return document.getElementById("slider-radius").value;
}
static getF(){
return document.getElementById("slider-force").value
}
static getS(){
return document.getElementById("slider-particle-size").value
}
}
// static = same between ALL the classes(instances) of a class thing, so:
// class A { static x = 7; this.y = 5 }
// * console.log(A.x) -> 7
// ! console.log(A.y) -> probably null, since you need to do console.log(new A().y)
// here I have it to keep the GUI class, but there is no need to keep this stuff
You will still need to do A LOT of work to get this going, like translating classes, for example class myVector extends PVector {...}. In p5.js there is no PVector, but I'm pretty sure there's p5.Vector though, so class myVector extends p5.Vector might work. File reading and writing will also be messed up, since JavaScript doesn't have the whole new File() and all the stuff like that.
You will also need to deal with CORS, good luck! I also changed most of the GUI stuff to .html stuff and a static class, bit hard words there, but can't really change them to anything.
Anyways, I probably made mistakes here!
It's 11:40 pm here by now, so yeah! this is very more or less transferrrr
I am using the npm xlsx (lib/parserScripts/readExcel.js)
and threads module to read a large excel file.
This works fine for the first time but if I simultaneously upload another large file then I get an error
Error: channel closed
at ChildProcess.target.send (internal/child_process.js:554:16)
at Worker.send (/app/node_modules/threads/lib/worker.node/worker.js:108:16)...
This is maybe due to the previous threads are still processing /have not been killed hence when a new pool is made for another request the previous threads are still busy processing.
How to solve this? Do I have to manually terminate the threads in the below piece of code? If so then how?
index.js
parseFile: ['fileHeaders', (results, cb) => {
const excelParserScript = __dirname + '/../lib/parserScripts/readExcel';
const worksheetIndex = 3;
const params = {
file.path,
worksheetIndex
}
// using worker process
// result will be of the type {error: false, message: '', data: {}}
lib.miniWorker.bufferedJob(excelParserScript, params, (err, result) => {
lib/miniworker.js
const Threads = require('threads');
const Pool = Threads.Pool;
const workerPool = new Pool();
module.exports = class JobManager {
static bufferedJob(pathToScript, params, callback){
workerPool
.run(pathToScript)
.send(params)
.on('done', (result, input) => {
console.log(`Worker Job done: ${pathToScript} `);
callback(null, result);
})
.on('error', (job, error) => {
console.log(`Error in executing Worker Job: ${pathToScript}`);
callback(job || error);
})
}
}
lib/parserScripts/readExcel.js
module.exports = function(input, done) {
const XLSX = require('xlsx');
let workbook;
const path = input.path;
const worksheetIndex = input.worksheetIndex;
const expectedHeaders = input.expectedHeaders || [];
const options = {};
if (expectedHeaders.length > 0) {
options.header = expectedHeaders;
}
const response = {
error: false,
message: '',
data: {}
}
try {
workbook = XLSX.readFile(path, {});
const sheet = workbook['Sheets'][workbook.SheetNames[worksheetIndex]];
const headers = getHeaders(sheet);
const fileData = XLSX.utils.sheet_to_json(workbook['Sheets'][workbook.SheetNames[worksheetIndex]], options);
response.data = fileData;
response.headers = headers;
return done(response)
} catch (err) {
response.error = true;
response.messsage = 'Error in reading the file';
return done(response);
}
function getHeaders(sheet) {
var header = 0, offset = 1;
var hdr = [];
var o = {};
if (sheet == null || sheet["!ref"] == null) return [];
var range = o.range !== undefined ? o.range : sheet["!ref"];
var r;
if (o.header === 1) header = 1;
else if (o.header === "A") header = 2;
else if (Array.isArray(o.header)) header = 3;
switch (typeof range) {
case 'string':
r = safe_decode_range(range);
break;
case 'number':
r = safe_decode_range(sheet["!ref"]);
r.s.r = range;
break;
default:
r = range;
}
if (header > 0) offset = 0;
var rr = XLSX.utils.encode_row(r.s.r);
var cols = new Array(r.e.c - r.s.c + 1);
for (var C = r.s.c; C <= r.e.c; ++C) {
cols[C] = XLSX.utils.encode_col(C);
var val = sheet[cols[C] + rr];
switch (header) {
case 1:
hdr.push(C);
break;
case 2:
hdr.push(cols[C]);
break;
case 3:
hdr.push(o.header[C - r.s.c]);
break;
default:
if (val === undefined) continue;
hdr.push(XLSX.utils.format_cell(val));
}
}
return hdr;
}
function safe_decode_range(range) {
var o = {s: {c: 0, r: 0}, e: {c: 0, r: 0}};
var idx = 0, i = 0, cc = 0;
var len = range.length;
for (idx = 0; i < len; ++i) {
if ((cc = range.charCodeAt(i) - 64) < 1 || cc > 26) break;
idx = 26 * idx + cc;
}
o.s.c = --idx;
for (idx = 0; i < len; ++i) {
if ((cc = range.charCodeAt(i) - 48) < 0 || cc > 9) break;
idx = 10 * idx + cc;
}
o.s.r = --idx;
if (i === len || range.charCodeAt(++i) === 58) {
o.e.c = o.s.c;
o.e.r = o.s.r;
return o;
}
for (idx = 0; i != len; ++i) {
if ((cc = range.charCodeAt(i) - 64) < 1 || cc > 26) break;
idx = 26 * idx + cc;
}
o.e.c = --idx;
for (idx = 0; i != len; ++i) {
if ((cc = range.charCodeAt(i) - 48) < 0 || cc > 9) break;
idx = 10 * idx + cc;
}
o.e.r = --idx;
return o;
}
}
This works fine for the first time but if I simultaneously upload another large file then I get an error.
you should upload a different file name like a final01.xlsx and then rename it to final.xlsx
The reason being when you upload file the readfile cant finish as writing a file locks the file and change content.
If upload file means you are simultaneously reading another large file in node.js code ignore my comment.
The issue is because of the older version module of threads. Updating to the new version and using the updated API which is not event-based can solve the purpose.
https://github.com/andywer/threads.js/issues/164
However, if you want to correct the event-based code(from older version) this is what you need to do (kill the threads after the event gets completed).
const Threads = require('threads');
const Pool = Threads.Pool;
module.exports = class JobManager {
static bufferedJob(pathToScript, params, callback){
let workerPool = new Pool();
workerPool
.run(pathToScript)
.send(params)
.on('done', (result, input) => {
console.log(`Worker Job done: ${pathToScript} `);
callback(null, result);
workerPool.killAll();
workerPool = null ;
})
.on('error', (job, error) => {
console.log(`Error in executing Worker Job: ${pathToScript}`);
callback(job || error);
workerPool.killAll();
workerPool = null ;
}).on('abort', (job, error)=>{
console.log(`Abort Worker Job: ${pathToScript}, Error : ${error}`);
callback(job || error);
workerPool.killAll();
workerPool = null ;
}).on('finished', ()=>{
console.log('Everything done, shutting down the thread pool.');
workerPool.killAll();
});
}
}
I am working on JS pitch shifter for uploaded files.
As a part of my code I used this source:
https://github.com/urtzurd/html-audio
Now I'm stuck on export. So I can upload locally stored file, then pitch-shift it, but then I want to export it, but can not found a way to do this.
I tried recorder.js from here:
https://github.com/mattdiamond/Recorderjs
but it seems to work only for live recorded files and I want to specifically export uploaded file.
Here is my code.
var pitchShifter = (function() {
var audioContext,
audioSources = [],
pitchShifterProcessor,
spectrumAudioAnalyser,
sonogramAudioAnalyser;
var validPitchRatio = [0.5, 1.0, 1.5, 2.0],
pitchRatio = validPitchRatio[1],
grainSize = 512,
overlapRatio = 0.50,
spectrumFFTSize = 128,
spectrumSmoothing = 0.8,
sonogramFFTSize = 2048,
sonogramSmoothing = 0;
function BufferLoader(context, urlList, callback) {
this.context = context;
this.urlList = urlList;
this.onload = callback;
this.bufferList = new Array();
this.loadCount = 0;
}
BufferLoader.prototype.loadBuffer = function(url, index) {
// Load buffer asynchronously
var request = new XMLHttpRequest();
request.open("GET", url, true);
request.responseType = "arraybuffer";
var loader = this;
request.onload = function() {
// Asynchronously decode the audio file data in request.response
loader.context.decodeAudioData(request.response, function(buffer) {
if(!buffer) {
alert('error decoding file data: ' + url);
return;
}
loader.bufferList[index] = buffer;
if(++loader.loadCount == loader.urlList.length) loader.onload(loader.bufferList);
}, function(error) {
console.error('decodeAudioData error', error);
});
}
request.onerror = function() {
alert('BufferLoader: XHR error');
}
request.send();
}
BufferLoader.prototype.load = function() {
for(var i = 0; i < this.urlList.length; ++i) this.loadBuffer(this.urlList[i], i);
}
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;
};
initAudio = function() {
if(!navigator.webkitGetUserMedia) {
alert('Your browser does not support the Media Stream API');
} else {
navigator.webkitGetUserMedia({
audio: true,
video: false
}, function(stream) {
audioSources[1] = audioContext.createMediaStreamSource(stream);
}, function(error) {
alert('Unable to get the user media');
});
}
spectrumAudioAnalyser = audioContext.createAnalyser();
spectrumAudioAnalyser.fftSize = spectrumFFTSize;
spectrumAudioAnalyser.smoothingTimeConstant = spectrumSmoothing;
sonogramAudioAnalyser = audioContext.createAnalyser();
sonogramAudioAnalyser.fftSize = sonogramFFTSize;
sonogramAudioAnalyser.smoothingTimeConstant = sonogramSmoothing;
var bufferLoader = new BufferLoader(audioContext, ['audio/voice.mp3'], function(bufferList) {
audioSources[0] = audioContext.createBufferSource();
audioSources[0].buffer = bufferList[0];
audioSources[0].loop = false;
audioSources[0].connect(pitchShifterProcessor);
audioSources[0].start(0);
});
bufferLoader.load();
};
initProcessor = function() {
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(spectrumAudioAnalyser);
pitchShifterProcessor.connect(sonogramAudioAnalyser);
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;
}
initAudio();
initProcessor();
}
}
}());
window.addEventListener("DOMContentLoaded", pitchShifter.init, true);
Would like to hear any tips. Thank you!