diff --git a/README.md b/README.md index 19ba88c75..40fa499bc 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Music Visualiser Project -Name: +Names: Aimee Mcgrane, Neil Fitzgerald, Jade Thornton, Jason O Sullivan, Chris Noblett -Student Number: +Student Numbers: C22393606, C22405604, C22394466, C22400796, C22454222 ## Instructions - Fork this repository and use it a starter project for your assignment @@ -13,12 +13,52 @@ Student Number: # Description of the assignment +## Aimee + +## Neil + +## Jade + +## Jason + +## Chris + # Instructions +## Main Menu + +Once you have ran the program, a separate menu window opens with the following options: +- Play Tune +- Aimee +- Neil +- Jade +- Jason +- Chris + +## Chris's Visual Option +Chris's visual has further visual change options based on keypress. +Press a corresponding number on your keyboard to change the visual. + +| Keycode | Visual | +|---------|-----------| +| '1' | | +| '2' | | +| '3' | | + # How it works # What I am most proud of in the assignment +## Aimee + +## Neil + +## Jade + +## Jason + +## Chris + # Markdown Tutorial This is *emphasis* @@ -33,7 +73,7 @@ This is a numbered list 1. Item 1. Item -This is a [hyperlink](http://bryanduggan.org) +This is a [hyperlink] # Headings ## Headings @@ -43,41 +83,19 @@ This is a [hyperlink](http://bryanduggan.org) 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) +![An image] 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) +![A different image] This is a youtube video: -[![YouTube](http://img.youtube.com/vi/J2kHSSFA4NU/0.jpg)](https://www.youtube.com/watch?v=J2kHSSFA4NU) - +![YouTube] This is a table: | Heading 1 | Heading 2 | diff --git a/java/.project b/java/.project index 0d5afed93..d3f96df3b 100644 --- a/java/.project +++ b/java/.project @@ -16,12 +16,12 @@ - 1616413840733 + 1711630517027 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/Project.mp3 b/java/data/Project.mp3 new file mode 100644 index 000000000..9a6d4d9df Binary files /dev/null and b/java/data/Project.mp3 differ diff --git a/java/data/Project.wav b/java/data/Project.wav new file mode 100644 index 000000000..f5af7b135 Binary files /dev/null and b/java/data/Project.wav differ 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/C22454222/AudioBandsVisual.java b/java/src/C22454222/AudioBandsVisual.java new file mode 100644 index 000000000..6d26b95dd --- /dev/null +++ b/java/src/C22454222/AudioBandsVisual.java @@ -0,0 +1,49 @@ +package C22454222; // Package declaration +import ie.tudublin.*; // Importing necessary classes from the ie.tudublin package +import ddf.minim.AudioBuffer; // Importing AudioBuffer class from the ddf.minim package + +// This is an example of a visual that uses the audio bands +public class AudioBandsVisual extends Visual // Class declaration, extending Visual class +{ + MainVisual mv; // Reference to MainVisual class + AudioBuffer ab; // Reference to AudioBuffer class + float[] lerpedBuffer; // Array to store lerped audio buffer values + float smoothedAmplitude = 0; // Variable to store smoothed amplitude value + + // Constructor for AudioBandsVisual class + public AudioBandsVisual(MainVisual mv) + { + this.mv = mv; // Initializing MainVisual reference + ab = mv.getAudioBuffer(); // Getting audio buffer from MainVisual + lerpedBuffer = new float[ab.size()]; // Initializing lerpedBuffer with size of audio buffer + } + + // Method to render the visual + public void render() + { + mv.beat.detect(mv.as.mix); // Detecting beat using MainVisual's AudioSum + mv.beat.detectMode(0); // Setting beat detection mode + mv.background(0); // Setting background color to black + float average = 0; // Variable to store average value + float sum = 0; // Variable to store sum of audio buffer values + + // Calculating sum of absolute values of audio buffer + for(int i = 0 ; i < ab.size() ; i ++) + { + sum += abs(ab.get(i)); // Adding absolute value of each audio buffer element to sum + lerpedBuffer[i] = lerp(lerpedBuffer[i], ab.get(i), 0.1f); // Applying linear interpolation to smooth audio buffer + } + + average = sum / (float) ab.size(); // Calculating average value + smoothedAmplitude = lerp(smoothedAmplitude, average, 0.1f); // Applying linear interpolation to smooth amplitude + + // Draw the visual using lerpedBuffer + for(int i = 0; i < ab.size(); i ++) + { + float c = map(i, 0, ab.size(), 0, 255); // Mapping index to color value + mv.stroke(c, 255, 255); // Setting stroke color based on mapped value + float f = lerpedBuffer[i] * mv.height / 2 * 4.0f; // Scaling lerped buffer value + mv.line(i, mv.height / 2 + f, i, mv.height / 2 - f); // Drawing line based on scaled value + } + } +} diff --git a/java/src/C22454222/ChrisVisual.java b/java/src/C22454222/ChrisVisual.java new file mode 100644 index 000000000..46cd538f9 --- /dev/null +++ b/java/src/C22454222/ChrisVisual.java @@ -0,0 +1,120 @@ +package C22454222; +import ddf.minim.AudioInput; +import ddf.minim.Minim; +import processing.core.PApplet; +import ie.tudublin.*; +import ddf.minim.AudioBuffer; + +public class ChrisVisual extends Visual +{ + MainVisual mv; + Minim minim; + AudioInput ai; + AudioBuffer ab; + + float[] lerpedBuffer; + float y = 0; + float smoothedY = 0; + float smoothedAmplitude = 0; + + public ChrisVisual(MainVisual mv) + { + this.mv = mv; + this.ab = mv.getAudioBuffer(); + this.ai = mv.getAudioInput(); + } + + float[] currentColours = new float[]{random(0,255),random(0,255),random(0,255)}; + float[] previousColours = new float[]{0,0,0}; + int kickCounter = 0; + + public float[] replacingColours(float[] currentColours) + { + float[] colours = new float[]{random(0,255),random(0,255),random(0,255)}; + for(int i = 0; i < 3; i++) + { + currentColours[i] = colours[i]; + } + return currentColours; + } + + public void render() + { + float radius = 20; + mv.background(0,0,0); + mv.beat.detect(mv.as.mix); + mv.beat.detectMode(0); + mv.fCounter++; + mv.translate(mv.width/2, mv.height/2); + + float smooth = mv.getSmoothedAmplitude(); + + if (mv.beat.isKick()) + { + kickCounter++; + } + + mv.fill(currentColours[0],currentColours[1],currentColours[2], 50); + + radius = 40*kickCounter; + mv.ellipse(0,0,radius,radius); + + mv.fill(previousColours[0],previousColours[1],previousColours[2], 25); + + mv.stroke(map(mv.getAmplitude(), 0, 1, 0,255),255,255); + + radius = 15*kickCounter; + mv.triangle(-200, -100, -140+(float)0.6*radius, radius, (-260-(float)0.6*radius), radius); + mv.triangle(200, -100, 260+(float)0.6*radius, radius, (140-(float)0.6*radius), radius); + mv.triangle(-400, -100, -340+(float)0.6*radius, radius, (-460-(float)0.6*radius), radius); + mv.triangle(400, -100, 460+(float)0.6*radius, radius, (340-(float)0.6*radius), radius); + mv.triangle(-600, -100, -540+(float)0.6*radius, radius, (-660-(float)0.6*radius), radius); + mv.triangle(600, -100, 660+(float)0.6*radius, radius, (540-(float)0.6*radius), radius); + + mv.triangle(-200, 100, -140+(float)0.6*radius, -radius, (-260-(float)0.6*radius), -radius); + mv.triangle(200, 100, 260+(float)0.6*radius, -radius, (140-(float)0.6*radius), -radius); + mv.triangle(-400, 100, -340+(float)0.6*radius, -radius, (-460-(float)0.6*radius), -radius); + mv.triangle(400, 100, 460+(float)0.6*radius, -radius, (340-(float)0.6*radius), -radius); + mv.triangle(-600, 100, -540+(float)0.6*radius, -radius, (-660-(float)0.6*radius), -radius); + mv.triangle(600, 100, 660+(float)0.6*radius, -radius, (540-(float)0.6*radius), -radius); + + if (radius > (float)mv.width / 2) + { + for (int i = 0; i < 3; i++) + { + previousColours[i] = currentColours[i]; + } + replacingColours(currentColours); + kickCounter = 0; + radius = 20; + } + + for (float i = 0; i < mv.width; i += 0.3) + { + float x1 = (PApplet.cos(i) * smooth * i); + float y1 = (PApplet.sin(i) * smooth * i); + mv.point(x1, y1); + } + + + for (float i = 0; i < mv.width; i += 0.3) + { + float centerX2 = -400; + float centerY2 = 0; + float x2 = centerX2 + (PApplet.cos(i) * smooth * i); + float y2 = centerY2 + (PApplet.sin(i) * smooth * i); + mv.point(x2, y2); + } + + for (float i = 0; i < mv.width; i += 0.3) + { + float centerX3 = +400; + float centerY3 = 0; + float x3 = centerX3 + (PApplet.cos(i) * smooth * i); + float y3 = centerY3 + (PApplet.sin(i) * smooth * i); + mv.point(x3, y3); + } + } +} + + diff --git a/java/src/C22454222/MainVisual.java b/java/src/C22454222/MainVisual.java new file mode 100644 index 000000000..1b58b84e4 --- /dev/null +++ b/java/src/C22454222/MainVisual.java @@ -0,0 +1,114 @@ +package C22454222; // Package declaration + +import ie.tudublin.*; // Importing necessary classes from the ie.tudublin package +import ddf.minim.AudioPlayer; +// MainVisual class extending Visual class +public class MainVisual extends Visual +{ + AudioPlayer ap; // Reference to AudioPlayer class + int visualSwap = 0; // Variable to control visual swapping + int playTune = 0; // Variable to control playing tune + int stopPlay = 0; // Variable to control stopping playback + public float eRadius = 20; + /* + AimeeVisual aimee; + NeilVisual neil; + JadeVisual jade; + JasonVisual jason; + */ + ChrisVisual chris; + AudioBandsVisual audioBandsVisual; // Instance of AudioBandsVisual class + + public float fCounter = 0; // Variable to store a floating-point counter value + public int chrisOption = 1; // Variable to store an option for Chris's visual + + // Method to set initial settings + public void settings() + { + // Setting window size + fullScreen(); + // fullScreen(P3D,SPAN); + } + + // Method to perform initial setup + public void setup() + { + startMinim(); // Starting Minim audio library + loadAudio("Project.wav"); // Loading audio file + BeatDetect(); // Initializing beat detection + colorMode(HSB); // Setting color mode + /* + aimee = new AimeeVisual(this); + neil = new NeilVisual(this); + jade = new JadeVisual(this); + jason = new JasonVisual(this); + */ + chris = new ChrisVisual(this); // Initializing ChrisVisual instance with appropriate constructor + audioBandsVisual = new AudioBandsVisual(this); // Initializing AudioBandsVisual instance + } + + // Method to handle key pressed events + public void keyPressed() + { + if (key == ' ') + { // If space bar is pressed + as.stop(); + as.trigger(); + } + // If numeric keys 1 to 3 are pressed + if (keyCode >= '1' && keyCode <= '3') + { + chrisOption = keyCode - '0'; // Update chrisOption with the corresponding numeric value + } + } + + // Method to draw visuals + public void draw() + { + if (playTune == 1) + { // If playTune flag is set + as.stop(); // Stop audio playback + as.trigger(); // Trigger audio playback + playTune = 0; // Reset playTune flag + } + + try + { + calculateFFT(); // Calculate Fast Fourier Transform + } + + catch (VisualException e) + { // Catch any VisualExceptions + e.printStackTrace(); // Print stack trace of the exception + } + + calculateFrequencyBands(); // Calculate frequency bands + calculateAverageAmplitude(); // Calculate average amplitude + + // Switch statement to determine which visual to render + switch (visualSwap) + { + case 0: + // aimee.render(); + break; + case 1: + // neil.render(); + break; + case 2: + // jade.render(); + break; + case 3: + // jason.render(); + break; + case 4: + chris.render(); + break; + case 5: + audioBandsVisual.render(); // Render AudioBandsVisual + break; + default: + background(0); // Set background color to black by default + break; + } + } +} diff --git a/java/src/C22454222/MainVisualMenu.java b/java/src/C22454222/MainVisualMenu.java new file mode 100644 index 000000000..fb8ddca73 --- /dev/null +++ b/java/src/C22454222/MainVisualMenu.java @@ -0,0 +1,112 @@ +package C22454222; // Package declaration + +import ie.tudublin.*; // Importing necessary classes from the ie.tudublin package + +// MainVisualMenu class extending Visual class +public class MainVisualMenu extends Visual +{ + MainVisual visualMode; // Reference to MainVisual class + + // Constructor to initialize MainVisualMenu instance + public MainVisualMenu(MainVisual visualMode) + { + this.visualMode = visualMode; // Assigning the reference to visualMode + } + + public int options = 6; // Variable to store the number of options + int boxHeight = 100; // Variable to store the height of the box + int boxWidth = 200; // + + public void settings() + { + size(200,700); + } + + public void setup() + { + colorMode(HSB); + } + + public void keyPressed() + { + if (key == ' ') + { + visualMode.visualSwap = (visualMode.visualSwap + 1) % options; + } + } + + public void draw() + { + background(0); // Set background to black + + for(int i = 0; i < options + 1; i++) + { + if (i == 0) + { + fill(25, 255, 255); // Red + stroke(110); + } + else if (i == 1) + { + fill(180, 255, 255); // Green + stroke(110); + } + else if (i == 2) + { + fill(0, 255, 255); // Blue + stroke(110); + } + else if (i == 3) + { + fill(90, 255, 255); // Yellow + stroke(110); + } + else if (i == 4) + { + fill(60, 255, 255); // Orange + stroke(110); + } + else if (i == 5) + { + fill(180, 255, 255); // Purple + stroke(110); + } + else if (i == 6) + { + fill(0); + stroke(110); + } + + rect(0, i * boxHeight, boxWidth, boxHeight); + + if (mouseY >= i * boxHeight && mouseY <= (i + 1) * boxHeight) + { + fill(0); // Set text color to white + rect(0, i * boxHeight, boxWidth, boxHeight); + + if (mousePressed) + { + if (i != 0) + { + visualMode.visualSwap = i - 1; + } + else + { + visualMode.playTune = 1; + } + } + } + } + textSize(30); + fill(255); // Set text color to white + textAlign(CENTER, CENTER); + + text("Play Tune", boxWidth / 2, boxHeight / 2); + text("Aimee", boxWidth / 2, 1 * boxHeight + boxHeight / 2); + text("Neil", boxWidth / 2, 2 * boxHeight + boxHeight / 2); + text("Jade", boxWidth / 2, 3 * boxHeight + boxHeight / 2); + text("Jason", boxWidth / 2, 4 * boxHeight + boxHeight / 2); + text("Chris", boxWidth / 2, 5 * boxHeight + boxHeight / 2); + text("Audiobands", boxWidth / 2, 6 * boxHeight + boxHeight / 2); + } +} \ No newline at end of file diff --git a/java/src/c123456/BryansVisual.java b/java/src/c123456/BryansVisual.java deleted file mode 100644 index e69de29bb..000000000 diff --git a/java/src/ie/tudublin/Main.java b/java/src/ie/tudublin/Main.java index 67e93d892..1680f6e75 100644 --- a/java/src/ie/tudublin/Main.java +++ b/java/src/ie/tudublin/Main.java @@ -1,17 +1,24 @@ +// This file contains the Main class which serves as the entry point for the application + package ie.tudublin; -import example.CubeVisual; -import example.MyVisual; -import example.RotatingAudioBands; +import C22454222.*; public class Main { - public void startUI() { + // The startUI method initializes the visualizer and runs the sketches + public void startUI() + { + MainVisual visualizer = new MainVisual(); String[] a = { "MAIN" }; - processing.core.PApplet.runSketch(a, new MyVisual()); + processing.core.PApplet.runSketch(a, visualizer); + String[] b = {"Second"}; + processing.core.PApplet.runSketch(b, new MainVisualMenu(visualizer)); } - public static void main(String[] args) { + // The main method creates an instance of the Main class and calls the startUI method + public static void main(String[] args) + { Main main = new Main(); main.startUI(); } diff --git a/java/src/ie/tudublin/Visual.java b/java/src/ie/tudublin/Visual.java index 927fe57b1..08791df6e 100644 --- a/java/src/ie/tudublin/Visual.java +++ b/java/src/ie/tudublin/Visual.java @@ -1,12 +1,12 @@ package ie.tudublin; - import processing.core.PApplet; import ddf.minim.*; +import ddf.minim.analysis.BeatDetect; import ddf.minim.analysis.FFT; public abstract class Visual extends PApplet { - private int frameSize = 512; + private int frameSize = 1024; private int sampleRate = 44100; private float[] bands; @@ -14,12 +14,14 @@ public abstract class Visual extends PApplet private Minim minim; private AudioInput ai; + public AudioSample as; private AudioPlayer ap; private AudioBuffer ab; + public BeatDetect beat; private FFT fft; - + private float amplitude = 0; - private float smothedAmplitude = 0; + private float smoothedAmplitude = 0; @@ -34,7 +36,8 @@ public void startMinim() } - float log2(float f) { + float log2(float f) + { return log(f) / log(2.0f); } @@ -60,17 +63,20 @@ public void calculateAverageAmplitude() total += abs(ab.get(i)); } amplitude = total / ab.size(); - smothedAmplitude = PApplet.lerp(smothedAmplitude, amplitude, 0.1f); + smoothedAmplitude = PApplet.lerp(smoothedAmplitude, amplitude, 0.1f); } - protected void calculateFrequencyBands() { - for (int i = 0; i < bands.length; i++) { + protected void calculateFrequencyBands() + { + for (int i = 0; i < bands.length; i++) + { int start = (int) pow(2, i) - 1; int w = (int) pow(2, i); int end = start + w; float average = 0; - for (int j = start; j < end; j++) { + for (int j = start; j < end; j++) + { average += fft.getBand(j) * (j + 1); } average /= (float) w; @@ -87,60 +93,84 @@ public void startListening() public void loadAudio(String filename) { - ap = minim.loadFile(filename, frameSize); - ab = ap.mix; + as = minim.loadSample(filename, frameSize); + ab = as.left; } - public int getFrameSize() { + public int getFrameSize() + { return frameSize; } - public void setFrameSize(int frameSize) { + public void setFrameSize(int frameSize) + { this.frameSize = frameSize; } - public int getSampleRate() { + public int getSampleRate() + { return sampleRate; } - public void setSampleRate(int sampleRate) { + public void setSampleRate(int sampleRate) + { this.sampleRate = sampleRate; } - public float[] getBands() { + public float[] getBands() + { return bands; } - public float[] getSmoothedBands() { + public float[] getSmoothedBands() + { return smoothedBands; } - public Minim getMinim() { + public Minim getMinim() + { return minim; } - public AudioInput getAudioInput() { + public AudioInput getAudioInput() + { return ai; } - public AudioBuffer getAudioBuffer() { + public AudioBuffer getAudioBuffer() + { return ab; } + + public AudioSample getAudioSample() + { + return as; + } - public float getAmplitude() { + public float getAmplitude() + { return amplitude; } - public float getSmoothedAmplitude() { - return smothedAmplitude; + public float getSmoothedAmplitude() + { + return smoothedAmplitude; } - public AudioPlayer getAudioPlayer() { + public AudioPlayer getAudioPlayer() + { return ap; } - public FFT getFFT() { + public FFT getFFT() + { return fft; } + + public BeatDetect BeatDetect() + { + beat = new BeatDetect(); + return beat; + } } diff --git a/java/src/ie/tudublin/VisualException.java b/java/src/ie/tudublin/VisualException.java index 65381bcb2..bd3286dca 100644 --- a/java/src/ie/tudublin/VisualException.java +++ b/java/src/ie/tudublin/VisualException.java @@ -2,11 +2,7 @@ public class VisualException extends Throwable { - /** - * - */ private static final long serialVersionUID = 1L; - private String message; public VisualException(String message)