// Based on starter code from sndpeek-minimal.ck // window size 1024 => int WINDOW_SIZE; // y position of waveform 2.5 => float WAVEFORM_Y; // width of waveform and spectrum display 10 => float DISPLAY_WIDTH; // uncomment to fullscreen // GG.fullscreen(); // put camera on a dolly GG.camera() --> GGen dolly --> GG.scene(); // position GG.camera().posZ( 10 ); // set bg color GG.scene().backgroundColor( @(0,0,0) ); // waveform renderer GLines waveform1 --> GG.scene(); waveform1.mat().lineWidth(1.0); GLines waveform2 --> GG.scene(); waveform2.mat().lineWidth(1.0); GLines waveform3 --> GG.scene(); waveform3.mat().lineWidth(1.0); // translate up waveform1.posY(WAVEFORM_Y+0.6); waveform2.posY(WAVEFORM_Y+0.3); waveform3.posY(WAVEFORM_Y); // color0 rgb waveform1.mat().color( @(1, 0, 0) ); waveform2.mat().color( @(1, .6, 0) ); waveform3.mat().color( @(1, 1, 0) ); // spectrum renderer GLines spectrum1 --> GG.scene(); spectrum1.mat().lineWidth(1.0); GLines spectrum2 --> GG.scene(); spectrum2.mat().lineWidth(1.0); GLines spectrum3 --> GG.scene(); spectrum2.mat().lineWidth(1.0); // translate down spectrum1.posY(-WAVEFORM_Y); spectrum2.posY(-WAVEFORM_Y-0.3); spectrum3.posY(-WAVEFORM_Y-0.6); // color0 rgb spectrum1.mat().color( @(0, 1, 0) ); spectrum2.mat().color( @(0, .7, 1) ); spectrum3.mat().color( @(.6, .3, 1) ); // Creating 2 cores of planet for ease of rotation GPoints core1 --> GG.scene(); GPoints core2 --> GG.scene(); GPoints core3 --> GG.scene(); // Creating planet GSphere planet --> GG.scene(); planet.scale( @(.5, .5, .5)); planet.mat().color( @(.01, 1, .3)); // neon green // Creating ring GTorus ring --> GG.scene(); ring.scale( @(.3, .3, .01)); ring.mat().color( @(1, .6, .7) ); // light pink // Creating many moons orbiting planet GSphere moon --> planet; // rotY moon.posX(3); moon.posY(.3); moon.scale( @(.6, .6, .6)); moon.mat().color( @(1, 1, 0)); // yellow GSphere moon1 --> core1; // -rotY moon1.posX(1.2); moon1.posY(-.3); moon1.scale( @(.15, .15, .15)); moon1.mat().color( @(1, .5, 0)); // orange GSphere moon2 --> core2; // rotZ moon2.posX(-1); moon2.scale( @(.15, .15, .15)); moon2.mat().color( @(0, .7, 1)); // light blue GSphere moon3 --> core3; // -rotZ moon3.posX(-1.5); moon3.scale( @(.2, .2, .2)); moon3.mat().color( @(.6, .3, 1)); // purple GSphere moon4 --> core2; // rotZ moon4.posX(-2.1); moon4.scale( @(.3, .3, .3)); moon4.mat().color( @(.7, .05, 0)); // red GSphere moon5 --> core3; // -rotZ moon5.posX(-1); moon5.posY(-1.2); moon5.scale( @(.22, .22, .22)); moon5.mat().color( @(.6, .2, .5)); // magenta // 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 waveform1.geo().positions( positions ); waveform2.geo().positions( positions ); waveform3.geo().positions( positions ); // map to spectrum display map2spectrum( response, positions ); // set the mesh position spectrum1.geo().positions( positions ); spectrum2.geo().positions( positions ); spectrum3.geo().positions( positions ); // rotating ggens in each frame planet.rotY(GG.dt()); ring.rotX(GG.dt()); core1.rotY(-GG.dt()); core2.rotZ(GG.dt()); core3.rotZ(-GG.dt()); // next graphics frame GG.nextFrame() => now; }