1024 => int WINDOW_SIZE; 0 => float WAVEFORM_Y; -10 => float WAVEFORM_2; 10 => float WAVEFORM_3; 60 => float WAVEFORM_4; -60 => float WAVEFORM_5; 90 => float WAVEFORM_6; -90 => float WAVEFORM_7; 1000 => float DISPLAY_WIDTH; // put camera on a dolly GG.camera() --> GGen dolly --> GG.scene(); // position GG.camera().posZ( 10 ); // set bg color // waveform renderer GLines waveform --> GG.scene(); waveform.mat().lineWidth(100.0); // translate up waveform.posY(WAVEFORM_Y); // color0 waveform.mat().color( @(.8, .4, 1) ); // waveform renderer GLines waveform2 --> GG.scene(); waveform.mat().lineWidth(100.0); // translate up waveform2.posY(WAVEFORM_2); // color0 waveform2.mat().color( @(.4, .4, 1) ); // waveform renderer GLines waveform3 --> GG.scene(); waveform.mat().lineWidth(100.0); // translate up waveform3.posY(WAVEFORM_3); // color0 waveform3.mat().color( @(.1, .4, 1) ); // waveform renderer GLines waveform4 --> GG.scene(); waveform.mat().lineWidth(100.0); // translate up waveform4.posY(WAVEFORM_4); // color0 waveform4.mat().color( @(.9, .3, 1) ); // waveform renderer GLines waveform5 --> GG.scene(); waveform.mat().lineWidth(100.0); // translate up waveform5.posY(WAVEFORM_5); // color0 waveform5.mat().color( @(.2, .1, 1) ); // waveform renderer GLines waveform6 --> GG.scene(); waveform.mat().lineWidth(100.0); // translate up waveform6.posY(WAVEFORM_6); // color0 waveform6.mat().color( @(.9, .4, 1) ); // waveform renderer GLines waveform7 --> GG.scene(); waveform.mat().lineWidth(100.0); // translate up waveform7.posY(WAVEFORM_7); // color0 waveform7.mat().color( @(.2, .4, 1) ); // spectrum renderer GLines spectrum --> GG.scene(); spectrum.mat().lineWidth(1.0); GG.scene() @=> GScene @ scene; scene.enableFog(); GSphere ball --> GG.scene(); GTorus torus --> scene; torus.mat().shine(2); ball.mat().color( @(.25, .25, .25) ); // accumulate samples from mic adc => Flip accum => blackhole; // take the FFT adc => PoleZero dcbloke => FFT fft => blackhole; // set DC blocker .95 => dcbloke.blockZero; // set size of flip WINDOW_SIZE => accum.size; // set window type and size Windowing.hann(WINDOW_SIZE) => fft.window; // set FFT size (will automatically zero pad) WINDOW_SIZE*2 => fft.size; // get a reference for our window for visual tapering of the waveform Windowing.hann(WINDOW_SIZE) @=> float window[]; // sample array float samples[0]; // FFT response complex response[0]; vec3 vertices[WINDOW_SIZE]; float positions[WINDOW_SIZE*3]; // map audio buffer to 3D positions fun void map2waveform( float in[], float out[] ) { if( in.size()*3 != out.size() ) { <<< "size mismatch in flatten()", "" >>>; return; } // mapping to xyz coordinate int i; DISPLAY_WIDTH => float width; for( auto s : in ) { // map -width/2 + width/WINDOW_SIZE*i => out[i*3]; s*6 * window[i] => out[i*3+1]; 0 => out[i*3+2]; // increment i++; } } // map FFT output to 3D positions fun void map2spectrum( complex in[], float out[] ) { if( in.size()*3 != out.size() ) { <<< "size mismatch in flatten()", "" >>>; return; } // mapping to xyz coordinate int i; DISPLAY_WIDTH => float width; for( auto s : in ) { // map -width/2 + width/WINDOW_SIZE*i => out[i*3]; 5 * Math.sqrt( (s$polar).mag * 25 ) => out[i*3+1]; 0 => out[i*3+2]; // increment i++; } } // do audio stuff fun void doAudio() { while( true ) { // upchuck to process accum accum.upchuck(); // get the last window size samples (waveform) accum.output( samples ); // upchuck to take FFT, get magnitude reposne fft.upchuck(); // get spectrum (as complex values) fft.spectrum( response ); // jump by samples WINDOW_SIZE::samp/2 => now; } } spork ~ doAudio(); // graphics render loop while( true ) { // map to interleaved format map2waveform( samples, positions ); // set the mesh position waveform.geo().positions( positions ); // map to spectrum display map2spectrum( response, positions ); // set the mesh position spectrum.geo().positions( positions ); // next graphics frame GG.nextFrame() => now; GG.dt() => float dt; ball.rotY(.5 * dt); torus.rotY(.9 * dt); torus.rotX(.2 * dt); ball.rotX(.5 * dt); GG.nextFrame() => now; }