xxxxxxxxxx
200
let video;
// let c, d, e, f, g, a, b
let c1, c2, c3, c4, c5, c6, c7;
let noteCircles = [];
let poseNet;
let pose;
let options = {
architecture: 'MobileNetV1',
imageScaleFactor: 0.3,
outputStride: 16,
flipHorizontal: true,
minConfidence: 0.5,
maxPoseDetections: 5,
scoreThreshold: 0.5,
nmsRadius: 20,
detectionType: 'multiple',
inputResolution: 513,
multiplier: 0.75,
quantBytes: 2,
};
let rwx, rwy;
let lwx, lwy;
function setup() {
createCanvas(640, 480);
video = createCapture(VIDEO);
video.hide();
// >>JHMOD
c1 = new GenericCircleNote(170, 320, "C4");
c2 = new GenericCircleNote(170, 220, "D4");
c3 = new GenericCircleNote(260, 120, "E4");
c4 = new GenericCircleNote(380, 120, "F4");
c5 = new GenericCircleNote(470, 220, "G4");
c6 = new GenericCircleNote(470, 320, "A5");
c7 = new GenericCircleNote(320, 410, "B5");
//Create array of notes for easier handling
noteCircles = [c1, c2, c3, c4, c5, c6, c7];
// <<JHMOD
poseNet = ml5.poseNet(video, options, 'flipHorizontal', modelLoaded);
poseNet.on('pose', gotPoses);
}
function gotPoses(poses) {
if (poses.length > 0) {
pose = poses[0].pose;
skeleton = poses[0].skeleton;
}
}
function modelLoaded() {
console.log('poseNet ready');
}
function draw() {
background(255)
push()
translate(video.width, 0);
//then scale it by -1 in the x-axis
//to flip the image
scale(-1, 1);
image(video, 0, 0)
pop()
if (pose) {
fill(255, 150, 100);
ellipse(pose.rightWrist.x, pose.rightWrist.y, 32);
rwx = pose.rightWrist.x;
rwy = pose.rightWrist.y;
ellipse(pose.leftWrist.x, pose.leftWrist.y, 32);
lwx = pose.leftWrist.x;
lwy = pose.leftWrist.y;
}
// >>>>>>>>>>>> JHMOD
for (let i = 0; i < noteCircles.length; i++) {
noteCircle = noteCircles[i];
//If there's a pose, check whether hand is overlapping:
if(pose){
noteCircle.detectOverlap(lwx, lwy, 16);
noteCircle.detectOverlap(rwx, rwy, 16);
}
//Regardless of pose data, we can perform the rest
//of the functions for this object:
noteCircle.handlePlayOrPause();
noteCircle.display();
//Handle end of frame (in this case
//just reset number of overlaps)
noteCircle.handleEndOfFrame()
}
// <<<<<<<<<<<< JHMOD
}
/*The idea with this class is to create an object that you
can put anywhere and it will interact with any x/y position
that you give to it. The object will store all the information
about where it is, what note to play, and how to interact,
BUT, unlike above, the object will not have any information about
/other/ notes, so there doesn't have to be a whole bunch of
'if' statements:
*/
class GenericCircleNote {
//pass in position and note value.
constructor(xPos, yPos, note) {
this.x = xPos;
this.y = yPos;
this.r = 50; //all circles are 50 for now
//Each object has its own synth, so you don't
//have to store a bunch of global synths
this.synth = new p5.MonoSynth();
//Each object also keeps track of the note it should play
this.note = note;
//Keep track of whether note is playing
this.isPlaying = false;
//Each frame count how many overlaps there are.
//If there are more than zero, play a note,
//if there are zero, then stop playing.
this.numberOfOverlaps = 0;
}
//Determine if other position overlaps circle
//and if so add to count.
detectOverlap(otherX, otherY, otherR) {
let distance = dist(this.x, this.y, otherX, otherY);
if (distance < this.r + otherR) {
this.numberOfOverlaps++;
}
}
/* This function starts playing if you note should be
playing, and stops playing if should be stopped */
handlePlayOrPause() {
//If you are not already playing this note,
if (!this.isPlaying) {
//Should you be playing this note?
if (this.numberOfOverlaps > 0) {
print("New note! Start playing!")
//If so, start playing this note:
this.synth.triggerAttack(this.note)
this.isPlaying = true;
}
}
//Otherwise (i.e. if you are already playing)
else {
//Should you stop playing (i.e. are there no overlaps)?
if (this.numberOfOverlaps == 0) {
print("No overlaps! Stop playing!")
//If so, stop playing:
this.synth.triggerRelease();
this.isPlaying = false;
}
}
}
display(){
fill(255, 0, 0);
noStroke();
ellipse(this.x, this.y, this.r, this.r)
}
//The end of frame resets the overlap counter
//and prepares the object for the next frame
handleEndOfFrame() {
this.numberOfOverlaps = 0;
}
}