summaryrefslogtreecommitdiff
path: root/gistanalysis/src
diff options
context:
space:
mode:
authorTim Redfern <tim@getdrop.com>2018-05-22 00:00:06 +0100
committerTim Redfern <tim@getdrop.com>2018-05-22 00:00:06 +0100
commit459d1daf71dd8991c60dc8c84d1154802eec331b (patch)
tree0a8407a7aad9d4e8fbbd51287bb921f69ae1d073 /gistanalysis/src
parent880f710768391dc3a3399fc1896447a9e6c34fa4 (diff)
OE started
Diffstat (limited to 'gistanalysis/src')
-rw-r--r--gistanalysis/src/main.cpp13
-rw-r--r--gistanalysis/src/ofApp.cpp456
-rw-r--r--gistanalysis/src/ofApp.h132
3 files changed, 601 insertions, 0 deletions
diff --git a/gistanalysis/src/main.cpp b/gistanalysis/src/main.cpp
new file mode 100644
index 0000000..e57370b
--- /dev/null
+++ b/gistanalysis/src/main.cpp
@@ -0,0 +1,13 @@
+#include "ofMain.h"
+#include "ofApp.h"
+
+//========================================================================
+int main( ){
+ ofSetupOpenGL(1024,768,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/gistanalysis/src/ofApp.cpp b/gistanalysis/src/ofApp.cpp
new file mode 100644
index 0000000..b6a0a1c
--- /dev/null
+++ b/gistanalysis/src/ofApp.cpp
@@ -0,0 +1,456 @@
+#include "ofApp.h"
+
+using namespace std;
+
+//--------------------------------------------------------------
+void ofApp::setup(){
+ ofSetCircleResolution(80);
+ ofSetFrameRate(60);
+ ofBackground(255);
+ ofEnableSmoothing();
+ ofEnableAlphaBlending();
+ ofSetVerticalSync(true);
+
+
+ bufferSize = 512;
+ sampleRate = 44100;
+
+
+
+
+ useMic = 1;
+ isPaused = 0;
+
+ player.setLoop(true);
+
+ mfccMax = 0;
+ showMFCC = 0;
+
+ vector<string> features = ofxGist::getFeatureNames();
+
+ int num = features.size();
+
+ for(int v = 0;v<num;v++){
+ GIST_FEATURE f = ofxGist::getFeatureFromName(features[v]);
+ gist.setDetect(f);
+ ofxHistoryPlot * graph = addGraph(features[v],1.0,ofColor(ofRandom(100)+150,ofRandom(100)+150,ofRandom(100)+150));
+ plots.push_back(graph);
+ }
+
+
+ num = 13;//happens to be 13 coefficients by default
+ for(int v = 0;v<num;v++){
+ ofxHistoryPlot * graph = addGraph("mfcc_"+ofToString(v),1.0,ofColor(ofRandom(100)+150,ofRandom(100)+150,ofRandom(100)+150));
+ mfccPlots.push_back(graph);
+ }
+
+
+
+
+
+
+
+ /*
+ //add special crest graph
+ ofxHistoryPlot*crest = addGraph("CREST_AVG",1.0,ofColor(ofRandom(100)+150,ofRandom(100)+150,ofRandom(100)+150));
+ crest->setShowSmoothedCurve(1);
+ */
+
+ //gist.setUseForOnsetDetection(GIST_PEAK_ENERGY);
+
+ //gist.setUseForOnsetDetection(GIST_SPECTRAL_DIFFERENCE);
+ //gist.setThreshold(GIST_SPECTRAL_DIFFERENCE, .2);
+
+ gist.setUseForOnsetDetection(GIST_PEAK_ENERGY);
+ gist.setThreshold(GIST_PEAK_ENERGY, .05);//
+
+ ofAddListener(GistEvent::ON,this,&ofApp::onNoteOn);
+ ofAddListener(GistEvent::OFF,this,&ofApp::onNoteOff);
+
+
+
+ noteOnRadius = 0;
+
+ soundStream.setup(this,0, 1, sampleRate, bufferSize, 1);
+
+ loadSong("passades/1 The Ninth Set-sector1:sector2pt.1.aiff");
+ //loadSong("assets/sounds/Coltrane_acc_VUIMM.wav");
+
+ plotter=Audioplotter(8);
+}
+
+
+void ofApp::onNoteOn(GistEvent &e){
+
+ noteOnRadius = 100;
+};
+
+
+void ofApp::onNoteOff(GistEvent &e){
+
+ //noteOnRadius = 0;
+};
+
+
+//--------------------------------------------------------------
+void ofApp::update(){
+
+
+
+ if(isPaused){
+ return;
+ }
+ if(!useMic){
+ if(player.isLoaded()){
+ vector<float> output = player.getCurrentBuffer(bufferSize);
+ processAudio(&output[0], bufferSize, 2);
+ fftSmoothed = player.getFFT();
+
+ plotter.addpoints(centre,256);
+ }
+ }
+
+
+
+ int num = ofxGist::getFeatureNames().size();
+
+ for(int v = 0;v<num;v++){
+ plots[v]->setRange(gist.getMin(v),gist.getMax(v));
+ plots[v]->update(gist.getValue(v));
+ }
+
+
+
+ vector<float>mfcc = gist.getMelFrequencyCepstralCoefficients();
+
+ //vector<float>mfcc = gist.getMelFrequencySpectrum();
+
+ if(mfccSmoothed.size()<mfcc.size()){
+ mfccSmoothed.assign(mfcc.size(),0.0);
+ }
+ float damping = .7;
+ int f = 0;
+ for (int i = 0; i < mfcc.size(); i++){
+ // take the max, either the smoothed or the incoming:
+ if (mfccSmoothed[f] < mfcc[i] || damping >.999f){
+ mfccSmoothed[f] = mfcc[i];
+ }
+ // let the smoothed value sink to zero:
+ mfccSmoothed[i] *= damping;
+ f++;
+
+ if(mfccMax<mfcc[i]){
+ mfccMax = mfcc[i];
+ }
+
+
+ mfccPlots[i]->setRange(gist.getMFCCMin(i),gist.getMFCCMax(i));
+
+ mfccPlots[i]->update(mfcc[i]);
+ }
+
+
+
+
+ /*
+ //crest avg
+ plots.back()->setRange(gist.getMin(GIST_SPECTRAL_CREST),gist.getMax(GIST_SPECTRAL_CREST));
+ plots.back()->update(gist.getAvg(GIST_SPECTRAL_CREST));
+*/
+
+
+ if(noteOnRadius>0){
+ noteOnRadius--;
+ }
+}
+
+//--------------------------------------------------------------
+void ofApp::draw(){
+ ofBackground(0);
+
+
+ ofFill();
+
+
+ // draw the left:
+ //ofSetHexColor(0x333333);
+ int waveHeight = ofGetHeight();
+
+ //ofRect(0,0,256,waveHeight);
+ float barW = ofGetWidth()/(float)fftSmoothed.size();
+ float currX = 0;
+
+ ofSetColor(255,255,255,100);
+
+ for (int i = 0; i < fftSmoothed.size(); i++){
+ ofRect(currX,waveHeight,barW,-fftSmoothed[i]*waveHeight);
+ currX+=barW;
+ }
+
+ currX = 0;
+ waveHeight = ofGetHeight();
+ barW = ofGetWidth()/(float)mfccSmoothed.size();
+ ofSetColor(255,100,100,200);
+ for (int i = 0; i < mfccSmoothed.size() && showMFCC; i++){
+
+ ofRect(currX,ofGetHeight(),barW,- ofMap(mfccSmoothed[i], 0.0,mfccMax, 0.0,1.0,true )*waveHeight);
+ currX+=barW;
+ }
+
+ ofNoFill();
+
+ ofSetColor(0,255,100,255);
+ for (int i = 0; i < left.size(); i++){
+ //ofLine(i,300+left[i]*waveHeight,i,300+left[i]*waveHeight+1);
+ }
+ ofSetColor(000,100,255,255);
+ for (int i = 0; i < right.size(); i++){
+ //ofLine(i,500+right[i]*waveHeight,i,500+right[i]*waveHeight+1);
+ }
+
+/*
+ int num;
+ int margin = 5;
+ if(showMFCC){
+ num = mfccPlots.size();
+ int plotHeight = (ofGetHeight()-margin*num)/(float)num;
+
+ for(int v = 0;v<num;v++){
+ mfccPlots[v]->draw(margin,margin+plotHeight*v, ofGetWidth()-20, 100);
+ }
+ }else{
+
+
+ num = plots.size();
+
+ int plotHeight = (ofGetHeight()-margin*num)/(float)num;
+
+ for(int v = 0;v<num;v++){
+ plots[v]->draw(margin,margin+plotHeight*v, ofGetWidth()-20, 100);
+ }
+
+ }
+ */
+
+ ofFill();
+
+ ofSetColor(255,0,0,200);
+ ofCircle(ofGetWidth()/2,ofGetHeight()/2,noteOnRadius);
+
+ /*
+ if(!showMFCC){
+
+
+ ofSetColor(0,0,0,250);
+ ofRect(5,5,600,180);
+ stringstream str;
+ if(plots.size() ){
+ for(int v = 0;v<num;v++){
+ str<<plots[v]->getVariableName()<<" | min: "<<gist.getMin(v)<<" | avg: "<<gist.getAvg(v)<<" | max: "<<gist.getMax(v)<<"\n";
+
+ }
+
+ str<<"Note freq: "<< gist.getNoteFrequency()<<" "<<gist.getNoteName() <<"\n";
+ }else{
+ str<<"Drag and drop wave files from data folder.";
+ }
+
+ ofSetColor(255);
+
+ ofDrawBitmapString(str.str(),10,10);
+ }
+
+ */
+
+ auto lines=plotter.output();
+ laser.draw(lines,50);
+
+ ofTranslate(0,ofGetHeight()/2);
+
+ for (auto line=lines.begin();line!=lines.end();line++){
+ line->draw();
+ }
+
+}
+
+
+
+ofxHistoryPlot* ofApp::addGraph(string varName,float max,ofColor color){
+
+ ofxHistoryPlot* graph = new ofxHistoryPlot(NULL, varName, max, false); //true for autoupdate
+ //graph2->setLowerRange(0); //set only the lowest part of the range upper is adaptative to curve
+ graph->setAutoRangeShrinksBack(true); //graph2 scale can shrink back after growing if graph2 curves requires it
+ graph->setRange(0,max);
+ graph->setColor(color);
+ graph->setShowNumericalInfo(true);
+ graph->setRespectBorders(true);
+ graph->setLineWidth(2);
+
+
+ graph->setDrawBackground(false);
+
+ graph->setDrawGrid(true);
+ graph->setGridColor(ofColor(30)); //grid lines color
+ graph->setGridUnit(14);
+ graph->setShowSmoothedCurve(0); //graph2 a smoothed version of the values, but alos the original in lesser alpha
+ graph->setSmoothFilter(0.1); //smooth filter strength
+
+ graph->setMaxHistory(2000);
+
+
+
+ return graph;
+
+};
+
+
+void ofApp::clear(){
+
+
+}
+
+
+void ofApp::loadSong(string str){
+
+ cout<<"loadSong "<<str<<endl;
+
+ player.stop();
+ player.loadSound(str);
+ player.setLoop(true);
+ player.play();
+ useMic = 0;
+ mfccMax = 0;
+ gist.clearHistory();
+}
+
+void ofApp::processAudio(float * input, int bufferSize, int nChannels){
+ //convert float array to vector
+
+
+
+ if (nChannels==2){
+
+
+ float max=0;
+
+ left.resize(bufferSize/nChannels);
+ right.resize(bufferSize/nChannels);
+ centre.resize(bufferSize/nChannels);
+
+ for (int i = 0; i < bufferSize/nChannels; i++){
+ left[i] = input[i*nChannels];
+ right[i] = input[i*nChannels+1];
+ centre[i] = (left[i]+right[i])*0.5;
+ if (centre[i]>max){
+ max=centre[i];
+ }
+ }
+
+ //ofLog()<<"audio data max "<<max;
+ //float audio data is +- 0.5
+
+
+ }
+ //else ofLog()<<nChannels<<" channels";
+
+
+ vector<float>buffer;
+ buffer.assign(&input[0],&input[bufferSize]);
+
+ gist.processAudio(buffer, bufferSize, nChannels,sampleRate);
+}
+
+
+void ofApp::audioIn(float * input, int bufferSize, int nChannels){
+ if(!useMic){
+ return;
+ }
+
+ processAudio(input, bufferSize, nChannels);
+
+}
+
+
+
+
+//--------------------------------------------------------------
+void ofApp::keyPressed(int key){
+ if(key =='f'){
+ ofToggleFullscreen();
+ }
+
+ if(key =='m'){
+ useMic = !useMic;
+
+ if(!useMic){
+ player.play();
+ }else{
+ player.stop();
+ }
+
+
+ gist.clearHistory();
+ }
+
+ if(key ==' '){
+ isPaused = !isPaused;
+ player.setPaused(isPaused);
+ }
+
+ if(key =='r'){
+ gist.clearHistory();
+ }
+
+
+ if(key =='c'){
+ showMFCC = !showMFCC;
+ }
+}
+
+//--------------------------------------------------------------
+void ofApp::keyReleased(int key){
+
+}
+
+//--------------------------------------------------------------
+void ofApp::mouseMoved(int x, int y ){
+
+}
+
+//--------------------------------------------------------------
+void ofApp::mouseDragged(int x, int y, int button){
+ if(!useMic){
+ player.setPosition(x/(float)ofGetWidth());
+ }
+
+ float t = x/(float)ofGetWidth();
+ gist.setThreshold(GIST_SPECTRAL_DIFFERENCE,t);
+}
+
+//--------------------------------------------------------------
+void ofApp::mousePressed(int x, int y, int button){
+
+}
+
+//--------------------------------------------------------------
+void ofApp::mouseReleased(int x, int y, int button){
+
+}
+
+//--------------------------------------------------------------
+void ofApp::windowResized(int w, int h){
+
+}
+
+//--------------------------------------------------------------
+void ofApp::gotMessage(ofMessage msg){
+
+}
+
+//--------------------------------------------------------------
+void ofApp::dragEvent(ofDragInfo dragInfo){
+ clear();
+ vector<string> paths = ofSplitString(dragInfo.files[0], "data/");
+ loadSong(paths[1]);
+
+}
diff --git a/gistanalysis/src/ofApp.h b/gistanalysis/src/ofApp.h
new file mode 100644
index 0000000..e3ad339
--- /dev/null
+++ b/gistanalysis/src/ofApp.h
@@ -0,0 +1,132 @@
+#pragma once
+
+#include "ofMain.h"
+#include "ofxHelios.h"
+#include "lineTransformer.h"
+
+//This is included only as a way of getting buffer out of loaded sound.
+//There are many other ways you can do that.
+//This player includes a version of kissFFT. You can remove the one included in Gist.
+//https://github.com/borg/ofxOpenALSoundPlayer
+#include "ofxOpenALSoundPlayer.h"
+
+
+//Slightly modified to add a dynamic getVariable method to be able to plot based on
+//gist feature list
+//https://github.com/local-projects/ofxHistoryPlot
+#include "ofxHistoryPlot.h"
+#include "ofxGist.h"
+
+
+class Audioplotter{
+ //store and draw a numbr of audio samples
+ //how best to handle transforms - maybe pass in a transform to be added to 2nd and subsequent
+ //how best to handle length of history data - fixed number that can be set, or line budget?
+public:
+ Audioplotter(int _size=1,bool _joined=true){
+ set_size(_size);
+ set_joined(_joined);
+ }
+ void set_size(int _size){
+ history_size=_size;
+ }
+ void set_joined(bool _joined){
+ joined=_joined;
+ }
+ const vector <colourPolyline> &output(const ofMatrix4x4 xform=ofMatrix4x4(1.0f,0.0f,0.0f,0.0f,
+ 0.0f,1.0f,0.0f,0.0f,
+ 0.0f,0.0f,1.0f,0.0f,
+ 0.0f,0.0f,0.0f,1.0f)){
+ //destructive or non?
+ float fadefactor=1.0f-(1.0f/history_size);
+
+ for (int i=0;i<data.size();i++){
+ data[i]=lineTransformer::polyLineTransform(xform,data[i],fadefactor);
+ }
+
+ return data;
+ }
+ void addpoints(vector <float> &audio,int number){
+ colourPolyline newdata;
+ int num=min(number,(int)audio.size());
+ int step=audio.size()/num;
+ int start=audio.size()/(num+1);
+ for (int i=0;i<num;i++){
+ newdata.addVertex((start+(i*step)*ofGetWidth())/audio.size(),audio[start+(i*step)]*ofGetHeight());
+ }
+ data.insert(data.begin(),newdata);
+ while (data.size()>history_size) {
+ data.pop_back();
+ }
+
+ }
+private:
+ vector <colourPolyline> data;
+ bool joined;
+ int history_size;
+};
+
+
+class ofApp : public ofBaseApp{
+
+ public:
+ void setup();
+ void update();
+ void draw();
+
+ void keyPressed(int key);
+ void keyReleased(int key);
+ void mouseMoved(int x, int y );
+ void mouseDragged(int x, int y, int button);
+ void mousePressed(int x, int y, int button);
+ void mouseReleased(int x, int y, int button);
+ void windowResized(int w, int h);
+ void dragEvent(ofDragInfo dragInfo);
+ void gotMessage(ofMessage msg);
+
+ ofSoundStream soundStream;
+ ofxOpenALSoundPlayer player;
+ void processAudio(float * input, int bufferSize, int nChannels);
+
+ void audioIn(float * input, int bufferSize, int nChannels);
+
+ vector<float>fftSmoothed;
+ vector <float> left;
+ vector <float> right;
+ vector <float> centre;
+ vector <float> volHistory;
+ vector<float>mfccSmoothed;
+ float mfccMax;
+
+
+ int bufferSize;
+ int sampleRate;
+ bool useMic;
+
+ bool isPaused;
+
+ void clear();
+ void loadSong(string str);
+
+
+ vector<ofxHistoryPlot *>plots;
+ map<string,ofxHistoryPlot *>plotMap;
+
+ ofxHistoryPlot* addGraph(string varName,float max,ofColor color);
+
+
+ ofxGist gist;
+ void onNoteOn(GistEvent &e);
+ void onNoteOff(GistEvent &e);
+
+ int noteOnRadius;
+
+
+ bool showMFCC;
+ vector<ofxHistoryPlot *>mfccPlots;
+
+ ofxHelios laser;
+
+ Audioplotter plotter;
+
+};