diff --git a/.gitignore b/.gitignore
index 259148f..aa77b1f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,7 @@
*.exe
*.out
*.app
+
+MusicVisualizer/bin/
+MusicVisualizer/MusicVisualizer.xcodeproj/
+MusicVisualizer/obj/
\ No newline at end of file
diff --git a/MusicVisualizer/Makefile b/MusicVisualizer/Makefile
new file mode 100644
index 0000000..a1425e7
--- /dev/null
+++ b/MusicVisualizer/Makefile
@@ -0,0 +1,13 @@
+# Attempt to load a config.make file.
+# If none is found, project defaults in config.project.make will be used.
+ifneq ($(wildcard config.make),)
+ include config.make
+endif
+
+# make sure the the OF_ROOT location is defined
+ifndef OF_ROOT
+ OF_ROOT=$(realpath ../../../of_v0.9.8_osx_release/of_v0.9.8_osx_release/of_v0.9.8_osx_release/of_v0.9.8_osx_release/of_v0.9.8_osx_release/of_v0.9.8_osx_release)
+endif
+
+# call the project makefile!
+include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk
diff --git a/MusicVisualizer/Project.xcconfig b/MusicVisualizer/Project.xcconfig
new file mode 100644
index 0000000..4c2b6be
--- /dev/null
+++ b/MusicVisualizer/Project.xcconfig
@@ -0,0 +1,17 @@
+//THE PATH TO THE ROOT OF OUR OF PATH RELATIVE TO THIS PROJECT.
+//THIS NEEDS TO BE DEFINED BEFORE CoreOF.xcconfig IS INCLUDED
+OF_PATH = ../../../of_v0.9.8_osx_release
+
+//THIS HAS ALL THE HEADER AND LIBS FOR OF CORE
+#include "../../../of_v0.9.8_osx_release/libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig"
+
+//ICONS - NEW IN 0072
+ICON_NAME_DEBUG = icon-debug.icns
+ICON_NAME_RELEASE = icon.icns
+//ICON_FILE_PATH = $(OF_PATH)/libs/openFrameworksCompiled/project/osx/
+
+//IF YOU WANT AN APP TO HAVE A CUSTOM ICON - PUT THEM IN YOUR DATA FOLDER AND CHANGE ICON_FILE_PATH to:
+ICON_FILE_PATH = bin/data/
+
+OTHER_LDFLAGS = $(OF_CORE_LIBS) $(OF_CORE_FRAMEWORKS)
+HEADER_SEARCH_PATHS = $(OF_CORE_HEADERS)
diff --git a/MusicVisualizer/addons.make b/MusicVisualizer/addons.make
new file mode 100644
index 0000000..7a6e880
--- /dev/null
+++ b/MusicVisualizer/addons.make
@@ -0,0 +1,3 @@
+ofxGui
+ofxHistoryPlot
+ofxPostProcessing
diff --git a/MusicVisualizer/config.make b/MusicVisualizer/config.make
new file mode 100644
index 0000000..1570e80
--- /dev/null
+++ b/MusicVisualizer/config.make
@@ -0,0 +1,142 @@
+################################################################################
+# CONFIGURE PROJECT MAKEFILE (optional)
+# This file is where we make project specific configurations.
+################################################################################
+
+################################################################################
+# OF ROOT
+# The location of your root openFrameworks installation
+# (default) OF_ROOT = ../../../of_v0.9.8_osx_release/of_v0.9.8_osx_release/of_v0.9.8_osx_release/of_v0.9.8_osx_release/of_v0.9.8_osx_release/of_v0.9.8_osx_release
+################################################################################
+# OF_ROOT = ../../../of_v0.9.8_osx_release/of_v0.9.8_osx_release/of_v0.9.8_osx_release/of_v0.9.8_osx_release/of_v0.9.8_osx_release/of_v0.9.8_osx_release
+
+################################################################################
+# PROJECT ROOT
+# The location of the project - a starting place for searching for files
+# (default) PROJECT_ROOT = . (this directory)
+#
+################################################################################
+# PROJECT_ROOT = .
+
+################################################################################
+# PROJECT SPECIFIC CHECKS
+# This is a project defined section to create internal makefile flags to
+# conditionally enable or disable the addition of various features within
+# this makefile. For instance, if you want to make changes based on whether
+# GTK is installed, one might test that here and create a variable to check.
+################################################################################
+# None
+
+################################################################################
+# PROJECT EXTERNAL SOURCE PATHS
+# These are fully qualified paths that are not within the PROJECT_ROOT folder.
+# Like source folders in the PROJECT_ROOT, these paths are subject to
+# exlclusion via the PROJECT_EXLCUSIONS list.
+#
+# (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank)
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_EXTERNAL_SOURCE_PATHS =
+
+################################################################################
+# PROJECT EXCLUSIONS
+# These makefiles assume that all folders in your current project directory
+# and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations
+# to look for source code. The any folders or files that match any of the
+# items in the PROJECT_EXCLUSIONS list below will be ignored.
+#
+# Each item in the PROJECT_EXCLUSIONS list will be treated as a complete
+# string unless teh user adds a wildcard (%) operator to match subdirectories.
+# GNU make only allows one wildcard for matching. The second wildcard (%) is
+# treated literally.
+#
+# (default) PROJECT_EXCLUSIONS = (blank)
+#
+# Will automatically exclude the following:
+#
+# $(PROJECT_ROOT)/bin%
+# $(PROJECT_ROOT)/obj%
+# $(PROJECT_ROOT)/%.xcodeproj
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_EXCLUSIONS =
+
+################################################################################
+# PROJECT LINKER FLAGS
+# These flags will be sent to the linker when compiling the executable.
+#
+# (default) PROJECT_LDFLAGS = -Wl,-rpath=./libs
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+
+# Currently, shared libraries that are needed are copied to the
+# $(PROJECT_ROOT)/bin/libs directory. The following LDFLAGS tell the linker to
+# add a runtime path to search for those shared libraries, since they aren't
+# incorporated directly into the final executable application binary.
+# TODO: should this be a default setting?
+# PROJECT_LDFLAGS=-Wl,-rpath=./libs
+
+################################################################################
+# PROJECT DEFINES
+# Create a space-delimited list of DEFINES. The list will be converted into
+# CFLAGS with the "-D" flag later in the makefile.
+#
+# (default) PROJECT_DEFINES = (blank)
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_DEFINES =
+
+################################################################################
+# PROJECT CFLAGS
+# This is a list of fully qualified CFLAGS required when compiling for this
+# project. These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS
+# defined in your platform specific core configuration files. These flags are
+# presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below.
+#
+# (default) PROJECT_CFLAGS = (blank)
+#
+# Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in
+# your platform specific configuration file will be applied by default and
+# further flags here may not be needed.
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_CFLAGS =
+
+################################################################################
+# PROJECT OPTIMIZATION CFLAGS
+# These are lists of CFLAGS that are target-specific. While any flags could
+# be conditionally added, they are usually limited to optimization flags.
+# These flags are added BEFORE the PROJECT_CFLAGS.
+#
+# PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets.
+#
+# (default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank)
+#
+# PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets.
+#
+# (default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank)
+#
+# Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the
+# PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration
+# file will be applied by default and further optimization flags here may not
+# be needed.
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_OPTIMIZATION_CFLAGS_RELEASE =
+# PROJECT_OPTIMIZATION_CFLAGS_DEBUG =
+
+################################################################################
+# PROJECT COMPILERS
+# Custom compilers can be set for CC and CXX
+# (default) PROJECT_CXX = (blank)
+# (default) PROJECT_CC = (blank)
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_CXX =
+# PROJECT_CC =
diff --git a/MusicVisualizer/openFrameworks-Info.plist b/MusicVisualizer/openFrameworks-Info.plist
new file mode 100644
index 0000000..8d64d2b
--- /dev/null
+++ b/MusicVisualizer/openFrameworks-Info.plist
@@ -0,0 +1,22 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ English
+ CFBundleExecutable
+ ${EXECUTABLE_NAME}
+ CFBundleIdentifier
+ cc.openFrameworks.ofapp
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundlePackageType
+ APPL
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1.0
+ CFBundleIconFile
+ ${ICON}
+
+
diff --git a/MusicVisualizer/src/main.cpp b/MusicVisualizer/src/main.cpp
new file mode 100644
index 0000000..9bcdc62
--- /dev/null
+++ b/MusicVisualizer/src/main.cpp
@@ -0,0 +1,13 @@
+#include "ofMain.h"
+#include "ofApp.h"
+
+//========================================================================
+int main( ){
+ ofSetupOpenGL(1500,750,OF_WINDOW); // <-------- setup the GL context
+
+ // this kicks off the running of my app
+ // can be OF_WINDOW or OF_FULLSCREEN
+ // pass in width and height too:
+ ofRunApp(new ofApp());
+
+}
diff --git a/MusicVisualizer/src/ofApp.cpp b/MusicVisualizer/src/ofApp.cpp
new file mode 100644
index 0000000..11836fa
--- /dev/null
+++ b/MusicVisualizer/src/ofApp.cpp
@@ -0,0 +1,511 @@
+#include "ofApp.h"
+#include
+
+//--------------------------------------------------------------
+void ofApp::setup(){
+ ofSetDataPathRoot("../Resources/data/");
+ filePicked = chooseFile();
+ beat.play();
+ beat.setLoop(true);
+ time.load("Raleway-Regular.ttf", 12);
+ settings.load("Raleway-Regular.ttf", 12);
+
+ fftSmooth = new float [BANDS];
+ for (int i = 0; i < BANDS; i++) {
+ fftSmooth[i] = 0;
+ }
+
+ //set random positions and movements
+ for (int i = 0; i < BANDS; i++) {
+ xValues.push_back(rand() % ofGetWidth());
+ int tempHeight = rand() % ofGetHeight();
+ if (tempHeight < OVERLAP) {
+ tempHeight += OVERLAP;
+ }
+ yValues.push_back(tempHeight);
+ movePattern.push_back(rand() % DIRECTIONS);
+ }
+ duration = beat.length / beat.internalFreq;
+
+ logo.load("pb_logo.png");
+ bg.load("backgrounds/castle.jpg");
+
+ //create post processing effects
+ post.init(ofGetWidth(), ofGetHeight());
+ post.createPass();
+
+ zoomPost.init(ofGetWidth(), ofGetHeight());
+ zoomPost.createPass();
+}
+
+//--------------------------------------------------------------
+void ofApp::update(){
+ //DERIVED FROM soundPlayerFFTExample within of/examples/sound/
+ ofSoundUpdate();
+
+ //update frequency values with smoothing factor
+ float * value = ofSoundGetSpectrum(BANDS);
+ for (int i = 0; i < BANDS; i++) {
+ fftSmooth[i] *= smoothing;
+ if (fftSmooth[i] < value[i]) {
+ fftSmooth[i] = value[i];
+ }
+ }
+}
+
+//--------------------------------------------------------------
+void ofApp::draw(){
+ ofBackground(backgroundColor);
+
+ ofSetColor(MAX_COLOR);
+
+
+ if (fftSmooth[BASS_FFT] * (smoothMultiplier) > 75) {
+ zoomPost.begin();
+ } else {
+ post.begin();
+ }
+
+ if (pianoSong) {
+ drawCircles(MAX_COLOR / pianoMult);
+ } else {
+ drawCircles(MAX_COLOR);
+ }
+
+ if (fftSmooth[BASS_FFT] * (smoothMultiplier) > 75) {
+ zoomPost.end();
+ } else {
+ post.end();
+ }
+
+ //non-rainbow preset, show transparent background
+ if (!rainbowSpec) {
+ ofSetColor(MAX_COLOR, MAX_COLOR, MAX_COLOR, 2 * MAX_COLOR / 3);
+ bg.draw(0, 0, ofGetWidth(), ofGetHeight());
+ }
+
+ ofSetColor(MAX_COLOR);
+
+ if (showGui) {
+ gui.draw();
+ }
+
+ if (showHist) {
+ updateHistory();
+ }
+
+ drawRects();
+
+ if (showLogo) {
+ if (swapColors) {
+ //automatically switch base colors with time delay
+ if (fftSmooth[BASS_FFT] * (smoothMultiplier) > 50 && colorSwitchGap > 25) {
+ colorTint = rand() % 255;
+ colorSwitchGap = 0;
+ }
+ colorSwitchGap++;
+ }
+
+ ofSetColor(MAX_COLOR);
+
+ logo.setAnchorPoint(logo.getWidth() / 4, logo.getHeight() / 4);
+ logo.draw((ofGetWidth() - fftSmooth[BASS_FFT] * smoothMultiplier) / 2, (ofGetHeight() - fftSmooth[BASS_FFT] * smoothMultiplier) / 2 + (TOP_PANEL_HEIGHT), (logo.getWidth() / 2) + fftSmooth[BASS_FFT] * smoothMultiplier, (logo.getHeight() / 2) + fftSmooth[BASS_FFT] * (smoothMultiplier));
+ }
+ drawUI();
+}
+
+//--------------------------------------------------------------
+void ofApp::keyPressed(int key){
+ switch (key){
+ case ' ':
+ //play/stop song
+ if(beat.isPlaying()){
+ beat.stop();
+ } else {
+ beat.play();
+ }
+ break;
+ case OF_KEY_RIGHT:
+ //fast forward song by ten seconds
+ beat.setPositionMS( beat.getPositionMS() + TIMESHIFT);
+ break;
+ case OF_KEY_LEFT:
+ //rewind song by ten seconds
+ beat.setPositionMS( beat.getPositionMS() - TIMESHIFT);
+ break;
+ case 's':
+ //toggle GUI
+ showGui = !showGui;
+ break;
+ case 'h':
+ //toggle history graph
+ showHist = !showHist;
+ break;
+ case 'n':
+ //choose new song
+ beat.stop();
+ filePicked = chooseFile();
+ beat.play();
+ beat.setLoop(true);
+ break;
+ case 'p':
+ //toggle piano preset
+ pianoSong = !pianoSong;
+ break;
+ case 'g':
+ //toggle guide text
+ showGuide = !showGuide;
+ break;
+ case 'l':
+ //toggle logo display
+ showLogo = !showLogo;
+ break;
+ case 'b':
+ //choose new background
+ beat.stop();
+ bgPicked = chooseBG();
+ beat.play();
+ beat.setLoop(true);
+ break;
+ case '1':
+ //manually change base colors
+ colorTint = rand() % (MAX_COLOR / 4);
+ break;
+ case '2':
+ colorTint = (rand() % (MAX_COLOR / 4)) + (MAX_COLOR / 4);
+ break;
+ case '3':
+ colorTint = (rand() % (MAX_COLOR / 4)) + (MAX_COLOR / 2);
+ break;
+ case '4':
+ colorTint = (rand() % (MAX_COLOR / 4)) + ((3 * MAX_COLOR) / 4);
+ break;
+ case 'r':
+ //toggle rainbow preset
+ rainbowSpec = !rainbowSpec;
+ break;
+
+ }
+}
+
+//--------------------------------------------------------------
+float ofApp::setXY(int i) {
+ float xPos;
+ float yPos;
+ float radius = (fftSmooth[i] * (smoothMultiplier / 16)) * log(i + 0.1) + MIN_SIZE;
+
+ float beatMult = beatSpeed;
+
+ //increase speed of larger particles
+ if (radius > fastThreshold) {
+ beatMult = beatSpeed * 4;
+ } else if (radius > fastThreshold / 2) {
+ beatMult = beatSpeed * 2;
+ }
+
+ switch (movePattern[i]) {
+ case 0:
+ xPos = (xValues[i] - beatMult);
+ yPos = (yValues[i] - beatMult);
+ break;
+ case 1:
+ xPos = (xValues[i] - beatMult);
+ yPos = (yValues[i]);
+ break;
+ case 2:
+ xPos = (xValues[i] - beatMult);
+ yPos = (yValues[i] + beatMult);
+ break;
+ case 3:
+ xPos = (xValues[i]);
+ yPos = (yValues[i] + beatMult);
+ break;
+ case 4:
+ xPos = (xValues[i] + beatMult);
+ yPos = (yValues[i] + beatMult);
+ break;
+ case 5:
+ xPos = (xValues[i] + beatMult);
+ yPos = (yValues[i]);
+ break;
+ case 6:
+ xPos = (xValues[i] + beatMult);
+ yPos = (yValues[i] - beatMult);
+ break;
+ default:
+ xPos = (xValues[i]);
+ yPos = (yValues[i] - beatMult);
+ break;
+ }
+
+ //move particle to other side of screen if off-screen
+ if (xPos < 0) {
+ xPos+=ofGetWidth();
+ }
+ if (yPos < 0) {
+ yPos+=ofGetHeight();
+ }
+ if (xPos > ofGetWidth()) {
+ xPos-=ofGetWidth();
+ }
+ if (yPos > ofGetHeight()) {
+ yPos-=ofGetHeight();
+ }
+
+ xValues[i] = xPos;
+ yValues[i] = yPos;
+
+ return radius;
+}
+
+//--------------------------------------------------------------
+void ofApp::drawCircles(int count) {
+ for (int i = 0; i < count; i++) {
+ ofColor currentColor;
+
+ //color based on rainbow and piano presets
+ if (rainbowSpec && pianoSong) {
+ currentColor.setHsb(i * pianoMult, (fftSmooth[i] * 500 + 1) / 1.2, (fftSmooth[i] * 500 + 1) / 1.2);
+ } else if (rainbowSpec) {
+ currentColor.setHsb(i, (fftSmooth[i] * 500 + 1) / 1.2, (fftSmooth[i] * 500 + 1) / 1.2);
+ } else {
+ currentColor.setHsb(colorTint, colorTint, (MAX_COLOR / 2) + ((fftSmooth[i] * 500 + 1) / 1.2));
+ }
+
+ float radius = setXY(i);
+
+ ofSetColor(currentColor, MAX_COLOR);
+
+ if (radius > minShow) {
+ ofSetCircleResolution(circleRes);
+ ofDrawCircle(xValues[i], yValues[i], radius);
+ }
+ }
+}
+
+//--------------------------------------------------------------
+void ofApp::drawRects() {
+ int whiteCount = 0;
+ if (pianoSong) {
+ for (int i = 0; i < MAX_COLOR / pianoMult; i++) {
+ ofColor currentColor;
+
+ if (rainbowSpec) {
+ currentColor.setHsb(i * pianoMult, MAX_COLOR, MAX_COLOR);
+ } else {
+ currentColor.setHsb(colorTint, colorTint, (MAX_COLOR / 2) + whiteCount * pianoMult);
+ }
+ ofSetColor(currentColor);
+
+ float height = (fftSmooth[i] * smoothMultiplier) * log(i + 1) + MIN_SIZE;
+ if (i < 2) {
+ height = (fftSmooth[i] * smoothMultiplier) + MIN_SIZE;
+ }
+ if (!rainbowSpec && height > minShow * 10) {
+ //color rainbow if height large enough
+ currentColor.setHsb(i * pianoMult, MAX_COLOR, (MAX_COLOR / 2) + whiteCount * pianoMult);
+ ofSetColor(currentColor);
+ }
+
+ float width = 9;
+
+ ofDrawRectRounded(i * 2 * width, 25, width, height, 4);
+
+ whiteCount++;
+ }
+ } else {
+ for (int i = 0; i < MAX_COLOR; i++) {
+ ofColor currentColor;
+
+ if (rainbowSpec) {
+ currentColor.setHsb(i, MAX_COLOR, MAX_COLOR);
+ } else {
+ currentColor.setHsb(colorTint, colorTint, (MAX_COLOR / 2) + whiteCount);
+ }
+ ofSetColor(currentColor);
+ //display every second frequency
+ if (i % 2 == 0) {
+ float height = (fftSmooth[i] * smoothMultiplier) * log(i + 1) + MIN_SIZE;
+ if (i < 2) {
+ height = (fftSmooth[i] * smoothMultiplier) + MIN_SIZE;
+ }
+ float width = 8;
+
+ if (!rainbowSpec && height > minShow * 10) {
+ //color rainbow if height large enough
+ currentColor.setHsb(i, MAX_COLOR, (MAX_COLOR / 2) + whiteCount);
+ ofSetColor(currentColor);
+ }
+
+ ofDrawRectRounded((i / 1.4) * width, 25, width, height, 4);
+
+ whiteCount++;
+ }
+ }
+ }
+}
+
+//--------------------------------------------------------------
+void ofApp::makeGui() {
+ if (firstTime) {
+ gui.setup("panel");
+ }
+ gui.setPosition(ofPoint(ofGetWidth() - 300, 150));
+
+ colors.setName("Color Settings");
+ colors.add(backgroundColor.set("Background Color", 25, 0, MAX_COLOR));
+ colors.add(lineColor.set("Line Color", 100, 0, MAX_COLOR));
+ colors.add(timeColor.set("Time Color", 200, 0, MAX_COLOR));
+ colors.add(topColor.set("Panel Color", 50, 0, MAX_COLOR));
+ colors.add(colorTint.set("Color Tint", 20, 0, MAX_COLOR));
+ colors.add(swapColors.set("Light Show", false));
+
+ visuals.setName("Visualization Settings");
+ visuals.add(smoothing.set("Smoothing", 0.9, 0.01, 0.99));
+ visuals.add(smoothMultiplier.set("Smooth Multiplier", 120, 1, 999));
+ visuals.add(beatSpeed.set("Beat Speed", 0.5, 0, 10));
+ visuals.add(fastThreshold.set("Fast Threshold", 20, 1, 50));
+ visuals.add(minShow.set("Minimum Circle Radius", 12, 1, 200));
+
+ uiPanel.setName("UI Settings");
+ uiPanel.add(showHist.set("Show History 'H'", false));
+ uiPanel.add(pianoSong.set("Piano Preset 'P'", false));
+ uiPanel.add(showGuide.set("Show Guide 'G'", true));
+ uiPanel.add(showLogo.set("Show Logo 'L'", true));
+ uiPanel.add(rainbowSpec.set("Rainbow Spectrum 'R'", false));
+
+ if (firstTime) {
+ //only draw gui groups once
+ firstTime = false;
+ gui.add(colors);
+ gui.add(visuals);
+ gui.add(uiPanel);
+ }
+}
+
+//--------------------------------------------------------------
+void ofApp::makeHistory() {
+ ofEnableSmoothing();
+ ofEnableAlphaBlending();
+ ofSetVerticalSync(true);
+ ofSetFrameRate(60);
+
+ for (int i = 0; i < totalPlots; i++) {
+ int numSamples = 600;
+ ofxHistoryPlot* plot = new ofxHistoryPlot( NULL, "", numSamples, false);
+ plot->setRange(0, 3);
+ plot->setShowNumericalInfo(false); //don't show text
+ plot->setLineWidth(3);
+ plot->setBackgroundColor(ofColor(backgroundColor, 0)); //transparent background
+ plot->setDrawGrid(false);
+ plots.push_back(plot);
+ }
+}
+
+//--------------------------------------------------------------
+void ofApp::updateHistory() {
+ int plotPoint = 20;
+ int plotMult = 1;
+ for (ofxHistoryPlot* plot : plots) {
+ plot->update(fftSmooth[plotPoint * plotMult]);
+ ofColor col;
+ col.setHsb(plotPoint * plotMult, MAX_COLOR, MAX_COLOR);
+ plot->setColor(col);
+ plot->draw(0, ofGetHeight() - 250, ofGetWidth(), 240);
+ plotMult++;
+ }
+}
+
+//--------------------------------------------------------------
+void ofApp::resetup() {
+ time.load("Raleway-Regular.ttf", 12);
+ settings.load("Raleway-Regular.ttf", 12);
+
+ fftSmooth = new float [BANDS];
+ for (int i = 0; i < BANDS; i++) {
+ fftSmooth[i] = 0;
+ }
+
+ ofBackground(backgroundColor);
+
+ for (int i = 0; i < BANDS; i++) {
+ xValues.push_back(rand() % ofGetWidth());
+ int tempHeight = rand() % ofGetHeight();
+ if (tempHeight < OVERLAP) {
+ tempHeight += OVERLAP;
+ }
+ yValues.push_back(tempHeight);
+ movePattern.push_back(rand() % DIRECTIONS);
+ }
+ duration = beat.length / beat.internalFreq;
+
+ makeGui();
+
+ plots.clear(); //remove previous graphs
+ makeHistory();
+}
+
+//--------------------------------------------------------------
+bool ofApp::chooseFile() {
+ //Open the Open File Dialog
+ ofFileDialogResult openFileResult= ofSystemLoadDialog("Select a new audio file");
+
+ //Check if the user opened a file
+ if (openFileResult.bSuccess){
+ ofFile file(openFileResult.getPath());
+ if (ofToUpper(file.getExtension()) == "MP3" || ofToUpper(file.getExtension()) == "WAV") {
+ beat.load(openFileResult.getPath());
+ resetup();
+ return true;
+ }
+ }
+ return false;
+}
+
+//--------------------------------------------------------------
+bool ofApp::chooseBG() {
+ //Open the Open File Dialog
+ ofFileDialogResult openFileResult= ofSystemLoadDialog("Select a new background file");
+
+ //Check if the user opened a file
+ if (openFileResult.bSuccess){
+ ofFile file(openFileResult.getPath());
+ if (ofToUpper(file.getExtension()) == "PNG" || ofToUpper(file.getExtension()) == "JPG") {
+ bg.load(openFileResult.getPath());
+ resetup();
+ return true;
+ }
+ }
+ return false;
+}
+
+//--------------------------------------------------------------
+void ofApp::drawUI() {
+ ofSetColor(topColor);
+ ofDrawRectangle(0, 0, ofGetWidth(), TOP_PANEL_HEIGHT);
+
+ ofSetColor(MAX_COLOR);
+
+ std::string timeStr = ofToString(beat.getPositionMS() / SECOND / MINUTE); //minutes
+ if ((beat.getPositionMS() / SECOND) % MINUTE < 10) {
+ timeStr += ":0" + ofToString((beat.getPositionMS() / SECOND) % MINUTE); //seconds if less than ten
+ } else {
+ timeStr += ":" + ofToString((beat.getPositionMS() / SECOND) % MINUTE); //seconds
+ }
+ time.drawString(timeStr, WORD_WIDTH - 5, WORD_HEIGHT);
+
+ if (showGuide) {
+ settings.drawString("settings = 's'", ofGetWidth() - WORD_WIDTH + 5, WORD_HEIGHT);
+ settings.drawString("new song = 'n'", 5, WORD_HEIGHT);
+ }
+
+ //static timeline length
+ ofSetLineWidth(10);
+ ofSetColor(lineColor);
+ ofDrawLine(TOP_PANEL_WIDTH + 5, 12, ofGetWidth() - TOP_PANEL_WIDTH, 12);
+
+ //movement based on time duration
+ ofSetColor(timeColor);
+ msecondGain = (ofGetWidth() - (TOP_PANEL_WIDTH * 2)) / (duration * SECOND);
+ ofDrawCircle(TOP_PANEL_WIDTH + msecondGain * beat.getPositionMS(), WORD_HEIGHT - 5, MIN_SIZE - 1 + fftSmooth[BASS_FFT] * 10);
+}
diff --git a/MusicVisualizer/src/ofApp.h b/MusicVisualizer/src/ofApp.h
new file mode 100644
index 0000000..f32bff0
--- /dev/null
+++ b/MusicVisualizer/src/ofApp.h
@@ -0,0 +1,102 @@
+#pragma once
+
+#include "ofMain.h"
+#include "ofxGui.h"
+#include "ofxHistoryPlot.h"
+#include "ofxPostProcessing.h"
+#include
+
+class ofApp : public ofBaseApp{
+
+public:
+ void setup();
+ void update();
+ void draw();
+
+ void keyPressed(int key);
+ float setXY(int i);
+ void drawCircles(int count);
+ void drawRects();
+ void makeGui();
+ void makeHistory();
+ void updateHistory();
+ void resetup();
+ bool chooseFile();
+ bool chooseBG();
+ void drawUI();
+
+ ofFmodSoundPlayer beat;
+ ofTrueTypeFont time;
+ ofTrueTypeFont settings;
+
+ std::vector plots;
+ int totalPlots = 6;
+
+ ofxPanel gui;
+
+ ofParameterGroup colors;
+ ofParameter backgroundColor;
+ ofParameter lineColor;
+ ofParameter timeColor;
+ ofParameter topColor;
+ ofParameter colorTint;
+ ofParameter swapColors;
+
+ ofParameterGroup visuals;
+ ofParameter smoothing;
+ ofParameter smoothMultiplier;
+ ofParameter beatSpeed;
+ ofParameter fastThreshold;
+ ofParameter minShow;
+
+ ofParameterGroup uiPanel;
+ ofParameter showHist;
+ ofParameter pianoSong;
+ ofParameter showGuide;
+ ofParameter showLogo;
+ ofParameter rainbowSpec;
+
+ float duration;
+ float* fftSmooth;
+ float msecondGain;
+
+ const int OVERLAP = 50;
+ const int BANDS = 1530;
+ const int DIRECTIONS = 8;
+ const int MAX_COLOR = 255;
+ const int MIN_SIZE = 5;
+
+ const int TOP_PANEL_HEIGHT = 25;
+ const int TOP_PANEL_WIDTH = 150;
+ const int WORD_WIDTH = 120;
+ const int WORD_HEIGHT = 17;
+
+ const int SECOND = 1000;
+ const int MINUTE = 60;
+ const int TIMESHIFT = 10000;
+
+ const int BASS_FFT = 10;
+
+ std::vector xValues;
+ std::vector yValues;
+ std::vector movePattern;
+ std::string fileName;
+
+ bool showGui = false;
+
+ float pianoMult = 3;
+
+ bool filePicked = false;
+ bool bgPicked = false;
+
+ int colorSwitchGap = 0;
+
+ ofImage logo;
+ ofImage bg;
+
+ int circleRes = 100;
+ bool firstTime = true;
+
+ ofxPostProcessing post;
+ ofxPostProcessing zoomPost;
+};
diff --git a/README.md b/README.md
index 0516b2d..03c6541 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,25 @@
-# OpenMusicVis
-OpenMusicVis - Customizable Music Visualizer built with OpenFrameworks
+# CS 126 Final Project: Music Visualizer
+
+This is a customizable music visualizer built with [openFrameworks](http://openframeworks.cc/). This visualizer takes any mp3/wav file as input and displays a real-time audio spectrum and particle system. It also takes any png/jpg file as image input for the background display.
+
+## Getting Started
+
+### Prerequisites
+
+You will need to download the latest [openFrameworks](http://openframeworks.cc/download/) library. This Music Visualizer uses the [ofxHistoryPlot](https://github.com/armadillu/ofxHistoryPlot) addon to display past data on audio frequencies as well as the [ofxPostProcessing](https://github.com/neilmendoza/ofxPostProcessing) addon for particle effects, so you will need to clone both repositories and add them to the `addons/` folder within your openFrameworks directory.
+
+### Installing
+
+Import the project using the Project Generator located within the `projectGenerator-osx` folder. Ensure the **ofxGui**, **ofxHistoryPlot**, and **ofxPostProcessing** addons are selected under the addons dropdown. Follow the setup guides within [here](http://openframeworks.cc/download/) to build and run with your favorite IDE.
+
+### Usage
+
+The program will prompt you with the system file directory. You can load a mp3/wav file from anywhere on your computer. The program comes with two presets, which can be toggled with the **p** key. The first preset is intended for solo instrument performances, such as piano and guitar songs. The second preset is for all other song types. Both presets are customizable with the **s** key, which contains the settings panel.
+
+Press the spacebar to stop and start the current song. Use the right and left arrow keys to fast forward and rewind the audio file by 10 seconds.
+
+To select a new song, press the **n** key. To change the background image, press the **b** key.
+
+Many of the elements in the display can be toggled to fit personal preferences. Press the **h** key to toggle the history plot display. Press the **g** key to toggle the guide messages at the top of the screen. Press the **l** key to toggle the image display at the center.
+
+The tint of the bars can be modified in the settings panel, but can also be changed randomly using the "Light Show" tickbox and the keyboard hotkeys 1-4.