diff --git a/.vscode/launch.json b/.vscode/launch.json index 5f0c7af3b..0ccc038d4 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,5 +1,19 @@ { "configurations": [ + { + "type": "java", + "name": "LarinasVisual", + "request": "launch", + "mainClass": "C22328351.LarinasVisual", + "projectName": "java" + }, + { + "type": "java", + "name": "C22328351", + "request": "launch", + "mainClass": "C22328351.C22328351", + "projectName": "java" + }, { "type": "java", "name": "CodeLens (Launch) - Main", diff --git a/README.md b/README.md index 19ba88c75..65d4e405a 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,17 @@ # Music Visualiser Project +Name: Michael Ferents +Student Number: C21325616 -Name: +Name: Patrick Akinsowon +Student Number: C22371846 + + +Name: Larina Yu +Student Number: C22328351 + +Name: Noel McCarthy +Student Number: C22533826 -Student Number: ## Instructions - Fork this repository and use it a starter project for your assignment @@ -14,6 +23,17 @@ Student Number: # Description of the assignment # Instructions +Run Main.java inside ie\tudublin, this will run our Heartbeat.java file where we handle rendering each persons visual. + +To switch between each persons visuals select 1-X keys. Press R to restart the song and Spacebar to pause the song. + +- Noels Visuals: You can interact with the stars in the background by hovering the cursor over them. This creates a 'blackhole' effect where they group around the cursor in a circle. + +- atricks Visuals: + +- Larinas Visuals: + +- Michaels Visuals: # How it works diff --git a/java/.project b/java/.project index 0d5afed93..afaf9dff8 100644 --- a/java/.project +++ b/java/.project @@ -16,12 +16,12 @@ - 1616413840733 + 1710347416250 30 org.eclipse.core.resources.regexFilterMatcher - node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ diff --git a/java/data/Heartbeat.mp3 b/java/data/Heartbeat.mp3 new file mode 100644 index 000000000..ca79271b0 Binary files /dev/null and b/java/data/Heartbeat.mp3 differ diff --git a/java/src/C21325616/Box.java b/java/src/C21325616/Box.java new file mode 100644 index 000000000..3b70c4fec --- /dev/null +++ b/java/src/C21325616/Box.java @@ -0,0 +1,39 @@ +package C21325616; + +import processing.core.PVector; + +import java.util.List; + +import example.MyVisual; +import ie.tudublin.Heartbeat; + +import java.util.*; + +import processing.core.PApplet; + +public class Box { + + public PVector position; + public PVector dimensions; + + public void setDimension(PVector dimension) + { + this.dimensions = dimension; + } + + public void setPosition(PVector position) + { + this.position = position; + } + + public void render(Heartbeat mv) + { + mv.pushMatrix(); + mv.translate(position.x, position.y, position.z); + mv.fill(220); + mv.noStroke(); + mv.box(dimensions.x, dimensions.y, dimensions.z); + mv.popMatrix(); + } + +} diff --git a/java/src/C21325616/BoxPlane.java b/java/src/C21325616/BoxPlane.java new file mode 100644 index 000000000..bc12ddfd2 --- /dev/null +++ b/java/src/C21325616/BoxPlane.java @@ -0,0 +1,121 @@ +package C21325616; + +import example.MyVisual; +import ie.tudublin.Heartbeat; + +import java.util.*; + +import processing.core.PApplet; +import processing.core.PVector; + +enum Side { + PositiveX, + PositiveY, + PositiveZ, + NegativeX, + NegativeY, + NegativeZ, +} + +public class BoxPlane { + + Box[][] plane = new Box[20][20]; + Random rand = new Random(); + + Side currentSide; + + PVector origin; + + public void init(Side side) + { + this.currentSide = side; + + for(int i = 0; i < 20; i++) + { + for(int j = 0; j < 20; j++) + { + plane[i][j] = new Box(); + plane[i][j].setDimension(new PVector(20, 20, 20)); + + switch(side) + { + case PositiveX: + plane[i][j].setPosition(new PVector(i * 20,j*20, 0)); + break; + + case PositiveY: + plane[i][j].setPosition(new PVector(i * 20,0, j*20)); + break; + + case PositiveZ: + plane[i][j].setPosition(new PVector( 0 , i * 20, j*20)); + break; + + case NegativeX: + plane[i][j].setPosition(new PVector(i * 20,j*20, 400)); + break; + + case NegativeY: + plane[i][j].setPosition(new PVector(i * 20, 400, j*20)); + break; + + case NegativeZ: + plane[i][j].setPosition(new PVector(400,i * 20, j*20)); + break; + } + } + } + } + + public void update(Heartbeat mv) + { + mv.getAudioBuffer().size(); + + for(int i = 0; i < 20; i++) + { + for(int j = 0; j < 20; j++) + { + switch(currentSide) + { + case PositiveX: + plane[i][j].setDimension(new PVector(20, 20,(mv.getAudioBuffer().get(i) * (rand.nextInt(500 - 150 + 1) + 150)) + 20)); + break; + + case PositiveY: + plane[i][j].setDimension(new PVector(20, (mv.getAudioBuffer().get(i) * (rand.nextInt(500 - 150 + 1) + 150)) + 20, 20)); + break; + + case PositiveZ: + plane[i][j].setDimension(new PVector((mv.getAudioBuffer().get(i) * (rand.nextInt(500 - 150 + 1) + 150)) + 20, 20, 20)); + break; + + case NegativeX: + plane[i][j].setDimension(new PVector(20, 20, (mv.getAudioBuffer().get(i) * (rand.nextInt(500 - 150 + 1) + 150)) + 20)); + break; + + case NegativeY: + plane[i][j].setDimension(new PVector(20, (mv.getAudioBuffer().get(i) * (rand.nextInt(500 - 150 + 1) + 150)) + 20, 20)); + break; + + case NegativeZ: + plane[i][j].setDimension(new PVector((mv.getAudioBuffer().get(i) * (rand.nextInt(500 - 150 + 1) + 150)) + 20, 20, 20)); + break; + } + + + } + } + } + + public void render(Heartbeat mv) + { + for(int i = 0; i < 20; i++) + { + for(int j = 0; j < 20; j++) + { + plane[i][j].render(mv); + } + } + } + +} diff --git a/java/src/C21325616/MichaelsVisuals.java b/java/src/C21325616/MichaelsVisuals.java new file mode 100644 index 000000000..65d4dbc4f --- /dev/null +++ b/java/src/C21325616/MichaelsVisuals.java @@ -0,0 +1,143 @@ +package C21325616; + +import java.util.Random; + +import example.MyVisual; +import ie.tudublin.Heartbeat; +import processing.core.PApplet; +import processing.core.PConstants; +import processing.core.PVector; +import processing.event.KeyEvent; + +public class MichaelsVisuals { + + Heartbeat mv; + + BoxPlane[] cube; + PointCube pc; + ParticleSystem ps; + + Random rand = new Random(); + + int width; + int height; + + float lastX; + float lastY; + + int State = 1; + boolean first = true; + + float rotation=0; + + public MichaelsVisuals(Heartbeat mv) + { + this.mv = mv; + + width = mv.displayWidth; + height = mv.displayHeight; + + initializeVisualOne(); + initializeVisualTwo(); + } + + private void initializeVisualOne() + { + + cube = new BoxPlane[6]; + + for(int i = 0; i < 6; i++) + { + cube[i] = new BoxPlane(); + } + + cube[0].init(Side.PositiveX); + cube[1].init(Side.PositiveY); + cube[2].init(Side.PositiveZ); + cube[3].init(Side.NegativeX); + cube[4].init(Side.NegativeY); + cube[5].init(Side.NegativeZ); + + } + + private void initializeVisualTwo() + { + pc = new PointCube(10); + ps = new ParticleSystem(300); + } + + private void renderVisualOne() + { + mv.beginCamera(); + mv.noFill(); + mv.background(0); + //camera.setCamera(mv); + mv.camera(-150, -400 * PApplet.cos(PApplet.radians(rotation)), -400 * PApplet.sin(PApplet.radians(rotation)), 100, 100, 100, 0.0f, 1.0f, 0.0f); + mv.directionalLight(100, 0, 300, -1, 1, -1); + mv.pointLight(0, 50, 300, 100 , 0, -100); + mv.pointLight(0, 50, 300, -100, 0, 100); + //mv.rotate(PApplet.atan2(dir.y, dir.x)); + //rotate2D(dir, PApplet.radians(3)); + /* + mv.translate(50, 50, 0); + mv.rotateX(-PConstants.PI/6); + mv.rotateY(PConstants.PI/3); + */ + //mv.box(45); + //ico.render(mv); + if(mv.frameCount % 5 == 0) + { + for(int i = 0; i < 6; i++) + { + cube[i].update(mv); + } + } + for(int i = 0; i < 6; i++) + { + cube[i].render(mv); + } + mv.endCamera(); + rotation++; + } + + public void setState(int state) + { + this.State = state; + } + + private void renderVisualTwo() + { + mv.beginCamera(); + mv.noFill(); + mv.background(0); + //camera.setCamera(mv); + mv.camera(-100, -100 * PApplet.cos(PApplet.radians(rotation)), -100 * PApplet.sin(PApplet.radians(rotation)), 100, 100, 100, 0.0f, 1.0f, 0.0f); + pc.update(mv); + pc.render(mv); + ps.render(mv); + ps.update(); + + mv.pushMatrix(); + mv.noStroke(); + //mv.lights(); + mv.fill(255); + mv.translate(50, 50, 50); + mv.calculateAverageAmplitude(); + System.out.println(mv.getAmplitude()); + mv.sphere(100 * mv.getAmplitude()); + mv.popMatrix(); + + mv.endCamera(); + rotation++; + } + + public void render() + { + if(State == 0) + renderVisualOne(); + + if(State == 1) + renderVisualTwo(); + } + +} \ No newline at end of file diff --git a/java/src/C21325616/ParticleSystem.java b/java/src/C21325616/ParticleSystem.java new file mode 100644 index 000000000..94c79ac26 --- /dev/null +++ b/java/src/C21325616/ParticleSystem.java @@ -0,0 +1,63 @@ +package C21325616; + +import example.MyVisual; +import ie.tudublin.Heartbeat; + +import java.util.*; + +import processing.core.PVector; + +public class ParticleSystem { + + private PVector[] particles; + int size = 0; + Random rand = new Random(); + + ParticleSystem(int size) + { + particles = new PVector[size * size]; + + this.size = size; + + for(int i = 0; i < size * size; i++) + { + particles[i] = new PVector((rand.nextInt(1500 + 1500 + 1) - 1500), (rand.nextInt(1500 + 1500 + 1) - 1500), (rand.nextInt(1500 + 1500 + 1) - 1500)); + } + } + + // center is 100, 100, 100 + public void update() + { + for(int i = 0; i < size * size; i++) + { + if(particles[i].x == 50 && particles[i].y == 50 && particles[i].z == 50) + { + particles[i] = new PVector((rand.nextInt(1500 + 1500 + 1) - 1500), (rand.nextInt(1500 + 1500 + 1) - 1500), (rand.nextInt(1500 + 1500 + 1) - 1500)); + } else { + if(particles[i].x > 50) + { + particles[i].x -= 1; + } else { particles[i].x += 1; } + + if(particles[i].y > 50) + { + particles[i].y -= 1; + } else { particles[i].y += 1; } + + if(particles[i].z > 50) + { + particles[i].z -= 1; + } else { particles[i].z += 1; } + } + } + } + + public void render(Heartbeat mv) + { + for(int i = 0; i < size * size; i++) + { + mv.stroke(255); + mv.point(particles[i].x, particles[i].y, particles[i].z); + } + } +} diff --git a/java/src/C21325616/PointCube.java b/java/src/C21325616/PointCube.java new file mode 100644 index 000000000..f1cf38fc6 --- /dev/null +++ b/java/src/C21325616/PointCube.java @@ -0,0 +1,119 @@ +package C21325616; + +import example.MyVisual; +import ie.tudublin.Heartbeat; + +import java.util.*; + +import processing.core.PApplet; +import processing.core.PVector; + +public class PointCube { + + private PVector[][] pointsOne; + private PVector[][] pointsTwo; + private PVector[][] pointsThree; + private PVector[][] pointsFour; + private PVector[][] pointsFive; + private PVector[][] pointsSix; + + private int size = 0; + Random rand = new Random(); + + int[] Distortion = { 1, 2, 3, 4, 5, 5, 4, 3, 2, 1 }; + + PointCube(int size) + { + pointsOne = new PVector[size][size]; + pointsTwo = new PVector[size][size]; + pointsThree = new PVector[size][size]; + pointsFour = new PVector[size][size]; + pointsFive = new PVector[size][size]; + pointsSix = new PVector[size][size]; + + this.size = size; + + for(int i = 0; i < size; i++) + { + for(int j = 0; j < size; j++) + { + int distortion = Distortion[i] * Distortion[j]; + pointsOne[i][j] = new PVector(i * 10, -distortion, j * 10); + pointsTwo[i][j] = new PVector(i * 10, size * 10 + distortion, j * 10); + pointsThree[i][j] = new PVector(-distortion, i * 10, j * 10); + pointsFour[i][j] = new PVector(size * 10 + distortion, i * 10, j * 10); + pointsFive[i][j] = new PVector(i * 10, j * 10, -distortion); + pointsSix[i][j] = new PVector(i * 10, j * 10, size * 10 + distortion); + } + } + } + + public void update(Heartbeat mv) + { + mv.getAudioBuffer().size(); + + for(int i = 0; i < size; i++) + { + for(int j = 0; j < size; j++) + { + int distortion = Distortion[i] * Distortion[j]; + pointsOne[i][j] = new PVector(i * 10, -(distortion + mv.constrain(mv.getAudioBuffer().get(i), 0.0f, 1.0f) * (rand.nextInt(100 - 10 + 1) + 10)), j * 10); + pointsTwo[i][j] = new PVector(i * 10, size * 10 + (distortion + mv.constrain(mv.getAudioBuffer().get(i), 0.0f, 1.0f) * (rand.nextInt(100 - 10 + 1) + 10)), j * 10); + pointsThree[i][j] = new PVector(-(distortion + mv.constrain(mv.getAudioBuffer().get(i), 0.0f, 1.0f) * (rand.nextInt(100 - 10 + 1) + 10)), i * 10, j * 10); + pointsFour[i][j] = new PVector(size * 10 + (distortion + mv.constrain(mv.getAudioBuffer().get(i), 0.0f, 1.0f) * (rand.nextInt(100 - 10 + 1) + 10)), i * 10, j * 10); + pointsFive[i][j] = new PVector(i * 10, j * 10, -(distortion + mv.constrain(mv.getAudioBuffer().get(i), 0.0f, 1.0f) * (rand.nextInt(100 - 10 + 1) + 10))); + pointsSix[i][j] = new PVector(i * 10, j * 10, size * 10 + (distortion + mv.constrain(mv.getAudioBuffer().get(i), 0.0f, 1.0f) * (rand.nextInt(100 - 10 + 1) + 10))); + } + } + } + + public void render(Heartbeat mv) + { + for(int i = 0; i < size; i++) + { + for(int j = 0; j < size; j++) + { + mv.stroke(255); + if(i - 1 > 0 && j - 1 > 0 && i + 1 < size && j + 1 < size) + { + mv.line(pointsOne[i][j].x, pointsOne[i][j].y, pointsOne[i][j].z, pointsOne[i + 1][j].x, pointsOne[i + 1][j].y, pointsOne[i + 1][j].z); + mv.line(pointsOne[i][j].x, pointsOne[i][j].y, pointsOne[i][j].z, pointsOne[i - 1][j].x, pointsOne[i - 1][j].y, pointsOne[i - 1][j].z); + mv.line(pointsOne[i][j].x, pointsOne[i][j].y, pointsOne[i][j].z, pointsOne[i][j + 1].x, pointsOne[i][j + 1].y, pointsOne[i][j + 1].z); + mv.line(pointsOne[i][j].x, pointsOne[i][j].y, pointsOne[i][j].z, pointsOne[i][j - 1].x, pointsOne[i][j - 1].y, pointsOne[i][j - 1].z); + + mv.line(pointsTwo[i][j].x, pointsTwo[i][j].y, pointsTwo[i][j].z, pointsTwo[i + 1][j].x, pointsTwo[i + 1][j].y, pointsTwo[i + 1][j].z); + mv.line(pointsTwo[i][j].x, pointsTwo[i][j].y, pointsTwo[i][j].z, pointsTwo[i - 1][j].x, pointsTwo[i - 1][j].y, pointsTwo[i - 1][j].z); + mv.line(pointsTwo[i][j].x, pointsTwo[i][j].y, pointsTwo[i][j].z, pointsTwo[i][j + 1].x, pointsTwo[i][j + 1].y, pointsTwo[i][j + 1].z); + mv.line(pointsTwo[i][j].x, pointsTwo[i][j].y, pointsTwo[i][j].z, pointsTwo[i][j - 1].x, pointsTwo[i][j - 1].y, pointsTwo[i][j - 1].z); + + mv.line(pointsThree[i][j].x, pointsThree[i][j].y, pointsThree[i][j].z, pointsThree[i + 1][j].x, pointsThree[i + 1][j].y, pointsThree[i + 1][j].z); + mv.line(pointsThree[i][j].x, pointsThree[i][j].y, pointsThree[i][j].z, pointsThree[i - 1][j].x, pointsThree[i - 1][j].y, pointsThree[i - 1][j].z); + mv.line(pointsThree[i][j].x, pointsThree[i][j].y, pointsThree[i][j].z, pointsThree[i][j + 1].x, pointsThree[i][j + 1].y, pointsThree[i][j + 1].z); + mv.line(pointsThree[i][j].x, pointsThree[i][j].y, pointsThree[i][j].z, pointsThree[i][j - 1].x, pointsThree[i][j - 1].y, pointsThree[i][j - 1].z); + + mv.line(pointsFour[i][j].x, pointsFour[i][j].y, pointsFour[i][j].z, pointsFour[i + 1][j].x, pointsFour[i + 1][j].y, pointsFour[i + 1][j].z); + mv.line(pointsFour[i][j].x, pointsFour[i][j].y, pointsFour[i][j].z, pointsFour[i - 1][j].x, pointsFour[i - 1][j].y, pointsFour[i - 1][j].z); + mv.line(pointsFour[i][j].x, pointsFour[i][j].y, pointsFour[i][j].z, pointsFour[i][j + 1].x, pointsFour[i][j + 1].y, pointsFour[i][j + 1].z); + mv.line(pointsFour[i][j].x, pointsFour[i][j].y, pointsFour[i][j].z, pointsFour[i][j - 1].x, pointsFour[i][j - 1].y, pointsFour[i][j - 1].z); + + mv.line(pointsFive[i][j].x, pointsFive[i][j].y, pointsFive[i][j].z, pointsFive[i + 1][j].x, pointsFive[i + 1][j].y, pointsFive[i + 1][j].z); + mv.line(pointsFive[i][j].x, pointsFive[i][j].y, pointsFive[i][j].z, pointsFive[i - 1][j].x, pointsFive[i - 1][j].y, pointsFive[i - 1][j].z); + mv.line(pointsFive[i][j].x, pointsFive[i][j].y, pointsFive[i][j].z, pointsFive[i][j + 1].x, pointsFive[i][j + 1].y, pointsFive[i][j + 1].z); + mv.line(pointsFive[i][j].x, pointsFive[i][j].y, pointsFive[i][j].z, pointsFive[i][j - 1].x, pointsFive[i][j - 1].y, pointsFive[i][j - 1].z); + + mv.line(pointsSix[i][j].x, pointsSix[i][j].y, pointsSix[i][j].z, pointsSix[i + 1][j].x, pointsSix[i + 1][j].y, pointsSix[i + 1][j].z); + mv.line(pointsSix[i][j].x, pointsSix[i][j].y, pointsSix[i][j].z, pointsSix[i - 1][j].x, pointsSix[i - 1][j].y, pointsSix[i - 1][j].z); + mv.line(pointsSix[i][j].x, pointsSix[i][j].y, pointsSix[i][j].z, pointsSix[i][j + 1].x, pointsSix[i][j + 1].y, pointsSix[i][j + 1].z); + mv.line(pointsSix[i][j].x, pointsSix[i][j].y, pointsSix[i][j].z, pointsSix[i][j - 1].x, pointsSix[i][j - 1].y, pointsSix[i][j - 1].z); + } + mv.point(pointsOne[i][j].x, pointsOne[i][j].y, pointsOne[i][j].z); + mv.point(pointsTwo[i][j].x, pointsTwo[i][j].y, pointsTwo[i][j].z); + mv.point(pointsThree[i][j].x, pointsThree[i][j].y, pointsThree[i][j].z); + mv.point(pointsFour[i][j].x, pointsFour[i][j].y, pointsFour[i][j].z); + mv.point(pointsFive[i][j].x, pointsFive[i][j].y, pointsFive[i][j].z); + mv.point(pointsSix[i][j].x, pointsSix[i][j].y, pointsSix[i][j].z); + } + } + } + +} diff --git a/java/src/C22328351/C22328351.java b/java/src/C22328351/C22328351.java new file mode 100644 index 000000000..2eea4cde6 --- /dev/null +++ b/java/src/C22328351/C22328351.java @@ -0,0 +1,182 @@ +package C22328351; + +import ddf.minim.AudioBuffer; +import ddf.minim.AudioPlayer; +import ddf.minim.Minim; +import processing.core.PApplet; + +public class C22328351 extends PApplet { + + // Rotating star variable + float rotX, rotY; + + // Star size and points variables + float radius = 200; + int points = 5; + + // Audio library objects + Minim minim; + AudioPlayer ap; + AudioBuffer ab; + + // int mode = 0; + + // Processing setup + public void settings() { + size(800, 800, P3D); + } + + // Setup function that initializes the color mode and loads the audio file + public void setup() { + // Color mode and rotation variables + colorMode(HSB, 360, 100, 100); + rotX = rotY = 0; + + // Initialize the rotation variables + // rotX = rotY; + + // Load the audio file + minim = new Minim(this); + ap = minim.loadFile("Heartbeat.mp3", 1024); + ap.play(); + + // Get the audio buffer + ab = ap.mix; + } + + /* + * public void keyPressed() + * { + * if (key >= '0' && key <= '9') + * { + * mode = key - '0'; + * } + * if (keyCode == ' ') + * { + * if (ap.isPlaying()) + * { + * ap.pause(); + * } + * else + * { + * ap.rewind(); + * ap.play(); + * } + * } + * } + */ + + // Draws function that calls every frame + public void draw() { + // Clear the background and set the lights + background(0); + lights(); + + // Translate the origin to the center of the screen + translate(width / 2, height / 2); + + // Rotates the star on the x and y axis + rotateX(rotX); + rotateY(rotY); + + float rotationSpeedX = map(getAmplitude(), 0, 1, 0.02f, 0.15f); + float rotationSpeedY = map(getAmplitude(), 0, 1, 0.02f, 0.3f); + + rotX += rotationSpeedX; + rotY += rotationSpeedY; + + // Map the frame count to create the different colours + float innerHue = map(getAmplitude(), 0, 1, 0, 360); + float outerHue = map(getAmplitude(), 0, 1, 0, 360); + + // Set the fill color + fill(innerHue, 100, 360); + stroke(innerHue, 90, 90, 150); + drawStar(radius, points, innerHue, outerHue); + strokeWeight(4); + + fill(outerHue, 200, 360); + stroke(innerHue, 90, 90, 150); + drawStar(radius, points, innerHue, outerHue); + strokeWeight(4); + + // Gets the amplitude of the audio and maps it to the star + float amplitude = getAmplitude(); + // float radius = this.radius + (amplitude * 200); + + float starSize = radius + sin(frameCount * 0.1f) * 500 * getAmplitude(); + + // Draw the star outer + drawStar(starSize, points, outerHue, innerHue); + + // Draw the star inner + drawStar(starSize * 0.5f, points, outerHue, innerHue); + + /* + * strokeWeight(10); + * stroke(outerHue, 200, 360, 100); + * line(0, 0, 0, height/2); + * + * noFill(); + * strokeWeight(5); + * stroke(outerHue, 100, 360); + * drawStar(starSize, points, outerHue, innerHue); + */ + + } + + // Draws the star shape + public void drawStar(float radius, int points, float innerHue, float outerHue) { + + // Calculates the angle and star angle + float angle = TWO_PI / points; + float starAngle = angle / 2; + + // Draws the star shape + beginShape(); // Begin the shape + for (float a = 0; a < TWO_PI; a += angle) { + float x = cos(a) * radius; + float y = sin(a) * radius; + float z1 = radius / 2; + float z2 = -radius / 2; + stroke(outerHue, 100, 360); // Use vibrant color with maximum saturation and brightness + vertex(x, y, z1); + vertex(0, 0, z2); + float sx = cos(a + starAngle) * radius / 2; + float sy = sin(a + starAngle) * radius / 2; + vertex(sx, sy, z1); + } + endShape(CLOSE); // End the shape + + float innerRadius = radius * 0.06f; + beginShape(); + for (float a = 0; a < TWO_PI; a += angle) { + float x = cos(a) * innerRadius; + float y = sin(a) * innerRadius; + float z1 = radius / 2; + float z2 = -radius / 2; + stroke(innerHue, 100, 100); + vertex(x, y, z1); + vertex(0, 0, z2); + float sx = cos(a + starAngle) * innerRadius / 2; + float sy = sin(a + starAngle) * innerRadius / 2; + } + endShape(CLOSE); + + } + + // Gets the amplitude of the audio + public float getAmplitude() { + float total = 0; + for (int i = 0; i < ab.size(); i++) { + total += abs(ab.get(i)); + } + return total / ab.size(); + } + + // Main function that runs the program + public static void main(String[] args) { + PApplet.main("C22328351.C22328351"); + } + +} diff --git a/java/src/C22328351/LarinasVisual.java b/java/src/C22328351/LarinasVisual.java new file mode 100644 index 000000000..64f6fc21d --- /dev/null +++ b/java/src/C22328351/LarinasVisual.java @@ -0,0 +1,126 @@ +package C22328351; + +import ie.tudublin.VisualException; +import ie.tudublin.Heartbeat; +import java.util.Random; + +public class LarinasVisual { + + static Heartbeat HB; + float rotX, rotY; + + float radius = 200; + int points = 5; + + static float outerHue; + static float innerHue; + + static int numSparkles = 100; + static float sparkleSize = 5; + + public LarinasVisual(Heartbeat HB) { + this.HB = HB; + HB.colorMode(HB.HSB, 360, 100, 100); + rotX = rotY = 0; + } + + public void draw() { + HB.background(0); + HB.pushMatrix(); + HB.lights(); + + HB.translate(HB.width / 2, HB.height / 2); + + HB.rotateX(rotX); + HB.rotateY(rotY); + + float rotationSpeedX = HB.map(HB.getAmplitude(), 0, 1, 0.02f, 0.15f); + float rotationSpeedY = HB.map(HB.getAmplitude(), 0, 1, 0.02f, 0.3f); + + rotX += rotationSpeedX; + rotY += rotationSpeedY; + + HB.calculateAverageAmplitude(); + + innerHue = HB.map(HB.getAmplitude(), 0, 1, 0, 360); + outerHue = HB.map(HB.getAmplitude(), 0, 1, 0, 360); + + HB.fill(innerHue, 100, 360); + HB.stroke(innerHue, 90, 90, 150); + drawStar(radius, points, innerHue, outerHue); + HB.strokeWeight(4); + + HB.fill(outerHue, 200, 360); + HB.stroke(innerHue, 90, 90, 150); + drawStar(radius, points, innerHue, outerHue); + HB.strokeWeight(4); + + //Gets the amplitude of the audio and maps it to the star + //float amplitude = HB.getAmplitude(); + //float radius = this.radius + (amplitude * 200); + + float starSize = radius + HB.sin(HB.frameCount * 0.5f) * 500 * HB.getAmplitude(); + + drawStar(starSize, points, outerHue, innerHue); + + drawStar(starSize * 0.5f, points, outerHue, innerHue); + + drawSparkles(); + HB.popMatrix(); + HB.noLights(); + } + + public void drawSparkles() { + HB.noStroke(); + HB.fill(255); + float amplitude = HB.getAmplitude(); + int numSparkles = (int) HB.map(amplitude, 0, 1, 100, 10); + Random random = new Random(); + for (int i = 0; i < numSparkles; i++) { + float x = random.nextFloat() * HB.width; + float y = random.nextFloat() * HB.height; + float sparkleSize = random.nextFloat() * 5; + float sparkleBrightness = HB.random(200, 255); + HB.fill(255, sparkleBrightness); + HB.ellipse(x, y, sparkleSize, sparkleSize); + + } + } + + public void drawStar(float radius, int points, float innerHue, float outerHue) { + float angle = HB.TWO_PI / points; + float starAngle = angle / 2; + + HB.beginShape(); + for (float a = 0; a < HB.TWO_PI; a += angle) { + float x = HB.cos(a) * radius; + float y = HB.sin(a) * radius; + float z1 = radius / 2; + float z2 = -radius / 2; + HB.stroke(outerHue, 100, 360); // Use vibrant color with maximum saturation and brightness + HB.vertex(x, y, z1); + HB.vertex(0, 0, z2); + float sx = HB.cos(a + starAngle) * radius / 2; + float sy = HB.sin(a + starAngle) * radius / 2; + HB.vertex(sx, sy, z1); + } + HB.endShape(HB.CLOSE); + + float innerRadius = radius * 0.06f; + HB.beginShape(); + for (float a = 0; a < HB.TWO_PI; a += angle) { + float x = HB.cos(a) * innerRadius; + float y = HB.sin(a) * innerRadius; + float z1 = radius / 2; + float z2 = -radius / 2; + HB.stroke(innerHue, 100, 100); + HB.vertex(x, y, z1); + HB.vertex(0, 0, z2); + float sx = HB.cos(a + starAngle) * innerRadius / 2; + float sy = HB.sin(a + starAngle) * innerRadius / 2; + } + HB.endShape(HB.CLOSE); + + } + +} diff --git a/java/src/C22533826/NoelsVisual.java b/java/src/C22533826/NoelsVisual.java new file mode 100644 index 000000000..6c2471ade --- /dev/null +++ b/java/src/C22533826/NoelsVisual.java @@ -0,0 +1,78 @@ +package C22533826; + +import ie.tudublin.VisualException; +import ie.tudublin.Heartbeat; + +public class NoelsVisual { + + // Declare variables. + Heartbeat HB; + starField sf; + terrainNoel tn; + heartSun hs; + nebulaBackground nb; + + int height; + int width; + + // Declaring camera values, names took from processing documentation. + // Used to ensure that visual remains consistent when rendering with other + // visuals, even if other visuals use camera functions. + float eyeX, eyeY, eyeZ; + float centerX, centerY, centerZ; + float upX, upY, upZ; + + public NoelsVisual(Heartbeat HB) { + + // Initialize variables. + this.HB = HB; + height = HB.displayHeight; + width = HB.displayWidth; + + // Create new instances of starField and terrainNoel. + this.sf = new starField(height, width, HB); + this.tn = new terrainNoel(height, width, HB); + this.hs = new heartSun(HB); + this.nb = new nebulaBackground(HB, sf); + + // Set default camera values. + setDefaultCamera(); + } + + // Render starField and terrainNoel. Reset camera to ensure that visuals are + // consistent. + public void renderScene() { + // HB.background(100); + resetCamera(); + HB.noLights(); + + nb.render(); + + sf.render(); + tn.render(); + + // resetCamera(); + // hs.render(); + } + + // Reset camera to default values. + public void resetCamera() { + HB.camera(eyeX, eyeY, eyeZ, + centerX, centerY, centerZ, + upX, upY, upZ); + } + + // Set default camera values, ensures consistency when rendering with other + // visuals. + public void setDefaultCamera() { + eyeX = HB.width / 2.0f; + eyeY = HB.height / 2.0f; + eyeZ = (HB.height / 2.0f) / HB.tan(HB.PI / 6.0f); // FOV is 60 degrees by default. + centerX = HB.width / 2.0f; + centerY = HB.height / 2.0f; + centerZ = 0; + upX = 0; + upY = 1; + upZ = 0; + } +} diff --git a/java/src/C22533826/heartSun.java b/java/src/C22533826/heartSun.java new file mode 100644 index 000000000..e56b3c06b --- /dev/null +++ b/java/src/C22533826/heartSun.java @@ -0,0 +1,52 @@ +package C22533826; + +import ie.tudublin.Heartbeat; +import ie.tudublin.VisualException; + +public class heartSun { + + Heartbeat HB; + + public heartSun(Heartbeat HB) { + // Initialize variables. + this.HB = HB; + } + + public void render() { + // Render the heart sun. + HB.calculateAverageAmplitude(); + + // Get the amplitude and calculate the size and position of the heart. + float amplitude = HB.getSmoothedAmplitude(); + float heartSize = HB.map(amplitude, 0, 1, 100, 150); + float heartX = HB.width / 2 + 15; + float heartY = HB.height / 4; + + HB.pushMatrix(); + HB.translate(heartX, heartY); + + // determines the size of the heart based on the amplitude and framecount for + // speed. + float pulsatingSize = heartSize + HB.sin((float) (HB.frameCount * 0.025)) * 40; + + // Calculate color based on volume + float volume = HB.getSmoothedAmplitude(); + float hue = HB.map(volume, 0, 1, 0, 255); + float saturation = 255; + float brightness = 255; + HB.colorMode(HB.HSB); + HB.fill(hue, saturation, brightness); + + // Draw the heart shape. + HB.beginShape(); + for (float angle = 0; angle < HB.TWO_PI; angle += 0.01) { + float xCoord = 16 * HB.pow(HB.sin(angle), 3); + float yCoord = -13 * HB.cos(angle) + 5 * HB.cos(2 * angle) + 2 * HB.cos(3 * angle) + HB.cos(4 * angle); + xCoord *= pulsatingSize / 10; + yCoord *= pulsatingSize / 10; + HB.vertex(xCoord, yCoord); + } + HB.endShape(HB.CLOSE); + HB.popMatrix(); + } +} diff --git a/java/src/C22533826/menuScreen.java b/java/src/C22533826/menuScreen.java new file mode 100644 index 000000000..411cc39f4 --- /dev/null +++ b/java/src/C22533826/menuScreen.java @@ -0,0 +1,25 @@ +package C22533826; + +import ie.tudublin.Heartbeat; +import ie.tudublin.VisualException; + +public class menuScreen { + + Heartbeat HB; + + public menuScreen(Heartbeat HB) { + // Initialize variables. + this.HB = HB; + } + + public void renderMenu() { + HB.background(0); + HB.textSize(32); + HB.fill(255); + HB.text("Press 1 for Noel's Visual", HB.width / 2, HB.height / 2 - 100); + HB.text("Press 2 for Patrick's Visual: Each arrow key displays a new visual.", HB.width / 2, + HB.height / 2 - 50); + HB.text("For Michael's Visual press 3 for Cube visual and 4 for Particle visual.", HB.width / 2, HB.height / 2); + HB.text("Press 5 for Larina's Visual", HB.width / 2, HB.height / 2 + 50); + } +} diff --git a/java/src/C22533826/nebulaBackground.java b/java/src/C22533826/nebulaBackground.java new file mode 100644 index 000000000..316a3e23a --- /dev/null +++ b/java/src/C22533826/nebulaBackground.java @@ -0,0 +1,115 @@ +package C22533826; + +import ie.tudublin.Heartbeat; +import ie.tudublin.VisualException; +import processing.core.PVector; +import java.util.ArrayList; + +public class nebulaBackground { + + Heartbeat HB; + starField sf; + // Create an arraylist of nebula. + ArrayList nebulas; + + public nebulaBackground(Heartbeat HB, starField sf) { + // Initialize variables. + this.HB = HB; + this.sf = sf; + + // Initialize arraylist of nebula. + nebulas = new ArrayList(); + init_nebulas(); + } + + public void render() { + HB.background(0); + + // Iterate through all pixels and then calculate the sum of the distance between + // each nebula to give the 'merging effect'. + HB.loadPixels(); + for (int x = 0; x < HB.width; x++) { + for (int y = 0; y < HB.height / 2f; y++) { + float sum = 0; + for (Nebula n : nebulas) { + float d = HB.dist(x, y, n.x, n.y); + sum += 10 * n.r / d; + } + HB.pixels[x + y * HB.width] = HB.color(sum); + } + } + HB.updatePixels(); + + // Update each nebula. + for (Nebula n : nebulas) { + n.update(); + } + + // Allows interaction between nebulas and particles in starField. + nebulaStarInteraction(); + } + + // Interaction between nebulas and particles in starField. + // Uses nebula distance instead of mouse distance like in starField.java. + public void nebulaStarInteraction() { + for (Nebula n : nebulas) { + for (PVector p : sf.particles) { + float d = HB.dist(p.x, p.y, n.x, n.y); + if (d < 75) { + float pushStrength = HB.map(d, 0, 100, 10, 0); // Adjust the strength of interaction + PVector pushDirection = new PVector(p.x - n.x, p.y - n.y); + pushDirection.normalize(); + pushDirection.mult(pushStrength); + p.add(pushDirection); + } + } + } + } + + // Initialize nebulas at random positions, ensures varied sizes. + public void init_nebulas() { + for (int i = 0; i < 7; i++) { + float x = HB.random(0, HB.width); + float y = HB.random(0, HB.height / 2.9f); // Draw only on top half of the screen. + float r = 150 + i * HB.random(50, 200); + nebulas.add(new Nebula(x, y, r)); + } + + } + + // Class to represent a nebula. + class Nebula { + // initialize variables + float x, y, xspeed, yspeed, r; + + public Nebula(float x, float y, float r) { + this.x = x; + this.y = y; + // Randomize speed and direction of nebula. + float angle = HB.random(HB.TWO_PI); + this.xspeed = HB.random(5, 10) * HB.cos(angle); + this.yspeed = HB.random(5, 10) * HB.sin(angle); + this.r = r; + } + + public void update() { + // updates position of a nebula based on amplitude. + HB.calculateAverageAmplitude(); + // Adjust speed based on amplitude. Speed multiplier ensures that nebulas move + // similar to starField.java + float speedMultiplier = HB.map(HB.getSmoothedAmplitude(), 0, 1, 0, 5); + x += xspeed * speedMultiplier; + y += yspeed * speedMultiplier; + if (this.x > HB.width || this.x < 0) + this.xspeed *= -1; + if (this.y > HB.height / 2.6f || this.y < 0) + this.yspeed *= -1; + } + + public void show() { + // Draws ellipse at the given position. + HB.noFill(); + HB.ellipse(this.x, this.y, this.r * 2, this.r * 2); + } + } +} diff --git a/java/src/C22533826/starField.java b/java/src/C22533826/starField.java new file mode 100644 index 000000000..6c0adb321 --- /dev/null +++ b/java/src/C22533826/starField.java @@ -0,0 +1,104 @@ +package C22533826; + +import ie.tudublin.Heartbeat; +import ie.tudublin.VisualException; +import processing.core.PVector; +import java.util.ArrayList; + +public class starField { + + int visHeight; + int visWidth; + Heartbeat HB; + + int numParticles = 3000; // Number of particles in the star field. + float noiseScalar = 0.05f; // Adjust the angle step for smoother transition. + + // Create an arraylist of particles. + ArrayList particles; + + public starField(int height, int width, Heartbeat HB) { + // Initialize variables. Setting the height and width of the visual. + this.visHeight = HB.floor(height / 2.9f); + this.visWidth = width; + this.HB = HB; + particles = new ArrayList(); + + // Create particles at random positions. + for (int i = 0; i < numParticles; i++) { + particles.add(new PVector(HB.random(visWidth), HB.random(visHeight))); + } + } + + public void render() { + // Handles audio processing for the visual. + audioHandler(); + + HB.stroke(255); + HB.fill(255, 150); + + // Loop through all particles and render them. + for (PVector p : particles) { + HB.strokeWeight(HB.random(1, 5)); + renderParticle(p); + updateParticlePos(p); + outOfBoundsCheck(p); + mouseInteraction(p); + } + } + + // Simply renders a particle at the given position. + private void renderParticle(PVector p) { + HB.point(p.x, p.y); + } + + // Updates the position of a particle based on noise and amplitude. + private void updateParticlePos(PVector p) { + float noiseAngle = HB.noise(p.x * noiseScalar, p.y * noiseScalar); + float angle = HB.map(noiseAngle, 0, 1, 0, HB.TWO_PI); + // Update particle position based on noise angle and amplitude. + float amplitude = HB.getSmoothedAmplitude(); + float stepSize = HB.map(amplitude, 0, 1, 0, 10); // Adjust speed based on amplitude. + p.x += HB.cos(angle) * stepSize; + p.y += HB.sin(angle) * stepSize; + } + + // Wraps the particle around the screen if it goes out of bounds. + private void outOfBoundsCheck(PVector p) { + if (p.x < 0) { + p.x = visWidth; + } else if (p.x > visWidth) { + p.x = 0; + } + if (p.y < 0) { + p.y = visHeight; + } else if (p.y > visHeight) { + p.y = 0; + } + } + + // Applies mouse interaction to the particle. + // Creates something similar to a black hole effect, where the particles are + // pulled towards the mouse position. + private void mouseInteraction(PVector p) { + float mouseDist = HB.dist(p.x, p.y, HB.mouseX, HB.mouseY); + if (mouseDist < 100) { + float pushStrength = HB.map(mouseDist, 0, 50, 10, 0); + PVector pushDirection = new PVector(p.x - HB.mouseX, p.y - HB.mouseY); + pushDirection.normalize(); + pushDirection.mult(pushStrength); + p.add(pushDirection); + } + } + + // Handles audio processing for the visual. + private void audioHandler() { + HB.calculateAverageAmplitude(); + try { + HB.calculateFFT(); + } catch (VisualException e) { + e.printStackTrace(); + } + HB.calculateFrequencyBands(); + } +} \ No newline at end of file diff --git a/java/src/C22533826/terrainNoel.java b/java/src/C22533826/terrainNoel.java new file mode 100644 index 000000000..57287f8e9 --- /dev/null +++ b/java/src/C22533826/terrainNoel.java @@ -0,0 +1,118 @@ +package C22533826; + +import ie.tudublin.VisualException; +import ddf.minim.analysis.FFT; +import ie.tudublin.Heartbeat; + +public class terrainNoel { + + Heartbeat HB; + + int cols, rows; + int scale = 30; // Determines how large the cubes are. + + int w = 2600; + int h = 1600; + + // Variables for the terrain. + float flying = 0; + float yOffset = 0; + float xoff = 0; + float[][] cubeTerrain; + + public terrainNoel(int height, int width, Heartbeat HB) { + this.HB = HB; + + // Set the number of columns and rows based on the scale, w, and h. + this.cols = HB.floor(w / scale); + this.rows = HB.floor(h / scale); + + // Initialize the terrain. + this.cubeTerrain = new float[cols][rows]; + init_cubeTerrain(); + } + + public void render() { + HB.stroke(255); + HB.noFill(); + HB.strokeWeight(0); + generate_Terrain(); + + // Get desired angle for terrain. + HB.translate(HB.width / 3.8f, HB.height / 1.5f); + HB.rotateX(HB.PI / 2.5f); + HB.translate(-HB.width / 2.5f, (-HB.height / 1.5f)); + + // Render the terrain, cube by cube. + render_Terrain(); + } + + public void render_Terrain() { + for (int x = 0; x < cols; x++) { + for (int y = 0; y < rows; y++) { + color_Terrain(x, y); + HB.pushMatrix(); + HB.translate(x * scale, y * scale, cubeTerrain[x][y]); + HB.box(scale, scale, scale * 8); + HB.popMatrix(); + yOffset += 0.5; + } + xoff += 0.5; + } + } + + public void generate_Terrain() { + HB.calculateAverageAmplitude(); + flying -= 0.025f; + yOffset = flying; + + // Variables to determine terrain bounds, where it is 'flat', and where it is + // 'hilly'. + float middleMax = cols / 3.3f * 2; + int outerStart = (int) (cols * 0.1); + int outerEnd = (int) (cols * 0.9); + + for (int y = 0; y < rows; y++) { + float xoff = 0; + for (int x = 0; x < cols; x++) { + // Using amplitude and noise to generate terrain. Creates a pseduorandom terrain + // initially and we add the amplitude to it for interactivity with the song. + float noiseVal = HB.noise(xoff, yOffset); + float amplitude = HB.getSmoothedAmplitude(); + float noiseHeight = HB.map(noiseVal, 0, 1, -100, 100); + float amplitudeHeight = amplitude * 200; + float height = noiseHeight + amplitudeHeight; + + if (x > cols / 2.4f && x < middleMax) { + cubeTerrain[x][y] = HB.map(HB.noise(xoff, yOffset), 0, 1, -50, -10) + (height) / 2.5f; + } else if (x < outerStart || x > outerEnd) { + cubeTerrain[x][y] = HB.map(HB.noise(xoff, yOffset), 0, 1, -100, 200) + height; + } else { + cubeTerrain[x][y] = HB.map(HB.noise(xoff, yOffset), 0, 1, -100, 150) + height; + } + xoff += 0.2; + } + yOffset += 0.2; + } + } + + public void init_cubeTerrain() { + // Initializes the terrain to 0. + for (int x = 0; x < cols; x++) { + for (int y = 0; y < rows; y++) { + cubeTerrain[x][y] = 0; + } + } + } + + public void color_Terrain(int x, int y) { + // Colors each cube based on the height of the terrain. Adds depth. + float hue = 180; // Constant hue. + float brightness = HB.map(cubeTerrain[x][y], -100, 100, 10, 90); // Map brightness based on height. + HB.fill(hue, 100, brightness); + // Uncomment below for a more colorful terrain, matches heart visual/colors. + // HB.calculateAverageAmplitude(); + // float volume = HB.getSmoothedAmplitude(); + // float hue = HB.map(volume, 0, 1, 0, 255); + } +} \ No newline at end of file diff --git a/java/src/c22371846/Animation.java b/java/src/c22371846/Animation.java new file mode 100644 index 000000000..18ee13e79 --- /dev/null +++ b/java/src/c22371846/Animation.java @@ -0,0 +1,176 @@ +package c22371846; + +import ie.tudublin.Heartbeat; + +public class Animation { + + Heartbeat HB; + + float angle = 0; + + float[] lerpedBuffer; + + public Animation(Heartbeat HB) { + this.HB = HB; + lerpedBuffer = new float[HB.width]; + } + + public void render() { + float separated = 10; + float sum = 0; + float off = 0; + float average = 0; + float smoothedAmplitude = 0; + + int bar_values = (int) (HB.mouseX / 20.0f); + float w = HB.width / (float) bar_values; + float h = HB.height / separated; + float H = HB.height / 2; + float W = HB.width / 2; + + for (int i = 0; i < HB.getAudioBuffer().size(); i++) { + sum += HB.abs(HB.getAudioBuffer().get(i)); + lerpedBuffer[i] = HB.lerp(lerpedBuffer[i], HB.getAudioBuffer().get(i), 0.05f); + } + average = sum / (float) HB.getAudioBuffer().size(); + + smoothedAmplitude = HB.lerp(smoothedAmplitude, average, 0.75f); + + HB.getFFT().forward(HB.getAudioBuffer()); + + int maxFFTIndex = 0; + for (int i = 0; i < HB.getFFT().specSize() / 2; i++) { + if (HB.getFFT().getBand(i) > HB.getFFT().getBand(maxFFTIndex)) { + maxFFTIndex = i; + } + } + float freq = HB.getFFT().indexToFreq(maxFFTIndex); + + off += 10; + HB.background((off) % 256, HB.mouseX); + for (int i = 0; i < HB.getFFT().specSize() / 2; i++) { + + float c = HB.map(i, 0, HB.getAudioBuffer().size(), 0, 255); + float cc = c * i; + + HB.translate(100, 0, 0); + HB.rotateY(angle); + HB.rotateX(angle); + + if (HB.keyCode == HB.LEFT) { + HB.square(W, H, HB.lerp(0, smoothedAmplitude, (HB.getFFT().getBand(i) * 100))); + HB.fill((cc + off) % 256, HB.mouseX, 255); + } + + if (HB.keyCode == HB.RIGHT) { + HB.triangle(W, H, H, H, i, (HB.getFFT().getBand(i))); + HB.triangle(W, H, H, H, i, (HB.getFFT().getBand(i))); + HB.fill((cc + off) % 256, HB.mouseX, 255); + } + + if (HB.keyCode == HB.UP) { + HB.circle(W, H, (HB.getFFT().getBand(i) * 12)); + HB.fill((cc + off) % 256, HB.mouseX, 255); + } + + if (HB.keyCode == HB.DOWN) { + HB.box((HB.getFFT().getBand(i) * 3)); + HB.fill((cc + off) % 256, HB.mouseX, 255); + } + } + angle += 0.01f; + } +} + +// package c22371846; + +// import ddf.minim.AudioBuffer; +// import ddf.minim.AudioInput; +// import ddf.minim.AudioPlayer; +// import ddf.minim.Minim; +// import ddf.minim.analysis.FFT; +// import ie.tudublin.*; + +// public class Animation +// { + +// Minim minim; +// AudioPlayer ap; +// AudioInput ai; +// AudioBuffer ab; +// FFT fft; +// Heartbeat HB; +// float lerpedBuffer[]; + +// public void Stuff(Heartbeat HB) { +// this.fft = fft; +// this.minim = minim; +// this.ab = ab; +// this.ap = ap; +// this.ai = ai; +// this.HB = HB; +// } + +// public void render() +// { +// float separated = 10; +// float sum = 0; +// float off = 0; +// float average = 0; +// float smoothedAmplitude = 0; +// int bar_values = (int) (HB.mouseX / 20.0f); +// float w = HB.width / (float) bar_values; +// float h = HB.height / separated; +// float H = HB.height / 2; +// float W = HB.width / 2; + +// HB.getAmplitude(); + +// HB.getAudioBuffer(); + +// int maxFFTIndex = 0; +// for(int i = 0 ; i < fft.specSize() /2 ; i ++) +// { +// if (fft.getBand(i) > fft.getBand(maxFFTIndex)) +// { +// maxFFTIndex = i; +// } +// } + +// off+=10; +// HB.background((off) % 256, HB.mouseX); +// for(int i = 0 ; i < HB.getFFT() / 2; i ++) +// { +// float c = HB.map(i, 0, HB.getAudioBuffer(), 0, 255); +// float cc = c * i; +// HB.translate(100, 0, 0); +// HB.rotateY(angle); +// HB.rotateX(angle); +// if (HB.keyCode == HB.LEFT) +// { +// HB.square(W, H, HB.lerp(0, smoothedAmplitude, (HB.getBands() * 100))); +// HB.fill((cc + off) % 256, HB.mouseX, 255); +// } + +// if (HB.keyCode == HB.RIGHT) +// { +// HB.triangle(W, H, H, H, W, (HB.getBand())); +// HB.fill((cc + off) % 256, HB.mouseX, 255); +// } + +// if (HB.keyCode == HB.UP) { +// HB.circle(W, H, (HB.getBand() * 6)); +// HB.fill((cc + off) % 256, HB.mouseX, 255); + +// } + +// if (HB.keyCode == HB.DOWN) { +// HB.box((HB.getBand() * 3)); +// HB.fill((cc + off) % 256, HB.mouseX, 255); +// HB.stroke(0); +// } +// } +// angle += 0.01f; +// } +// float angle = 0; +// } diff --git a/java/src/c22371846/Graph.java b/java/src/c22371846/Graph.java new file mode 100644 index 000000000..4a12965df --- /dev/null +++ b/java/src/c22371846/Graph.java @@ -0,0 +1,75 @@ +package c22371846; + + +import ddf.minim.AudioBuffer; +import ddf.minim.AudioInput; +import ddf.minim.AudioPlayer; +import ddf.minim.Minim; +import ddf.minim.analysis.FFT; +import ie.tudublin.Heartbeat; + +public class Graph +{ + + Heartbeat HB; + float lerpedBuffer[]; + + public Graph(Heartbeat HB) { + this.HB = HB; + lerpedBuffer = new float[HB.width]; + } + + public void render() + { + float separated = 10; + float off = 0; + int bar_values = (int) (HB.mouseX / 20.0f); + float w = HB.width / (float) bar_values; + float h = HB.height / separated; + float H = HB.height / 2; + float sum = 0; + float average = 0; + float smoothedAmplitude = 0; + + HB.getAmplitude(); + + HB.getFFT().forward(HB.getAudioBuffer()); + + int maxFFTIndex = 0; + for (int i = 0; i < HB.getFFT().specSize() / 2; i++) { + if (HB.getFFT().getBand(i) > HB.getFFT().getBand(maxFFTIndex)) { + maxFFTIndex = i; + } + } + float freq = HB.getFFT().indexToFreq(maxFFTIndex); + + for (int i = 0; i < HB.getAudioBuffer().size(); i++) { + sum += HB.abs(HB.getAudioBuffer().get(i)); + lerpedBuffer[i] = HB.lerp(lerpedBuffer[i], HB.getAudioBuffer().get(i), 0.05f); + } + average = sum / (float) HB.getAudioBuffer().size(); + + smoothedAmplitude = HB.lerp(smoothedAmplitude, average, 0.75f); + off += 10; + HB.background(0); + HB.text("Frequencies: " + freq, HB.width - 300, HB.height - 50); + + //bar values + for (int i = 1; i < HB.getAudioBuffer().size(); i++) + { + float num = 50; + float f = lerpedBuffer[i] * H * 4.0f; + float x = HB.map(num * i, HB.width - 450, HB.width, num, HB.width); + float c = HB.map((off), 0, 200, 0, 255); + float cc = c * i; + HB.fill(cc % 256, 255, 255); + HB.rect(x, 0, w, f * H * 0.1F); + HB.noStroke(); + } + + for (int i = 0; i < 20; i++) + { + HB.text(i * 50, 25, (i * 50) + 10); + } + } +} \ No newline at end of file diff --git a/java/src/c22371846/PatricksVisual.java b/java/src/c22371846/PatricksVisual.java new file mode 100644 index 000000000..11c95a8db --- /dev/null +++ b/java/src/c22371846/PatricksVisual.java @@ -0,0 +1,177 @@ +package c22371846; + +import ie.tudublin.VisualException; +import ie.tudublin.Heartbeat; + +public class PatricksVisual { + + Heartbeat HB; + Graph graphVisual; + Animation animationVisual; + + int width, height; + + public PatricksVisual(Heartbeat HB) { + this.HB = HB; + this.graphVisual = new Graph(HB); + this.animationVisual = new Animation(HB); + + this.width = HB.width; + this.height = HB.height; + } + + public void renderGraph() { + graphVisual.render(); + } + + public void renderAnimation() { + animationVisual.render(); + } +} + +// package c22371846; + +// import ddf.minim.AudioBuffer; +// import ddf.minim.AudioInput; +// import ddf.minim.AudioPlayer; +// import ddf.minim.Minim; +// import processing.core.PApplet; +// import ddf.minim.analysis.FFT; + +// public class PatricksVisuals extends PApplet { +// Minim minim; +// AudioPlayer ap; +// AudioInput ai; +// AudioBuffer ab; +// FFT fft; + +// int mode = 0; +// float[] lerpedBuffer; + +// public void settings() { +// size(1024, 800, P3D); +// // fullScreen(P3D, SPAN); +// } + +// public void setup() { +// colorMode(HSB); +// background(0); +// minim = new Minim(this); +// // Microphone +// // ai = minim.getLineIn(Minim.MONO, width, 44100, 16); +// // ab = ai.mix; + +// // Music +// ap = minim.loadFile("Heartbeat.mp3", 1024); +// ap.play(); +// ab = ap.mix; +// fft = new FFT(width, 44100); + +// lerpedBuffer = new float[width]; +// } + +// public void keyPressed() { +// if (key >= '0' && key <= '9') { +// mode = key - '0'; +// } +// if (keyCode == ' ') { +// if (ap.isPlaying()) { +// ap.pause(); +// } else { +// ap.rewind(); +// ap.play(); +// } +// } +// } + +// public void draw() { +// float separated = 10; +// float sum = 0; +// float off = 0; +// float average = 0; +// float smoothedAmplitude = 0; +// int bar_values = (int) (mouseX / 20.0f); +// float w = width / (float) bar_values; +// float h = height / separated; +// float H = height / 2; +// float W = width / 2; + +// for (int i = 0; i < ab.size(); i++) { +// sum += abs(ab.get(i)); +// lerpedBuffer[i] = lerp(lerpedBuffer[i], ab.get(i), 0.05f); +// } +// average = sum / (float) ab.size(); + +// smoothedAmplitude = lerp(smoothedAmplitude, average, 0.75f); + +// fft.forward(ab); + +// int maxFFTIndex = 0; +// for (int i = 0; i < fft.specSize() / 2; i++) { +// if (fft.getBand(i) > fft.getBand(maxFFTIndex)) { +// maxFFTIndex = i; +// } +// } +// float freq = fft.indexToFreq(maxFFTIndex); + +// switch (mode) { +// case 0: { +// off += 10; +// background(0); +// text("Frequencies: " + freq, width - 300, height - 50); + +// // bar values +// for (int i = 1; i < ab.size(); i++) { +// float num = 50; +// float f = lerpedBuffer[i] * H * 4.0f; +// float x = map(num * i, width - 450, width, num, width); +// float c = map((off), 0, 200, 0, 255); +// float cc = c * i; +// fill(cc % 256, 255, 255); +// rect(x, 0, w, f * h * 0.15F); +// noStroke(); +// } + +// for (int i = 0; i < 20; i++) { +// text(i * 50, 25, (i * 50) + 10); +// } +// break; +// } +// case 1: { +// off += 10; +// background((off) % 256, mouseX); +// for (int i = 0; i < fft.specSize() / 2; i++) { +// float c = map(i, 0, ab.size(), 0, 255); +// float cc = c * i; +// translate(100, 0, 0); +// rotateY(angle); +// rotateX(angle); +// if (keyCode == LEFT) { +// square(W, H, lerp(0, smoothedAmplitude, (fft.getBand(i) * 100))); +// fill((cc + off) % 256, mouseX, 255); +// } + +// if (keyCode == RIGHT) { +// triangle(W, H, H, H, i, (fft.getBand(i))); +// fill((cc + off) % 256, mouseX, 255); +// } + +// if (keyCode == UP) { +// circle(W, H, (fft.getBand(i) * 6)); +// fill((cc + off) % 256, mouseX, 255); + +// } + +// if (keyCode == DOWN) { +// box((fft.getBand(i) * 3)); +// fill((cc + off) % 256, mouseX, 255); +// } +// } +// angle += 0.01f; +// break; +// } +// } +// } + +// float angle = 0; +// } \ No newline at end of file diff --git a/java/src/c22371846/Saved.java b/java/src/c22371846/Saved.java new file mode 100644 index 000000000..e9c2056a1 --- /dev/null +++ b/java/src/c22371846/Saved.java @@ -0,0 +1,24 @@ +package c22371846; + +import ie.tudublin.*; + + +public class Saved +{ + Graph G; + Animation A; + Heartbeat HB; + + public Saved(Heartbeat HB) { + this.HB = HB; + //this.A = new Animation(); + // this.G = new Graph(); + } + + public void render() { + HB.background(0); + A.render(); + G.render(); + } +} + diff --git a/java/src/example/MyVisual.java b/java/src/example/MyVisual.java index 8a71fe3f6..9ad07d62d 100644 --- a/java/src/example/MyVisual.java +++ b/java/src/example/MyVisual.java @@ -1,5 +1,6 @@ package example; +import C21325616.MichaelsVisuals; import ie.tudublin.*; public class MyVisual extends Visual { @@ -7,7 +8,7 @@ public class MyVisual extends Visual { AudioBandsVisual abv; public void settings() { - size(1024, 500); + size(1024, 500, P3D); // Use this to make fullscreen // fullScreen(); @@ -49,7 +50,7 @@ public void draw() { // Call this is you want to get the average amplitude calculateAverageAmplitude(); - wf.render(); - abv.render(); + //wf.render(); + //abv.render(); } } diff --git a/java/src/example/RotatingAudioBands.java b/java/src/example/RotatingAudioBands.java index 72fd7a223..69de42750 100644 --- a/java/src/example/RotatingAudioBands.java +++ b/java/src/example/RotatingAudioBands.java @@ -5,37 +5,31 @@ public class RotatingAudioBands extends Visual { - - public void settings() - { + public void settings() { size(800, 800, P3D); println("CWD: " + System.getProperty("user.dir")); - //fullScreen(P3D, SPAN); + // fullScreen(P3D, SPAN); } - public void keyPressed() - { - if (key == ' ') - { + public void keyPressed() { + if (key == ' ') { getAudioPlayer().cue(0); getAudioPlayer().play(); - } - + } - public void setup() - { + public void setup() { colorMode(HSB); noCursor(); - + setFrameSize(256); startMinim(); - loadAudio("heroplanet.mp3"); + loadAudio("Heartbeat.mp3"); getAudioPlayer().play(); - //startListening(); - + // startListening(); + } float radius = 200; @@ -44,15 +38,11 @@ public void setup() float rot = 0; - public void draw() - { + public void draw() { calculateAverageAmplitude(); - try - { + try { calculateFFT(); - } - catch(VisualException e) - { + } catch (VisualException e) { e.printStackTrace(); } calculateFrequencyBands(); @@ -62,14 +52,13 @@ public void draw() lights(); stroke(map(getSmoothedAmplitude(), 0, 1, 0, 255), 255, 255); camera(0, -500, 500, 0, 0, 0, 0, 1, 0); - //translate(0, 0, -250); + // translate(0, 0, -250); rot += getAmplitude() / 8.0f; rotateY(rot); float[] bands = getSmoothedBands(); - for(int i = 0 ; i < bands.length ; i ++) - { + for (int i = 0; i < bands.length; i++) { float theta = map(i, 0, bands.length, 0, TWO_PI); stroke(map(i, 0, bands.length, 0, 255), 255, 255); @@ -77,13 +66,14 @@ public void draw() float z = cos(theta) * radius; float h = bands[i]; pushMatrix(); - translate(x, - h / 2 , z); + translate(x, -h / 2, z); rotateY(theta); box(50, h, 50); popMatrix(); } } + float angle = 0; } \ No newline at end of file diff --git a/java/src/ie/tudublin/Heartbeat.java b/java/src/ie/tudublin/Heartbeat.java new file mode 100644 index 000000000..c0cbe02bb --- /dev/null +++ b/java/src/ie/tudublin/Heartbeat.java @@ -0,0 +1,113 @@ +package ie.tudublin; + +import C21325616.MichaelsVisuals; +import C22533826.NoelsVisual; +import C22533826.menuScreen; +import c22371846.PatricksVisual; +import C22328351.LarinasVisual; + +public class Heartbeat extends Visual { + + int mode = 0; + NoelsVisual noelsVisual; + MichaelsVisuals michaelsVisuals; + LarinasVisual LarinasVisual; + PatricksVisual patricksVisuals; + menuScreen MenuScreen; + + public void settings() { + println("CWD: " + System.getProperty("user.dir")); + fullScreen(P3D, SPAN); + } + + public void setup() { + colorMode(HSB); + setFrameSize(512); + startMinim(); + loadAudio("/Users/michaelferents/Desktop/OOPAssignment/MusicVisuals/java/data/Heartbeat.mp3"); + getAudioPlayer().play(); + // startListening(); + // noCursor(); + + noelsVisual = new NoelsVisual(this); + michaelsVisuals = new MichaelsVisuals(this); + patricksVisuals = new PatricksVisual(this); + LarinasVisual = new LarinasVisual(this); + MenuScreen = new menuScreen(this); + + } + + public void draw() { + switch (mode) { + + + case 0: + getAudioPlayer().pause(); + MenuScreen.renderMenu(); + break; + + case 1: + getAudioPlayer().play(); + noelsVisual.renderScene(); + break; + case 2: + getAudioPlayer().play(); + noelsVisual.resetCamera(); + noelsVisual.setDefaultCamera(); + patricksVisuals.renderAnimation(); + break; + case 3: + getAudioPlayer().play(); + michaelsVisuals.renderVisualOne(); + break; + case 4: + getAudioPlayer().play(); + noelsVisual.resetCamera(); + noelsVisual.setDefaultCamera(); + LarinasVisual.draw(); + break; + case 5: + noelsVisual.resetCamera(); + noelsVisual.setDefaultCamera(); + patricksVisuals.renderGraph(); + + michaelsVisuals.renderVisualTwo(); + break; + case 5: + getAudioPlayer().play(); + noelsVisual.resetCamera(); + noelsVisual.setDefaultCamera(); + LarinasVisual.render(); + break; + case 6: + // Addtional renderings... + + break; + default: + break; + } + } + + public void keyPressed() { + // Pauses playback of the song + if (key == ' ') { + if (getAudioPlayer().isPlaying()) { + getAudioPlayer().pause(); + } else { + getAudioPlayer().play(); + } + } + + // Uses mode variable to switch between visuals + if (keyCode >= '0' && keyCode <= '9') { + mode = keyCode - '0'; + } + + // Restarts the song + if (key == 'r') { + getAudioPlayer().cue(0); + getAudioPlayer().play(); + } + } + +} \ No newline at end of file diff --git a/java/src/ie/tudublin/Main.java b/java/src/ie/tudublin/Main.java index 67e93d892..fc1d74988 100644 --- a/java/src/ie/tudublin/Main.java +++ b/java/src/ie/tudublin/Main.java @@ -1,18 +1,14 @@ package ie.tudublin; -import example.CubeVisual; -import example.MyVisual; -import example.RotatingAudioBands; - public class Main { public void startUI() { String[] a = { "MAIN" }; - processing.core.PApplet.runSketch(a, new MyVisual()); + processing.core.PApplet.runSketch(a, new Heartbeat()); } public static void main(String[] args) { - Main main = new Main(); + Main main = new Main(); main.startUI(); } -} \ No newline at end of file +} diff --git a/java/src/ie/tudublin/Visual.java b/java/src/ie/tudublin/Visual.java index 927fe57b1..a51a931cd 100644 --- a/java/src/ie/tudublin/Visual.java +++ b/java/src/ie/tudublin/Visual.java @@ -4,8 +4,7 @@ import ddf.minim.*; import ddf.minim.analysis.FFT; -public abstract class Visual extends PApplet -{ +public abstract class Visual extends PApplet { private int frameSize = 512; private int sampleRate = 44100; @@ -18,19 +17,16 @@ public abstract class Visual extends PApplet private AudioBuffer ab; private FFT fft; - private float amplitude = 0; + private float amplitude = 0; private float smothedAmplitude = 0; - - - public void startMinim() - { + public void startMinim() { minim = new Minim(this); fft = new FFT(frameSize, sampleRate); bands = new float[(int) log2(frameSize)]; - smoothedBands = new float[bands.length]; + smoothedBands = new float[bands.length]; } @@ -38,33 +34,25 @@ float log2(float f) { return log(f) / log(2.0f); } - protected void calculateFFT() throws VisualException - { + public void calculateFFT() throws VisualException { fft.window(FFT.HAMMING); - if (ab != null) - { + if (ab != null) { fft.forward(ab); - } - else - { + } else { throw new VisualException("You must call startListening or loadAudio before calling fft"); } } - - public void calculateAverageAmplitude() - { + public void calculateAverageAmplitude() { float total = 0; - for(int i = 0 ; i < ab.size() ; i ++) - { + for (int i = 0; i < ab.size(); i++) { total += abs(ab.get(i)); } amplitude = total / ab.size(); smothedAmplitude = PApplet.lerp(smothedAmplitude, amplitude, 0.1f); } - - protected void calculateFrequencyBands() { + public void calculateFrequencyBands() { for (int i = 0; i < bands.length; i++) { int start = (int) pow(2, i) - 1; int w = (int) pow(2, i); @@ -79,14 +67,12 @@ protected void calculateFrequencyBands() { } } - public void startListening() - { + public void startListening() { ai = minim.getLineIn(Minim.MONO, frameSize, 44100, 16); ab = ai.left; } - public void loadAudio(String filename) - { + public void loadAudio(String filename) { ap = minim.loadFile(filename, frameSize); ab = ap.mix; } @@ -123,7 +109,6 @@ public AudioInput getAudioInput() { return ai; } - public AudioBuffer getAudioBuffer() { return ab; } @@ -143,4 +128,9 @@ public AudioPlayer getAudioPlayer() { public FFT getFFT() { return fft; } + + public static void render() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'render'"); + } }