
๋ง์ดํฌ/์ฌ์ด๋ ์
๋ ฅ โ FFT/Amplitude ๋ถ์ โ ํํ ๋ณํ
ํํฐํด ์/์๋/ํฌ๊ธฐ/์ง๋์ด ๋ชจ๋ ์ค๋์ค์ ๋ฐ์ํจ

// p5.sound ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์
let mic;
let fft;
let particles = [];
let audioStarted = false;
function setup() {
createCanvas(800, 500);
noStroke();
}
function draw() {
background(12, 12, 12);
// ์ค๋์ค ์์ ์ ์๋ด ๋ฉ์์ง
if (!audioStarted) {
fill(255);
textAlign(CENTER, CENTER);
textSize(24);
text("ํด๋ฆญํด์ ์์", width / 2, height / 2);
return;
}
// โ
์ค๋์ค ๋ถ์
let spectrum = fft.analyze();
let bass = fft.getEnergy("bass") * 2; // ์ ์ 20โ140Hz
let mid = fft.getEnergy("mid") * 2; // ์ค์ 400โ2600Hz
let treble = fft.getEnergy("treble") * 2; // ๊ณ ์ 6000Hz~
// โ
๊ฐ์ด๋ฐ ์ โ ์ ์ฒด ์๋์ง ๋ฐ์(ํ์คํ๊ฒ ๋ณด์ด๋๋ก ๊ฐํ)
let level = fft.getEnergy("lowMid");
let r = map(level, 0, 255, 30, 160);
fill(255, 255, 255, 255);
circle(width / 2, height / 2, r * 2);
// โ
ํํฐํด ์
๋ฐ์ดํธ ๋ฐ ๋ ๋
particles.forEach((p) => {
p.update(bass, mid, treble);
p.show();
});
}
// ํด๋ฆญ ์ ์ค๋์ค ์์
function mousePressed() {
if (!audioStarted) {
// โ
๋ง์ดํฌ ์
๋ ฅ ์์
mic = new p5.AudioIn();
mic.start();
// โ
FFT ์ด๊ธฐํ
fft = new p5.FFT(0.9, 256);
fft.setInput(mic);
// โ
ํํฐํด ์์ฑ
for (let i = 0; i < 200; i++) {
particles.push(new Particle());
}
audioStarted = true;
}
}
// ---------------------------------------------
// โ
Particle Class
// ์ค๋์ค ์ฃผํ์ ๊ฐ์ ๋ฐ๋ผ ์๋ยท์ยทํฌ๊ธฐยทjitter ๋ชจ๋ ๋ฐ์
// ---------------------------------------------
class Particle {
constructor() {
this.pos = createVector(random(width), random(height));
this.vel = p5.Vector.random2D().mult(random(0.5, 2));
this.size = random(3, 6);
// ์์ ์ด๊ธฐ๊ฐ
this.col = color(180, 150, 255, 200);
}
update(bass, mid, treble) {
// โ
์ค๋์ค ๋ฐ์ ๊ฐ๋ ์กฐ์ (ํ์คํ๊ฒ ๋ณด์ด๋๋ก ๊ณผ์ฅ)
let bassAmp = map(bass, 0, 255, 0, 8); // ํฌ๊ณ ๊ฐ๋ ฌํ ๋ฐ์
let midAmp = map(mid, 0, 255, 0, 4); // ์ด๋ ์๋
let trebleAmp = map(treble, 0, 255, 0, 3); // ์ ๋ฐ์ง์
// โ
์๋ ์ฆ๊ฐ โ mid์ ๊ฐํ๊ฒ ๋ฐ์
this.pos.add(this.vel.copy().mult(0.4 + midAmp * 1.3));
// โ
jitter โ ๊ณ ์ treble ๊ธฐ๋ฐ ์์ ์ง๋
this.pos.add(p5.Vector.random2D().mult(trebleAmp * 3.5));
// โ
ํ๋ฉด ๋ฐ์ผ๋ก ๋๊ฐ๋ฉด wrap-around
if (this.pos.x > width) this.pos.x = 0;
if (this.pos.x < 0) this.pos.x = width;
if (this.pos.y > height) this.pos.y = 0;
if (this.pos.y < 0) this.pos.y = height;
// โ
์์ ๋ฐ์ โ bass/mid/treble ๋ชจ๋ ๋ฐ์
this.col = color(
map(bass, 0, 255, 0, 255), // ์ ์ โ ๋นจ๊ฐ ์ต๋์น๊น์ง
map(mid, 0, 255, 50, 255), // ์ค์ โ ์ด๋ก ๊ฐํ๊ฒ ๋ฐ์
map(treble, 0, 255, 100, 255), // ๊ณ ์ โ ํ๋ ๋ฐ์ง์
240
);
// โ
ํฌ๊ธฐ โ bass์ ๋ฐ์
this.currentSize = this.size + bassAmp * 2.2;
}
show() {
fill(this.col);
circle(this.pos.x, this.pos.y, this.currentSize);
}
}
โ
๊ตฌ์กฐ ์ค๋ช
1) ๋ง์ดํฌ ์
๋ ฅ
mic = new p5.AudioIn();
mic.start();
2) FFT ๋ถ์
fft = new p5.FFT(0.8, 128);
fft.setInput(mic);
3) ์ฃผํ์ ๋์ญ๊ฐ ์ถ์ถ
fft.getEnergy("bass");
fft.getEnergy("mid");
fft.getEnergy("treble");
4) ๊ฐ ์ฃผํ์ ๋์ญ โ ํํ ๋ณํ ๋งคํ
5) ํํฐํด ์์คํ
โ
ํ์ฅ ์์ด๋์ด
1) ์คํํธ๋ผ ๋ฐ(Visualizer) ์คํ์ผ
2) Circles / Lines / Mesh vibrating
3) ์์ด๋(Shaders)์ ๊ฒฐํฉํ Audio-Reactive
4) ์ค๋์ค ํ์ผ ์ ๋ก๋ (.mp3)
5) 3D ์ค๋์ค ๋ฐ์ Visual (Three.js)

