diff --git a/.DS_Store b/.DS_Store index 55c1fcbeb..43043ed6b 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..174a5cca3 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "github.copilot" + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..c995aa5ce --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.debug.settings.onBuildFailureProceed": true +} \ No newline at end of file diff --git a/DS_Store b/DS_Store new file mode 100644 index 000000000..e69de29bb diff --git a/README.md b/README.md index 19ba88c75..694d4a72a 100644 --- a/README.md +++ b/README.md @@ -1,89 +1,53 @@ # Music Visualiser Project -Name: +Name: +Arushi Singh +Jenied Sayago +Tania Satavalekar. Student Number: - -## Instructions -- Fork this repository and use it a starter project for your assignment -- Create a new package named your student number and put all your code in this package. -- You should start by creating a subclass of ie.tudublin.Visual -- There is an example visualiser called MyVisual in the example package -- Check out the WaveForm and AudioBandsVisual for examples of how to call the Processing functions from other classes that are not subclasses of PApplet +C22359751 +C22380473 +C21331753 # Description of the assignment +We chose the song "Meet Me Halfway" by the Black-Eyed Peas for our project. We felt as though there was a lot to work with within the song, whether it was the beat, the pace or the lyrics. We were also familiar with the song and upon our intial analysis of the song when we began this project, we agreed that the song rose and fell sufficiently to work with for our visuals. -# Instructions - -# How it works - -# What I am most proud of in the assignment - -# Markdown Tutorial +Some parts that stood out to us were the lyrics, the constantly changing pace and intensity and the cover art for the 2009 album, "The End" which depicts a green skull. We thought it would be really interesting to implement and combine with the song along with other visuals. -This is *emphasis* +In this visual assignment, you will find visuals of a pulsing heart, a breaking heart, the cover art implemented as a visual, a spinning "The End" CD with surrounding synth strobe lights and a pair of eyes with moving, colour changing pupils that pulse to the beat, accompanied by "Game of Life" visuals. -This is a bulleted list - -- Item -- Item - -This is a numbered list - -1. Item -1. Item - -This is a [hyperlink](http://bryanduggan.org) +# Instructions +Press SPACEBAR to run the code. +Hit numbers from 1 to 6 to view the visuals! -# Headings -## Headings -#### Headings -##### Headings +# How it works +We used components of MyVisual such as the amplitude and frequency of the song to make our shapes or images react to the song. The visuals use this in real time as they are rendered when their respective key is pressed. All our visuals use various shapes that also visualise the lyrics of the song - whether it be a plants revolving around each other or heart split into half. This adds an even more immersive feel to our visuals. -This is code: -```Java -public void render() -{ - ui.noFill(); - ui.stroke(255); - ui.rect(x, y, width, height); - ui.textAlign(PApplet.CENTER, PApplet.CENTER); - ui.text(text, x + width * 0.5f, y + height * 0.5f); -} -``` +# Arushi Singh: What I am most proud of in the assignment +For me, I really enjoyed this assignment and branching out with other creative choices while also implementing ideas from this module too. +I am incredibly proud of my heart visual as it was very much a trial and error process, with a lot of finicking around and adjusting. I had made my heart visual using trignometry and though it was hard and out of my depth at times, I really used features from sin, cos and tan to map out a heart shape. I'm also really glad that I managed to get it pulsating and beat like a heart to the beat and that I had the heart split directly down and came together without overlapping. -So is this without specifying the language: +As for my second visual, I really wanted to implement something similar to having a face or using the art that the song is almost always associated with and so, managing to get the image and to recolour it to a grey so it could truly change colour was a challenge but in my opinion, a really smart move. I really liked how it came together overall. -``` -public void render() -{ - ui.noFill(); - ui.stroke(255); - ui.rect(x, y, width, height); - ui.textAlign(PApplet.CENTER, PApplet.CENTER); - ui.text(text, x + width * 0.5f, y + height * 0.5f); -} -``` +If I had more time, I would've liked to have the eyes in the art to have been like strobe lights or lasers just to add a bit more to the visual. I would have also liked to have a camera feature that uses the laptop camera to register bodies and faces (using OpenCV library for example) and have that react to the music and combine the two visuals together. Overall, I am really proud of the how my visuals came together and enjoyed it thoroughly. -This is an image using a relative URL: -![An image](images/p8.png) +# Jenied Sayago: What I am most proud of in the assignment +I found this assignment to be really interersting and a great opportunity for learning. I used some elements of my learning and taking it to a whole other level. -This is an image using an absolute URL: +For my visuals, I felt really proud of designing my planets visual. It took time trying to get all the different features and elements to work alongside each other but it came through. It was really intricate with beat spikes, stars and a Saturn-like planet along with having it display with different colours and I'm glad I put that work in and it shows. The rings were proven to be some challenge but with a lot of attempts and rendering, I got there and it really did pay off, I feel super proud of how it came together. -![A different image](https://bryanduggandotorg.files.wordpress.com/2019/02/infinite-forms-00045.png?w=595&h=&zoom=2) +As for my hearts visual, I was glad I could fill my screen entirely without it being overwhelming. I really liked the synth especially, I like that I got it to flow rather than spike, almost like an ocean wave. The heart beating was really nice and I felt as though it was really in theme with the other visuals. This visual took time to map out placements and was tediuous in this way but other than that there was no big issues. -This is a youtube video: +If I had more time to put in, I would've liked to make my heart visual stand out a bit more by either having the eye behind my heart visual blink or I would transform the squares into cubes in the heart visual so that they could pulse and explode to the beat or with timing. Other than that, I am pleased with how it all came together and feel proud and happy with my visuals overrall. -[![YouTube](http://img.youtube.com/vi/J2kHSSFA4NU/0.jpg)](https://www.youtube.com/watch?v=J2kHSSFA4NU) +# Tania Satavalekar: What I am most proud of in the assignment +Reflecting onn this assignment, I am really proud of how I applied the concepts I learned throughout this module. I think that this sentiment is really evident in my visual components. -This is a table: +One standout feature is the grid visual code. I enjoyed making the grid, however, initally, I was trying to implement of the Game of Life code. Although it presented a significant challenge during the labs, it resulted in one of the most memorable visuals I've ever created and it was something I was really proud of. I really enjoyed that it looked like confetti or fireworks and it struck a chord with me so I found it to be perfect to implement into this project, I was hoping to incorporate it in some way, it was a bummer I wasn't able to incorporate it due to render difficulties. The eyes were also a part that brought me pride. The sketching out a pair of circles and mapping visuals and creating borders to bounce back and forth was somewhat simple but it adds a whimsical charm and a bit of fun. Sometimes, the most straightforward elements can put the most fun into a visual composition, and in this case, it added a playful twist that resonated with all of us. -| Heading 1 | Heading 2 | -|-----------|-----------| -|Some stuff | Some more stuff in this column | -|Some stuff | Some more stuff in this column | -|Some stuff | Some more stuff in this column | -|Some stuff | Some more stuff in this column | +I'm thrilled with the outcome of my synth waves. It took a lot of work to map it so they look like they come out of the CD rather than have it off centre, but with many attempts I got it to work. They turned out even better than I had imagined, and they complemented the spinning CD visual seamlessly. The CD idea was in my head for a long time and I found myself making it so much more complicated than it had to be, especially with the way they rotate to the beat and pacing of the song. A simple image I made transparent sufficed perfectly and was all that was needed to make this visual sing. The synergy between these effects enchanced the overall both these effects really complimented each other, leaving me proud. +If given the time, i would've loved to implement and code up live lyrics that sync up to the song but it was proving to be much harder than I thought when I did attempt. Having lyrics pop up and circles explode to the beat would've had a great effect. Another idea I had was a Synesthesia water like effect that would move and rise and fall like water but also change colour. This would've taken up a lot of time however, I hope to create that visual someday soon as a side project. diff --git a/images/.DS_Store b/images/.DS_Store new file mode 100644 index 000000000..5fda50042 Binary files /dev/null and b/images/.DS_Store differ diff --git a/images/cover.png b/images/cover.png new file mode 100644 index 000000000..5455c2afc Binary files /dev/null and b/images/cover.png differ diff --git a/images/coverCD.png b/images/coverCD.png new file mode 100644 index 000000000..0dbec1bc0 Binary files /dev/null and b/images/coverCD.png differ diff --git a/java/.DS_Store b/java/.DS_Store index 629e3335c..9f9266a2f 100644 Binary files a/java/.DS_Store and b/java/.DS_Store differ diff --git a/java/.project b/java/.project index 0d5afed93..1b5ab661e 100644 --- a/java/.project +++ b/java/.project @@ -16,12 +16,12 @@ - 1616413840733 + 1710347915364 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/.DS_Store b/java/data/.DS_Store new file mode 100644 index 000000000..75d2b708a Binary files /dev/null and b/java/data/.DS_Store differ diff --git a/java/data/meetmehalfway copy.mp3 b/java/data/meetmehalfway copy.mp3 new file mode 100644 index 000000000..7ad97b03a Binary files /dev/null and b/java/data/meetmehalfway copy.mp3 differ diff --git a/java/data/meetmehalfway.mp3 b/java/data/meetmehalfway.mp3 new file mode 100644 index 000000000..7ad97b03a Binary files /dev/null and b/java/data/meetmehalfway.mp3 differ diff --git a/java/src/c21331753/TaniaVisual1.java b/java/src/c21331753/TaniaVisual1.java new file mode 100644 index 000000000..b0d3e87a5 --- /dev/null +++ b/java/src/c21331753/TaniaVisual1.java @@ -0,0 +1,120 @@ +package c21331753; + +import ie.tudublin.CombinedVisual; +import processing.core.PApplet; + +public class TaniaVisual1 extends PApplet { + CombinedVisual cv; + int cols, rows; + int resolution = 20; // Change the resolution to 1 for a grid covering the entire screen + boolean[][] grid; + boolean[][] next; + + public TaniaVisual1(CombinedVisual cv) { + this.cv = cv; + } + + public void render() { + cv.calculateAverageAmplitude(); + float amplitude = cv.getSmoothedAmplitude(); + cv.background(0); + cv.colorMode(HSB, 360, 100, 100); + + // Call setup method to initialize the Game of Life grid + setup(); + updateGrid(); + drawGrid(); + + float eyeSize = 300; // Increase eye size + + // Draw eyes in the center of the screen + float centerX = cv.width / 2; + float centerY = cv.height / 2; + cv.fill(255); // Eye color (white) + cv.stroke(255); // Eye stroke (white) + drawEye(centerX - 200, centerY, eyeSize); // Left eye + drawEye(centerX + 200, centerY, eyeSize); // Right eye + } + + + + private void drawEye(float x, float y, float size) { + // Draw outer eye + cv.strokeWeight(2); + cv.fill(255); // Eye color (white) + cv.ellipse(x, y, size, size); + + // Calculate pupil movement based on amplitude + float pupilDiameter = size / 4; + float pupilX = map(cv.getSmoothedAmplitude(), 0, 1, x - 100, x + 300); // Map amplitude to pupil's diameter range + + // Calculate pupil color based on amplitude + float pupilColor = map(cv.getSmoothedAmplitude(), 0, 1, 0, 360); // Map amplitude to hue + + // Draw pupils + cv.fill(pupilColor, 80, 80); // Set pupil color + float bounceOffset = map(sin(frameCount * 0.5f), -1, 1, -size / 2, size / 2); // Calculate bouncing offset + cv.ellipse(pupilX, y + bounceOffset*2, pupilDiameter, pupilDiameter); // Draw pupil at calculated X position with bouncing effect + } + + public void setup() { + cols = width; + rows = height; + grid = new boolean[cols][rows]; + next = new boolean[cols][rows]; + // Initialize grid randomly + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + grid[i][j] = random(1) > 0.5; + } + } + } + + private void updateGrid() { + // Compute next generation based on rules + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + int neighbors = countNeighbors(grid, i, j); + if (grid[i][j]) { + next[i][j] = (neighbors == 2 || neighbors == 3); + } else { + next[i][j] = (neighbors == 3); + } + } + } + // Swap grids + boolean[][] temp = grid; + grid = next; + next = temp; + } + + private int countNeighbors(boolean[][] grid, int x, int y) { + int count = 0; + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + int col = (x + i + cols) % cols; + int row = (y + j + rows) % rows; + if (grid[col][row]) { + count++; + } + } + } + if (grid[x][y]) { + count--; + } + return count; + } + + private void drawGrid() { + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + float x = i * resolution; + float y = j * resolution; + float hue = random(360); // Generate a random hue value + cv.fill(hue, 80, 80); // Set fill color using the random hue + cv.stroke(255); + cv.rect(x, y, resolution - 1, resolution - 1); + } + } + } +} diff --git a/java/src/c21331753/TaniaVisual2.java b/java/src/c21331753/TaniaVisual2.java new file mode 100644 index 000000000..deea4d963 --- /dev/null +++ b/java/src/c21331753/TaniaVisual2.java @@ -0,0 +1,56 @@ +package c21331753; + +import ie.tudublin.CombinedVisual; +import processing.core.PApplet; +import processing.core.PImage; + +public class TaniaVisual2 extends PApplet { + CombinedVisual cv; + PImage img; + float angle = 0; + float circleSize = 700; // Increase circle size to make it larger + float imgAngle = 0; // Initial angle for image rotation + + public TaniaVisual2(CombinedVisual cv) { + this.cv = cv; + img = cv.loadImage("images/coverCD.png"); + img.resize(cv.width / 3, cv.height / 3); // Resize the image to make it smaller + } + + public void render() { + cv.calculateAverageAmplitude(); + float amplitude = cv.getSmoothedAmplitude(); + cv.colorMode(HSB, 255); + cv.background(0); + drawRainbowSynthRing(); // Draw rainbow synth ring first so it's behind the image + drawSpinningImage(cv.width / 2, cv.height / 2); // Draw the spinning image in the center + //drawAmplitudeCircles(); // Draw amplitude circles + } + + + private void drawRainbowSynthRing() { + float halfWidth = cv.width / 2; + float halfHeight = cv.height / 2; + float circleSize = (float) (cv.getSmoothedAmplitude() * halfHeight * 2); + cv.noFill(); + float amplitude = cv.getSmoothedAmplitude(); + for (int i = 0; i < 360; i += 10) { + float hue = cv.frameCount % 360; + cv.stroke(hue, 255, 255); + float x = halfWidth + cos(radians(i)) * circleSize; + float y = halfHeight + sin(radians(i)) * circleSize; + cv.ellipse(halfWidth, halfHeight, x, y); + } + } + + private void drawSpinningImage(float x, float y) { + cv.pushStyle(); + cv.imageMode(CENTER); + cv.translate(x, y); + cv.rotate(angle); + cv.image(img, 0, 0); + cv.popStyle(); + float amplitude = cv.getSmoothedAmplitude(); + angle += amplitude; + } +} diff --git a/java/src/c22359751/ArushiVisual1.java b/java/src/c22359751/ArushiVisual1.java new file mode 100644 index 000000000..3d7066019 --- /dev/null +++ b/java/src/c22359751/ArushiVisual1.java @@ -0,0 +1,125 @@ +package c22359751; + +import processing.core.PApplet; +import ie.tudublin.CombinedVisual; + + +public class ArushiVisual1 extends PApplet { + + CombinedVisual cv; + + public ArushiVisual1(CombinedVisual cv) { + this.cv = cv; + + } + + public void render() { + cv.calculateAverageAmplitude(); + float amplitude = cv.getSmoothedAmplitude(); + cv.background(0); + cv.colorMode(HSB, 360, 100, 100); + float hue = map(amplitude, 0, 1, 0, 360); + cv.stroke(hue, 80, 80); + cv.fill(hue, 80, 80); + //camera(0, 0, 0, 0, 0, -1, 0, 1, 0); + //translate(0, 0, -250); + float scale = 0.4f; + + drawHeartCircle(scale, amplitude); + drawHeart(scale); + drawGrid(); + + } + + private void drawHeartCircle(float scale, float amplitude) { + cv.stroke(360); + + float centerX = cv.width / 2; + float centerY = cv.height / 2; + + float circleSize = 350 + amplitude * 200; + + int numHearts = 40; // Number of small hearts + float angleIncrement = TWO_PI / numHearts; + + float rotationSpeed = map(amplitude, 0, 1, 0, TWO_PI); + + float scaleHeart = 0.1f; // Scale of the small hearts + for (int i = 0; i < numHearts; i++) { + float angle = i * angleIncrement + rotationSpeed;; + float x = centerX + cos(angle) * circleSize; + float y = centerY + sin(angle) * circleSize; + for (float a = 0; a < PI; a += 0.01) { + float r = 10; + float heartX = x - r * 16 * pow(sin(a), 3) * scaleHeart; + float heartY = y - r * (13 * cos(a) - 5 * cos(2 * a) - 2 * cos(3 * a) - cos(4 * a)) * scaleHeart; + drawSmallHeart(heartX, heartY, r, scaleHeart); + } + for (float a = 0; a < PI; a += 0.01) { + float r = 10; + float heartX = x + r * 16 * pow(sin(a), 3) * scaleHeart; + float heartY = y - r * (13 * cos(a) - 5 * cos(2 * a) - 2 * cos(3 * a) - cos(4 * a)) * scaleHeart; + + drawSmallHeart(heartX, heartY, r, scaleHeart); + } + } + } + + private void drawSmallHeart(float x, float y, float radius, float scale) { + cv.ellipse(x, y, radius * scale, radius * scale); + } + + + private void drawHeart(float scale) { + float amplitude = cv.getSmoothedAmplitude(); + cv.colorMode(HSB, 360, 100, 100); + float hue = map(amplitude, 0, 1, 0, 360); + cv.stroke(hue, 80, 80); + cv.fill(hue, 80, 80); + + float centerX = cv.width / 2; + float centerY = cv.height / 2; + + // First half of the heart + cv.beginShape(); + for (float a = 0; a < PI; a += 0.01) { + float r = 40; + float x = centerX + r * 16 * pow(sin(a), 3) * scale + (map(cv.getSmoothedAmplitude()*2, 0, 1, 0, 255)); + float y = centerY - r * (13 * cos(a) - 5 * cos(2 * a) - 2 * cos(3 * a) - cos(4 * a)) * scale; + cv.vertex(x, y, -5); + } + cv.endShape(); + + // Draw second half of the heart + cv.beginShape(); + for (float a = 0; a < PI; a += 0.01) { + float r = 40; + float x = centerX - r * 16 * pow(sin(a), 3) * scale - (map(cv.getSmoothedAmplitude()*2, 0, 1, 0, 255)); + float y = centerY - r * (13 * cos(a) - 5 * cos(2 * a) - 2 * cos(3 * a) - cos(4 * a)) * scale; + cv.vertex(x, y, -5); + } + cv.endShape(); + } + + private void drawGrid() { + float amplitude = cv.getSmoothedAmplitude(); + float spacing = 50; + cv.colorMode(HSB, 360, 100, 100); + float hue = map(amplitude, 0, 1, 0, 360); + cv.stroke(hue, 80, 80); + float centerX = cv.width; + float centerY = cv.height; + + for (float x = -centerX; x < centerX; x += spacing) { + cv.line(x, -centerY, 0, x, centerY, 0); + } + + for (float y = -centerY; y < centerY; y += spacing) { + cv.line(-centerX, y, 0, centerX, y, 0); + } + + + } + + +} diff --git a/java/src/c22359751/ArushiVisual2.java b/java/src/c22359751/ArushiVisual2.java new file mode 100644 index 000000000..94fa487e0 --- /dev/null +++ b/java/src/c22359751/ArushiVisual2.java @@ -0,0 +1,62 @@ +package c22359751; + +import ie.tudublin.CombinedVisual; +import processing.core.PApplet; +import processing.core.PImage; + +public class ArushiVisual2 extends PApplet { + + CombinedVisual cv; + PImage albumCover; + float angleOffset; + int numLines; + + public ArushiVisual2(CombinedVisual cv) { + this.cv = cv; + albumCover = cv.loadImage("images/cover.png"); + albumCover.resize(cv.width * 2 / 3, cv.height); + angleOffset = 0; + numLines = 30; + + } + + public void render() { + cv.calculateAverageAmplitude(); + cv.background(0); + cv.colorMode(HSB, 360, 100, 100); + + float amplitude = cv.getSmoothedAmplitude(); + + cv.blendMode(ADD); + + // Lines moving in a circle + cv.strokeWeight(2); + float angleStep = TWO_PI / numLines; + for (int i = 0; i < numLines; i++) { + float angle = angleOffset + i * angleStep; + float radius = min(cv.width, cv.height) * 4; + + float x1 = cv.width / 2; + float y1 = cv.height / 2; + float x2 = x1 + cos(angle) * radius; + float y2 = y1 + sin(angle) * radius; + + float hue = map(i, 0, numLines, 0, 360); + cv.stroke(hue, 80, 80); + cv.line(x1, y1, -x2, -y2); + + angleOffset += cv.getSmoothedAmplitude(); + } + + cv.blendMode(BLEND); + + cv.pushMatrix(); + cv.translate(0, 0, 1); + cv.imageMode(PApplet.CENTER); + float hue = cv.frameCount % 360; + cv.tint(hue, 180, 180); + cv.image(albumCover, cv.width / 2, cv.height / 2); + cv.popMatrix(); + } + +} diff --git a/java/src/c22380473/JeniedVisual1.java b/java/src/c22380473/JeniedVisual1.java new file mode 100644 index 000000000..271564684 --- /dev/null +++ b/java/src/c22380473/JeniedVisual1.java @@ -0,0 +1,149 @@ +package c22380473; + +import processing.core.PApplet; +import ie.tudublin.CombinedVisual; + +public class JeniedVisual1 extends PApplet { + + CombinedVisual cv; + + int maxDots = 2000; + float[] dotX = new float[maxDots]; + float[] dotY = new float[maxDots]; + float[] dotSizes = new float[maxDots]; + float maxDotSize = 15; + float minDotSize = 5; + float maxSpread = 700; + float minSpread = 700; + float sphereSize = 0; + float prevAmplitude = 0; + float angle = 0; + + + // Constructor that takes a parameter of type CombinedVisual + public JeniedVisual1(CombinedVisual cv) { + this.cv = cv; + } + + public void settings() { + println("CWD: " + System.getProperty("user.dir")); + cv.fullScreen(P3D, SPAN); + } + + public void setup() { + cv.colorMode(HSB); + cv.setFrameSize(256); + cv.startMinim(); + } + + + public void render() { + cv.calculateAverageAmplitude(); + cv.background(0); + cv.colorMode(HSB, 360, 100, 100); + + float hue = cv.frameCount % 360; + cv.noStroke(); + cv.fill(0, 100); + + // Calculate the number of dots based on the amplitude + float amplitude = cv.getSmoothedAmplitude(); + int newDots = (int) map(amplitude, 0, 1, 0, maxDots); + + // Drop new dots based on the audio + for (int i = 0; i < newDots; i++) { + // Map dot spread based on amplitude + float spread = map(amplitude, 0, 1, minSpread, maxSpread); + // Randomly position the dots based on the spread + dotX[i] = cv.random(-spread, spread); + dotY[i] = cv.random(-spread, spread); + } + + // Draw all dots + for (int i = 0; i < newDots; i++) { + // Map dot size based on amplitude + float size = map(amplitude, 0, 1, minDotSize, maxDotSize); + float brightness = map(i, 0, newDots, 50, 100); + cv.fill(hue, 80, brightness); + cv.ellipse(cv.width / 2 + dotX[i], cv.height / 2 + dotY[i], size, size); + } + + prevAmplitude = amplitude; + + // Draw the sphere + drawSphere(); + } + + void drawSphere() { + // Calculate the amplitude of the audio signal + float amplitude = cv.getSmoothedAmplitude(); + + sphereSize = constrain(sphereSize, 190, 200); + + // Rotate the centre sphere based on the amplitude + float rotationSpeed = map(amplitude, 0, 1, 0, TWO_PI); + rotationSpeed *= -0.1; + angle += rotationSpeed; + + // Draw the centre sphere in middle of canvas + cv.pushMatrix(); + cv.translate(cv.width / 2, cv.height / 2, 0); + cv.rotateY(angle); + cv.noFill(); + cv.stroke(cv.frameCount % 360, 80, 100); + + // Draw a ring to 2nd planet + float mainRingRadius = 450; + float mainRingThickness = 8; + cv.rotateX(angle); + cv.ellipse(0, 0, mainRingRadius * 2, mainRingRadius * 2); + + // Draw a ring to 3rd planet + float mainRingRadius2 = 312; + float mainRingThickness2 = 8; + cv.rotateX(angle); + cv.ellipse(0, 0, mainRingRadius2 * 2, mainRingRadius2 * 2); + + // Draw the main sphere + cv.sphere(sphereSize); + + // Draw beat visualiser + float smallSphereSize = map(amplitude, 0, 1, 0, 800); // Map amplitude to small sphere size + cv.fill(cv.frameCount % 360, 80, 100); + cv.noStroke(); + cv.sphere(smallSphereSize); + + // Calculate the position of the 2nd sphere + float circleRadius = 300; + float circleX1 = cv.width / 5; + float circleY1 = cv.height / 2 - 500; + float circleZ1 = 0; + + // Draw the 2nd sphere + cv.pushMatrix(); + cv.translate(circleX1, circleY1, circleZ1); + cv.rotateX(angle); + cv.sphere(50); + + // Calculate the position of the spinning sphere relative to the centre sphere + float spinRadius = 150; + float spinX = spinRadius; + float spinY = 0; + + // Draw the 3rd spinning sphere + cv.pushMatrix(); + cv.translate(spinX, spinY, 0); + cv.rotateX(angle); + cv.sphere(30); + + // Draw a ring around the last sphere + float ringRadius = 40; + float ringThickness = 300; + cv.ellipse(0, 0, ringRadius * 2, ringRadius * 2); + cv.stroke(100); + + cv.popMatrix(); + cv.popMatrix(); + cv.popMatrix(); + } +} diff --git a/java/src/c22380473/JeniedVisual2.java b/java/src/c22380473/JeniedVisual2.java new file mode 100644 index 000000000..0c1f56ba2 --- /dev/null +++ b/java/src/c22380473/JeniedVisual2.java @@ -0,0 +1,186 @@ +package c22380473; + +import ie.tudublin.CombinedVisual; +import processing.core.PApplet; + +public class JeniedVisual2 extends PApplet { + + CombinedVisual cv; + + float rotationSpeed = 0.02f; + float eyeWidth = 800; + float eyeHeight = 500; + + // Constructor that takes a parameter of type CombinedVisual + public JeniedVisual2(CombinedVisual cv) { + this.cv = cv; + } + + public void settings() { + cv.fullScreen(P3D, SPAN); + } + + public void setup() { + cv.colorMode(HSB); + cv.setFrameSize(256); + cv.startMinim(); + } + + public void render() { + cv.calculateAverageAmplitude(); + cv.background(0); + cv.colorMode(HSB, 360, 100, 100); + + float amplitude = cv.getSmoothedAmplitude(); + + drawBackgroundPattern(amplitude); + + drawEyeOutline(); + + drawEyeball(amplitude); + + drawAudioBands(amplitude); + } + + void drawBackgroundPattern(float amplitude) { + int cols = 10; + int rows = 10; + + // Calculate the size of each square + float squareSize = cv.width / cols; + + // Calculate rotation speed based on amplitude + float rotationSpeed = map(amplitude, 0f, 1f, 0.01f, 0.1f); + + // Loop through each column and row + for (int x = 0; x < cols; x++) { + for (int y = 0; y < rows; y++) { + // Calculate the position of the square + float xPos = x * squareSize + squareSize / 2; + float yPos = y * squareSize + squareSize / 2; + + // Calculate the size of the square based on amplitude + float size = map(amplitude, 0, 1, 10, 50); + + // Calculate the hue based on position and amplitude + float hue = map(x * y + amplitude * 100, 0, cols * rows + 100, 0, 360); + + // Set the fill color + cv.fill(hue, 80, 100); + + // Draw the square + cv.pushMatrix(); + cv.translate(xPos, yPos, -size / 2); // Move to the center of the square + cv.rotateX(frameCount * rotationSpeed); + cv.rotateY(frameCount * rotationSpeed); + cv.rectMode(CENTER); + cv.rect(0, 0, size, size); + cv.popMatrix(); + } + } + + // Draw another set of squares based on beat amplitude + int beatSquares = 5; // Number of beat squares + float beatSize = map(amplitude, 0, 1, 10, 50); // Size based on amplitude + for (int i = 0; i < beatSquares; i++) { + float x = random(cv.width); + float y = random(cv.height); + float beatHue = random(360); + cv.fill(beatHue, 80, 100); + cv.rectMode(CENTER); + cv.rect(x, y, beatSize, beatSize); + } + } + + void drawEyeball(float amplitude) { + // Calculate the size of the eyeball based on amplitude + float eyeballSize = map(amplitude, 0, 1, 200, 300); + + // Draw the black eyeball + cv.fill(0); // Set fill color to black + cv.ellipse(cv.width / 2, cv.height / 2, eyeballSize, eyeballSize); + + // Calculate the size of the heart based on amplitude + float heartSize = map(amplitude, 0, 1, 20, 60); + + // Calculate the hue for the heart based on amplitude + float heartHue = map(amplitude, 0, 1, 0, 360); + + // Draw the white heart inside the eyeball + cv.fill(heartHue, 80, 100); // Set fill color to heartHue + cv.noStroke(); + cv.beginShape(); + float yOffsetHeart = 20; + cv.vertex(cv.width / 2, cv.height / 2 - eyeballSize / 4 + yOffsetHeart); + cv.bezierVertex(cv.width / 2 + heartSize * 2, cv.height / 2 - eyeballSize / 4 - heartSize * 1.5f + yOffsetHeart, + cv.width / 2 + heartSize * 4, cv.height / 2 - eyeballSize / 4 - heartSize * 0.5f + yOffsetHeart, + cv.width / 2, cv.height / 2 + heartSize + yOffsetHeart); + cv.bezierVertex(cv.width / 2 - heartSize * 4, cv.height / 2 - eyeballSize / 4 - heartSize * 0.5f + yOffsetHeart, + cv.width / 2 - heartSize * 2, cv.height / 2 - eyeballSize / 4 - heartSize * 1.5f + yOffsetHeart, + cv.width / 2, cv.height / 2 - eyeballSize / 4 + yOffsetHeart); + cv.endShape(CLOSE); + + } + + void drawAudioBands(float amplitude) { + // Number of bands + int bands = 16; + + // Calculate the radius based on the eyeball size + float radius = map(amplitude, 0, 1, 115, 215); + + // Loop through each band + for (int i = 0; i < bands; i++) { + // Calculate the angle + float angle = map(i, 0, bands, 0, TWO_PI) + cv.frameCount * rotationSpeed; + + // Calculate the position of the point on the circle + float x = cv.width / 2 + radius * cos(angle); + float y = cv.height / 2 + radius * sin(angle); + + // Calculate the size of the band + float bandSize = map(amplitude, 0, 1, 10, 50); + + // Set the fill color + float hue = map(i, 0, bands, 0, 360); + cv.fill(hue, 80, 100); + cv.noStroke(); + // Draw the filled circle + cv.ellipse(x, y, bandSize, bandSize); + } + } + + void drawEyeOutline() { + cv.fill(255); + cv.stroke(255); + cv.strokeWeight(3); + cv.ellipse(cv.width / 2, cv.height / 2, eyeWidth, eyeHeight); + + // Draw audio waveform inside the eye outline + cv.noFill(); + cv.stroke(255, 0, 0); + cv.strokeWeight(2); + + // Number of points in the waveform + int numPoints = 1000; + + // Calculate waveform parameters based on eye outline size + float waveHeight = eyeHeight / 4; // Height of the waveform + float waveLength = eyeWidth; // Length of the waveform + float xStep = waveLength / numPoints; // Step between x values + + // Start drawing the waveform + cv.beginShape(); + for (int i = 0; i < numPoints; i++) { + float x = cv.width / 2 - eyeWidth / 2 + i * xStep; + float angle = map(i, 0, numPoints, 0, TWO_PI); + float yOffset = waveHeight * sin(angle * 2 + frameCount * 0.05f); // Adjust frequency with frameCount + float amplitude = cv.getSmoothedAmplitude(); // Get the current amplitude + yOffset *= amplitude; // Modulate the height of the waveform based on amplitude + float y = cv.height / 2 + yOffset; + cv.vertex(x, y); + } + cv.endShape(); + } + +} diff --git a/java/src/example/CubeVisual.java b/java/src/example/CubeVisual.java index ff8e58798..67c1f08df 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("java/data/meetmehalfway.mp3"); //getAp().play(); //startListening(); diff --git a/java/src/example/MyVisual.java b/java/src/example/MyVisual.java index 8a71fe3f6..9d6a5b187 100644 --- a/java/src/example/MyVisual.java +++ b/java/src/example/MyVisual.java @@ -10,20 +10,20 @@ public void settings() { size(1024, 500); // Use this to make fullscreen - // fullScreen(); + fullScreen(); // Use this to make fullscreen and use P3D for 3D graphics - // fullScreen(P3D, SPAN); + //fullScreen(P3D, SPAN); } public void setup() { startMinim(); // Call loadAudio to load an audio file to process - // loadAudio("heroplanet.mp3"); + loadAudio("java/data/meetmehalfway.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..534ff2a81 100644 --- a/java/src/example/RotatingAudioBands.java +++ b/java/src/example/RotatingAudioBands.java @@ -10,7 +10,7 @@ public void settings() { size(800, 800, P3D); println("CWD: " + System.getProperty("user.dir")); - //fullScreen(P3D, SPAN); + fullScreen(P3D, SPAN); } public void keyPressed() @@ -32,7 +32,7 @@ public void setup() setFrameSize(256); startMinim(); - loadAudio("heroplanet.mp3"); + loadAudio("java/data/heroplanet.mp3"); getAudioPlayer().play(); //startListening(); diff --git a/java/src/ie/tudublin/CombinedVisual.java b/java/src/ie/tudublin/CombinedVisual.java new file mode 100644 index 000000000..4ede504d9 --- /dev/null +++ b/java/src/ie/tudublin/CombinedVisual.java @@ -0,0 +1,93 @@ +package ie.tudublin; + +import c22359751.ArushiVisual1; +import c22359751.ArushiVisual2; +import c22380473.JeniedVisual1; +import c22380473.JeniedVisual2; +import c21331753.TaniaVisual1; +import c21331753.TaniaVisual2; + +public class CombinedVisual extends Visual { + ArushiVisual1 as1; + ArushiVisual2 as2; + JeniedVisual1 js1; + JeniedVisual2 js2; + TaniaVisual1 ts1; + TaniaVisual2 ts2; + + char visualSelected = ' '; + + public void settings() { + println("CWD: " + System.getProperty("user.dir")); + size(1024, 500); + // Use this to make fullscreen + fullScreen(); + + // Use this to make fullscreen and use P3D for 3D graphics + fullScreen(P3D, SPAN); + } + + public void setup() { + startMinim(); + // Call loadAudio to load an audio file to process + loadAudio("java/data/meetmehalfway.mp3"); + + // Call this instead to read audio from the microphone + // startListening(); + + as1 = new ArushiVisual1(this); + as2 = new ArushiVisual2(this); + js1 = new JeniedVisual1(this); + js2 = new JeniedVisual2(this); + ts1 = new TaniaVisual1(this); + ts2 = new TaniaVisual2(this); + } + + public void keyPressed() { + if (key == ' ') { + getAudioPlayer().cue(0); + getAudioPlayer().play(); + } else { + visualSelected = key; + } + } + + public void draw() { + background(0); + + switch (visualSelected) { + case '1': + js1.render(); + break; + case '2': + as2.render(); + break; + case '3': + as1.render(); + break; + case '4': + js2.render(); + break; + case '5': + ts1.render(); + break; + case '6': + ts2.render(); + break; + default: + break; + } + + try { + // Call this if you want to use FFT data + calculateFFT(); + } catch (VisualException e) { + e.printStackTrace(); + } + // Call this is you want to use frequency bands + calculateFrequencyBands(); + + // Call this is you want to get the average amplitude + calculateAverageAmplitude(); + } +} diff --git a/java/src/ie/tudublin/Main.java b/java/src/ie/tudublin/Main.java index 67e93d892..ed2019e78 100644 --- a/java/src/ie/tudublin/Main.java +++ b/java/src/ie/tudublin/Main.java @@ -1,18 +1,15 @@ 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 CombinedVisual()); } public static void main(String[] args) { 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..d33864946 100644 --- a/java/src/ie/tudublin/Visual.java +++ b/java/src/ie/tudublin/Visual.java @@ -4,6 +4,7 @@ import ddf.minim.*; import ddf.minim.analysis.FFT; + public abstract class Visual extends PApplet { private int frameSize = 512; @@ -33,6 +34,15 @@ public void startMinim() smoothedBands = new float[bands.length]; } + + public void setup() { + startMinim(); + + // Call loadAudio to load an audio file to process + loadAudio("java/data/meetmehalfway.mp3"); + + + } float log2(float f) { return log(f) / log(2.0f);