// main function // add grocery list as musical scores // initialize mouse manager Mouse mouse; spork ~ mouse.start(0); // start listening for mouse events spork ~ mouse.selfUpdate(); // start updating mouse position // simulated calculator 15 => int numNum; // 10 numbers, =, +, C, and chuck Event buttonReleaseEvent; //create registers global int currInput; int lastInput; 0 => int MODE; // 0 for nothing, 1 for plus, 2 for minus, 3 for equal 0 => int LAST_MODE; 10 => int EQUAL; 11 => int PLUS; 12 => int MINUS; 13 => int CLEAR; 14 => int CHUCK; "" => string register; 5 => int maxReg; 0 => int prevNum; 0 => int currNum; 0 => int result; 0.6 => float gs; // grid size [ @(-2, -4, 0) * gs, @(-2, -2, 0) * gs, @( 0, -2, 0) * gs, @( 2, -2, 0) * gs, @(-2, 0, 0) * gs, @( 0, 0, 0) * gs, @( 2, 0, 0) * gs, @(-2, 2, 0) * gs, @( 0, 2, 0) * gs, @( 2, 2, 0) * gs, @( 1, -4, 0) * gs, @( 4, 2, 0) * gs, // 11 + @( 4, 0, 0) * gs, // 12 - @( 4, -2, 0) * gs, // 13 C @( 4, -4, 0) * gs, // chuck ] @=> vec3 positions[]; vec3 sizes[numNum]; for(int i; i < 10; i++) { @(1, 1, 0) => sizes[i]; } gs * 2 - 1 => float gap; @(gap + 2, 1, 0) => sizes[10]; // @(1, gap + 2, 0) => sizes[11]; @(1, 1, 0) => sizes[11]; @(1, 1, 0) => sizes[12]; @(1, 1, 0) => sizes[13]; @(1, 1, 0) => sizes[14]; [ 55, 60, 62, 64, 65, 67, 69, 71, 72, 74, 76, 79, 84, 86, 0 ] @=> int pitches[]; [ @(237, 233, 216)/255, // NONE Color.WHITE, // HOVERED @(242, 235, 191)/255, // ACTIVE Color.GREEN // PLAYING ] @=> vec3 cm1[]; [ Color.BROWN * 0.8, // NONE Color.BROWN, // HOVERED @(242, 235, 191)/255, // ACTIVE Color.GREEN // PLAYING ] @=> vec3 cm2[]; GButton buttons[numNum]; Printing prints[numNum]; for(int i; i < numNum; i++) { prints[i].init(i, buttons[i]); buttons[i].pos(positions[i]); buttons[i] --> GG.scene(); if( i > 9) { buttons[i].init(mouse, prints[i], pitches[i], sizes[i], cm2, i, buttonReleaseEvent); } else { buttons[i].init(mouse, prints[i], pitches[i], sizes[i], cm1, i, buttonReleaseEvent); } } GPlane backplate --> GG.scene(); backplate.mat().color( @( 0.2, 0.2, 0.2 ) ); backplate.sca( @( 8 * gs, 10 * gs, 0 ) * 1.1 ) ; backplate.pos( @( 1 * gs, 0 * gs, -1 ) ); Display mainDisplay --> GG.scene(); MusicBox mb; mb.setSpeed(80); mainDisplay.pos( @( gs, 4 * gs + 0.1, 0 ) ); GG.scene().backgroundColor( @(1, 1, 1) * 0.2 ); // GG.fullscreen(); GG.camera().orthographic(); GG.camera().viewSize(10); // GG.camera().pos(@(0, 0, 20)); GG.resolution(1080, 1080); // global int currInput; fun void buttonListener() { while (true) { buttonReleaseEvent => now; <<<"Button Pressed: ", currInput>>>; } } spork ~ buttonListener(); fun string toString(int input) { return "" + input; } fun void inputMonitor() { while ( true ) { buttonReleaseEvent => now; if( currInput < 10 ) { if( lastInput == EQUAL ) { "" => register; } if( register.length() < maxReg ) { toString(currInput) +=> register; } } else { // equal if( currInput == CLEAR) { "" => register; if( lastInput == CLEAR ) { spork ~ mb.stopPlay(); } } else if( currInput == CHUCK) { mb.setScore(register); spork ~ mb.startPlay(); } else if( currInput == EQUAL ) { // in plus mode if( MODE == 1 ) { register.toInt() => currNum; prevNum + currNum => result; toString(result) => register; // result => prevNum; <<<"Result: ", result>>>; <<<"Register: " + register>>>; } // in minus mode else if( MODE == 2 ) { register.toInt() => currNum; prevNum - currNum => result; // result => prevNum; <<<"Result: ", result>>>; <<<"Register: " + register>>>; } 0 => MODE; } // plus else if( currInput == PLUS ) { <<>>; register.toInt() => prevNum; 1 => MODE; "" => register; <<<"Prev: ", prevNum>>>; } // minus else if ( currInput == MINUS ) { register.toInt() => prevNum; 2 => MODE; "" => register; <<<"Prev: ", prevNum>>>; } } 100::ms => now; currInput => lastInput; } } spork ~ inputMonitor(); fun void displayListener() { while( true ) { mainDisplay.dispReg(register); 50::ms => now; // buttonReleaseEvent => now; } } spork ~ displayListener(); // game loop while (true) { GG.nextFrame() => now; } // this class is defined only inside calculator.ck class Display extends GGen { Printing digits[maxReg][10]; GPlane bg --> this; bg.mat().color( @( 0.0, 0.6, 0.1 ) ); 3 * gap + 3.8 => float bgW; 1 => float bgH; (3*gap + 4) / 6 => float dGap; dGap * 0/8 => float dW => float dH; bg.sca( @( bgW, bgH, 0 ) ) ; for( int i; i < maxReg; i++ ) { for( int j; j < 10; j++ ) { digits[i][j].init(j, this); (-2 + i) * dGap => float xloc; // assume maxReg = 5 // <<>>; digits[i][j].pos( @(xloc, 0, -5) ); } } fun void resetDigits() { for( int i; i < maxReg; i++ ) { for( int j; j < 10; j++ ) { (-2 + i) * dGap => float xloc; // assume maxReg = 5 digits[i][j].pos( @(xloc, 0, -5) ); } } } fun void dispReg(string reg) { 0 => int currDigit; resetDigits(); if( reg.length() > maxReg ) { <<<"Invalid Register Length">>>; } else { maxReg - 1 => int counter; for( reg.length() => int i; i > 0; i-- ) { reg.substring(i - 1, 1).toInt() => currDigit; digits[counter][currDigit].posZ(0); 1 -=> counter; } } } } class MusicBox { // should be an array of score int score[]; NewBass nb; dur STEP; int PLAYING; // set score after a register is received fun void setScore(string reg) { <<<"Reg: " + reg>>>; int temp[reg.length()]; for( int i; i < reg.length(); i++ ) { // <<>>; reg.substring(i, 1).toInt() => temp[i]; } temp @=> score; } fun void setSpeed(int BPM) { (1.0/BPM)::minute / 2.0 => STEP; // step duration } fun void startPlay() { 1 => PLAYING; 1::second => now; while( PLAYING ) { for( int i; i < score.size(); i++ ) { nb.play(pitches[score[i]]); STEP => now; } } } fun void stopPlay() { 0 => PLAYING; } } class NewBass{ float freq; SawOsc saw1, saw2; SqrOsc sqr1; ADSR env; // amplitude EG Step step => Envelope filterEnv => blackhole; // filter cutoff EG LPF filter; TriOsc freqLFO => blackhole; // LFO to modulate filter frequency TriOsc qLFO => blackhole; // LFO to modulate filter resonance saw1 => env => filter => Gain g => dac; // saw2 => env => filter; sqr1 => env; 0.1 => g.gain; // initialize amp EG env.set(40::ms, 10::ms, .6, 150::ms); // initialize filter EG step.next(1.0); filterEnv.duration(50::ms); // initialize filter LFOs freqLFO.period(8::second); qLFO.period(10::second); // initialize filter filter.freq(2000); filter.Q(2); fun void play(int pitch) { Std.mtof(pitch) / 4 => freq; // set frequencies saw1.freq(freq); sqr1.freq(2 * freq * 1.02); // slight detune for more harmonic content // activate EGs env.keyOn(); filterEnv.keyOn(); // wait for note to hit sustain portion of ADSR env.attackTime() + env.decayTime() => now; // deactivate EGs env.keyOff(); filterEnv.keyOff(); // wait for note to finish env.releaseTime() => now; } }