xxxxxxxxxx
215
/*
* Main Sketch
* Jack B. Du (github@jackbdup)
* https://instagram.com/jackbdu/
*/
// Todos:
// [ ] add clearing option
// - multiple events are tricky
// [ ] fine tune pinch detection threshold
// [x] put nodes in an array and draw with a for loop instead of recursive
const sketch = ( p ) => {
p.specs = {
fps: 60,
numLoopFrames: 120,
backgroundColor: 0,
outputWidth: 'auto',
outputHeight: 'auto',
}
p.options = {
sound: {
midiScale: [60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84],
noteIndices: [0, 2, 4, 5, 7, 9, 11, 12, 14, 16, 17, 19, 21, 23, 24], // major
// noteIndices: [0, 2, 3, 5, 7, 8, 10, 12, 14, 15, 17, 19, 20, 22, 24], // minor
bpm: 960,
interval: '16n',
synth: {
maxPolyphony: 32,
// voice: Tone.MembraneSynth,
// voice: Tone.AMSynth,
},
meter: {
smoothing: 0.9,
normalRange: true,
channels: 1,
},
},
node: {
diameter: 0.1,
},
ui: {
fontUrl: 'assets/Ubuntu-Bold.ttf',
messages: {
loading: 'Loading...',
welcome: 'Pinch to Start!',
},
textColor: 255,
// showFrameRate: true,
},
ml5: {
minScore: 0.5,
pinchSensitivity: 0.5,
smoothness: 0.5, // data processing smoothness
countdownDuration: 500,
handpose: {
maxHands: 1,
runtime: "mediapipe",
modelType: "full",
solutionPath: "https://cdn.jsdelivr.net/npm/@mediapipe/hands",
},
// isDebugging: true,
},
video: {
pixelationShortSideNum: 24,
pixelationStyle: 0,
isMirrored: true,
fit: p.COVER,
},
};
p.uiManager = uiManager;
p.soundManager = soundManager;
p.nodeManager = nodeManager;
p.videoManager = videoManager;
p.ml5Manager = ml5Manager;
p.preload = () => {
p.uiManager.preload(p.options.ui);
};
p.setup = () => {
p.updateCanvas(p.specs.outputWidth, p.specs.outputHeight);
p.frameRate(p.specs.fps);
p.smooth();
p.nodeManager.setup(p.width, p.height, p.options.node);
p.videoManager.setup(p.width, p.height, {p.options.video, video: p.VIDEO});
p.ml5Manager.setup({p.options.ml5, graphics: p.videoManager.captureGraphics});
p.uiManager.setup(p.width, p.height, p.options.ui);
p.soundManager.setup(p.options.sound);
};
p.draw = () => {
if (p.beforeDraw) p.beforeDraw();
p.videoManager.display(p.options.video);
p.ml5Manager.update(p.millis());
// const [mouseX, mouseY] = p.convertMousePosition(p.mouseX, p.mouseY);
// p.nodeManager.update(p.mouseIsPressed, mouseX, mouseY, p.millis());
const [handX, handY] = p.convertMousePosition(p.ml5Manager.handX, p.ml5Manager.handY);
const thumbIndexDistance = p.ml5Manager.thumbIndexDistance;
const status = p.ml5Manager.status;
p.nodeManager.update(p.ml5Manager.thumbIndexStatus === 'pinched', handX, handY, p.millis());
p.uiManager.update(handX, handY, thumbIndexDistance, status, p.ml5Manager.timer.progress);
p.nodeManager.drawNodes(p.soundManager.activeMelody, p.soundManager.meter);
// p.circle(p.ml5Manager.handX, p.ml5Manager.handY, 100);
// p.ml5Manager.update();
p.uiManager.display();
if (p.afterDraw) p.afterDraw();
};
p.ml5Manager.handPinched = (event) => {
const [handX, handY] = p.convertMousePosition(event.x, event.y);
const percentageY = 1-event.y/p.height;
p.nodeManager.mousePressed(handX, handY, p.soundManager.getNoteByPercentage(percentageY), p.millis());
p.uiManager.mousePressed(event);
};
p.ml5Manager.handDragged = (event) => {
const [handX, handY] = p.convertMousePosition(event.x, event.y);
const percentageY = 1-event.y/p.height;
p.nodeManager.mouseDragged(handX, handY, p.soundManager.getNoteByPercentage(percentageY), p.millis());
};
p.ml5Manager.handUnpinched = (event) => {
if (!p.soundManager.activeMelody) {
p.soundManager.activeMelody = p.nodeManager.melodies[0];
p.soundManager.nextMelody = p.soundManager.activeMelody;
Tone.Transport.start();
}
// p.soundManager.playNode(p.soundManager.nextMelody, Tone.now());
};
p.ml5Manager.handSpread = (event) => {
p.nodeManager.clear();
p.soundManager.clear();
};
p.ml5Manager.handUnspread = (event) => {
};
// p.mousePressed = (event) => {
// const [mouseX, mouseY] = p.convertMousePosition(event.x, event.y);
// const percentageY = 1-event.y/p.height;
// p.nodeManager.mousePressed(mouseX, mouseY, p.soundManager.getNoteByPercentage(percentageY), p.millis());
// p.uiManager.mousePressed(event);
// }
// p.mouseDragged = (event) => {
// const [mouseX, mouseY] = p.convertMousePosition(event.x, event.y);
// const percentageY = 1-event.y/p.height;
// p.nodeManager.mouseDragged(mouseX, mouseY, p.soundManager.getNoteByPercentage(percentageY), p.millis());
// }
// p.mouseReleased = (event) => {
// if (!p.soundManager.activeMelody) {
// p.soundManager.activeMelody = p.nodeManager.melodies[0];
// p.soundManager.nextMelody = p.soundManager.activeMelody;
// Tone.Transport.start();
// }
// // p.soundManager.playNode(p.soundManager.nextMelody, Tone.now());
// }
p.convertMousePosition = (mx, my) => {
const mouseX = p.map(mx, 0, p.width, -p.width/2, p.width/2)
const mouseY = p.map(my, 0, p.height, -p.height/2, p.height/2)
return [mouseX, mouseY];
}
p.beforeDraw = () => {
if (p.beginCapture) p.beginCapture();
p.background(p.specs.backgroundColor);
}
p.afterDraw = () => {
if (p.endCapture) p.endCapture();
}
p.windowResized = () => {
p.updateCanvas(p.specs.outputWidth, p.specs.outputHeight);
p.nodeManager.updateRefSize(p.width, p.height);
p.uiManager.updateRefSize(p.width, p.height);
p.videoManager.updateDimensions(p.width, p.height);
}
p.updateCanvas = (outputWidth = 'auto', outputHeight = 'auto') => {
const pd = p.pixelDensity();
const canvasWidth = outputWidth && outputWidth !== 'auto' ? outputWidth/pd : p.windowWidth;
const canvasHeight = outputHeight && outputHeight !== 'auto' ? outputHeight/pd : p.windowHeight;
if (canvasWidth !== p.width || canvasHeight !== p.height) {
if (!p.hasCanvas) {
p.createCanvas(canvasWidth, canvasHeight, p.WEBGL);
p.hasCanvas = true;
} else {
p.resizeCanvas(canvasWidth, canvasHeight);
}
}
}
};
// workaround for ml5-next-gen in p5 instance mode
window._incrementPreload = () => {
console.log("ml5.bodypose called window._incrementPreload");
};
window._decrementPreload = () => {
console.log("ml5.bodypose called window._decrementPreload");
};
const p = new p5(sketch);