diff --git a/.vscode/launch.json b/.vscode/launch.json index 5f0c7af3b..5bac21f06 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,5 +1,26 @@ { "configurations": [ + { + "type": "java", + "name": "Start", + "request": "launch", + "mainClass": "OOP2023.Start", + "projectName": "java" + }, + { + "type": "java", + "name": "AudioVisualizer", + "request": "launch", + "mainClass": "OOP2023.AudioVisualizer", + "projectName": "java" + }, + { + "type": "java", + "name": "Main", + "request": "launch", + "mainClass": "OOP2023.Main", + "projectName": "java" + }, { "type": "java", "name": "CodeLens (Launch) - Main", diff --git a/README.md b/README.md index 19ba88c75..159ddd74a 100644 --- a/README.md +++ b/README.md @@ -1,89 +1,30 @@ -# Music Visualiser Project +My music visualizer project -Name: +Name: Mabu chemelie michael -Student Number: +Student Number: D19123717 -## 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 +Description: this program is like nature as i would like to call it, firstly i adopted a music that plays when you run the program. the music has this ecstaic rave vibe, which is the reason i choose it. However, the music is not where the fun ends, the program is menu-driven with just two options, frist option to exit the program and the other to visualize the project. -# Description of the assignment -# Instructions +Instruction: the instruction of the code is pretty much self explanatory but i will go through it. so when the program runs it initiaties the GUI which shows a menu with calm colours and music playing. in the menu you have a promtp message with two options as mentioned earlier in the description. when 1 is pressed it takes you to the visulaizer primarily designed to visualize an audio input using clouds flowers and other natural elemnts implemented in the program -# How it works -# What I am most proud of in the assignment +The Visualizer program is designed to create a visual representation based on some form of audio input. a liitle summary on how the program works. + + for the audio input and amplitude calculation, the program processes audio data to compute an amplitude value using the getAmplitude() method, which converts the audio buffer to an array. the applitude is calaculated by squaring each value in the buffer, summing them up, and then taking the square root of the average of those squared values. The amplitude will typically rise and fall based on the loudness and intensity of the audio. + + for visual representation like drawing static components, the method drawsun is used to draw the sun on the canvas as well as the drawGround method which draws a rectangle that visually represents the ground. the render() method is responsible for drawing the entire scene on the canvas. The sequence of drawing is: + Draw the sun. + Draw the flowers. + Draw the ground. + Draw ellipses based on the amplitude (perhaps some visual feedback). + Draw clouds, with sizes influenced by the audio's amplitude. + It seems the render() method is called repeatedly (probably in a loop), which means the visualization will be dynamic and continuously update as the audio plays. -# Markdown Tutorial +finally When audio plays, this program visualizes it by displaying a scene with a sun, ground, flowers, and clouds. The flowers rotate, and the clouds change size based on the audio's amplitude, providing a dynamic visual representation of the audio. -This is *emphasis* +i am proud of many things in this project although some of the methods in the program were very diffcult to implement because of its complexity and also the kind of design i had in mind for the methods. The code is organized using an object-oriented approach. The use of classes, methods, encapsulation, and inheritance (e.g., extending the Visual class) is a clear indication of a structured and modular design. attention to details was one of the great factor that helped me with some design implementaion like having the flowers rotate in opposite directions relative to their stems. +finally this project serves as a learning experience, although i faced some challenges working on the program buh at the same time i gained some skills that i would be adding in my arsenal. -This is a bulleted list - -- Item -- Item - -This is a numbered list - -1. Item -1. Item - -This is a [hyperlink](http://bryanduggan.org) - -# Headings -## Headings -#### Headings -##### Headings - -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); -} -``` - -So is this without specifying the language: - -``` -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); -} -``` - -This is an image using a relative URL: - -![An image](images/p8.png) - -This is an image using an absolute URL: - -![A different image](https://bryanduggandotorg.files.wordpress.com/2019/02/infinite-forms-00045.png?w=595&h=&zoom=2) - -This is a youtube video: - -[![YouTube](http://img.youtube.com/vi/J2kHSSFA4NU/0.jpg)](https://www.youtube.com/watch?v=J2kHSSFA4NU) - -This is a table: - -| 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 | diff --git a/images/bread.png b/images/bread.png new file mode 100644 index 000000000..b533f73b2 Binary files /dev/null and b/images/bread.png differ diff --git a/images/cheese.png b/images/cheese.png new file mode 100644 index 000000000..38560e8c6 Binary files /dev/null and b/images/cheese.png differ diff --git a/images/ham.png b/images/ham.png new file mode 100644 index 000000000..041fd7a72 Binary files /dev/null and b/images/ham.png differ diff --git a/images/lettuce.png b/images/lettuce.png new file mode 100644 index 000000000..c945bb721 Binary files /dev/null and b/images/lettuce.png differ diff --git a/images/mayo.png b/images/mayo.png new file mode 100644 index 000000000..0d6edefdf Binary files /dev/null and b/images/mayo.png differ diff --git a/images/mustard.png b/images/mustard.png new file mode 100644 index 000000000..18ce07f77 Binary files /dev/null and b/images/mustard.png differ diff --git a/images/tomato.png b/images/tomato.png new file mode 100644 index 000000000..7e7f7dfb5 Binary files /dev/null and b/images/tomato.png differ diff --git a/java/.project b/java/.project index 0d5afed93..7d2d47086 100644 --- a/java/.project +++ b/java/.project @@ -16,12 +16,12 @@ - 1616413840733 + 1692362523697 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/rave.mp3 b/java/data/rave.mp3 new file mode 100644 index 000000000..3fef0733c Binary files /dev/null and b/java/data/rave.mp3 differ diff --git a/java/src/OOP2023/Start.java b/java/src/OOP2023/Start.java new file mode 100644 index 000000000..feb57f846 --- /dev/null +++ b/java/src/OOP2023/Start.java @@ -0,0 +1,74 @@ +package OOP2023; + +import ie.tudublin.Visual; + +public class Start extends Visual { + Anne anne = new Anne(this); + + //For menu buttons + int mode = 0; + + + + public void keyPressed() + { + if(key == '0') + { + mode = 0; + } + + if(key == '1') + { + mode = 1; + } + } + + public void setup() + { + startMinim(); + loadAudio("rave.mp3"); + getAudioPlayer().play(); + + colorMode(RGB); + } + + public void settings() + { + size(600, 600, P3D); + } + + public void draw() { + switch (mode) { + // For the main menu + case 0: + background(50, 50, 70); // Dark Blue-Gray background + fill(210, 210, 230); // Light Blue-Gray for text + textAlign(CENTER); + textSize(width / 20.0f); + + // Title with a bit of shadow for a modern touch + text("Ecstatic song", width / 2.0f, height / 4.0f); + textSize(width / 30.0f); + fill(220, 220, 240); // Slightly lighter shade for options + + text("Press 0: MENU", width / 2.0f, (height / 2.0f)); + text("Press 1: Nature", width / 2.0f, (height / 2.0f) + 50); + + break; + + // Audio + case 1: + background(153, 204, 255); + anne.render(); + + } + + + + + + + + } + +} \ No newline at end of file diff --git a/java/src/OOP2023/Visualizer.java b/java/src/OOP2023/Visualizer.java new file mode 100644 index 000000000..731678d1f --- /dev/null +++ b/java/src/OOP2023/Visualizer.java @@ -0,0 +1,122 @@ +package OOP2023; + +import ie.tudublin.Visual; + +public class Anne extends Visual { + private Start anne; + + // Constants + private static final int PETAL_COUNT = 5; + private static final int PETAL_ANGLE = 72; + + public Anne(Start anne) { + this.anne = anne; + } + + public float getAmplitude() { + float[] flowers = getAudioBuffer().toArray(); + float sum = 0; + for (float flower : flowers) { + sum += flower * flower; + } + return (float) Math.sqrt(sum / flowers.length); + } + + public void drawCloud(int a, int b, int c, float d) { + anne.noStroke(); + anne.fill(255); + + int[] ellipseOffsetsX = {530, 510, 460, 480, 470, 510, 490}; + int[] ellipseOffsetsY = {295, 305, 295, 305, 285, 285, 280}; + int[] ellipseWidths = {60, 40, 40, 40, 40, 40, 40}; + int[] ellipseHeights = {30, 30, 30, 30, 30, 30, 30}; + + for (int i = 0; i < ellipseOffsetsX.length; i++) { + anne.ellipse(a + ellipseOffsetsX[i], b + ellipseOffsetsY[i], c + ellipseWidths[i], d + ellipseHeights[i]); + } + } + + public void drawGround() { + anne.stroke(114, 180, 58); + anne.fill(65, 101, 34); + anne.rect(0, 850, 2000, 500); + } + + public void drawSun() { + anne.pushMatrix(); + anne.smooth(); + anne.noSmooth(); + anne.fill(245, 187, 87); + anne.ellipse(224, 184, 220, 220); + anne.popMatrix(); + } + + private void drawFlower(int translateX, int translateY, float rotateFactor, int[] flowerColor, int[] flowerCenterColor) { + float amplitude = getAmplitude(); + anne.pushMatrix(); + anne.smooth(); + anne.noStroke(); + anne.translate(anne.width / 2, anne.height / 2); + anne.translate(translateX, translateY); + anne.rotate(radians(amplitude * rotateFactor)); + + anne.fill(flowerColor[0], flowerColor[1], flowerColor[2]); + for (int i = 0; i < PETAL_COUNT; i++) { + anne.ellipse(0, -40, 50, 50); + anne.rotate(radians(PETAL_ANGLE)); + } + + anne.pushMatrix(); + anne.rotate(-radians(amplitude * rotateFactor)); + anne.stroke(41, 63, 22); + anne.strokeWeight(3); + anne.line(0, 44, 0, 255); + anne.popMatrix(); + + anne.stroke(flowerCenterColor[0], flowerCenterColor[1], flowerCenterColor[2]); + anne.fill(flowerCenterColor[0], flowerCenterColor[1], flowerCenterColor[2]); + anne.ellipse(0, 0, 50, 50); + + anne.popMatrix(); + } + + public void drawFlowers() { + drawFlower(-100, 100, 180, new int[]{191, 155, 48}, new int[]{141, 85, 36}); + drawFlower(-200, -100, 360, new int[]{141, 158, 199}, new int[]{195, 227, 220}); + drawFlower(200, 200, 60, new int[]{246, 234, 219}, new int[]{255, 200, 109}); + drawFlower(-400, 50, 250, new int[]{149, 125, 173}, new int[]{255, 223, 211}); + } + + public void render() { + float avg = 0; + for (int i = 0; i < ab.size(); i++) { + avg += Math.abs(ab.get(i)); + } + avg /= ab.size(); + float smoothedavg = lerp(0, avg, 0.01f); + + anne.colorMode(RGB); + drawSun(); + drawFlowers(); + drawGround(); + + anne.fill(0, 10); + anne.fill(255); + anne.noStroke(); + + if (anne.frameCount % 30 == 0) { + anne.ellipse(anne.width, anne.height, smoothedavg, smoothedavg); + } + + anne.translate(anne.width / 2, anne.height / 2, 0); + + // Cloud rendering calls + drawCloud(-600, -544, 10, 30 * smoothedavg * 200); + drawCloud(-800, -644, 10, 30 * smoothedavg * 200); + drawCloud(-1000, -644, 10, 30 * smoothedavg * 200); + drawCloud(-100, -544, 10, 30 * smoothedavg * 200); + drawCloud(-300, -600, 10, 30 * smoothedavg * 200); + drawCloud(0, -644, 10, 30 * smoothedavg * 200); + + } +} diff --git a/java/src/ie/tudublin/Main.java b/java/src/ie/tudublin/Main.java index 27489f824..f6be7ec80 100644 --- a/java/src/ie/tudublin/Main.java +++ b/java/src/ie/tudublin/Main.java @@ -1,8 +1,6 @@ package ie.tudublin; -import example.CubeVisual; -import example.MyVisual; -import example.RotatingAudioBands; +import OOP2023.*; public class Main { @@ -10,7 +8,7 @@ public class Main public void startUI() { String[] a = {"MAIN"}; - processing.core.PApplet.runSketch( a, new MyVisual()); + processing.core.PApplet.runSketch( a, new Start()); } public static void main(String[] args) diff --git a/java/src/ie/tudublin/Visual.java b/java/src/ie/tudublin/Visual.java index 927fe57b1..d741f9430 100644 --- a/java/src/ie/tudublin/Visual.java +++ b/java/src/ie/tudublin/Visual.java @@ -15,7 +15,7 @@ public abstract class Visual extends PApplet private Minim minim; private AudioInput ai; private AudioPlayer ap; - private AudioBuffer ab; + protected AudioBuffer ab; private FFT fft; private float amplitude = 0;