From 58ca3a80542ef42a628dac3a785d3b73a46125a9 Mon Sep 17 00:00:00 2001 From: villenje Date: Mon, 8 Jul 2019 09:05:03 +0200 Subject: [PATCH] BeamBender example --- examples/2_Audio/BeamBender/BeamBender.pde | 210 +++++++++++++++++++++ examples/2_Audio/BeamBender/createBeam.pde | 170 +++++++++++++++++ examples/2_Audio/BeamBender/phyUGen.pde | 144 ++++++++++++++ 3 files changed, 524 insertions(+) create mode 100644 examples/2_Audio/BeamBender/BeamBender.pde create mode 100644 examples/2_Audio/BeamBender/createBeam.pde create mode 100644 examples/2_Audio/BeamBender/phyUGen.pde diff --git a/examples/2_Audio/BeamBender/BeamBender.pde b/examples/2_Audio/BeamBender/BeamBender.pde new file mode 100644 index 0000000..f79512b --- /dev/null +++ b/examples/2_Audio/BeamBender/BeamBender.pde @@ -0,0 +1,210 @@ + +import ddf.minim.*; +import ddf.minim.ugens.*; +import peasy.*; +import controlP5.*; + +PeasyCam cam; +ControlP5 cp5; +ModelRenderer renderer; +Minim minim; +PhyUGen simUGen; +Gain gain; +AudioOutput out; +AudioRecorder recorder; + +int baseFrameRate = 60; + +boolean wIsPressed; + +int gridSpacing = 2; +int xOffset= 0; +int yOffset= 0; + +float currAudio = 0; +float gainVal = 1.; + +float percsize = 200; + +float speed = 0; +float pos = 100; + +float Ctrl_damping, Ctrl_friction, Ctrl_stiffness, Ctrl_gain, Ctrl_attack; + + +/////////////////////////////////////// + +void setup() +{ + //fullScreen(P3D,2); + size(1000, 700, P3D); + + cam = new PeasyCam(this, 100); + cam.setMinimumDistance(50); + cam.setMaximumDistance(500000); + + minim = new Minim(this); + + // use the getLineOut method of the Minim object to get an AudioOutput object + out = minim.getLineOut(); + + recorder = minim.createRecorder(out, "myrecording.wav"); + + // start the Gain at 0 dB, which means no change in amplitude + gain = new Gain(0); + + // create a physicalModel UGEN + simUGen = new PhyUGen(44100); + + // patch the Oscil to the output + simUGen.patch(gain).patch(out); + + renderer = new ModelRenderer(this); + + renderer.displayMats(true); + renderer.setSize(matModuleType.Mass3D, 1); + renderer.setColor(matModuleType.Mass3D, 50, 255, 200); + renderer.setSize(matModuleType.Ground3D, 3); + renderer.setColor(matModuleType.Ground3D, 120, 200, 100); + renderer.setColor(linkModuleType.SpringDamper3D, 135, 70, 70, 255); + renderer.setStrainGradient(linkModuleType.SpringDamper3D, true, 0.5); + renderer.setStrainColor(linkModuleType.SpringDamper3D, 105, 100, 200, 255); + + cam.setDistance(500); // distance from looked-at point + + frameRate(baseFrameRate); + + // Interface elements for quick parametric exploration + cp5 = new ControlP5(this); + cp5.setAutoDraw(false); + + cp5.addSlider("Ctrl_damping").setPosition(20,20).setRange(0.00001, 0.001); + cp5.addSlider("Ctrl_friction").setPosition(20,40).setRange(0.000001, 0.0001); + cp5.addSlider("Ctrl_stiffness").setPosition(20,60).setRange(0.0001, 0.2); + cp5.addSlider("Ctrl_gain").setPosition(20,80).setRange(0, 1.); + cp5.addSlider("Ctrl_attack").setPosition(20,100).setRange(0, 1.); + + //ButtonBar b = cp5.addButtonBar("preset") + // .setPosition(0, 120) + // .setSize(200, 20) + // .addItems(split("a b c d e"," ")); + //b.changeItem("a","text","default"); + //b.changeItem("b","text","p1"); + //b.changeItem("c","text","p2"); + //b.changeItem("d","text","p3"); + //b.changeItem("e","text","p4"); + preset(0); +} + +void draw() +{ + background(0,0,25); + directionalLight(126, 126, 126, 100, 0, -1); + ambientLight(182, 182, 182); + + renderer.renderModel(simUGen.mdl); + + cam.beginHUD(); + + fill(100); + rect(0,0,200,140); + cp5.draw(); + + cam.endHUD(); + + simUGen.mdl.changeDampingParamOfSubset(Ctrl_damping,"stretchingFactor"); + simUGen.mdl.changeDampingParamOfSubset(Ctrl_damping,"myBeam"); + simUGen.mdl.setFriction(Ctrl_friction); + simUGen.mdl.changeStiffnessParamOfSubset(Ctrl_stiffness,"myBeam"); + gainControl = Ctrl_gain; + + cam.setActive(wIsPressed); +} + +void keyPressed() { + // Series of various attack interaction + if (key =='a'){ + frcRate = 1; + forcePeak = 0.1*Ctrl_attack; + triggerForceRamp = true; + } + if (key =='z'){ + frcRate = 1; + forcePeak = 0.5*Ctrl_attack; + triggerForceRamp = true; + } + if (key =='e'){ + frcRate = 1; + forcePeak = 1*Ctrl_attack; + triggerForceRamp = true; + } + if (key =='r'){ + frcRate = 1; + forcePeak = 2*Ctrl_attack; + triggerForceRamp = true; + } + if (key =='t'){ + frcRate = 1; + forcePeak = 6*Ctrl_attack; + triggerForceRamp = true; + } + if (key =='y'){ + frcRate = 0.01; + forcePeak = 6*Ctrl_attack; + triggerForceRamp = true; + } + // hold that key for horizontal stretching activation (control with horizontal mouse movement) + if (key =='q'){ + lenghtStrech = true; + } + // hold that key for vertical homothetic stretching activation (control with vertical mouse movement) + if (key =='s'){ + sectionStrech = true; + } + // hold that key for beam twisting activation (control with vertical mouse movement) + if (key =='d'){ + twist = true; + } + // hold that key for camera control activation (unfreeze peasyCam standard control) + if (key =='w') { + wIsPressed = true; + } +} + + +void keyReleased() { + if (key =='q'){ + lenghtStrech = false; + } + if (key =='s'){ + sectionStrech = false; + } + if (key =='d'){ + twist = false; + } + if (key =='w') { + wIsPressed = false; + } +} + + +// PRESETS +void preset(int n) { + println("bar clicked, item-value:", n); + if (n == 0){ + cp5.getController("Ctrl_damping").setValue(0.00001); + cp5.getController("Ctrl_friction").setValue(0.0001); + cp5.getController("Ctrl_stiffness").setValue(0.04); + cp5.getController("Ctrl_gain").setValue(0.04); + cp5.getController("Ctrl_attack").setValue(1.0); + updateModelParam(); + } +} + +void updateModelParam(){ + println("MaJ Param"); + simUGen.mdl.changeDampingParamOfSubset(Ctrl_damping,"myBeam"); + simUGen.mdl.setFriction(Ctrl_friction); + simUGen.mdl.changeStiffnessParamOfSubset(Ctrl_stiffness,"myBeam"); + gainControl = Ctrl_gain; +} diff --git a/examples/2_Audio/BeamBender/createBeam.pde b/examples/2_Audio/BeamBender/createBeam.pde new file mode 100644 index 0000000..0e1d15b --- /dev/null +++ b/examples/2_Audio/BeamBender/createBeam.pde @@ -0,0 +1,170 @@ +void generateVolume(PhysicalModel mdl, int dimX, int dimY, int dimZ, String mName, String lName, String subSetName, float masValue, float l0, float dist, float K, float Z) { + + String masName; + Vect3D X0, V0; + String springName; + mdl.createLinkSubset(subSetName); + mdl.createLinkSubset(subSetName+"_1axe"); + mdl.createLinkSubset(subSetName+"_2axes"); + mdl.createLinkSubset(subSetName+"_3axes"); + + + + + // add the masses to the model: name, mass, initial pos, init speed + for (int k = 0; k < dimZ; k++) { + for (int i = 0; i < dimY; i++) { + for (int j = 1; j <= dimX; j++) { + masName = mName +(j+i*dimX+k*dimX*dimY); + println(masName); + masValue = 1.0; + X0 = new Vect3D(j*dist-(dimX/2*dist), i*dist, k*dist); + V0 = new Vect3D(0., 0., 0.); + if(j==1){ + mdl.addGround3D(masName, X0); + groundsL.append(masName); + } + else if (j==dimX){ + mdl.addGround3D(masName, X0); + groundsR.append(masName); + } + else + mdl.addMass3D(masName, masValue, X0, V0); + } + } + } + println(groundsL); + println(groundsR); + + + + // add the spring to the model: length, stiffness, connected mats + String masName1, masName2; + + for (int k = 0; k < dimZ; k++) { + for (int i = 0; i < dimY; i++) { + for (int j = 1; j < dimX; j++) { + masName1 = mName +(j+i*dimX+k*(dimX*dimY)); + masName2 = mName +(j+i*dimX+k*(dimX*dimY)+1); + springName = lName + "1_" +i+j+k; + mdl.addSpringDamper3D(springName, l0, K, Z, masName1, masName2); + mdl.addLinkToSubset(springName,subSetName+"_1axe"); + mdl.addLinkToSubset(springName,subSetName); + } + } + } + + for (int k = 0; k < dimZ; k++) { + for (int i = 1; i < dimX+1; i++) { + for (int j = 0; j < dimY-1; j++) { + masName1 = mName +(i+j*dimX+k*(dimX*dimY)); + masName2 = mName +(i+(j+1)*dimX+k*(dimX*dimY)); + springName = lName + "1_" +i+j+k; + mdl.addSpringDamper3D(springName, l0, K, Z, masName1, masName2); + mdl.addLinkToSubset(springName,subSetName+"_1axe"); + mdl.addLinkToSubset(springName,subSetName); + } + } + } + + for (int i = 1; i < dimX+1; i++) { + for (int j = 0; j < dimY; j++) { + for (int k = 0; k < dimZ-1; k++) { + masName1 = mName +(i+j*dimX+k*(dimX*dimY)); + masName2 = mName +(i+j*dimX+(k+1)*(dimX*dimY)); + springName = lName + "1_" +i+j+k; + mdl.addSpringDamper3D(springName, l0, K, Z, masName1, masName2); + mdl.addLinkToSubset(springName,subSetName+"_1axe"); + mdl.addLinkToSubset(springName,subSetName); + } + } + } + + // Create cross links (for structural integrity) here! + double h1 = sqrt(2)*l0; + double h2 = sqrt(3)*l0; + + for (int i = 1; i < dimX; i++) { + for (int j = 0; j < dimY-1; j++) { + for (int k = 0; k < dimZ; k++) { + masName1 = mName +(i+j*dimX+k*(dimX*dimY)); + masName2 = mName +(i+1+(j+1)*dimX+k*(dimX*dimY)); + springName = lName + "1_" +i+j+k; + mdl.addSpringDamper3D(springName, h1, K, Z, masName1, masName2); + mdl.addLinkToSubset(springName,subSetName+"_2axes"); + + masName1 = mName +(i+(j+1)*dimX+k*(dimX*dimY)); + masName2 = mName +(i+1+(j)*dimX+k*(dimX*dimY)); + mdl.addSpringDamper3D(springName, h1, K, Z, masName1, masName2); + mdl.addLinkToSubset(springName,subSetName+"_2axes"); + mdl.addLinkToSubset(springName,subSetName); + } + } + } + for (int i = 1; i < dimX; i++) { + for (int j = 0; j < dimY; j++) { + for (int k = 0; k < dimZ-1; k++) { + masName1 = mName +(i+j*dimX+k*(dimX*dimY)); + masName2 = mName +(i+1+(j)*dimX+(k+1)*(dimX*dimY)); + springName = lName + "1_" +i+j+k; + mdl.addSpringDamper3D(springName, h1, K, Z, masName1, masName2); + mdl.addLinkToSubset(springName,subSetName+"_2axes"); + mdl.addLinkToSubset(springName,subSetName); + + masName1 = mName +(i+(j)*dimX+(k+1)*(dimX*dimY)); + masName2 = mName +(i+1+(j)*dimX+k*(dimX*dimY)); + mdl.addSpringDamper3D(springName, h1, K, Z, masName1, masName2); + mdl.addLinkToSubset(springName,subSetName+"_2axes"); + mdl.addLinkToSubset(springName,subSetName); + } + } + } + for (int i = 1; i < dimX+1; i++) { + for (int j = 0; j < dimY-1; j++) { + for (int k = 0; k < dimZ-1; k++) { + masName1 = mName +(i+j*dimX+k*(dimX*dimY)); + masName2 = mName +(i+(j+1)*dimX+(k+1)*((dimX)*(dimY))); + springName = lName + "1_" +i+j+k; + mdl.addSpringDamper3D(springName, h1, K, Z, masName1, masName2); + mdl.addLinkToSubset(springName,subSetName+"_2axes"); + mdl.addLinkToSubset(springName,subSetName); + + masName1 = mName +(i+j*dimX+(k+1)*(dimX*dimY)); + masName2 = mName +(i+(j+1)*dimX+(k)*((dimX)*(dimY))); + mdl.addSpringDamper3D(springName, h1, K, Z, masName1, masName2); + mdl.addLinkToSubset(springName,subSetName+"_2axes"); + mdl.addLinkToSubset(springName,subSetName); + } + } + } + for (int i = 1; i < dimX; i++) { + for (int j = 0; j < dimY-1; j++) { + for (int k = 0; k < dimZ-1; k++) { + masName1 = mName +(i+j*dimX+k*(dimX*dimY)); + masName2 = mName +(i+1+(j+1)*dimX+(k+1)*((dimX)*(dimY))); + springName = lName + "1_" +i+j+k; + mdl.addSpringDamper3D(springName, h2, K, Z, masName1, masName2); + mdl.addLinkToSubset(springName,subSetName+"_3axes"); + mdl.addLinkToSubset(springName,subSetName); + + masName1 = mName +(i+(j+1)*dimX+(k+1)*(dimX*dimY)); + masName2 = mName +(i+1+(j)*dimX+(k)*((dimX)*(dimY))); + mdl.addSpringDamper3D(springName, h2, K, Z, masName1, masName2); + mdl.addLinkToSubset(springName,subSetName+"_3axes"); + mdl.addLinkToSubset(springName,subSetName); + + masName1 = mName +(i+1+(j+1)*dimX+(k)*(dimX*dimY)); + masName2 = mName +(i+(j)*dimX+(k+1)*((dimX)*(dimY))); + mdl.addSpringDamper3D(springName, h2, K, Z, masName1, masName2); + mdl.addLinkToSubset(springName,subSetName+"_3axes"); + mdl.addLinkToSubset(springName,subSetName); + + masName1 = mName +(i+1+(j)*dimX+(k+1)*(dimX*dimY)); + masName2 = mName +(i+(j+1)*dimX+(k)*((dimX)*(dimY))); + mdl.addSpringDamper3D(springName, h2, K, Z, masName1, masName2); + mdl.addLinkToSubset(springName,subSetName+"_3axes"); + mdl.addLinkToSubset(springName,subSetName); + } + } + } +} diff --git a/examples/2_Audio/BeamBender/phyUGen.pde b/examples/2_Audio/BeamBender/phyUGen.pde new file mode 100644 index 0000000..055cdc4 --- /dev/null +++ b/examples/2_Audio/BeamBender/phyUGen.pde @@ -0,0 +1,144 @@ +import java.util.Arrays; +import ddf.minim.UGen; + +import miPhysics.*; + +/* Phyiscal parameters for the model */ +float m = 1.0; +float k = 0.01; +float z = 0.00001; + +// slight pre-strain on the beam by using a shorter l0 +float l0 = 25.; + +// spacing between the masses, imposed by the fixed points at each end +float dist = 25.; + +float fric = 0.00001; +float grav = 0.; + +int dimX = 15; +int dimY = 3; +int dimZ = 3; + +boolean triggerForceRamp = false; +float forcePeak = 10; + +boolean lenghtStrech = false; +boolean sectionStrech = false; +boolean twist = false; + + +float frc = 0; +float frcRate = 0.01; + +float gainControl = 0; + +StringList groundsL = new StringList(); + +StringList groundsR = new StringList(); + +public class PhyUGen extends UGen +{ + + private String listeningPoint; + private String excitationPoint; + + private float oneOverSampleRate; + + float prevSample; + float audioOut; + float audioRamp; + + PhysicalModel mdl; + + public PhyUGen(int sampleRate) + { + super(); + + this.mdl = new PhysicalModel(sampleRate, (int)baseFrameRate); + mdl.setGravity(grav); + mdl.setFriction(fric); + + audioOut = 0; + audioRamp = 0; + + + generateVolume(mdl, dimX, dimY, dimZ, "mass", "spring", "myBeam", m, l0, dist, k, z); + listeningPoint = "mass85"; + excitationPoint = "mass5"; + + this.mdl.init(); + } + + /* + * This routine will be called any time the sample rate changes. + */ + protected void sampleRateChanged() + { + oneOverSampleRate = 1 / sampleRate(); + this.mdl.setSimRate((int)sampleRate()); + } + + @Override + protected void uGenerate(float[] channels) + { + float sample; + if(lenghtStrech){ + for (int k = 0; k < groundsL.size(); k++) { + this.mdl.setMatPosition(groundsL.get(k), new Vect3D(mdl.getMatPosition(groundsL.get(k)).x+(mouseX-pmouseX)/100., mdl.getMatPosition(groundsL.get(k)).y, mdl.getMatPosition(groundsL.get(k)).z)); + this.mdl.setMatPosition(groundsR.get(k), new Vect3D(mdl.getMatPosition(groundsR.get(k)).x-(mouseX-pmouseX)/100., mdl.getMatPosition(groundsR.get(k)).y, mdl.getMatPosition(groundsR.get(k)).z)); + } + } + + if(sectionStrech){ + for (int k = 0; k < groundsL.size(); k++) { + this.mdl.setMatPosition(groundsL.get(k), new Vect3D(mdl.getMatPosition(groundsL.get(k)).x, mdl.getMatPosition(groundsL.get(k)).y*(1+(mouseY-pmouseY)/100000.), mdl.getMatPosition(groundsL.get(k)).z)); + this.mdl.setMatPosition(groundsL.get(k), new Vect3D(mdl.getMatPosition(groundsL.get(k)).x, mdl.getMatPosition(groundsL.get(k)).y, mdl.getMatPosition(groundsL.get(k)).z*(1+(mouseY-pmouseY)/100000.))); + this.mdl.setMatPosition(groundsR.get(k), new Vect3D(mdl.getMatPosition(groundsR.get(k)).x, mdl.getMatPosition(groundsR.get(k)).y*(1+(mouseY-pmouseY)/100000.), mdl.getMatPosition(groundsR.get(k)).z)); + this.mdl.setMatPosition(groundsR.get(k), new Vect3D(mdl.getMatPosition(groundsR.get(k)).x, mdl.getMatPosition(groundsR.get(k)).y, mdl.getMatPosition(groundsR.get(k)).z*(1+(mouseY-pmouseY)/100000.))); + } + } + + if(twist){ + for (int k = 0; k < groundsL.size(); k++) { + this.mdl.setMatPosition(groundsL.get(k), new Vect3D( mdl.getMatPosition(groundsL.get(k)).x, + (cos((mouseY-pmouseY)/10000.)*(mdl.getMatPosition(groundsL.get(k)).y - (dist*(dimY-1))/2.) - sin((mouseY-pmouseY)/10000.)*(mdl.getMatPosition(groundsL.get(k)).z - (dist*(dimZ-1))/2.) + (dist*(dimY-1))/2.), + (sin((mouseY-pmouseY)/10000.)*(mdl.getMatPosition(groundsL.get(k)).y - (dist*(dimY-1))/2.) + cos((mouseY-pmouseY)/10000.)*(mdl.getMatPosition(groundsL.get(k)).z - (dist*(dimZ-1))/2.) + (dist*(dimZ-1))/2.))); + } + } + + this.mdl.computeStep(); + + if (audioRamp < 1) + audioRamp +=0.00001; + + // Triggered force (for "plucking") + if(triggerForceRamp){ + frc = frc + frcRate * 0.1; + simUGen.mdl.triggerForceImpulse(excitationPoint,0,frc,0); + + if (frc > forcePeak){ + triggerForceRamp = false; + frc = 0; + } + } + + // calculate the sample value + if (simUGen.mdl.matExists(listeningPoint)) { + sample =(float)(this.mdl.getMatPosition(listeningPoint).x)* 0.15 + + (float)(this.mdl.getMatPosition(listeningPoint).y)* 0.15 + + (float)(this.mdl.getMatPosition(listeningPoint).z)* 0.15; + + sample*=gainControl; + + /* High pass filter to remove the DC offset */ + audioOut = (sample - prevSample + 0.95 * audioOut) * audioRamp;; + prevSample = sample; + } else + sample = 0; + + Arrays.fill( channels, audioOut ); + currAudio = audioOut; + } +}