// Karplus Strong circuit simulator // Copyright 2010 Les Hall float CV; float CVprev; class KarplusStrong { // the patch Step step => Gain sum => LPF lpf => dac; lpf => Gain feedback => Dyno limiter => DelayA delay => sum; limiter.limit(); 100::ms => delay.max; fun void set(dur dly, float freq, float fb) { dly => delay.delay; freq => lpf.freq; fb => feedback.gain; } fun void stim(float amplitude) { amplitude => step.next; 3::ms => now; 0 => step.next; } } class BooleanSequencer { [[0, 1], [0, 1], [0, 1], [0, 1]] @=> int inputSwitches[][]; [2, 2, 2, 2] @=> int gateSwitches[]; [[0, 0], [0, 4], [4, 8], [8, 8]] @=> int offsets[][]; int masks[4][2]; int inputs[4][2]; int gateOutputs[4]; float sum; int c; (Math.pow(2, 12) - 1) $ int => int bitMask; int gate; fun void set(int inputs[][], int gates[]) { inputs @=> inputSwitches; gates @=> gateSwitches; } fun void mainLoop() { // generate masks for (int i; i<4; i++) { for (int j; j<2; j++) { (1 << offsets[i][j]) << inputSwitches[i][j] => masks[i][j]; } } // find input values for (int i; i<4; i++) { for (int j; j<2; j++) { if (masks[i][j] & c) { true => inputs[i][j]; } else { false => inputs[i][j]; } } } // calculate outputs for (int i; i<4; i++) { if (gateSwitches[i] == 0) { !(inputs[i][0] | inputs[i][1]) => gateOutputs[i]; } if (gateSwitches[i] == 1) { !(inputs[i][0] & inputs[i][1]) => gateOutputs[i]; } if (gateSwitches[i] == 2) { (inputs[i][0] ^ inputs[i][1]) => gateOutputs[i]; } if (gateSwitches[i] == 3) { (inputs[i][0] & inputs[i][1]) => gateOutputs[i]; } } // sum the weighted output selections 0 => sum; for (int i; i<4; i++) { Math.pow(2.0, -i) * gateOutputs[i] +=> sum; } // add to the CV sum +=> CV; if (sum == 0) { 0 => gate; } else { 1 => gate; } 1 +=> c; bitMask & c => c; } } BooleanSequencer BS[2]; BS[0].set([[0,1],[0,1],[0,1],[0,1]], [3,2,1,0]); BS[1].set([[2,3],[1,3],[1,2],[0,3]], [0,1,2,3]); KarplusStrong KS; while(true) { CV => CVprev; 0 => CV; BS[0].mainLoop(); BS[1].mainLoop(); KS.set((12.8*CV)::ms, 2000*CV, 0.85); KS.stim(CV - CVprev); 250::ms => now; }