let mic, fft;
let audioStarted = false;
function setup() {
createCanvas(600, 600);
angleMode(DEGREES);
}
function draw() {
background(5);
translate(width / 2, height / 2);
// ์ค๋์ค ์์ ์ ์๋ด ๋ฉ์์ง
if (!audioStarted) {
fill(255);
textAlign(CENTER, CENTER);
textSize(24);
text("ํด๋ฆญํด์ ์์", 0, 0);
return;
}
let spectrum = fft.analyze();
let rotateSpeed = map(fft.getEnergy("bass"), 0, 255, 0, 9);
rotate(frameCount * -0.5 + rotateSpeed);
noStroke();
for (let i = 0; i < spectrum.length; i++) {
let r = map(i, 0, spectrum.length, 40, 250);
let angle = i * 6;
let amp = spectrum[i];
let x = r * cos(angle);
let y = r * sin(angle);
fill(
map(amp, 0, 255, 100, 255),
map(i, 0, spectrum.length, 50, 200),
255,
200
);
circle(x, y, map(amp, 0, 255, 2, 72));
}
}
// ํด๋ฆญ ์ ์ค๋์ค ์์
function mousePressed() {
if (!audioStarted) {
mic = new p5.AudioIn();
mic.start();
fft = new p5.FFT(0.8, 512);
fft.setInput(mic);
audioStarted = true;
}
}

