1024 => global int WINDOW_SIZE; // window size 3.5 => global float WAVEFORM_Y; // y position of waveform -2.8 => global float SPECTRUM_Y; // y position of spectrum 15 => global float DISPLAY_WIDTH; // width of waveform and spectrum display 76 => int WATERFALL_DEPTH; // waterfall depth; number of lines deep Math.PI / 2 => float radians; //rotate 90 degrees 16 => int NUM_RAYS; 0.0 => global float maxHeight; 0 => global int maxInd; /* scene setup */ // GG.fullscreen(); // uncomment to fullscreen GG.camera() --> GGen dolly --> GG.scene(); // put camera on a dolly GG.camera().posZ( 10 ); // position GG.camera().clip( .05, WATERFALL_DEPTH * 10 ); // set clipping plane GG.camera().perspective(); GG.camera().fov(45.0); 1 => float lightIntensity; GG.scene().light().ambient(@(lightIntensity,lightIntensity,lightIntensity)); GG.scene().light().diffuse(@(lightIntensity,lightIntensity,lightIntensity)); //fog it. go back and forth in fog intensity GG.scene().enableFog(); @(0.95, 1, 0.99) => vec3 fogColor; GG.scene().fogColor(fogColor); GG.scene().fogType(GG.scene().FOG_EXP); fun void pingPongFogDensity() { // oscillate fog density while (true) { GG.scene().fogDensity(Math.sin(0.2 * (now/second)) * 0.2 + 0.1); GG.nextFrame() => now; } } spork ~ pingPongFogDensity(); //sea sound that gradually gets louder SndBuf ocean => dac; //sound buffer ugen lets us playback from file system 0.0 => ocean.gain; me.dir() + "ocean.wav" => ocean.read; fun void audio() { 35::second => now; ocean.samples() / 10 => ocean.pos; for (int i; i < 30000; i++) { // i * 0.0008 => ocean.gain; 0.05 * (Math.log(i+1)+2) => ocean.gain; 50::ms => now; } } spork ~ audio(); Sun sun --> GG.scene(); Sky sky --> GG.scene(); //sea material/setup FlatMaterial matSea; FileTexture bgSea; bgSea.path("bg_sea.png"); bgSea.wrap(1, 1); matSea.diffuseMap(bgSea); GPlane sea --> GG.scene(); sea.mat(matSea); sea.pos(@(0, -2.3, 2.5)); sea.sca(@(30,2.5,1)); //set up waterfall Waterfall waterfall --> GG.scene(); waterfall.posY( .1 ); // translate down waterfall.posZ(.001); //don't change. from soundpeek adc => Gain input; // which input? input => Flip accum => blackhole; // accumulate samples from mic input => PoleZero dcbloke => FFT fft => blackhole; // take the FFT .95 => dcbloke.blockZero; // set DC blocker WINDOW_SIZE => accum.size; // set size of flip Windowing.hann(WINDOW_SIZE) => fft.window; // set window type and size WINDOW_SIZE*2 => fft.size; // set FFT size (will automatically zero pad) Windowing.hann(WINDOW_SIZE) @=> float window[]; // get a reference for our window for visual tapering of the waveform float samples[0]; // sample array complex response[0]; // FFT response vec3 positions[WINDOW_SIZE]; // a vector to hold positions vec3 positionsCircle[WINDOW_SIZE]; // a vector to hold positions // map audio buffer to 3D positions. for time. from soundpeek fun void map2waveformCircle( float in[], vec3 out[] ) { if( in.size() != out.size() ) { <<< "size mismatch in map2waveform()", "" >>>; return; } int i; DISPLAY_WIDTH - 3.71 => float width; for( auto s : in ) { // space evenly in X (2.8 + Math.sqrt((s$polar).mag * 100)) * Math.cos(width/WINDOW_SIZE*i) => out[i].x; // map frequency bin magnitide in Y (2.8 + Math.sqrt((s$polar).mag * 100)) * Math.sin(width/WINDOW_SIZE*i) => out[i].y; 0 => out[i].z; // constant 0 for Z i++; } } // map FFT output to 3D positions; from soundpeek fun void map2spectrum( complex in[], vec3 out[] ) { if( in.size() != out.size() ) { <<< "size mismatch in map2spectrum()", "" >>>; return; } 0.0 => maxHeight; 0 => maxInd; // mapping to xyz coordinate int i; DISPLAY_WIDTH => float width; for( auto s : in ) { -width/2 + width/WINDOW_SIZE*i => out[i].x; // space evenly in X 5 * Math.sqrt( (s$polar).mag * 25 ) => out[i].y; // map frequency bin magnitide in Y 0 => out[i].z; // constant 0 for Z indexOfMax(out[i].y, i); i++; } waterfall.latest( out, maxInd ); } //get the index of the tallest peak fun int indexOfMax (float curr, int ind) { if (Math.max(curr, maxHeight) == curr) { // update to be curr curr => maxHeight; ind => maxInd; } return maxInd; } // do audio stuff; from soundpeek fun void doAudio() { while( true ) { accum.upchuck(); // upchuck to process accum accum.output( samples ); // get the last window size samples (waveform) fft.upchuck(); // upchuck to take FFT, get magnitude reposne fft.spectrum( response ); // get spectrum (as complex values) WINDOW_SIZE::samp/2 => now; // jump by samples } } spork ~ doAudio(); 0 => int skyMov; 0.0005 => float seaRot; sea.rotZ(0.025); sky.posZ(5.8); sky.posY(-1.2); // graphics render loop while( true ) { sky.rotY(.001); //constant sky rotation //camera and sea movement if (skyMov % 100 == 0) -1 * seaRot => seaRot; //reverse direction once it hits a certain point sea.rotZ(seaRot); skyMov++; dolly.posX(0.08 * Math.sin((skyMov$float) / 35)); dolly.posY(0.05 * Math.cos((skyMov$float) / 30)); dolly.posZ(0.05 * Math.cos((skyMov$float) / 20)); map2spectrum( response, positions ); // map to spectrum display GG.nextFrame() => now; // next graphics frame }