Dancers
Silly characters listen and react as you play music. This sketch was tuned for violin but may work with other instruments, or your voice!
This sketch needs permission to use your microphone.
Source Code for this Sketch
// activationThreshold is the energy required for
// the dancers to dance in response to any given
// note.
//
// Depending on your microphone, background noise,
// type of instrument, or volume of your voice,
// you may need to adjust this value.
const activationThreshold = 255*.35
// You can use this multiplier value to make the
// dancers more energetic. A value of 2 will make
// them dance twice as quickly, for example.
const dancerSpeed = 1
const eNote = 660
const aNote = 440
const dNote = 293.33333
const gNote = 195.55555
const height = 200
const topOffset = 10;
const bottomOffset = height-10;
let fft = new p5.FFT()
let averages = []
let count = 0
let hue = 0
class Wiggler {
constructor(range, speed) {
this.range = range ? range : 30
this.speed = speed ? speed/100 : 40/100
this._x = 0
this.x = 0
}
update() {
this._x += PI*this.speed
this.x = sin(this._x) * this.range
}
}
let eos = new Wiggler(20, 10 * dancerSpeed)
let aos = new Wiggler(30, 6 * dancerSpeed)
let dos = new Wiggler(40, 6 * dancerSpeed)
let gos = new Wiggler(25, 8 * dancerSpeed)
function eye(x, y) {
fill(100)
circle(x, y, 12)
fill(0)
circle(x, y, 5)
}
function setup() {
createCanvas(600, height, P2D, canvas)
colorMode(HSL)
mic = new p5.AudioIn()
mic.start()
fft.setInput(mic)
for (let i = 0; i < 1024; i++) {
averages[i] = [0, 0, 0, 0, 0]
}
}
function draw() {
background(100)
fft.analyze()
// Instruments don't produce pure tones so
// you may see other dancers participating
// even if they are not the primary note.
// And for some reason, A likes to join in
// with G, even when a pure tone is used.
// Maybe it's harmonics, maybe it's a bug.
// E note
if (fft.getEnergy(eNote/2) > activationThreshold ||
fft.getEnergy(eNote) > activationThreshold ||
fft.getEnergy(eNote*2) > activationThreshold) {
eos.update()
}
fill(0, 100, 50)
beginShape()
vertex(500, topOffset)
bezierVertex(490+eos.x, 60, 490+eos.x, 60, 500, bottomOffset)
bezierVertex( 510+eos.x, 140, 510+eos.x, 140, 500, topOffset)
endShape()
eye(480, 50)
eye(520, 50)
// A note
if (fft.getEnergy(aNote/2) > activationThreshold ||
fft.getEnergy(aNote) > activationThreshold ||
fft.getEnergy(aNote*2) > activationThreshold) {
aos.update()
}
fill(50, 100, 50)
beginShape()
vertex(400, topOffset)
bezierVertex(400, topOffset+50, 350-aos.x, bottomOffset, 400, bottomOffset)
bezierVertex( 450+aos.x, bottomOffset, 400, topOffset+50, 400, topOffset)
endShape()
eye(390, bottomOffset-20)
eye(410, bottomOffset-20)
// D note
if (fft.getEnergy(dNote) > activationThreshold ||
fft.getEnergy(dNote*2) > activationThreshold ||
fft.getEnergy(dNote*4) > activationThreshold) {
dos.update()
}
fill(110, 81, 40)
beginShape()
vertex(300, topOffset)
// Curve handles are pulled 20px toward their primary axes
// Left side
bezierVertex(300, topOffset+20, 275, topOffset+45+dos.x, 255, topOffset+45+dos.x)
bezierVertex(300, topOffset+45+dos.x, 300, bottomOffset-45-dos.x, 255, bottomOffset-45-dos.x)
bezierVertex(275, bottomOffset-45-dos.x, 300, bottomOffset-20, 300, bottomOffset)
// Right side
bezierVertex(300, bottomOffset-20, 325, bottomOffset-45-dos.x, 345, bottomOffset-45-dos.x)
bezierVertex(300, bottomOffset-45-dos.x, 300, topOffset+45+dos.x, 345, topOffset+45+dos.x)
bezierVertex(325, topOffset+45+dos.x, 300, topOffset+20, 300, topOffset)
endShape()
eye(290, 100)
eye(310, 100)
// G note
if (fft.getEnergy(gNote) > activationThreshold ||
fft.getEnergy(gNote*2) > activationThreshold ||
fft.getEnergy(gNote*4) > activationThreshold) {
gos.update()
}
const midpoint = 130
fill(237, 53, 40)
beginShape()
vertex(150, topOffset)
bezierVertex(100-gos.x, topOffset+40, 100-gos.x, midpoint-40, 140, midpoint)
bezierVertex(100-gos.x, midpoint+20, 100-gos.x, bottomOffset-20, 150, bottomOffset)
bezierVertex(200+gos.x, bottomOffset-20, 200+gos.x, midpoint+20, 160, midpoint)
bezierVertex( 200+gos.x, midpoint-40, 200+gos.x, topOffset+40, 150, topOffset)
endShape()
eye(140, midpoint)
eye(160, midpoint)
}
You may use all or part of the p5 code seen on this page for your own creations, without restriction. Attribution is appreciated but not required.
This sketch also includes the following sources: p5common.js p5.sound.js . Sources are available under their respective licenses.