let mic, fft;
let particles = [];
let audioStarted = false;
function setup() {
createCanvas(600, 600);
angleMode(DEGREES);
colorMode(RGB, 255);
mic = new p5.AudioIn();
fft = new p5.FFT(0.8, 64);
fft.setInput(mic);
for (let i = 0; i < 160; i++) {
particles.push(new Particle());
}
noStroke();
}
function draw() {
background(15, 15, 20, 10);
if (!audioStarted) {
displayStartMessage();
return;
}
fft.analyze();
let bass = fft.getEnergy("bass");
let mid = fft.getEnergy("mid");
let treble = fft.getEnergy("treble");
renderUndulatingCircle(bass, mid, treble);
updateParticles(bass, mid, treble);
}
function displayStartMessage() {
fill(220);
textSize(24);
textAlign(CENTER, CENTER);
noStroke();
text("ํด๋ฆญํด์ ์์", width / 2, height / 2);
}
function mousePressed() {
if (getAudioContext().state !== "running") {
getAudioContext()
.resume()
.then(() => {
mic.start();
audioStarted = true;
})
.catch((err) => {
console.error("Error starting audio context:", err);
});
} else if (!audioStarted) {
mic.start();
audioStarted = true;
}
}
function renderUndulatingCircle(bass, mid, treble) {
push();
translate(width / 2, height / 2);
// ๋
ธ์ด์ฆ ๊ธฐ๋ฐ ์ธ๋๋ ์ดํ
์ํด
// ์์น๋ฅผ ์ฌ๋ฆฌ๋ฉด ๋ณํ๊ฐ ๋ ์ปค์ง
let baseRadius = 180;
let noiseScale = map(mid, 0, 255, 0.01, 0.5); // ์ค์์ ๋ฐ๋ผ ๋
ธ์ด์ฆ ๊ฐ๋ ๋ณํ
let amplitude = map(bass, 0, 255, 30, 200); // ์ ์์ ๋ฐ๋ผ ์งํญ ๋ณํ
// ์์ - ๊ณ ์๊ณผ ์ค์์ ๋ฐ๋ผ ๋ ํ๋ คํ๊ฒ ๋ณํ
let hue = (frameCount * 0.5 + treble * 0.3) % 360;
let r = map(sin(hue), -1, 1, 80, 255);
let g = map(sin(hue + 120), -1, 1, 100, 255);
let b = map(sin(hue + 240), -1, 1, 150, 255);
// ์ค์์ ๋ฐ๋ผ ์ฑ๋ ๊ฐ๋ ์กฐ์
let saturation = map(mid, 0, 255, 0.3, 1);
r = lerp(150, r, saturation);
g = lerp(150, g, saturation);
b = lerp(150, b, saturation);
fill(r, g, b, 200);
beginShape();
for (let angle = 0; angle < 360; angle += 2) {
let xoff = cos(angle) * noiseScale;
let yoff = sin(angle) * noiseScale;
// ๋
ธ์ด์ฆ ๊ฐ ๊ณ์ฐ - 0.01์ ๋์ด๋ฉด ๋
ธ์ด์ฆ ๋นจ๋ผ์ง
let n = noise(xoff + frameCount * 0.01, yoff + frameCount * 0.01);
let offset = map(n, 0, 1, -amplitude, amplitude);
let r = baseRadius + offset;
let x = r * cos(angle);
let y = r * sin(angle);
vertex(x, y);
}
endShape(CLOSE);
pop();
}
function updateParticles(bass, mid, treble) {
for (let p of particles) {
p.update(bass, mid, treble);
p.show();
}
}
class Particle {
constructor() {
this.reset();
}
reset() {
this.pos = createVector(width / 2, height / 2);
this.vel = p5.Vector.random2D().mult(random(0.3, 1.0));
this.size = random(4, 8); // ํฌ๊ธฐ ์ฆ๊ฐ
this.life = random(150, 250);
this.maxLife = this.life;
}
update(bass, mid, treble) {
this.life -= 1;
let speedBoost = 0.4 + mid * 0.004;
this.pos.add(this.vel.copy().mult(speedBoost));
// ๋ฏธ์ธํ ํ๋ค๋ฆผ
this.pos.add(p5.Vector.random2D().mult(treble * 0.002));
if (this.life <= 0) {
this.reset();
}
}
show() {
let alpha = map(this.life, 0, this.maxLife, 0, 220);
// ํํฐํด
noStroke();
fill(200, 220, 255, alpha);
circle(this.pos.x, this.pos.y, this.size);
// ๊ธ๋ก์ฐ ํจ๊ณผ
fill(200, 220, 255, alpha * 0.3);
circle(this.pos.x, this.pos.y, this.size * 1.8);
}
}