summaryrefslogtreecommitdiff
path: root/passadesgui/src/ofApp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'passadesgui/src/ofApp.cpp')
-rw-r--r--passadesgui/src/ofApp.cpp1294
1 files changed, 1294 insertions, 0 deletions
diff --git a/passadesgui/src/ofApp.cpp b/passadesgui/src/ofApp.cpp
new file mode 100644
index 0000000..36e0785
--- /dev/null
+++ b/passadesgui/src/ofApp.cpp
@@ -0,0 +1,1294 @@
+#include "ofApp.h"
+#include "glew.h"
+
+const ofPoint outputWindowSize=ofPoint(1200,900);
+const float guiScale=560.0f/4096.0f;
+
+
+string sourcenames[5]={
+ "TEST",
+// "NDI",
+ "Player",
+ "SVG outlines",
+ "SVG segmenters",
+ "Audio"
+};
+
+//--------------------------------------------------------------
+void ofApp::setup(){
+
+ source=Audio;
+/*
+ //==================================================== ofxNDI
+
+ senderName[0] = 0; // The sender name used for display
+ nSenders = 0; // Total number of NDI senders
+ senderWidth = 0; // Sender width
+ senderHeight = 0; // Sender height
+ bNDIreceiver = false; // Receiver creation
+
+ // Create an intial receiving image
+ ndiImage.allocate(ofGetWidth(), ofGetHeight(), OF_IMAGE_COLOR_ALPHA);
+
+ // For received frame fps calculations - independent of the rendering rate
+ startTime = lastTime = frameTime = 0;
+ fps = frameRate = 1; // starting value
+*/
+
+ //============================= Audio
+
+ plotter.setup(5,true);
+
+ bufferSize = 2048;
+ sampleRate = 44100;
+
+ gist.setUseForOnsetDetection(GIST_PEAK_ENERGY);
+ gist.setThreshold(GIST_PEAK_ENERGY, .05);//
+
+ ofAddListener(GistEvent::ON,this,&ofApp::onNoteOn);
+ ofAddListener(GistEvent::OFF,this,&ofApp::onNoteOff);
+
+ // ofAddListener(ofApp::useMic->Value,this,&ofApp::useMicChanged);
+
+ soundStream.setup(this,0, 1, sampleRate, bufferSize, 1);
+
+ //loadSong("12 Ferric Appetite.aiff");
+ loadSong("passades/1 The Ninth Set-sector1:sector2pt.1.aiff");
+
+ //============================ gui
+
+ lasergui.setup("laser","",230,820);
+ lasergui.add(laser_power.set("power", false));
+ lasergui.add(laser_intensity.set("intensity", 30, 0, 255));
+ lasergui.add(laser_points.set("points", 30000, 0, 40000));
+ lasergui.add(laser_subdivide.set("subdivide", 15, 1, 100));
+ lasergui.add(laser_blank_num.set("blank points", 8, 0, 32));
+ lasergui.add(laser_max_angle.set("max angle", 15.0f, 1.0f, 90.0f));
+
+ responsegui.setup("audio response","",230,970);
+ responsegui.add(onset_threshold.set("onset threshold", 0.05f, 0.0f, 1.0f ));
+ responsegui.add(use_onset.set("trigger onset",false));
+ responsegui.add(onset_duration.set("duration", 10, 1, 100));
+
+ onset_frame=0;
+
+ chaosgui.setup("chaos","",460,820);
+ chaosgui.add(plotter.usechaos.set("use",false));
+ chaosgui.add(plotter.chaosamount.set("amount", 0.0f, -0.1f, 0.1f));
+ chaosgui.add(plotter.chaosscale.set("scale", 100.0f, 1.0f, 1000.0f));
+ chaosgui.add(plotter.chaos_a.set("a", 0.85f, 0.0f, 10.0f));
+ chaosgui.add(plotter.chaos_b.set("b", 0.9f, 0.0f, 10.0f));
+ chaosgui.add(plotter.chaos_k.set("k", 0.4f, 0.0f, 10.0f));
+ chaosgui.add(plotter.chaos_p.set("p", 7.7f, 0.0f, 10.0f));
+
+ drawgui.setup("drawing","",10,0);
+ drawgui.add(contour_threshold.setup("threshold", 140, 0, 255));
+ drawgui.add(contour_simplify.setup("simplify", 0.8, 0.0, 10.0));
+ drawgui.add(contour_useColour.setup("use colour", true));
+ drawgui.add(laser_R.setup("red", 140, 0, 255));
+ drawgui.add(laser_G.setup("green", 140, 0, 255));
+ drawgui.add(laser_B.setup("blue", 140, 0, 255));
+ drawgui.add(video_speed.setup("playback speed", 1.0, 0.0, 3.0));
+ drawgui.add(shapes_randomise.setup("randomise shapes", true));
+ drawgui.add(shapes_amount.setup("shapes amount", 0.2, 0.0, 0.8));
+ drawgui.add(shapes_duration.setup("shape duration", 5, 0, 25));
+ drawgui.add(use_mask.setup("use mask", true));
+ drawgui.add(invert_mask.setup("invert mask", false));
+ drawgui.add(use_segmenter.setup("use segmenter", false));
+ drawgui.add(segmenter_speed.setup("segmenter speed", 0.2, -1.0, 1.0));
+ drawgui.add(segmenter_length.setup("segmenter length", 0.2, 0.0, 1.0));
+ drawgui.add(segmenter_number.setup("segmenter number", 1, 1, 8));
+ drawgui.add(use_rotate.setup("XF rotate", false));
+ drawgui.add(xf_rotate.setup("rotate speed", 0.0, -1.0, 1.0));
+ drawgui.add(use_scale.setup("XF scale", false));
+ drawgui.add(xf_scale_speed.setup("scale speed", 1.0, 0.0, 10.0));
+ drawgui.add(xf_scale_min.setup("scale min", 1.0, 0.0, 3.0));
+ drawgui.add(xf_scale_max.setup("scale max", 2.0, 0.0, 3.0));
+
+ audiogui.setup("audio","",10,450);
+ audiogui.add(useMic.set("mic",false));
+ audiogui.add(useFft.set("fft",false));
+ audiogui.add(scalePlot.set("plotscale", 0.1f, 0.0f, 1.0f )); //parameters are recognised by name only?
+ audiogui.add(decayPlot.set("decay", 0.9f, 0.0f, 1.0f ));
+ audiogui.add(plotter.random.set("random",true));
+ audiogui.add(plotter.joined.set("joined",true));
+ audiogui.add(plotter.bars.set("bars",true));
+ audiogui.add(plotter.mirror.set("mirror",false));
+ audiogui.add(plotter.width.set("point width", 2, 1, 256));
+ audiogui.add(plotter.num_points.set("num points", 50, 1, 64));
+ audiogui.add(plotter.history_size.set("num plots", 5, 1, 64));
+ audiogui.add(plotter.translate.set("translate",ofVec2f(0,0),ofVec2f(-50,-50),ofVec2f(50,50)));
+ audiogui.add(plotter.rotate.set("rotate",0.0f,-10.0f,10.0f));
+ audiogui.add(plotter.scale.set("scale",ofVec2f(1.0f,1.0f),ofVec2f(0.5f,0.5f),ofVec2f(2.0f,2.0f)));
+ audiogui.add(plotter.startColour.set("start",ofColor(255,255,255)));
+ audiogui.add(plotter.endColour.set("end",ofColor(0,0,0)));
+
+ framecounter=0;
+
+ //============================ MIDI
+
+ midiIn.listInPorts();
+ midiIn.openPort(0);
+ midiIn.addListener(this);
+
+ //======================================= //positioning interface
+
+ safety_frame.addVertex(0,0); //etc
+
+ bShowPositionInterface=false;
+ bOutputSelected=false;
+
+ outputOffsetScale=1.0f;
+ commandPressed=false;
+
+
+ select_warpframe=-1;
+ bDrawFrame=false;
+
+ if( XML.loadFile("settings.xml") ){
+ cout << "settings.xml loaded!" <<std::endl;
+
+ }
+ else{
+ cout << "unable to load settings.xml"<<std::endl;
+ }
+
+ warpframe[0]=glm::vec2(
+ XML.getValue("WARP:p0:X", 0),
+ XML.getValue("WARP:p0:Y", 0)
+ );
+ warpframe[1]=glm::vec2(
+ XML.getValue("WARP:p1:X", outputWindowSize.x),
+ XML.getValue("WARP:p1:Y", 0)
+ );
+ warpframe[2]=glm::vec2(
+ XML.getValue("WARP:p2:X", outputWindowSize.x),
+ XML.getValue("WARP:p2:Y", outputWindowSize.y)
+ );
+ warpframe[3]=glm::vec2(
+ XML.getValue("WARP:p3:X", 0),
+ XML.getValue("WARP:p3:Y", outputWindowSize.y)
+ );
+
+ outputPosition=ofPoint(
+ XML.getValue("POSITION:X", 0),
+ XML.getValue("POSITION:Y", 0)
+ );
+
+ outputScale=XML.getValue("SCALE", 1.0f);
+
+}
+
+//====================== audio functions
+
+void ofApp::loadSong(string str){
+
+ cout<<"loadSong "<<str<<endl;
+
+ player.stop();
+ player.loadSound(str);
+ player.setLoop(true);
+ player.play();
+ useMic = 0;
+ gist.clearHistory();
+}
+
+void ofApp::onNoteOn(GistEvent &e){
+ //ofLog() << "<<NOTE ON>>";
+ onset_frame=0;
+ onset_number++;
+ //noteOnRadius = 100;
+};
+
+
+void ofApp::onNoteOff(GistEvent &e){
+ //ofLog() << "<<NOTE OFF>>";
+ //turn off?
+ //noteOnRadius = 0;
+};
+
+void ofApp::processAudio(float * input, int bufferSize, int nChannels){
+ //convert float array to vector
+
+
+ left.resize(bufferSize/nChannels);
+ right.resize(bufferSize/nChannels);
+ centre.resize(bufferSize/nChannels);
+
+ float max=0.0f;
+
+
+ if (nChannels==2){
+
+
+ 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];
+ }
+ }
+
+
+ }
+ else if (nChannels==1){
+ for (int i = 0; i < bufferSize;i++){
+ left[i] = input[i];
+ right[i] = input[i];
+ centre[i] = input[i];
+ if (centre[i]>max){
+ max=centre[i];
+ }
+ }
+ }
+
+ //ofLog()<<"audio data max "<<max;
+ //float audio data is +- 0.5
+
+
+ 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;
+ }
+
+ //ofLog() << "processing "<<bufferSize<<" samples from mic";
+
+ processAudio(input, bufferSize, nChannels);
+
+}
+
+void ofApp::useMicChanged(){
+ if (useMic) {
+ player.stop();
+ }
+ else {
+ player.play();
+ }
+}
+
+//====================== settings
+
+void ofApp::default_settings(){
+ warpframe[0]=glm::vec2(0,0);
+ warpframe[1]=glm::vec2(outputWindowSize.x,0);
+ warpframe[2]=glm::vec2(outputWindowSize.x,outputWindowSize.y);
+ warpframe[3]=glm::vec2(0,outputWindowSize.y);
+ outputPosition=ofPoint(0,0);
+ outputScale=1.0f;
+}
+
+void ofApp::save_settings(){
+ XML.setValue("WARP:p0:X", warpframe[0].x);
+ XML.setValue("WARP:p0:Y", warpframe[0].y);
+ XML.setValue("WARP:p1:X", warpframe[1].x);
+ XML.setValue("WARP:p1:Y", warpframe[1].y);
+ XML.setValue("WARP:p2:X", warpframe[2].x);
+ XML.setValue("WARP:p2:Y", warpframe[2].y);
+ XML.setValue("WARP:p3:X", warpframe[3].x);
+ XML.setValue("WARP:p3:Y", warpframe[3].y);
+
+ XML.setValue("POSITION:X", outputPosition.x);
+ XML.setValue("POSITION:Y", outputPosition.y);
+
+ XML.setValue("SCALE", outputScale);
+
+ XML.saveFile("settings.xml");
+ cout << "settings.xml saved!" <<std::endl;
+}
+
+//--------------------------------------------------------------
+void ofApp::updateOutput(ofEventArgs & args){
+//todo: set up listener for laser params or move them into a lasergui class
+ laser.set_pts(laser_points);
+ laser.set_subdivide(laser_subdivide);
+ laser.set_blanknum(laser_blank_num);
+ laser.set_maxangle(laser_max_angle);
+
+ laser.set_intensity(laser_intensity);
+
+ movie.setSpeed(video_speed);
+
+ if(!useMic){
+ if(player.isLoaded()){
+ if (player.isPlaying()){
+ vector<float> output = player.getCurrentBuffer(bufferSize);
+ processAudio(&output[0], bufferSize, 2);
+ //
+ if (useFft){
+ fftSmoothed = player.getFFT();
+ /*
+ float * fft = ofSoundGetSpectrum(plotter.num_points);
+ fftSmoothed.resize(plotter.num_points);
+ //printf("fft: ");
+ for (int i=0;i<plotter.num_points;i++){
+ fftSmoothed[i]=fft[i];
+ //printf("%f,",fftSmoothed[i]);
+ }
+ //printf("\r\n");
+ */
+ plotter.addpoints(fftSmoothed);
+ }
+ else {
+ plotter.addpoints(centre);
+ }
+ }
+ else {
+ player.play();
+ }
+ }
+
+ }
+ else {
+ if (player.isPlaying()){
+ player.stop();
+ }
+ if (centre.size()){
+ if (useFft){
+ float * fft = ofSoundGetSpectrum(plotter.num_points);
+ fftSmoothed.resize(plotter.num_points);
+ printf("fft: ");
+ for (int i=0;i<plotter.num_points;i++){
+ fftSmoothed[i]=fft[i];
+ printf("%f,",fftSmoothed[i]);
+ }
+ printf("\r\n");
+ plotter.addpoints(fftSmoothed);
+ }
+ else {
+ if (!use_onset||onset_frame<onset_duration){
+ plotter.addpoints(centre);
+ }
+ else {
+ plotter.blankframe();
+ }
+ }
+ }
+ }
+
+}
+
+void ofApp::update(){
+/*
+ // Update the NDI sender list to find new senders
+ // There is no delay if no new senders are found
+ nSenders = ndiReceiver.FindSenders();
+
+ if(nSenders > 0) {
+
+ // Has the user changed the sender index ?
+ if(ndiReceiver.SenderSelected()) {
+ // Release the current receiver.
+ // A new one is then created from the selected sender index.
+ ndiReceiver.ReleaseReceiver();
+ bNDIreceiver = false;
+ }
+
+ // Create a new receiver if one does not exist.
+ // We don't know the sender dimensions until a frame is received.
+ if(!bNDIreceiver) {
+
+ // The receiver will detect which format a sender is using and convert
+ // the pixel buffer to BGRA for return. However, we can specify here
+ // that RGBA is the preferred format.
+ bNDIreceiver = ndiReceiver.CreateReceiver(NDIlib_recv_color_format_e_RGBX_RGBA);
+ // bNDIreceiver = ndiReceiver.CreateReceiver(); // default is BRRA
+
+ //
+ // A receiver is created from an index into a list of sender names.
+ // The current user selected index is saved in the NDIreceiver class
+ // and is used to create the receiver unless you specify a particular index.
+ //
+ // The name of the sender can also be retrieved if you need it.
+ // If you specified a particular sender index to create the receiver
+ // use that index to retrieve it's name.
+ //
+ // In this application we use it to display the sender name.
+ //
+
+ ndiReceiver.GetSenderName(senderName);
+ if(bNDIreceiver)
+ cout << "Created NDI receiver for " << senderName << endl;
+
+ // Reset the starting values for frame rate calulations
+ fps = frameRate = 1;
+
+ }
+
+ }
+
+ if(bNDIreceiver) {
+
+ unsigned int width = 0;
+ unsigned int height = 0;
+
+ // If the NDI sender uses BGRA format, the received buffer is converted to rgba by ReceiveImage.
+ // Optionally you can flip the image if necessary.
+
+ // !CHECKME MACOS
+ // ReceiveImage needs an unsigned char* so changed
+ // ndiImage.getPixels() to ndiImage.getPixels().getData()
+ // to avoid type error
+ if(ndiReceiver.ReceiveImage(ndiImage.getPixels().getData(), width, height, false)) { // receives as rgba
+
+ ndiImage.update();
+
+ // ----------------------------
+ // Calculate received frame fps
+ lastTime = startTime;
+ startTime = ofGetElapsedTimeMicros();
+ frameTime = (startTime - lastTime)/1000000; // seconds
+ if( frameTime > 0.01) {
+ frameRate = floor(1.0/frameTime + 0.5);
+ // damping from a starting fps value
+ fps *= 0.95;
+ fps += 0.05*frameRate;
+ }
+ // ----------------------------
+
+ // Have the NDI sender dimensions changed ?
+ if(senderWidth != width || senderHeight != height) {
+
+ // Update the sender dimensions
+ senderWidth = width;
+ senderHeight = height;
+
+ // Update the receiving image size
+ ndiImage.allocate(senderWidth, senderHeight, OF_IMAGE_COLOR_ALPHA);
+
+ }
+ }
+
+ }
+*/
+ if (movie.isLoaded()){
+ movie.update();
+ }
+
+ gist.setThreshold(GIST_PEAK_ENERGY,onset_threshold);
+
+ onset_frame++;
+}
+
+const ofPoint previewframesize=ofPoint(320,240);
+
+//-------------------------------------------------------------- GUI
+void ofApp::draw(){
+ ofBackground(0);
+
+ ofSetColor(255);
+ ofNoFill();
+
+ if (bShowPositionInterface){
+
+ glPushMatrix();
+
+ glTranslatef(20,20,0);
+
+ ofDrawRectangle(0,0,560,560);
+
+ glTranslatef(outputOffset.x,outputOffset.y,0);
+
+ glScalef(guiScale,guiScale,guiScale );
+
+ glTranslatef(2048.0f+outputPosition.x,2048.0f+outputPosition.y,0);
+
+ if (bOutputSelected) {
+ if (commandPressed) {
+ ofSetColor(0,255,0);
+ }
+ else {
+ ofSetColor(255,0,0);
+ }
+ }
+
+ ofDrawRectangle(
+ (-outputWindowSize.x/2)*outputScale*outputOffsetScale,
+ (-outputWindowSize.y/2)*outputScale*outputOffsetScale,
+ outputWindowSize.x*outputScale*outputOffsetScale,
+ outputWindowSize.y*outputScale*outputOffsetScale);
+
+ glPopMatrix();
+ }
+ else {
+ lasergui.draw();
+ drawgui.draw();
+ audiogui.draw();
+ chaosgui.draw();
+ responsegui.draw();
+
+ //================================== NDI
+/*
+ glPushMatrix();
+
+ glTranslatef(230,0,0);
+
+ ofDrawRectangle(20,20,previewframesize.x+4,previewframesize.y+4);
+
+ char str[256];
+
+ if(bNDIreceiver) {
+
+ ndiImage.draw(22, 22, previewframesize.x, previewframesize.y);
+
+ // Show fps etc.
+ if(nSenders > 0) {
+ if(bNDIreceiver) {
+ #ifdef _MSC_VER
+ sprintf_s(str, 256, "[%s] (%dx%d) - fps %2.0f", senderName, senderWidth, senderHeight, fps);
+ #else
+ // !CHECK MACOS
+ snprintf(str, 256, "[%s] (%dx%d) - fps %2.0f", senderName, senderWidth, senderHeight, fps);
+ str[255] = 0;
+ #endif
+ ofDrawBitmapString(str, 20, previewframesize.y+42);
+ }
+
+ if(nSenders == 1) {
+ ofDrawBitmapString("1 network source", 25, 32);
+ }
+ else {
+ #ifdef _MSC_VER
+ sprintf_s(str, 256, "%d network sources", nSenders);
+ #else
+ // !CHECK MACOS
+ snprintf(str, 256, "%d network sources", nSenders);
+ str[255] = 0;
+ #endif
+ ofDrawBitmapString(str, 25, 32);
+ //ofDrawBitmapString("'SPACE' to list senders or RH click to open sender dialog", 20, ofGetHeight()-20);
+ }
+ }
+ }
+ else {
+ ofDrawBitmapString("Connecting . . .", 25, 32);
+ }
+
+ glPopMatrix();
+
+ //================================== NDI
+
+ glPushMatrix();
+
+ glTranslatef(230,300,0);
+ */
+ //================================== video
+
+ glPushMatrix();
+
+ glTranslatef(230,0,0);
+
+ ofDrawRectangle(20,20,previewframesize.x+4,previewframesize.y+4);
+
+ if (movie.isLoaded()){
+ movie.draw(22, 22, previewframesize.x, previewframesize.y);
+ }
+
+ glPopMatrix();
+
+ //================================== SVG + mask
+
+ float scale=previewframesize.x/outputWindowSize.x;
+
+ //================================== SVG
+
+ glPushMatrix();
+
+
+ glTranslatef(230,270,0);
+
+ ofDrawRectangle(20,20,previewframesize.x+4,previewframesize.y+4);
+
+ glTranslatef(22,22,0);
+
+ glScalef(scale,scale,scale);
+
+ for (auto shape=segmenters.begin();shape!=segmenters.end();shape++){
+ shape->getPoly().draw();
+ }
+
+ glPopMatrix();
+
+ //================================== Mask
+
+ glPushMatrix();
+
+ glTranslatef(230,540,0);
+
+ ofDrawRectangle(20,20,previewframesize.x+4,previewframesize.y+4);
+
+ ofFill();
+
+ glTranslatef(22,22,0);
+
+ glScalef(scale,scale,scale);
+
+ for (auto& shape:mask){
+ shape.draw();
+ }
+
+ ofNoFill();
+
+ glPopMatrix();
+
+ }
+
+ ofSetColor(255);
+
+ ofDrawBitmapString(ofToString(onset_number)+":"+(onset_frame==0?"BEAT":ofToString(onset_frame)),10,ofGetHeight()-15);
+
+}
+
+void ofApp::drawOutput(ofEventArgs & args){
+ ofBackground(0);
+ //composite output window
+
+ ofSetColor(255,255,255);
+
+ vector <colourPolyline> polyOutput;
+
+ float interval=ofGetElapsedTimef()-prev_time;
+ rotate_amt+=interval*xf_rotate*5;
+
+ phase=fmod(phase+(interval*segmenter_speed),1);
+ prev_time=ofGetElapsedTimef();
+
+ while (phase<0.0f) {
+ phase+=1.0f;
+ }
+
+ scale_phase+=(interval*xf_scale_speed);
+
+ scale_amt=(((sin(scale_phase)*0.5)+0.5)*(xf_scale_max-xf_scale_min))+xf_scale_min;
+
+ switch (source){
+ case TEST:{
+ ofMatrix4x4 m = ofMatrix4x4::newIdentityMatrix();
+ m.rotateRad(ofGetElapsedTimef(),0,0,1);
+ m.translate(ofGetWidth()/2,ofGetHeight()/2,0);
+
+ glm::vec2 src[]={
+ glm::vec2(0,0),
+ glm::vec2(ofGetWidth(),0),
+ glm::vec2(ofGetWidth(),ofGetHeight()),
+ glm::vec2(0,ofGetHeight())
+ };
+
+ ofMatrix4x4 warp =lineTransformer::getPerspectiveTransformMatrix(src,warpframe);
+
+ //drawPoly(polyLineTransform(makePolygon(4,200),m),200,200);
+ //drawPoly(polyLineTransform(makePolygon(5,200),m),-200,200);
+ //drawPoly(polyLineTransform(makePolygon(6,200),m),-200,-200);
+
+ ofPolyline poly=lineTransformer::polyLineTransform(warp,
+ lineTransformer::polyLineTransform(m,
+ lineTransformer::makePolygon(6,200)
+ )
+ );
+ polyOutput.push_back(colourPolyline(poly,ofColor(laser_R,laser_G,laser_B)));
+
+ }
+/*
+ case NDI:{
+ ofPoint scale=ofPoint(outputWindowSize.x/ndiImage.getWidth(),outputWindowSize.x/ndiImage.getHeight());
+
+ //does not work no matter what the fuck you do
+
+ //grayImage.setFromPixels(pixels.getData(),ndiImage.getWidth(),ndiImage.getHeight());
+
+ //grayImage.draw(0,0,outputWindowSize.x,outputWindowSize.y);
+
+ grayImage = colorImg;
+
+ grayImage.threshold(contour_threshold);
+
+ //virtual int findContours( ofxCvGrayscaleImage& input,
+ // int minArea, int maxArea,
+ // int nConsidered, bool bFindHoles,
+ // bool bUseApproximation = true);
+ contourFinder.findContours(grayImage, 20, (340*240)/3, 10, true);
+
+ for (int i = 0; i < contourFinder.nBlobs; i++){
+ colourPolyline shape;
+ for (auto& point:contourFinder.blobs[i].pts){
+ ofVec3f p=point*scale;
+ ofColor c=colorImg.getPixels().getColor(point.x,point.y);
+ shape.addVertex(p,contour_useColour?c:ofColor(laser_R,laser_G,laser_B));
+ }
+ shape.simplify(contour_simplify);
+ polyOutput.push_back(shape);
+ }
+ break;
+
+ }
+*/
+ case Player:{
+ if (!use_onset||onset_frame<onset_duration){
+ if (movie.isLoaded()){
+ ofPoint scale=ofPoint(outputWindowSize.x/movie.getWidth(),outputWindowSize.y/movie.getHeight());
+ colorImg.setFromPixels(movie.getPixels());
+ if (grayImage.getWidth()!=colorImg.getWidth()||grayImage.getHeight()!=colorImg.getHeight()){
+ grayImage.clear();
+ }
+ grayImage=colorImg;
+ grayImage.threshold(contour_threshold);
+ contourFinder.findContours(grayImage, 20, (340*240)/3, 10, true);
+ for (int i = 0; i < contourFinder.nBlobs; i++){
+ colourPolyline shape;
+ for (auto& point:contourFinder.blobs[i].pts){
+ ofVec3f p=point*scale;
+ ofColor c=colorImg.getPixels().getColor(point.x,point.y);
+ shape.addVertex(p,contour_useColour?c:ofColor(laser_R,laser_G,laser_B));
+ }
+ shape.simplify(contour_simplify);
+ polyOutput.push_back(shape);
+ }
+ }
+ }
+ break;
+ }
+ case SVG_outlines:{
+ if (shapes_randomise){
+ if (framecounter==0){
+ select_random_shapes();
+ framecounter=shapes_duration;
+ }
+ for (auto s:shape_selection){
+ if (use_segmenter){
+ auto segments=segmenters[s].getSegments(segmenter_number,segmenter_length,phase);
+ for (auto segment=segments.begin();segment!=segments.end();segment++){
+ polyOutput.push_back(colourPolyline(*segment,ofColor(laser_R,laser_G,laser_B)));
+ }
+ }
+ else {
+ polyOutput.push_back(colourPolyline(segmenters[s].getPoly(),ofColor(laser_R,laser_G,laser_B)));
+ }
+ }
+ framecounter--;
+ }
+ else {
+ for (auto shape=segmenters.begin();shape!=segmenters.end();shape++){
+ if (use_segmenter){
+ auto segments=shape->getSegments(segmenter_number,segmenter_length,phase);
+ for (auto segment=segments.begin();segment!=segments.end();segment++){
+ polyOutput.push_back(colourPolyline(*segment,ofColor(laser_R,laser_G,laser_B)));
+ }
+ }
+ else {
+ polyOutput.push_back(colourPolyline(shape->getPoly(),ofColor(laser_R,laser_G,laser_B)));
+
+ }
+ }
+ }
+ break;
+ }
+ case Audio:{
+ ofMatrix4x4 x=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);
+ polyOutput=plotter.output(scalePlot,decayPlot);
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ vector <colourPolyline> transformedOutput;
+
+ if (use_rotate||use_scale){
+ ofMatrix4x4 rm = ofMatrix4x4::newIdentityMatrix();
+ rm.translate(-outputWindowSize.x/2,-outputWindowSize.y/2,0);
+ if (use_rotate){
+ rm.rotateRad(rotate_amt,0,0,1);
+ }
+ if (use_scale){
+ rm.scale(scale_amt,scale_amt,scale_amt);
+ }
+ rm.translate(outputWindowSize.x/2,outputWindowSize.y/2,0);
+ for (auto& shape:polyOutput){
+ transformedOutput.push_back(lineTransformer::polyLineTransform(rm,shape));
+ }
+ }
+ else {
+ transformedOutput=polyOutput;
+ }
+
+ vector <colourPolyline> clippedOutput;
+
+ if (mask.size()&&use_mask){
+ clipper.Clear();
+ clipper.addPolylines(mask, ClipperLib::ptClip);
+ vector <ofPolyline> shapes; //TODO make clipper clip colourpolylines
+ for (auto& poly: transformedOutput)
+ {
+ shapes.push_back(poly);
+ }
+ clipper.addPolylines(shapes,ClipperLib::ptSubject);
+ vector <ofPolyline> clipped;
+ if (invert_mask){
+ clipped = clipper.getClippedLines(ClipperLib::ctDifference);
+ }else {
+ clipped = clipper.getClippedLines(ClipperLib::ctIntersection);
+ }
+ for (auto& clip: clipped)
+ {
+ clip.simplify(contour_simplify);
+ clippedOutput.push_back(colourPolyline(clip,ofColor(laser_R,laser_G,laser_B)));
+ }
+ }
+ else {
+ clippedOutput=transformedOutput;
+ }
+
+ glm::vec2 src[]={
+ glm::vec2(0,0),
+ glm::vec2(ofGetWidth(),0),
+ glm::vec2(ofGetWidth(),ofGetHeight()),
+ glm::vec2(0,ofGetHeight())
+ };
+
+ glm::vec2 mp=glm::vec2(outputWindowSize.x/2,outputWindowSize.y/2);
+
+ glm::vec2 scaled_dest[]={
+ ((warpframe[0]-mp)*outputScale*outputOffsetScale)+mp,
+ ((warpframe[1]-mp)*outputScale*outputOffsetScale)+mp,
+ ((warpframe[2]-mp)*outputScale*outputOffsetScale)+mp,
+ ((warpframe[3]-mp)*outputScale*outputOffsetScale)+mp
+ };
+
+ ofMatrix4x4 scaled_warp =lineTransformer::getPerspectiveTransformMatrix(src,scaled_dest);
+ ofMatrix4x4 warp =lineTransformer::getPerspectiveTransformMatrix(src,warpframe);
+
+ vector <colourPolyline> warpedOutput;
+ vector <colourPolyline> scaledWarpedOutput;
+
+ for (auto s:clippedOutput){
+ warpedOutput.push_back(lineTransformer::polyLineTransform(warp,s));
+ scaledWarpedOutput.push_back(lineTransformer::polyLineTransform(scaled_warp,s));
+ }
+
+ int num = 0;
+ int pnum=0;
+
+
+ if (laser_power&&polyOutput.size()) {
+ num=laser.draw(scaledWarpedOutput);
+ }
+ else {
+ colourPolyline blank;
+ for (int i=0;i<100;i++){
+ blank.addVertex(ofGetWidth()/2,ofGetHeight()/2,0,0,0);
+ }
+ laser.draw(blank);
+ }
+ for (auto& shape:warpedOutput){
+ shape.draw();
+ pnum+=shape.size();
+ }
+
+
+ if (bDrawFrame){
+ lineTransformer::drawWarpFrame(warpframe);
+ }
+
+ if (num>0){
+ ofSetWindowTitle(sourcenames[source]+": "+ofToString(ofGetFrameRate(), 2)+" fps laser points: "+ofToString(num));
+ }
+ else {
+
+ ofSetWindowTitle(sourcenames[source]+": "+ofToString(ofGetFrameRate(), 2)+" fps laser error points: "+ofToString(pnum));
+ }
+
+}
+
+//--------------------------------------------------------------
+void ofApp::exit() {
+ audiogui.clear();
+
+}
+
+
+
+//--------------------------------------------------------------
+void ofApp::outputKeyPressed(ofKeyEventArgs &args){
+
+ keyPressed(args);
+
+
+}
+
+void ofApp::keyPressed(ofKeyEventArgs &args){
+ if (args.key==OF_KEY_COMMAND){
+ commandPressed=true;
+ }
+
+ switch(args.key){
+ case '`':{
+ bShowPositionInterface=!bShowPositionInterface;
+ break;
+ }
+ case 'q':{
+ source--;
+ if (source<0){
+ source=Source_end-1;
+ }
+ break;
+ }
+ case 'p':{
+ source=(source+1)%Source_end;
+ break;
+ }
+ case 'w':{
+ bDrawFrame=!bDrawFrame;
+ break;
+ }
+ case 'd':{
+ default_settings();
+ break;
+ }
+ case 's':{
+ save_settings();
+ break;
+ }
+ }
+}
+
+//--------------------------------------------------------------
+void ofApp::outputKeyReleased(ofKeyEventArgs &args){
+
+ outputKeyReleased(args);
+
+
+}
+
+void ofApp::keyReleased(ofKeyEventArgs &args){
+ if (args.key==OF_KEY_COMMAND){
+ commandPressed=false;
+ }
+}
+
+
+//--------------------------------------------------------------
+void ofApp::mouseMoved(int x, int y ){
+
+}
+
+//--------------------------------------------------------------
+void ofApp::outputMouseDragged(ofMouseEventArgs & args){
+ if (select_warpframe>-1){
+ warpframe[select_warpframe]=glm::vec2(args.x,args.y);
+ }
+}
+
+void ofApp::mouseDragged(int x, int y, int button){
+ if (bOutputSelected){
+ if (commandPressed){
+ float startDistance=((outputPosition*guiScale)+ofPoint(300,300)).distance(outputSelectionPoint);
+ float currentDistance=((outputPosition*guiScale)+ofPoint(300,300)).distance(ofPoint(x,y));
+ outputOffsetScale=currentDistance/startDistance;
+ }
+ else {
+ outputOffset=ofPoint(x,y)-outputSelectionPoint;
+ laser.set_centre(ofPoint(
+ outputPosition.x+(outputOffset.x/guiScale),
+ outputPosition.y+(outputOffset.y/guiScale)
+ ));
+ }
+ }
+}
+
+//--------------------------------------------------------------
+void ofApp::outputMousePressed(ofMouseEventArgs & args){
+ for (int i=0;i<4;i++){
+ if (ofPoint(args.x,args.y).distance(warpframe[i])<25){
+ select_warpframe=i;
+ }
+ }
+}
+
+void ofApp::mousePressed(int x, int y, int button){
+ if (bShowPositionInterface){
+ if (x>(300+((outputPosition.x-((outputWindowSize.x/2)*outputScale))*guiScale))&&
+ x<(300+((outputPosition.x+((outputWindowSize.x/2)*outputScale))*guiScale))&&
+ y>(300+((outputPosition.y-((outputWindowSize.y/2)*outputScale))*guiScale))&&
+ y<(300+((outputPosition.y+((outputWindowSize.y/2)*outputScale))*guiScale))
+ ){
+ outputSelectionPoint=ofPoint(x,y);
+ bOutputSelected=true;
+ }
+ }
+
+}
+
+//--------------------------------------------------------------
+void ofApp::outputMouseReleased(ofMouseEventArgs & args){
+ select_warpframe=-1;
+}
+
+void ofApp::mouseReleased(int x, int y, int button){
+ if (bOutputSelected){
+ if (commandPressed){
+ outputScale*=outputOffsetScale;
+ }
+ else {
+ outputPosition+=outputOffset/guiScale;
+ }
+ bOutputSelected=false;
+ outputOffset=ofPoint(0,0);
+ outputOffsetScale=1.0f;
+ }
+
+}
+
+//--------------------------------------------------------------
+void ofApp::mouseEntered(int x, int y){
+
+}
+
+//--------------------------------------------------------------
+void ofApp::mouseExited(int x, int y){
+
+}
+
+//--------------------------------------------------------------
+void ofApp::outputWindowResized(ofResizeEventArgs &resizeargs){
+
+}
+
+void ofApp::windowResized(int w, int h){
+
+}
+
+void ofApp::select_random_shapes(){
+ shape_selection.clear();
+ while (shape_selection.size()<(segmenters.size()*shapes_amount)){
+ int selection=rand()%segmenters.size();
+ if (shape_selection.find(selection)==shape_selection.end()){
+ shape_selection.insert(selection);
+ }
+ }
+ std::stringstream strm;
+ for (auto& s:shape_selection){
+ strm << s <<" ";
+ }
+ //cout << "randomly selected (" << strm.str() <<") \n";
+}
+
+//--------------------------------------------------------------
+void ofApp::dragEvent(ofDragInfo dragInfo){
+
+ if (dragInfo.position.x>250&&dragInfo.position.x<570&&dragInfo.position.y>20&&dragInfo.position.y<266){
+ std::string filename= *dragInfo.files.begin();
+ if (movie.load(filename)){
+ cout << "loaded "<< filename<<std::endl;
+ movie.setLoopState(OF_LOOP_NORMAL);
+ movie.setVolume(0.0f);
+ movie.play();
+ }
+ else {
+ cout << "failed to load"<<std::endl;
+ }
+ }
+
+ if (dragInfo.position.x>250&&dragInfo.position.x<570&&dragInfo.position.y>320&&dragInfo.position.y<566){
+ std::string filename= *dragInfo.files.begin();
+ svg.load(filename);
+ vector <ofPath> imagepaths= svg.getPaths();
+
+ std::stringstream strm;
+
+ if (imagepaths.size()){
+ segmenters.clear();
+ for (auto& path:imagepaths){
+ path.setPolyWindingMode(OF_POLY_WINDING_ODD);
+
+ vector <ofPolyline> outlines= path.getOutline();
+ for (auto& outline:outlines){
+ strm << outline.size() << "->";
+ outline.simplify(contour_simplify);
+ strm << outline.size() << " ";
+ segmenters.push_back(lineSegmenter(outline));
+ }
+ strm << " , ";
+ }
+
+ cout << "SVG: found " << imagepaths.size() << " paths with " << segmenters.size() << " shapes [ " << strm.str() << " ]" <<std::endl;
+ select_random_shapes();
+ }
+
+ }
+
+ if (dragInfo.position.x>250&&dragInfo.position.x<570&&dragInfo.position.y>620&&dragInfo.position.y<866){
+ std::string filename= *dragInfo.files.begin();
+ svg.load(filename);
+ vector <ofPath> imagepaths= svg.getPaths();
+
+ std::stringstream strm;
+
+ if (imagepaths.size()){
+ mask.clear();
+ for (auto& path:imagepaths){
+ path.setPolyWindingMode(OF_POLY_WINDING_ODD);
+
+ vector <ofPolyline> outlines= path.getOutline();
+ for (auto& outline:outlines){
+ strm << outline.size() << "->";
+ outline.simplify(contour_simplify);
+ strm << outline.size() << " ";
+ mask.push_back(outline);
+ }
+ strm << " , ";
+ }
+
+ cout << "Mask: found " << imagepaths.size() << " paths with " << mask.size() << " shapes [ " << strm.str() << " ]" <<std::endl;
+
+ }
+
+ }
+
+}
+
+void ofApp::newMidiMessage(ofxMidiMessage& msg) {
+ //column 0 for general controls
+ //printf("Midi: %i %i %i\n",msg.channel,msg.control,msg.value);
+
+ int offset;
+
+ //===============================================
+ offset=0;
+
+ if (msg.channel==1&&msg.control==1+offset){
+ //pot
+ xf_rotate=(((float)msg.value)/64.0f)-1.0f;
+ }
+ if (msg.channel==1&&msg.control==33+offset){
+ //pot button
+ use_rotate=use_rotate?false:true;
+ }
+ if (msg.channel==1&&msg.control==65+offset){
+ //top button
+ rotate_amt=ofRandom(5.0f);
+ }
+ if (msg.channel==1&&msg.control==73+offset){
+ //bottom button
+ }
+ if (msg.channel==1&&msg.control==81+offset){
+ //fader
+ laser_intensity=msg.value*2;
+ }
+
+ //===============================================
+ offset=1;
+
+ if (msg.channel==1&&msg.control==1+offset){
+ //pot
+ xf_scale_speed=(((float)msg.value)/128.0f)*10.0f;
+ }
+ if (msg.channel==1&&msg.control==33+offset){
+ //pot button
+ use_scale=use_scale?false:true;
+ }
+ if (msg.channel==1&&msg.control==65+offset){
+ //top button
+ scale_phase=ofRandom(5.0f);
+ }
+ if (msg.channel==1&&msg.control==73+offset){
+ //bottom button
+ }
+ if (msg.channel==1&&msg.control==81+offset){
+ //fader
+ laser_R=msg.value*2;
+ }
+
+ //===============================================
+ offset=2;
+
+ if (msg.channel==1&&msg.control==1+offset){
+ //pot
+ xf_scale_min=(((float)msg.value)/128.0f);
+ }
+ if (msg.channel==1&&msg.control==33+offset){
+ //pot button
+ }
+ if (msg.channel==1&&msg.control==65+offset){
+ //top button
+ }
+ if (msg.channel==1&&msg.control==73+offset){
+ //bottom button
+ }
+ if (msg.channel==1&&msg.control==81+offset){
+ //fader
+ laser_G=msg.value*2;
+ }
+
+ //===============================================
+ offset=3;
+
+ if (msg.channel==1&&msg.control==1+offset){
+ //pot
+ xf_scale_max=(((float)msg.value)/128.0f);
+ }
+ if (msg.channel==1&&msg.control==33+offset){
+ //pot button
+ }
+ if (msg.channel==1&&msg.control==65+offset){
+ //top button
+ }
+ if (msg.channel==1&&msg.control==73+offset){
+ //bottom button
+ }
+ if (msg.channel==1&&msg.control==81+offset){
+ //fader
+ laser_B=msg.value*2;
+ }
+
+ //===============================================
+ offset=4;
+
+ if (msg.channel==1&&msg.control==1+offset){
+ //pot
+ }
+ if (msg.channel==1&&msg.control==33+offset){
+ //pot button
+ }
+ if (msg.channel==1&&msg.control==65+offset){
+ //top button
+ }
+ if (msg.channel==1&&msg.control==73+offset){
+ //bottom button
+ }
+ if (msg.channel==1&&msg.control==81+offset){
+ //fader
+ video_speed=((float)msg.value)/40.0f;
+ }
+
+ //===============================================
+ offset=5;
+
+ if (msg.channel==1&&msg.control==1+offset){
+ //pot
+ }
+ if (msg.channel==1&&msg.control==33+offset){
+ //pot button
+ }
+ if (msg.channel==1&&msg.control==65+offset){
+ //top button
+ }
+ if (msg.channel==1&&msg.control==73+offset){
+ //bottom button
+ }
+ if (msg.channel==1&&msg.control==81+offset){
+ //fader
+ segmenter_speed=(((float)msg.value)/64.0f)-1.0f;
+ }
+}
+