https://experiments.withgoogle.com/ai/ai-duet/view/
AI Duet primarily uses Recurrent Neural Networks (RNNs), specifically Long Short-Term Memory (LSTM) networks. The model was trained by a large number of MIDI files. These MIDI files encode music in a format that specifies the pitch, intensity, and duration of each note played. LSTMs are particularly well-suited for tasks that involve predictions based on time series data, which is a natural fit for music to create notes after the user input their notes.
I changed the wrist position into index finger position this week.
https://editor.p5js.org/YuhongSun/sketches/K3qdQEiXl
let handPose;
let video;
let hands = [];
let squares = [];
let score = 0;
let gameTimer = 30;
let gameActive = false;
let numSquares = 5;
function preload() {
handPose = ml5.handPose();
}
function setup() {
createCanvas(640, 480);
video = createCapture(VIDEO);
video.size(640, 480);
video.hide();
handPose.detectStart(video, gotHands);
resetGame();
}
function draw() {
background(0);
image(video, 0, 0, width, height);
if (gameActive) {
updateGame();
displayScoreAndTime();
}
if (gameTimer <= 0) {
displayFinalScore();
gameActive = false;
}
}
function resetGame() {
squares = createRandomSquares(numSquares);
score = 0;
gameTimer = 30;
gameActive = true;
loop();
}
function updateGame() {
drawSquares();
if (hands.length > 0) {
for (let i = 0; i < hands.length; i++) {
let hand = hands[i];
drawHandCircles(hand);
checkCollision(hand);
}
}
if (squares.length === 0) {
squares = createRandomSquares(numSquares);
}
}
function drawSquares() {
fill(0, 255, 0);
noStroke();
squares.forEach(square => {
rect(square.x, square.y, square.size, square.size);
});
}
function drawHandCircles(hand) {
let indexTip = hand.keypoints[8];
fill(255, 0, 0);
noStroke();
if (indexTip) circle(indexTip.x, indexTip.y, 20);
}
function checkCollision(hand) {
let indexTip = hand.keypoints[8];
squares = squares.filter(square => {
if (isPointInSquare(indexTip, square)) {
score++;
return false;
}
return true;
});
}
function isPointInSquare(point, square) {
return point.x > square.x && point.x < square.x + square.size &&
point.y > square.y && point.y < square.y + square.size;
}
function createRandomSquares(num) {
let newSquares = [];
for (let i = 0; i < num; i++) {
let size = random(20, 50);
newSquares.push({
x: random(0, width - size),
y: random(0, height - size),
size: size
});
}
return newSquares;
}
function displayScoreAndTime() {
fill(255);
textSize(24);
textStyle(BOLD);
text(`Score: ${score}`, 30, 40);
text(`Time Left: ${gameTimer}`, 30, 70);
if (frameCount % 60 == 0 && gameTimer > 0) {
gameTimer--;
}
}
function displayFinalScore() {
fill(255);
textSize(64);
textStyle(BOLD);
textAlign(CENTER);
text(`Your Score: ${score}`, width / 2, height / 2 + 30);
}
function mousePressed() {
if (!gameActive || gameTimer <= 0) {
resetGame();
}
}
function gotHands(results) {
hands = results;
}