diff --git a/README.md b/README.md
index 19ba88c75..c120bdbc8 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
# Music Visualiser Project
-Name:
+Name:Seán Flood & Ralph Cruz
-Student Number:
+Student Number: C22421292 & C22427602
## Instructions
- Fork this repository and use it a starter project for your assignment
@@ -14,10 +14,71 @@ Student Number:
# Description of the assignment
# Instructions
+Using keyboard keys ‘1’ and ‘2’ you can change scenes:
+
+
+
+
+
+‘ ‘ (spacebar) pauses and plays the song
+
+
+
+‘r’ clears the current scene just leaving the screen black with the lyrics still playing
+
+
+
+‘s’ enters “spam mode” on when scene 2 is active. Spam mode just calls the “sceneChange” function in SeanVisuals.java very fast.
+Not actually screenshotable because it uses motion and screenshots are freezeframes.
# How it works
+In the Main.java file we call our "Seno.java" file and create that sketch
+```Java
+package ie.tudublin;
+
+public class Main {
+
+ public void startUI() {
+ String[] a = { "MAIN" };
+ processing.core.PApplet.runSketch(a, new Seno()); // <-- Call Seno file here
+ }
+
+ public static void main(String[] args) {
+ Main main = new Main();
+ main.startUI();
+ }
+}
+```
+
+In the Seno.java file we then import our respective files
+```Java
+import c22427602.RalphVisuals;
+import c22421292.SeanVisuals;
+
+public class Seno extends Visual {
+ RalphVisuals Ralph;
+ private boolean drawSphere = false;
+ SeanVisuals Sean;
+ private boolean drawCube = false;
+
+ public void setup() {
+ Ralph = new RalphVisuals(); // Instantiate Ralph object
+ Ralph.setParent(this);
+
+ Sean = new SeanVisuals(); // Instantiate Sean object
+ Sean.setParent(this);
+
+ public void draw() {
+ if (drawSphere) {
+ Ralph.draw();
+ }
+ else if (drawCube) {
+ Sean.draw();
+ }
+```
# What I am most proud of in the assignment
+I am most proud of making a scene that I beleive is fun to watch and interactable in many ways which can keep the user entertained and interested. There are many objects that move based on the music which makes it visually apealing and being able to change the appearance using keyboard keys makes it interesting.
# Markdown Tutorial
diff --git a/java/.project b/java/.project
index 0d5afed93..07a0234c2 100644
--- a/java/.project
+++ b/java/.project
@@ -16,12 +16,12 @@
- 1616413840733
+ 1710347475853
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/Renai Circulation\346\201\213\346\204\233\343\202\265\343\203\274\343\202\255\343\203\245\343\203\254\343\203\274\343\202\267\343\203\247\343\203\263Kana Hanazawa.mp3" "b/java/data/Renai Circulation\346\201\213\346\204\233\343\202\265\343\203\274\343\202\255\343\203\245\343\203\254\343\203\274\343\202\267\343\203\247\343\203\263Kana Hanazawa.mp3"
new file mode 100644
index 000000000..027b13dc5
Binary files /dev/null and "b/java/data/Renai Circulation\346\201\213\346\204\233\343\202\265\343\203\274\343\202\255\343\203\245\343\203\254\343\203\274\343\202\267\343\203\247\343\203\263Kana Hanazawa.mp3" differ
diff --git "a/java/data/[Japanese] Renai Circulation\343\200\214\346\201\213\346\204\233\343\202\265\343\203\274\343\202\255\343\203\245\343\203\254\343\203\274\343\202\267\343\203\247\343\203\263\343\200\215Kana Hanazawa [DownSub.com].srt" "b/java/data/[Japanese] Renai Circulation\343\200\214\346\201\213\346\204\233\343\202\265\343\203\274\343\202\255\343\203\245\343\203\254\343\203\274\343\202\267\343\203\247\343\203\263\343\200\215Kana Hanazawa [DownSub.com].srt"
new file mode 100644
index 000000000..6357ffed3
--- /dev/null
+++ "b/java/data/[Japanese] Renai Circulation\343\200\214\346\201\213\346\204\233\343\202\265\343\203\274\343\202\255\343\203\245\343\203\254\343\203\274\343\202\267\343\203\247\343\203\263\343\200\215Kana Hanazawa [DownSub.com].srt"
@@ -0,0 +1,308 @@
+1
+00:00:00,700 --> 00:00:01,610
+(se~ no!)
+
+2
+00:00:01,610 --> 00:00:03,620
+demo sonnan ja dame
+
+3
+00:00:03,620 --> 00:00:05,610
+mou sonnan ja hora
+
+4
+00:00:05,610 --> 00:00:07,870
+kokoro wa shinka suru yo
+
+5
+00:00:07,870 --> 00:00:10,170
+motto motto
+
+6
+00:00:25,370 --> 00:00:27,860
+kotoba ni sureba kiechau kankei nara
+
+7
+00:00:27,860 --> 00:00:29,610
+kotoba o keseba ii ya tte
+
+8
+00:00:29,610 --> 00:00:31,370
+omotteta osoreteta
+
+9
+00:00:31,370 --> 00:00:33,359
+dakedo are? nanka chigau kamo…
+
+10
+00:00:33,359 --> 00:00:35,370
+senri no michi mo ippo kara!
+
+11
+00:00:35,370 --> 00:00:37,609
+ishi no you ni katai sonna ishi de
+
+12
+00:00:37,609 --> 00:00:39,870
+chiri mo tsumoreba Yamato Nadeshiko?
+
+13
+00:00:39,870 --> 00:00:41,859
+‘shi’ nuki de iya shinu ki de!
+
+14
+00:00:41,859 --> 00:00:44,859
+fuwafuwari fuwafuwaru
+
+15
+00:00:44,859 --> 00:00:46,870
+anata ga namae o yobu
+
+16
+00:00:46,870 --> 00:00:47,870
+sore dake de
+
+17
+00:00:47,870 --> 00:00:49,870
+chuu e ukabu
+
+18
+00:00:49,870 --> 00:00:52,870
+fuwafuwaru fuwafuwari
+
+19
+00:00:52,870 --> 00:00:54,870
+anata ga waratte iru
+
+20
+00:00:54,870 --> 00:00:55,870
+sore dake de
+
+21
+00:00:55,870 --> 00:00:57,860
+egao ni naru
+
+22
+00:00:57,860 --> 00:01:01,610
+kami-sama arigatou
+
+23
+00:01:01,610 --> 00:01:05,860
+unmei no itazura demo
+
+24
+00:01:05,860 --> 00:01:09,370
+meguriaeta koto ga
+
+25
+00:01:09,370 --> 00:01:13,620
+shiawase na no
+
+26
+00:01:13,620 --> 00:01:15,610
+demo sonnan ja dame
+
+27
+00:01:15,610 --> 00:01:17,620
+mou sonnan ja hora
+
+28
+00:01:17,620 --> 00:01:19,860
+kokoro wa shinka suru yo
+
+29
+00:01:19,860 --> 00:01:21,620
+motto motto
+
+30
+00:01:21,620 --> 00:01:23,370
+sou sonnan ja ya da
+
+31
+00:01:23,370 --> 00:01:25,620
+nee sonnan ja mada
+
+32
+00:01:25,620 --> 00:01:27,860
+watashi no koto mitete ne
+
+33
+00:01:27,860 --> 00:01:30,160
+zutto zutto
+
+34
+00:01:45,610 --> 00:01:47,370
+watashi no naka no anata hodo
+
+35
+00:01:47,370 --> 00:01:49,620
+anata no naka no watashi no sonzai wa
+
+36
+00:01:49,620 --> 00:01:52,110
+madamada ookikunai koto mo
+
+37
+00:01:52,110 --> 00:01:53,370
+wakatteru keredo
+
+38
+00:01:53,370 --> 00:01:55,610
+ima kono onaji shunkan
+
+39
+00:01:55,610 --> 00:01:57,620
+kyouyuu shiteru jikkan
+
+40
+00:01:57,620 --> 00:01:59,860
+chiri mo tsumoreba Yamato Nadeshiko!
+
+41
+00:01:59,860 --> 00:02:01,870
+ryakushite? chiri-tsumo Yamato Nadeko!
+
+42
+00:02:01,870 --> 00:02:04,620
+kurakurari kurakuraru
+
+43
+00:02:04,620 --> 00:02:06,860
+anata o miagetara
+
+44
+00:02:06,860 --> 00:02:07,860
+sore dake de
+
+45
+00:02:07,860 --> 00:02:09,869
+mabushisugite
+
+46
+00:02:09,869 --> 00:02:12,619
+kurakuraru kurakurari
+
+47
+00:02:12,619 --> 00:02:14,860
+anata o omotte iru
+
+48
+00:02:14,860 --> 00:02:15,869
+sore dake de
+
+49
+00:02:15,869 --> 00:02:17,870
+tokete shimau
+
+50
+00:02:17,870 --> 00:02:21,620
+kami-sama arigatou
+
+51
+00:02:21,620 --> 00:02:25,870
+unmei no itazura demo
+
+52
+00:02:25,870 --> 00:02:29,620
+meguriaeta koto ga
+
+53
+00:02:29,620 --> 00:02:33,870
+shiawase na no
+
+54
+00:02:33,870 --> 00:02:42,110
+KO I SU RU KI SE TSU WA YO KU BA RI Circulation
+
+55
+00:02:42,110 --> 00:02:49,870
+KO I SU RU KI MO CHI WA YO KU BA RI Circulation
+
+56
+00:02:49,870 --> 00:02:57,610
+KO I SU RU HI TO MI WA YO KU BA RI Circulation
+
+57
+00:02:57,610 --> 00:03:05,919
+KO I SU RU O TO ME WA YO KU BA RI Circulation
+
+58
+00:03:07,619 --> 00:03:10,869
+fuwafuwari fuwafuwaru
+
+59
+00:03:10,869 --> 00:03:12,869
+anata ga namae o yobu
+
+60
+00:03:12,869 --> 00:03:13,860
+sore dake de
+
+61
+00:03:13,860 --> 00:03:15,860
+chuu e ukabu
+
+62
+00:03:15,860 --> 00:03:18,870
+fuwafuwaru fuwafuwari
+
+63
+00:03:18,870 --> 00:03:20,870
+anata ga waratte iru
+
+64
+00:03:20,870 --> 00:03:21,860
+sore dake de
+
+65
+00:03:21,860 --> 00:03:23,870
+egao ni naru
+
+66
+00:03:23,870 --> 00:03:27,610
+kami-sama arigatou
+
+67
+00:03:27,610 --> 00:03:31,870
+unmei no itazura demo
+
+68
+00:03:31,870 --> 00:03:35,610
+meguriaeta koto ga
+
+69
+00:03:35,610 --> 00:03:39,620
+shiawase na no
+
+70
+00:03:55,500 --> 00:03:57,610
+demo sonnan ja dame
+
+71
+00:03:57,610 --> 00:03:59,620
+mou sonnan ja hora
+
+72
+00:03:59,620 --> 00:04:01,870
+kokoro wa shinka suru yo
+
+73
+00:04:01,870 --> 00:04:03,620
+motto motto
+
+74
+00:04:03,620 --> 00:04:05,610
+sou sonnan ja ya da
+
+75
+00:04:05,610 --> 00:04:07,630
+nee sonnan ja mada
+
+76
+00:04:07,630 --> 00:04:09,870
+watashi no koto mitete ne
+
+77
+00:04:09,870 --> 00:04:12,870
+zutto zutto
+
diff --git a/java/data/heroplanet.mp3 b/java/data/heroplanet.mp3
deleted file mode 100644
index 681f02d31..000000000
Binary files a/java/data/heroplanet.mp3 and /dev/null differ
diff --git a/java/src/C22421292/SeanVisuals.java b/java/src/C22421292/SeanVisuals.java
new file mode 100644
index 000000000..6ac7430fc
--- /dev/null
+++ b/java/src/C22421292/SeanVisuals.java
@@ -0,0 +1,215 @@
+package c22421292;
+
+import ie.tudublin.*;
+import processing.core.PVector;
+import processing.core.PApplet;
+import java.util.ArrayList;
+
+public class SeanVisuals extends Visual{
+ private PApplet parent; //Reference to PApplet app
+ private float angle = 0.0f; //Used for cube spinning
+ public int scene = 0; //Used for keeping track of which scene is active
+ public float cameraX, cameraY; //Camera position
+ public int sunColor, moonColor; //Color of sun and moon spheres
+ public int bgHue, bgBrightness = 0; //Used for color of background
+ public int bandColor = 0; //Color of the audiobands also used for stars fill
+ private boolean spamMode = false; //Boolean for whether spam is on or off
+ private ArrayList stars; //Store positions of stars
+
+ public void setParent(PApplet parent) {
+ this.parent = parent;
+ this.g = parent.g;
+ this.width = parent.width;
+ this.height = parent.height;
+ stars = new ArrayList<>();
+ addStars(500); //Add stars in background
+ }
+
+ public void sceneChange() {
+ if (scene < 3) {
+ scene++; //Next scene if scene is less than 3
+ } else {
+ scene = 1; //if scene is == 3 set it back to 1 to let it cycle through
+ }
+ }
+
+ public void spamMode() {
+ if (spamMode == true) {
+ spamMode = false; //if spamMode is on, turn it off
+ }
+ else {
+ spamMode = true; //if spamMode is off, turn it on
+ }
+ }
+
+ private void drawSingleCube(float xPosition, float yPosition, float sizeMod, int cubeColor) {
+ float amplitude = ((Visual)parent).getSmoothedAmplitude(); //Get amplitude
+
+ parent.pushMatrix();
+ parent.translate(xPosition, yPosition, -200); //Position cube
+ parent.rotateX(PApplet.radians(-15)); //Tilt cubes downwards
+ parent.rotateY(-angle); //Rotate anti-clockwise
+ float size = 1000 * (0.5f + 1.1f * amplitude); //Cube size based on amplitude
+ parent.fill(cubeColor); //Fill cubes with color
+ parent.box(size*sizeMod); //Draw the cube
+ parent.popMatrix();
+ }
+
+
+ private void drawCube() {
+ int colorBottomCube, colorTopLeftCube, colorTopRightCube; //Variables to hold color values
+
+ switch(scene) {
+ case 1:
+ colorBottomCube = parent.color(180, 155, 255);
+ colorTopLeftCube = parent.color(300, 155, 255);
+ colorTopRightCube = parent.color(60, 190, 255);
+ sunColor = parent.color(300, 155, 255);
+ moonColor = parent.color(60, 190, 255);
+ bandColor = parent.color(180, 155, 255);
+ break;
+ case 2:
+ colorBottomCube = parent.color(60, 190, 255);
+ colorTopLeftCube = parent.color(180, 155, 255);
+ colorTopRightCube = parent.color(300, 155, 255);
+ sunColor = parent.color(180, 155, 255);
+ moonColor = parent.color(300, 155, 255);
+ bandColor = parent.color(60, 190, 255);
+ break;
+ case 3:
+ colorBottomCube = parent.color(300, 155, 255);
+ colorTopLeftCube = parent.color(60, 190, 255);
+ colorTopRightCube = parent.color(180, 155, 255);
+ sunColor = parent.color(60, 190, 255);
+ moonColor = parent.color(180, 155, 255);
+ bandColor = parent.color(300, 155, 255);
+ break;
+ default:
+ colorBottomCube = colorTopLeftCube = colorTopRightCube = parent.color(0, 0, 255); //Give cubes a color value. Wont show up
+ }
+
+ if (parent instanceof Visual) {
+ ((Visual)parent).calculateAverageAmplitude(); //get average amplitude
+ }
+ float amplitude = ((Visual)parent).getSmoothedAmplitude(); //Smooth amplitude
+ float baseY = map(amplitude, 0, 1, parent.height * 0.9f, parent.height * 0.1f);
+
+ parent.lights();
+ parent.noStroke();
+
+ float sizeMod = 1.0f; //Change size of cubes certain cubes
+
+ //Coordinates and drawing for the bottom cube
+ float bottomX = parent.width * 0.5f;
+ float bottomY = baseY;
+ drawSingleCube(bottomX, bottomY, 1.45f, colorBottomCube);
+
+ //Coordinates and drawing for the top left and top right cubes
+ float topXOffset = 1800;
+ float topY = bottomY - (1000 * (0.5f + 1.1f * amplitude) * sizeMod * 0.8f);
+ drawSingleCube(bottomX - topXOffset, topY, 1, colorTopLeftCube);
+ drawSingleCube(bottomX + topXOffset, topY, 1, colorTopRightCube);
+
+ angle += 0.05; //Rotate cubes
+ }
+
+ public void addStars(int number) {
+ for (int i = 0; i < number; i++) {
+ float x = parent.random(-parent.width * 1.5f, parent.width * 1.5f);
+ float y = parent.random(-parent.height * 1.5f, parent.height * 1.5f);
+ float z = parent.random(-5000, 5000);
+ stars.add(new PVector(x, y, z)); //Fill array with random positions for stars to spawn into
+ }
+ }
+
+ private void drawStars() {
+ float amplitude = parent instanceof Visual ? ((Visual) parent).getSmoothedAmplitude() : 0;
+ for (PVector star : stars) {
+ parent.pushMatrix();
+ parent.noStroke();
+
+ float bopAmplitude = 30 * amplitude;
+ float rate = map(star.x, -parent.width, parent.width, 5.0f, 15.0f);
+ float dynamicY = star.y + bopAmplitude * sin(parent.frameCount / rate);
+
+ parent.fill(parent.color(bandColor, 128));
+ parent.translate(star.x, dynamicY, star.z);
+ float size = 10 + 5 * sin(parent.frameCount / 40.0f);
+ parent.sphere(size);
+
+ parent.popMatrix();
+ }
+ }
+
+ private void drawSpheres() { //Draw both spheres using single function
+ drawLeftSphere();
+ drawRightSphere();
+ }
+
+ private void drawLeftSphere() {
+ if (parent instanceof Visual) {
+ ((Visual)parent).calculateAverageAmplitude();
+ }
+ float amplitude = ((Visual)parent).getSmoothedAmplitude();
+ float yPosition = parent.height-15000 * 0.2f + map(amplitude, 0, 1, 50, -50);
+
+ float baseX = parent.width * -0.9f;
+ float oscillationRange = parent.width * 0.4f * amplitude;
+ float xPosition = baseX - oscillationRange * sin(parent.frameCount * 0.05f);
+
+ parent.lights();
+ parent.noStroke();
+ parent.fill(sunColor);
+
+ int detail = (int) map(amplitude, 0, 1, 6, 24);
+ parent.sphereDetail(detail);
+ float size = 300 * (0.5f + 3.0f * amplitude);
+
+ parent.pushMatrix();
+ parent.translate(xPosition, yPosition, -200);
+ parent.sphere(size);
+ parent.popMatrix();
+ }
+
+ private void drawRightSphere() {
+ if (parent instanceof Visual) {
+ ((Visual)parent).calculateAverageAmplitude();
+ }
+ float amplitude = ((Visual)parent).getSmoothedAmplitude();
+ float yPosition = parent.height-15000 * 0.2f + map(amplitude, 0, 1, 50, -50);
+
+ float baseX = parent.width+2400 * 0.9f;
+ float oscillationRange = parent.width * 0.4f * amplitude;
+ float xPosition = baseX + oscillationRange * sin(parent.frameCount * 0.05f);
+
+ parent.lights();
+ parent.noStroke();
+ parent.fill(moonColor);
+
+ int detail = (int) map(amplitude, 0, 1, 6, 24);
+ parent.sphereDetail(detail);
+ float size = 300 * (0.5f + 3.0f * amplitude);
+
+ parent.pushMatrix();
+ parent.translate(xPosition, yPosition, -200);
+ parent.sphere(size);
+ parent.popMatrix();
+ }
+
+ public void draw() {
+ float fov = PApplet.PI / 3; //Calculate fov of camera
+ float cameraY = parent.height / 2.0f; //Calculate height of camera
+ float cameraZ = (cameraY / PApplet.tan(fov / 2.0f)) * 4; //Calculate distance of camera to scene
+ parent.perspective(fov, (float) parent.width / (float) parent.height, 1, 10000); //Set fov and distance of camera
+ parent.camera(parent.width / 2.0f, cameraY, cameraZ, parent.width / 2.0f, cameraY, 0, 0, 1, 0); //Make camera in set position
+ parent.background(bgHue, 255, bgBrightness); //Set background color
+
+ drawStars(); //Draw stars
+ drawCube(); //Draw the cubes
+ drawSpheres(); //Draw both top left and top right sphere
+
+ if (spamMode) {
+ sceneChange(); //Call sceneChange function A LOT
+ }
+ }
+}
\ No newline at end of file
diff --git a/java/src/c22427602/RalphVisuals.java b/java/src/c22427602/RalphVisuals.java
new file mode 100644
index 000000000..451d425b9
--- /dev/null
+++ b/java/src/c22427602/RalphVisuals.java
@@ -0,0 +1,211 @@
+package c22427602;
+
+import ie.tudublin.*;
+import processing.core.PVector;
+import processing.core.PApplet;
+import processing.core.PMatrix3D;
+import java.util.ArrayList;
+//import processing.core.PShape; //may need to re-enable
+
+public class RalphVisuals extends Visual {
+ private PApplet parent; // Reference to PApplet app
+ //private float angle = 0.0f; // Angle for sine wave calculation //may need to re-enable
+ private ArrayList stars; // Store positions of stars
+ private float currentX = 0;
+ private float targetX = 0;
+ public float cameraX;
+ public float cameraY;
+ public float x, y, z = 0;
+ float angle = 0.0f; // Angle for sine wave calculation
+
+ // Method to set the parent PApplet
+ public void setParent(PApplet parent) {
+ this.parent = parent;
+ this.g = parent.g;
+ this.width = parent.width;
+ this.height = parent.height;
+ stars = new ArrayList<>();
+
+ }
+
+ public void addStars(int number) {
+ for (int i = 0; i < number; i++) {
+ float x = parent.random(-parent.width * 1.5f, parent.width * 1.5f);
+ float y = parent.random(-parent.height * 1.5f, parent.height * 1.5f);
+ float z = parent.random(-5000, 5000);
+ stars.add(new PVector(x, y, z));
+ }
+ }
+
+ private void drawStars() {
+ float amplitude = parent instanceof Visual ? ((Visual)parent).getSmoothedAmplitude() : 0;
+ for (PVector star : stars) {
+ parent.pushMatrix();
+ parent.noStroke();
+
+ float hue = (parent.frameCount * 10 + 360 * (star.x + parent.width) / (2 * parent.width)) % 360;
+ // Brightness that cycles with frameCount, giving a pulsating effect
+ float brightness = 100 + 155 * (0.5f * (1 + sin(parent.frameCount / 30.0f + star.y)));
+ float bopAmplitude = 30 * amplitude;
+ float rate = map(star.x, -parent.width, parent.width, 5.0f, 15.0f);
+ float dynamicY = star.y + bopAmplitude * sin(parent.frameCount/rate);
+
+ parent.fill(parent.color(hue, 255, brightness, 128));
+ parent.translate(star.x, dynamicY, star.z);
+
+ float size = 10 + 5 * sin(parent.frameCount / 40.0f);
+ parent.sphere(size);
+
+ parent.popMatrix();
+ }
+ }
+
+ private void drawSphere() {
+ if (parent instanceof Visual) {
+ ((Visual)parent).calculateAverageAmplitude();
+ }
+ float amplitude = ((Visual)parent).getSmoothedAmplitude();
+ float yPosition = map(amplitude, 0, 1, parent.height * 0.9f, parent.height * 0.1f);
+
+ if (parent.frameCount % 60 == 0) {
+ targetX = parent.random(-10, 1000);
+ }
+ currentX = PApplet.lerp(currentX*1.032f, targetX, 0.05f);
+
+ parent.lights();
+
+ // Adjust the sphere's outer glow using stroke
+ float hue = (parent.frameCount * 10 + 360 * (currentX + parent.width) / (2 * parent.width)) % 360;
+ float alpha = map(amplitude, 0, 1, 10, 255); // Adjust alpha based on amplitude for a pulsating effect
+ parent.fill(hue, 255, 255, alpha);
+ parent.noStroke();
+
+ // Sphere settings
+ int detail = (int) map(amplitude, 0, 1, 6, 24);
+ parent.sphereDetail(detail);
+ float size = 300 * (0.5f + 4.5f * amplitude);
+
+ parent.pushMatrix();
+ parent.translate(currentX, yPosition, -200);
+ parent.sphere(300*(amplitude*5));
+ parent.popMatrix();
+
+ addShell(currentX, yPosition, size + 20, 60, 160); // Slightly larger than the sphere
+ addHaloRing(currentX, yPosition, 500, hue, alpha);
+ angle += 0.05;
+ }
+
+ private void addShell(float x, float y, float size, float hue, float alpha) {
+ parent.pushMatrix();
+ parent.translate(x, y, -200);
+ parent.noFill();
+
+ // First halo layer
+ parent.stroke(hue, 50, 255, alpha / 2); // Soft yellow with reduced saturation
+ parent.sphereDetail(10);
+ parent.sphere(size);
+
+ // Additional outer halo layer with a different color or transparency
+ float outerHue = hue + 30; // Shift the hue for visual distinction, optional
+ if (outerHue > 360) {
+ outerHue -= 360; // Wrap the hue value to stay within color wheel limits
+ }
+ float outerAlpha = alpha / 4; // More subtle than the inner halo
+ parent.stroke(outerHue, 100, 255, outerAlpha); // More saturated and less transparent
+ parent.sphere(size + 20); // Slightly larger radius for the outer halo
+
+ parent.popMatrix();
+ }
+
+ private void addHaloRing(float x, float y, float baseSize, float hue, float alpha) {
+ parent.pushMatrix();
+ parent.translate(x, y, -200);
+
+ // Calculate the orbit radius to ensure it's clearly separated from the sphere
+ float orbitRadius = baseSize + 170; // Increased for clear separation
+
+ // Radius outside of orbit radius
+ float visualRadius = orbitRadius + 10;
+
+ // Interpolated angle for rotation
+ float startAngle = PApplet.PI / 2;
+ float endAngle = 3 * PApplet.PI / 2;
+ float interpolationFactor = 0.5f * (1 + PApplet.sin(parent.millis() * 0.001f)); // Slowly oscillates between 0 and 1
+ float interpolatedAngle = PApplet.lerp(startAngle, endAngle, interpolationFactor);
+
+ // Rotate the plane of the ring
+ parent.rotateX(interpolatedAngle);
+ parent.noFill();
+ parent.stroke(hue, 255, 255, alpha);
+ parent.strokeWeight(5);
+ float diameter = visualRadius * 2;
+ parent.ellipse(0, 0, diameter, diameter + 20);
+ parent.popMatrix();
+ }
+
+
+ public PVector getCameraRotation() {
+ PMatrix3D m = (PMatrix3D)parent.g.getMatrix();
+
+ // Calculate Euler angles
+ float sy = -m.m02;
+ float cy = PApplet.sqrt(m.m00 * m.m00 + m.m01 * m.m01);
+ boolean singular = cy < 1e-6; // If close to singular
+
+ float x, y, z;
+ if (!singular) {
+ x = PApplet.atan2(m.m12, m.m22);
+ y = PApplet.atan2(sy, cy);
+ z = PApplet.atan2(m.m01, m.m00);
+ } else {
+ x = PApplet.atan2(-m.m21, m.m11);
+ y = PApplet.atan2(sy, cy);
+ z = 0;
+ }
+
+ return new PVector(x, y, z);
+ }
+
+ public void resetCameraAngles() {
+ x = 0;
+ y = 0;
+ z = 0;
+ }
+
+ public void draw() {
+ // // dynamic cam
+ // float fov = PApplet.PI / 6; // A moderate field of view for a good initial perspective
+ // if (parent.mouseX != 0) { // Check if the mouse has moved from the default position
+ // fov = parent.mouseX / (float) parent.width * PApplet.PI / 2;
+ // }
+
+ // cameraY = parent.height / 1.5f; // Start with the camera at half the height of the window
+ // float cameraZ = cameraY / PApplet.tan(fov / 2.0f); // Calculate camera Z based on the updated FOV
+
+ // parent.perspective(fov, (float) parent.width / (float) parent.height, cameraZ / 10.0f, cameraZ * 10.0f);
+
+ // // Calculate angle for circular camera movement
+ // float angle = parent.frameCount * 0.03f; // Change 0.01 to adjust speed of rotation
+ // cameraX = parent.width / 2.0f + cameraZ * PApplet.sin(angle);
+ // float cameraZPosition = cameraZ * PApplet.cos(angle);
+
+ // // Updated camera setup to circle around the sphere
+ // parent.camera(cameraX, cameraY, cameraZPosition,
+ // parent.width / 2.0f, cameraY, 0,
+ // 0, 1, 0);
+
+ //Static cam
+ float fov = PApplet.PI / 3;
+ float cameraY = parent.height / 2.0f;
+ float cameraZ = (cameraY / PApplet.tan(fov / 2.0f)) * 4; // Increase distance
+
+ parent.perspective(fov, (float) parent.width / (float) parent.height, 1, 10000);
+ parent.camera(parent.width / 2.0f, cameraY, cameraZ,
+ parent.width / 2.0f, cameraY, 0,
+ 0, 1, 0);
+
+ parent.background(0); // Clear the screen
+ drawStars();
+ drawSphere();
+ }
+}
diff --git a/java/src/example/AudioBandsVisual.java b/java/src/example/AudioBandsVisual.java
index b6b99d6e5..97cb2811a 100644
--- a/java/src/example/AudioBandsVisual.java
+++ b/java/src/example/AudioBandsVisual.java
@@ -3,7 +3,7 @@
import processing.core.*;
// This is an example of a visual that uses the audio bands
-public class AudioBandsVisual
+public class AudioBandsVisual extends PApplet
{
MyVisual mv;
diff --git a/java/src/example/CubeVisual.java b/java/src/example/CubeVisual.java
index ff8e58798..32ff7b6b5 100644
--- a/java/src/example/CubeVisual.java
+++ b/java/src/example/CubeVisual.java
@@ -36,7 +36,7 @@ public void setup()
setFrameSize(256);
startMinim();
- loadAudio("heroplanet.mp3");
+ loadAudio("Renai Circulation恋愛サーキュレーション歌ってみたなみりん.mp3");
//getAp().play();
//startListening();
diff --git a/java/src/example/CubeVisual1.java b/java/src/example/CubeVisual1.java
index 8eebd97f8..510e426ac 100644
--- a/java/src/example/CubeVisual1.java
+++ b/java/src/example/CubeVisual1.java
@@ -14,7 +14,7 @@ public void setup()
{
startMinim();
//startListening();
- loadAudio("heroplanet.mp3");
+ loadAudio("song.mp3");
colorMode(HSB);
}
diff --git a/java/src/example/MyVisual.java b/java/src/example/MyVisual.java
index 8a71fe3f6..675e202c4 100644
--- a/java/src/example/MyVisual.java
+++ b/java/src/example/MyVisual.java
@@ -20,10 +20,10 @@ public void setup() {
startMinim();
// Call loadAudio to load an audio file to process
- // loadAudio("heroplanet.mp3");
+ loadAudio("Renai Circulation恋愛サーキュレーションKana Hanazawa.mp3");
// Call this instead to read audio from the microphone
- startListening();
+ //startListening();
wf = new WaveForm(this);
abv = new AudioBandsVisual(this);
diff --git a/java/src/example/RotatingAudioBands.java b/java/src/example/RotatingAudioBands.java
index 72fd7a223..c454b7e1f 100644
--- a/java/src/example/RotatingAudioBands.java
+++ b/java/src/example/RotatingAudioBands.java
@@ -32,9 +32,9 @@ public void setup()
setFrameSize(256);
startMinim();
- loadAudio("heroplanet.mp3");
+ loadAudio("Renai Circulation恋愛サーキュレーションKana Hanazawa.mp3");
getAudioPlayer().play();
- //startListening();
+ //startListening();
}
diff --git a/java/src/ie/tudublin/AudioBandsVisual.java b/java/src/ie/tudublin/AudioBandsVisual.java
new file mode 100644
index 000000000..f75eaa432
--- /dev/null
+++ b/java/src/ie/tudublin/AudioBandsVisual.java
@@ -0,0 +1,26 @@
+package ie.tudublin;
+
+import processing.core.*;
+
+public class AudioBandsVisual extends PApplet
+{
+ Seno seno;
+
+ public AudioBandsVisual(Seno seno)
+ {
+ this.seno = seno;
+ }
+
+ public void render(int bandColor)
+ {
+ float gap = seno.width / (float) seno.getBands().length * 4.0f;
+ seno.noStroke();
+ seno.fill(bandColor);
+
+ for(int i = 0 ; i < seno.getBands().length ; i ++)
+ {
+ //draw rectangle for each band
+ seno.rect((i * gap - gap / 2)-3120, seno.height+2300, gap,-seno.getSmoothedBands()[i] * 1f);
+ }
+ }
+}
\ No newline at end of file
diff --git a/java/src/ie/tudublin/Intro.java b/java/src/ie/tudublin/Intro.java
new file mode 100644
index 000000000..688959346
--- /dev/null
+++ b/java/src/ie/tudublin/Intro.java
@@ -0,0 +1,87 @@
+package ie.tudublin;
+
+public class Intro extends Visual {
+
+ private float sX = -100;
+ private float nX;
+ private final float textSpeed = 45;
+ private boolean seInPlace = false; // Checks if SE is in place
+ private boolean displayStarted = false;
+ private int displayStartTime;
+ private final int displayDuration = 700; // 0.5 seconds in milliseconds
+
+ public void settings()
+ {
+ size(1000, 1000, P3D);
+ //fullScreen(P3D, SPAN);
+ }
+
+ public void keyPressed()
+ {
+ if (key == ' ') {
+ getAudioPlayer().cue(0);
+ getAudioPlayer().play();
+ }
+ }
+
+ public void setup() {
+ colorMode(HSB, 360, 100, 100);
+ //noCursor();
+
+ textSize(270); // Set the text size for width calculation
+
+ float textWidthNO = textWidth("NO");
+ nX = width + textWidthNO; // Start "NO" off-screen to the right
+ }
+
+ public void draw()
+ {
+ background(0);
+
+ //have other files function here
+ if (!displayStarted || millis() - displayStartTime < displayDuration)
+ {
+ fill(328, 90, 82); // Pink color in HSB mode
+ noStroke();
+
+ updatePositions();
+
+ // Draw "SE" and "NO" as they move into place
+ text("SE", (sX - 210), height / 2);
+ if (seInPlace) {
+ text("NO", (nX + 210), height / 2);
+
+ // Below is to clear text once it is completed
+ if (!displayStarted)
+ {
+ displayStarted = true;
+ displayStartTime = millis();
+ }
+ }
+ }
+ }
+
+ private void updatePositions()
+ {
+ // Delay
+ int startDelayFrames = 50;
+
+ if (frameCount > startDelayFrames) {
+ if (sX < width / 2 - textWidth("SE") / 2)
+ {
+ sX += textSpeed;
+ }
+ else if (!seInPlace)
+ {
+ seInPlace = true; // Mark "SE" as in place
+ }
+
+ if (seInPlace && nX > width / 2 + textWidth("SE") / 2 - textWidth("NO"))
+ {
+ nX -= (textSpeed + 5);
+ }
+ }
+ }
+}
+
+
diff --git a/java/src/ie/tudublin/Main.java b/java/src/ie/tudublin/Main.java
index 67e93d892..a3300776d 100644
--- a/java/src/ie/tudublin/Main.java
+++ b/java/src/ie/tudublin/Main.java
@@ -1,14 +1,10 @@
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 Seno()); //Run Seno.java file
}
public static void main(String[] args) {
diff --git a/java/src/ie/tudublin/Seno.java b/java/src/ie/tudublin/Seno.java
new file mode 100644
index 000000000..435bf4c59
--- /dev/null
+++ b/java/src/ie/tudublin/Seno.java
@@ -0,0 +1,218 @@
+package ie.tudublin;
+
+import c22427602.RalphVisuals;
+import c22421292.SeanVisuals;
+
+import processing.core.PMatrix3D;
+import java.util.ArrayList;
+import processing.core.PVector;
+
+public class Seno extends Visual {
+ RalphVisuals Ralph;
+ private boolean drawSphere = false;
+ SeanVisuals Sean;
+ private boolean drawCube = false;
+ ArrayList lyrics = new ArrayList();
+
+ AudioBandsVisual audioBands; //Variable to store audioband file.
+ int currentScene; //Used to redraw current scene after pressing spacebar or 'r'
+ boolean resetScreen = false; //Used to keep track of if the screen was cleared
+
+
+ public void settings() {
+ size(1920, 1080, P3D);
+ fullScreen(P3D, SPAN);
+ }
+
+ public void setup() {
+ colorMode(HSB, 360, 255, 255); //Set HSB color mode
+ noCursor(); //Disable cursor on screen
+ startMinim(); //Start audio engine
+ loadAudio("Renai Circulation恋愛サーキュレーションKana Hanazawa.mp3"); //Load song
+ getAudioPlayer().play(); //Play the song
+
+ Ralph = new RalphVisuals(); // Instantiate Ralph object
+ Ralph.setParent(this);
+
+ Sean = new SeanVisuals(); // Instantiate Sean object
+ Sean.setParent(this);
+
+ loadLyrics();
+
+ audioBands = new AudioBandsVisual(this); //Import audiobands file
+ }
+
+ void loadLyrics() { //Load lyrics from srt file
+ String[] lines = loadStrings("[Japanese] Renai Circulation「恋愛サーキュレーション」Kana Hanazawa [DownSub.com].srt");
+ int i = 0;
+ while (i < lines.length) {
+ if (lines[i].trim().matches("\\d+")) { // Checks if the line is a sequence number
+ i++;
+ if (i < lines.length && lines[i].contains("-->")) {
+ String[] timeCodes = lines[i].trim().split(" --> ");
+ float startTime = parseSrtTime(timeCodes[0]);
+ float endTime = parseSrtTime(timeCodes[1]);
+
+ i++;
+ StringBuilder textBuilder = new StringBuilder();
+ while (i < lines.length && !lines[i].trim().isEmpty()) {
+ if (textBuilder.length() > 0) textBuilder.append("\n");
+ textBuilder.append(lines[i].trim());
+ i++;
+ }
+ lyrics.add(new Lyric(textBuilder.toString(), startTime, endTime));
+ //DEBUG
+ println("Loaded lyric: " + textBuilder.toString() + " [" + startTime + " to " + endTime + "]");
+ }
+ } else {
+ i++;
+ }
+ }
+ }
+
+ float parseSrtTime(String srtTime) {
+ String[] parts = srtTime.split(":");
+ String[] secParts = parts[2].split(",");
+ float hours = Float.parseFloat(parts[0]);
+ float minutes = Float.parseFloat(parts[1]);
+ float seconds = Float.parseFloat(secParts[0]);
+ float milliseconds = Float.parseFloat(secParts[1]);
+ return (float) (hours * 3600 + minutes * 60 + seconds + milliseconds / 1000.0);
+ }
+
+ class Lyric {
+ String text;
+ float startTime; // in seconds
+ float endTime; // in seconds
+
+ Lyric(String text, double d, double e) {
+ this.text = text;
+ this.startTime = (float) d;
+ this.endTime = (float) e;
+ }
+ }
+
+ public float[] getCameraNormal() { //Calculates the vector of the camera facing direction
+ PMatrix3D m = (PMatrix3D)this.g.getMatrix();
+ float[] camNormal = new float[3];
+ camNormal[0] = -m.m02;
+ camNormal[1] = -m.m12;
+ camNormal[2] = -m.m22;
+ return camNormal;
+ }
+
+ public void draw() {
+ background(0);
+
+ try {
+ calculateFFT();
+ } catch (VisualException e) {
+ e.printStackTrace();
+ }
+ calculateFrequencyBands();
+
+ float currentTime = getAudioPlayer().position() / 1000.0f;
+
+ if (drawSphere) {
+ Ralph.draw();
+ }
+ else if (drawCube) {
+ Sean.draw();
+ audioBands.render(Sean.bandColor);
+ }
+
+ hint(DISABLE_DEPTH_TEST);
+
+ textSize(80);
+ textAlign(CENTER, BOTTOM);
+
+ // Get the rotation angles from RalphVisuals
+ PVector rotationAngles = Ralph.getCameraRotation(); //Eular angles
+ colorMode(HSB, 360, 255, 255, 255);
+
+ for (Lyric lyric : lyrics) {
+ int lyricColor = 255;
+ if (currentTime >= lyric.startTime && currentTime <= lyric.endTime) {
+ pushMatrix();
+
+ // Set the position for text in front of the camera
+ translate(width / 2, height - 70, 10); // Center and a bit in front
+
+ // Inverse rotation to face cam
+ rotateX(rotationAngles.x);
+ rotateY(rotationAngles.y);
+ rotateZ(rotationAngles.z);
+
+ fill(lyricColor); //white lyrics
+
+ text(lyric.text, 0, 0); //Draw at the adjusted position
+ popMatrix();
+ break;
+ }
+ }
+ hint(ENABLE_DEPTH_TEST);
+
+ }
+
+ public void keyPressed() {
+ println("Key pressed: " + key); //Debug output to check key press
+ switch(key) {
+ case '1': //Scene 1
+ currentScene = 1;
+ drawSphere = true; //Enable drawing the sphere
+ drawCube = false;
+ Ralph.addStars(200); //commented out while testing cause too many fricking stars bro
+ break;
+ case '2': //Scene 2
+ currentScene = 2;
+ drawSphere = false; //Disable drawing the sphere to show only cube
+ drawCube = true;
+ Sean.sceneChange();
+ break;
+ case ' ': //play and pause
+ if (getAudioPlayer().isPlaying()) {
+ getAudioPlayer().pause();
+ } else {
+ getAudioPlayer().play();
+ }
+ restoreLastScene();
+ break;
+ case 'r': //Clear screen
+ if(resetScreen==false) {
+ drawSphere = false;
+ drawCube = false;
+ resetScreen = true;
+ }
+ else {
+ resetScreen = false;
+ restoreLastScene();
+ }
+ break;
+ case 's': //enable/disable spam mode
+ Sean.spamMode();
+ default: //Print console message if pressed key has no use
+ println("No function assigned to this key");
+ break;
+ }
+ }
+
+ private void restoreLastScene() {
+ println("Last scene: " + currentScene);
+ switch(currentScene) {
+ case 1:
+ drawSphere = true;
+ drawCube = false;
+ break;
+ case 2:
+ drawSphere = false;
+ drawCube = true;
+ break;
+ default:
+ drawSphere = false;
+ drawCube = false;
+ break;
+ }
+ }
+}
+
+
diff --git a/java/src/ie/tudublin/Visual.java b/java/src/ie/tudublin/Visual.java
index 927fe57b1..b7a4de840 100644
--- a/java/src/ie/tudublin/Visual.java
+++ b/java/src/ie/tudublin/Visual.java
@@ -143,4 +143,4 @@ public AudioPlayer getAudioPlayer() {
public FFT getFFT() {
return fft;
}
-}
+}
\ No newline at end of file