Skip to content

Instantly share code, notes, and snippets.

@kylemcdonald
Created January 7, 2014 19:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kylemcdonald/8305512 to your computer and use it in GitHub Desktop.
Save kylemcdonald/8305512 to your computer and use it in GitHub Desktop.
Simulation of synthesizer built from 256 perfect logic gates with 32 fixed inputs.
#include "ofMain.h"
// what happens when we can look back in time? i.e., add delays to io?
// this can be modeled with one pass-through-gate or two not-gates.
// or with a single and-gate with both inputs connect to the same output.
// what happens when the the circuit can control its own topology?
// this can be modeled with a very large circuit that switches between sub-circuits
// what happens when we use gates with more than two inputs?
// this can be modeled with a sub-circuit
// what happens when gates have floating point values with schmitt triggers?
// not sure that this can be modeled.
// how does distance from the inputs affect the randomness of the behavior?
// this can be evaluated much faster for large circuits on the GPU.
typedef bool (*Operation) (bool, bool);
bool bool_or(bool a, bool b) {return a || b;}
bool bool_nor(bool a, bool b) {return !(a || b);}
bool bool_and(bool a, bool b) {return a && b;}
bool bool_nand(bool a, bool b) {return !(a && b);}
bool bool_xor(bool a, bool b) {return a ^ b;}
bool bool_xnor(bool a, bool b) {return !(a ^ b);}
class HasOutput {
private:
bool output, bufferedOutput;
protected:
void bufferOutput(bool output) {
this->bufferedOutput = output;
}
void updateOutput() {
this->output = this->bufferedOutput;
}
public:
HasOutput()
:output(false)
,bufferedOutput(false) {
}
bool getOutput() const {
return output;
}
};
class Input : public HasOutput {
public:
void setOutput(bool output) {
bufferOutput(output);
updateOutput();
}
};
class Gate : public HasOutput {
protected:
HasOutput *input0, *input1;
Operation operation;
public:
Gate()
:input0(NULL)
,input1(NULL)
,operation(NULL) {
}
void setOperation(Operation operation) {
this->operation = operation;
}
void setInput0(HasOutput& input) {
input0 = &input;
}
void setInput1(HasOutput& input) {
input1 = &input;
}
void evaluate() {
bufferOutput((*operation) (input0->getOutput(), input1->getOutput()));
}
void update() {
updateOutput();
}
};
template <class T>
T& randomElement(vector<T>& elements) {
return elements[ofRandom(0, elements.size())];
}
int n = 256;
int downsample = 1;
float volume = .1;
vector<Input> inputs(32);
vector<Gate> gates(n);
vector<Operation> operations;
class ofApp : public ofBaseApp {
public:
bool needToReset = false;
ofImage raw, img;
void setup() {
raw.allocate(gates.size(), n, OF_IMAGE_GRAYSCALE);
raw.setColor(ofColor::black);
img.allocate(gates.size(), n, OF_IMAGE_GRAYSCALE);
img.setColor(ofColor::black);
operations.push_back(&bool_or);
operations.push_back(&bool_nor);
operations.push_back(&bool_and);
operations.push_back(&bool_nand);
operations.push_back(&bool_xor);
operations.push_back(&bool_xnor);
reset();
ofSoundStreamSetup(2, 0, 44100, n, 4);
}
void reset() {
// randomly connect all the gates
for(int i = 0; i < n; i++) {
gates[i] = Gate();
gates[i].setOperation(randomElement(operations));
gates[i].setInput0(randomElement(gates));
gates[i].setInput1(randomElement(gates));
}
// connect and set all the inputs
for(int i = 0; i < inputs.size(); i++) {
inputs[i].setOutput(ofRandom(1) > .5);
randomElement(gates).setInput0(inputs[i]);
}
}
void update() {
img.update();
raw.update();
}
void draw() {
raw.draw(0, 0);
img.draw(n, 0);
}
void keyPressed(int key) {
if(key == ' ') {
needToReset = true;
}
}
void audioOut(float* input, int bufferSize, int nChannels) {
if(needToReset) {
reset();
needToReset = false;
}
int sqn = sqrt(n);
int mx = ofClamp(mouseX, 0, n - 1) / sqn, my = ofClamp(mouseY, 0, n - 1) / sqn;
int request = my * sqn + mx;
int totalIterations = bufferSize / downsample;
int duplicates = nChannels * downsample;
for(int i = 0; i < totalIterations; i++) {
// evaluate all gates
for(int j = 0; j < n; j++) {
gates[j].evaluate();
}
// update all gates
for(int j = 0; j < n; j++) {
gates[j].update();
}
// save state to image
for(int j = 0; j < n; j++) {
int xs = i % sqn, ys = i / sqn;
int xb = j % sqn, yb = j / sqn;
int x = xb * sqn + xs, y = yb * sqn + ys;
raw.setColor(x, y, gates[j].getOutput() ? ofColor::white : ofColor::black);
img.setColor(i, j, gates[j].getOutput() ? ofColor::white : ofColor::black);
}
float result = gates[request].getOutput() ? +volume : -volume;
for(int j = 0; j < duplicates; j++) {
input[i * duplicates + j] = result;
}
}
}
};
int main() {
ofSetupOpenGL(2 * n, n, OF_WINDOW);
ofRunApp(new ofApp());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment