• fullscreen
  • ByteSynth.pde
  • PppArt.pde
  • PppProgram.pde
  • StringFunctions.pde
  •  import ddf.minim.*;
    import ddf.minim.signals.*;
    
    Minim minim;
    AudioOutput out;
    ByteSynth byteSynth;
    
    float frequencyScale = PI / 2;
    
    void setupSynth(PppProgram program) {
        minim = new Minim(this);
        out = minim.getLineOut(Minim.MONO, 1024, 44100 / 2);
        byteSynth = new ByteSynth(program);
        out.addSignal(byteSynth);
    }
    
    void stop() {
      out.close();
      minim.stop();
      super.stop();
    }
    
    class ByteSynth implements AudioSignal {
      PppProgram program;
      
      ByteSynth(PppProgram program) {
        this.program = program;
      }
      
      int curPosition = 0;
      int feedbackPosition = 0;
      void generate(float[] samp) {
        float sumPosition = 0;
        for(int i = 0; i < samp.length; i++) {
          sumPosition += program.loopGet(curPosition) * frequencyScale;
          samp[i] = sin(sumPosition);
          curPosition++;
        }
        frequencyScale = map(samp[feedbackPosition], -1, +1, -TWO_PI, +TWO_PI);
        feedbackPosition = (feedbackPosition + mouseY) % samp.length;
      }
      
      // this is a stricly mono signal
      void generate(float[] left, float[] right) {
        generate(left);
        generate(right);
      }
    }
    
    /*
      also, code == data
      but that's another project
    */
    
    PppProgram program;
    
    int zoom = 8;
    int sizeScale = 2;
    
    int updateRate = 256;
    int colorOffset = 8;
    
    void setup() {
      frameRate(30);
      size(1280 / sizeScale, 720 / sizeScale, P2D);
      
      program = new PppProgram();
      program.randomize();
      setupSynth(program);
    }
    
    void draw() {
      background(0);
      
      for(int i = 0; i < updateRate; i++)
        program.step();
        
      noStroke();
      int i = 0;
      for(int x = 0; x < width / zoom; x++) {
        for(int y = 0; y < height / zoom; y++) {
          color curColor = palette[abs(program.loopGet(i) + colorOffset) % palette.length];
          fill(curColor);
          rect(x * zoom, y * zoom, zoom, zoom);
          i++;
        }
      }
      
      frequencyScale = map(mouseX, 0, width, -TWO_PI, TWO_PI);
    }
    
    void mousePressed() {
      program.randomize();
    }
    
    int maxMemory = 256;
    int baseRefreshTime = 2 << 12;
    int refreshTime = baseRefreshTime;
    
    class PppProgram {
      TreeMap memory;
      int memoryPtr;
      String code;
      int codePtr;
      PppProgram(String code) {
        this();
        this.code = code;
      }
      PppProgram() {
        memory = new TreeMap();
        memoryPtr = 0;
        codePtr = 0;
      }
      
      synchronized void randomize() {
        int codeLength = (int) random(0, 2 << 12);
        int loops = (int) random(1, 128);
        code = randomCode(codeLength, loops);
        maxMemory = (int) random(2, 1024);
        //println("Made code: " + codeLength + "/" + loops + "/" + maxMemory);
        colorOffset = (int) random(0, 16);
      }
      
      void gotoMatchedBracket() {
        int count = 0;
        char cur = code.charAt(codePtr);
        int direction = cur == '[' ? +1 : -1;
        do {
          cur = code.charAt(codePtr);
          if(cur == '[')
            count++;
          if(cur == ']')
            count--;
          codePtr += direction;
        } while (count != 0);
      }
      
      int loopGet(int location) {
        if(maxLocation == 0)
          return 0;
        return get(location % maxLocation);
      }
      int get(int location) {
        location %= maxMemory;
        Integer value = (Integer) memory.get(location);
        if(value == null)
          return 0;
        else
          return (int) value;
      }
      int get() {
        return get(memoryPtr);
      }
      int maxLocation = 0;
      void set(int location, int newValue) {
        location %= maxMemory;
        if(location > maxLocation)
          maxLocation = location;
        memory.put(location, newValue);
      }
      void set(int newValue) {
        set(memoryPtr, newValue);
      }
      
      void plus() {
        set(get() + 1);
      }
      void minus() {
        set(get() - 1);
      }
      void left() {
        memoryPtr--;
      }
      void right() {
        memoryPtr++;
      }
      void startWhile() {
        if(get() == 0)
          gotoMatchedBracket();
      }
      void endWhile() {
        if(get() != 0)
          gotoMatchedBracket();
      }
      
      int size() {
        return code.length();
      }
      
      int steps = 0;
      void step() {
        if(codePtr < size() && codePtr >= 0) {
          char cur = code.charAt(codePtr);
          switch(cur) {
            case '+': plus(); break;
            case '-': minus(); break;
            case '<': left(); break;
            case '>': right(); break;
            case '[': startWhile(); break;
            case ']': endWhile(); break;
          }
          codePtr++;
        } 
        if(steps > refreshTime) {
          memory = new TreeMap();
          randomize();
          codePtr = 0;
          steps = 0;
          refreshTime = (int) (baseRefreshTime * random(0, 1));
        }
        steps++;
      }
    }
    
    String randomCode(int size, int loops) {
      String code = "";
      for(int i = 0; i < size; i++) {
        code += randomCommand();
      }
      for(int i = 0; i < loops; i++) {
        size = code.length();
        int left = (int) random(0, size - 1);
        code = insert(code, left, "[");
        int right = (int) random(left + 2, size + 1);
        code = insert(code, right, "]");
      }
      return replace(code, "\\[\\]", "");
    }
    
    String[] commands = {"<", ">", "+", "-"};
    String randomCommand() {
      float choice = random(0, 3);
      for(int i = 0; i < 4; i++)
        if(choice < i)
          return commands[i];
      return "";
    }
    
    String replace(String trunk, String oldText, String newText) {
      String[] parts = trunk.split(oldText);
      String newTrunk = "";
      for(int i = 0; i < parts.length - 1; i++) {
        newTrunk += parts[i] + newText;
      }
      newTrunk += parts[parts.length - 1];
      return newTrunk;
    }
    
    String insert(String trunk, int position, String branch) {
      return trunk.substring(0, position) + branch + trunk.substring(position, trunk.length());
    }
    
    color[] palette = {
      0xff888888,
      0xffffffff,
      0xff0000ff,
      0xff00ff00,
      0xffff0000,
      0xffffff00,
      0xff00ffff,
      0xffff00ff,
      0xff000000,
      0xff000088,
      0xff008800,
      0xff880000,
      0xff88ff00,
      0xff0088ff,
      0xffff0088,
      0xff888800,
      0xff008888,
      0xff880088,
      0xffff8800,
      0xff00ff88,
      0xff8800ff
    };
    

    code

    tweaks (0)

    about this sketch

    This sketch is running as Java applet, exported from Processing.

    license

    advertisement

    Kyle McDonald

    pppd

    Add to Faves Me Likey@! 20
    You must login/register to add this sketch to your favorites.

    pppd is a highly formalized audiovisual composition built around the esoteric programming language p'' ("p prime prime"). During each brief scene, a random sequence of p'' code is generated and run, while the memory it uses is visualized and sonified. pppd is an artistic re-imagining of the otherwise academic field of computability theory. It functions simultaneously as an investigation of complex behavior emerging from formally simple systems, and as a playful exploration of computational dreams.

    p'' is a subset of the programming language better known as Brainfuck.

    tacit dynamite
    6 Mar 2009
    Nice! I saw something like this at SPARK '08 and was super impressed - could that have been you ... ?
    http://spark.cla.umn.edu/schedule.html
    Kyle McDonald
    6 Mar 2009
    Unless someone recorded some of their own footage and submitted it, that wasn't me :) But if you saw something similar, perhaps I should submit this then?
    Luke Loeffler
    8 Oct 2010
    Enjoyed seeing your VIA talk at CMU--I forgot to ask if you'd considered adding a genetic algorithm to it to evolve more complicated sounds/visuals. Perhaps the fitness function could measure entropy or something.
    Kyle McDonald
    8 Oct 2010
    Thanks, Luke! I have considered it, but that metric would be really hard to describe. Using entropy would just make the images more "noisy" looking. Maybe a better metric would be Kolmogorov complexity? It'd try to evolve things that can't be expressed in simpler terms. I'm not sure how you would calculate the Kolmogorov complexity for an arbitrary p'' program, though...! Definitely check out Jonathan McCabe's work http://www.flickr.com/photos/33409576@N08/ he has done a lot with using GA to evolve visuals.
    Luke Loeffler
    8 Oct 2010
    I'm not familiar with Kolmogorov complexity--will read more.

    I'm curious if bioinformatics toolkits would be of any use as they're solved a lot of problems related to searching and comparing what are essentially long strings. Maybe helpful if searching for longest repetitive string.

    Also, I wonder if computing the DFT for the images may be of use--"noisy images" would have a lot of high frequency content, while things with interesting patterns would probably have more mid-frequency content.

    McCabe's work is pretty wild!
    Brendan Flynn
    5 Apr 2013
    wow
    You need to login/register to comment.