July 3, 2014
Shifting

Shifting

June 11, 2014

PureDatrocessarduinoMOS - A workshop

June 14th + 15th in NYC @Harvestworks for the Dark Circuits Festival

Sign up here: http://tammen.org/workshop-pure-datrocessorduinomos/

(Source: vimeo.com)

May 16, 2014
[Jun 14/15] Workshop Pure DatrocessorduinoMOS

A crash course in building connections between Pure Data or Processing and DIY CMOS circuits using Arduino. This is a really fun way of learning how to integrate software based interfaces, custom code, and physical hardware through music! Don’t worry if you’re not a seasoned expert in any of these areas. Beginners are welcome! Examples will be provided and explained along with brief introductions to the systems/environments and how to explore them further on your own. This workshop is part of the Dark Circuits Festival 2014. http://www.darkcircuitsfestival.com

April 23, 2014

adamkilledeve said: You sir, are a pioneer. I was wondering if you would be so kind as to make the source code for your chris christie pixel sorting piece available? that would be amazing and helpful. (I am struggling to learn processing, and any help would be greatly appreciated) Thank you!

/*
RGB Sorting

Made in Processing 2.1.2
By Phillip Stearns

A less glitchy approach to pixel sorting.

Part of the glitchiness, or glitch-like look and feel of Kim Asendorf's
brilliant ASDFPixelSort lies in the fact that when you apply the sort()
method to an array of pixels, you're actually sorting according to the
numeric value of that pixel. Processing treats the color of a pixel
as a single 32 bit number, ordered ARGB in 24 bit colorspace w/ alpha.

A 100% opaque red pixel would have the binary representation of
11111111111111110000000000000000
Alpha  |  Red  | Green  | Blue   
^                              ^
|                              |
MSB                           LSB

MSB = most significant bit, like the 9 in 900 for those used to base ten counting
LSB = least significant bit, like the 1 in 5 million and 21.

This also means that red pixel is a bigger number than a green pixel, which
is greater than a blue pixel.

It's not so much based on a perceptual color evaluation; pixel sorting
looks the way it does because the sorting criteria is based on numbers alone,
which don't quite line up with perception. Why things look interesting when you sort pixels this way is
a result of how we use numbers to describe the color of a pixel.

THIS little program sorts the channels separately, which has a slightly
different, smoother effect overall. Rather than sort the pixels according to their ARGB value, RGBsort first breaks up the image into R G B channels, sorts them individually, then recombines them.  Have a look!
*/


PImage sourceImg;
int sortDirection;

void setup(){
  sourceImg = loadImage("random.jpg");
  size(sourceImg.width, sourceImg.height);
  noLoop(); //stops the draw from looping
  sortDirection = 0; //0 sorts all the rows, 1 sorts all the columns
}

void draw(){
  
  //switch lets us do different things for different cases 
  switch(sortDirection) {
    
    //ror sorting
    case 0: 
      for(int row = 0 ; row < sourceImg.height ; row++){
        RGBsortRow(sourceImg, row);
      }
      break;
    
    //column sorting
    case 1: 
      for(int col = 0 ; col < sourceImg.width ; col++){
        RGBsortColumn(sourceImg, col);
      }
      break;
  }
  
  //display the sorted image
  image(sourceImg, 0, 0);  
}


void RGBsortRow(PImage image, int row){
  
  int[] bufferR = new int[image.width];
  int[] bufferG = new int[image.width];
  int[] bufferB = new int[image.width];
  
  //make sure that the row number exists
  if (row < 0 || row >= height){
    //if it doesn't, please let me know
    println("Row value is out of range.");
  } else{
    //otherwise, please sort
    
    for(int i = 0; i < image.width ; i++){
      //basically we're walking through the row specified in the function arguments and separating the RGB values into their respective buffers
      //to do this, we use the bitwise >> or shift right operator and mask the extraneous bits with the & (AND) 0xFF or 11111111
      bufferR[i] = image.pixels[row*image.width+i] >> 16 & 0xFF;
      bufferG[i] = image.pixels[row*image.width+i] >> 8 & 0xFF;
      bufferB[i] = image.pixels[row*image.width+i] & 0xFF;
    }
    
    //sort the pixels in the buffers
    bufferR = sort(bufferR);
    bufferG = sort(bufferG);
    bufferB = sort(bufferB);
    
    //recombine the RGB values using the << shift left and | (OR) operator
    for(int j = 0; j < image.width ; j++){
      image.pixels[row*image.width+j] = (255 << 24) | (bufferR[j] << 16) | (bufferG[j] << 8) | (bufferB[j]);
    } 
  }
}


//the column sorting works in the same manner
void RGBsortColumn(PImage image, int column){
  int[] bufferR = new int[image.height];
  int[] bufferG = new int[image.height];
  int[] bufferB = new int[image.height];
  if (column < 0 || column >= width){
    println("Column value is out of range.");
  } else{
    for(int i = 0; i < image.height ; i++){
      bufferR[i] = image.pixels[i*image.width+column] >> 16 & 0xFF;
      bufferG[i] = image.pixels[i*image.width+column] >> 8 & 0xFF;
      bufferB[i] = image.pixels[i*image.width+column] & 0xFF;
    }
    bufferR = sort(bufferR);
    bufferG = sort(bufferG);
    bufferB = sort(bufferB);
    for(int j = 0; j < image.height ; j++){
      image.pixels[j*image.width+column] = (255 << 24) | (bufferR[j] << 16) | (bufferG[j] << 8) | (bufferB[j]);
    }
  }
}

April 21, 2014

April 21, 2014

January 30, 2014

RGB Channel Shifting

Top Image Source

Bottom Image Source

January 30, 2014

Sorting Governor Chris Christie

on left: sorting by 32bit ARGB color values

on right: sorting RGB channel values separately

Source Image

January 30, 2014

January 30, 2014
More pixel shifting experiments&#8230;
Source Image:
Processing Code:
//PixelShifting by Phillip Stearns 2014
PImage sourceImg;
int iteration;

void setup(){
  iteration=0;
  sourceImg = loadImage("shift.jpg");
  size(sourceImg.width, sourceImg.height);
}

void draw(){
  int yoffset = int(random(height));
  int xoffset= int(random(width));
  int randomRows= int(random(height)) - yoffset;
  int randomColumns=int(random(width)) - xoffset;
  
  for(int i = 0 ; i &lt; randomRows ; i++){
  shiftRow(sourceImg, i+yoffset, 15);
  }
  for(int j = 0 ; j &lt; randomColumns ; j++){
  shiftColumn(sourceImg, j+xoffset, 15);
  }
  image(sourceImg, 0, 0);
  sourceImg.save("shifted_" +nf(iteration, 3)+ ".png");
  iteration++;
}

void shiftRow(PImage image, int row, int shift){
  int[] buffer = new int[image.width];
  if (row &lt; 0 || row &gt;= height){
    println("Row value is out of range.");
  } else{
    for(int i = 0 ; i &lt; image.width ; i++){
      buffer[(i+shift) % (image.width)] = image.pixels[row*image.width+i];
    }
    for(int j = 0 ; j &lt; image.width ; j++){  

      sourceImg.pixels[row*image.width+j] = buffer[j];
    }
  }
  sourceImg.updatePixels();
}

void shiftColumn(PImage image, int column, int shift){
  int[] buffer = new int[image.height];
  if(column &lt; 0 || column &gt;= width){
    println("Column value is out of range.");
  }else{ 
    for(int i = 0 ; i &lt; image.height ; i++){
      buffer[(i+shift) % (image.height)] = image.pixels[i*image.width+column];
    }
    for(int j = 0 ; j &lt; image.height ; j++){  
      sourceImg.pixels[j*image.width+column] = buffer[j];
    }
  }
  sourceImg.updatePixels();
}

More pixel shifting experiments…

Source Image:

Processing Code:

//PixelShifting by Phillip Stearns 2014
PImage sourceImg;
int iteration;

void setup(){
  iteration=0;
  sourceImg = loadImage("shift.jpg");
  size(sourceImg.width, sourceImg.height);
}

void draw(){
  int yoffset = int(random(height));
  int xoffset= int(random(width));
  int randomRows= int(random(height)) - yoffset;
  int randomColumns=int(random(width)) - xoffset;
  
  for(int i = 0 ; i < randomRows ; i++){
  shiftRow(sourceImg, i+yoffset, 15);
  }
  for(int j = 0 ; j < randomColumns ; j++){
  shiftColumn(sourceImg, j+xoffset, 15);
  }
  image(sourceImg, 0, 0);
  sourceImg.save("shifted_" +nf(iteration, 3)+ ".png");
  iteration++;
}

void shiftRow(PImage image, int row, int shift){
  int[] buffer = new int[image.width];
  if (row < 0 || row >= height){
    println("Row value is out of range.");
  } else{
    for(int i = 0 ; i < image.width ; i++){
      buffer[(i+shift) % (image.width)] = image.pixels[row*image.width+i];
    }
    for(int j = 0 ; j < image.width ; j++){  

      sourceImg.pixels[row*image.width+j] = buffer[j];
    }
  }
  sourceImg.updatePixels();
}

void shiftColumn(PImage image, int column, int shift){
  int[] buffer = new int[image.height];
  if(column < 0 || column >= width){
    println("Column value is out of range.");
  }else{ 
    for(int i = 0 ; i < image.height ; i++){
      buffer[(i+shift) % (image.height)] = image.pixels[i*image.width+column];
    }
    for(int j = 0 ; j < image.height ; j++){  
      sourceImg.pixels[j*image.width+column] = buffer[j];
    }
  }
  sourceImg.updatePixels();
}

January 29, 2014
Playing with wrap around, pixel shift registers. Each row of pixels has been shifted a random amount.
Source Image

Playing with wrap around, pixel shift registers. Each row of pixels has been shifted a random amount.

Source Image

January 29, 2014
Image Source

Image Source

January 29, 2014

Toying around with averaging and sorting on RGB channels…

Source Image

January 27, 2014
Shift Registers and Ripple Counters

Shift Registers and Ripple Counters

January 26, 2014

//counter.pde by Phillip Stearns
//an exercise in creating composite objects in Processing
//logic circuit simulation

Counter counter;

void setup() {
  background(0);
  size(5, 5);
  counter = new Counter(height);
}

void draw() {
  saveFrame("counter_###.png");
  counter.clock();
  for (int x = 0 ; x < width ; x++) {    
    for (int y = 0 ; y < counter.length() ; y++) {
      counter.display(y, x, y);
    }
  }
  if (frameCount == pow(2,height)) {
    exit();
  }
}

/*********begin class definitions********/

//Counter is a class of objects that have n number of stages.
//The counter operates like a binary ripple counter similar to the CD4040.
//Creation arguments: int size
//Methods:
//clock() - increments the counter
//clock(boolean clockInput) - allows an external clock to increment the counter. triggered on "falling edge" transistion from true to false.
//reset() - sets all stages to false
//display() - prints the counter's internal state from Least significant bit to Most significant bit from left to right (reverse binary)
//display(int Q, int x, int y) - changes the pixel at the coordinates x, y to match the output state of stage Q
//length() returns int - number of stages in the current counter
//getState(int Q) - returns boolean - the value of stage Q


class Counter {
  FlipFlop[] register;

  Counter(int size) {
    register = new FlipFlop[size];
    for (int i = 0 ; i < register.length ; i++) {
      register[i] = new FlipFlop();
    }
  }

  void reset() {
    for (int i = 0 ; i < register.length ; i++) {
      register[i].reset();
    }
  }

  int length() {
    return register.length;
  }

  void clock() {
    for (int i = 0; i < register.length ; i++) {
      if (i == 0) {
        if (register[0].getState() == true) {
          register[0].setState(false);
        } 
        else if (register[0].getState() == false) {
          register[0].setState(true);
        }
      } 
      else if (i > 0) {
        register[i].flip(register[i-1].getState());
      }
    }
  }

  void clock(boolean clockInput) {
    for (int i = 0; i < register.length ; i++) {
      if (i == 0) {
        register[0].flip(clockInput);
      } 
      else if (i > 0) {
        register[i].flip(register[i-1].getState());
      }
    }
  }

  boolean getState(int Q) {
    return register[Q].getState();
  }

  void display() {
    for (int i = 0 ; i < register.length ; i++) {
      print(int(register[i].getState()));
    }
    println();
  }

  void display(int Q, int x, int y) {
    loadPixels();
    pixels[y*width + x]=color(int(register[Q].getState())*255);
    updatePixels();
  }

  //FlipFlop is a clas of objects that behave like flipflop logic circuits.
  //Creation arguments: boolean init - sets initial state (optional)
  //Methods:
  //flip(boolean clock) - causes the flipflop to change states. triggered by "falling edge", true to false, logic transistion.
  //setState(boolean set) - sets register to set
  //reset() - resets register state to false
  //getState() - returns boolean - the value of the state
  
  class FlipFlop {  
    boolean state;
    boolean currentClock;
    boolean previousClock;

    FlipFlop() {
      state=false;
    }

    FlipFlop(boolean init) {
      state=init;
    }

    void flip(boolean clock) {
      currentClock = clock;
      if (currentClock == false && previousClock == true) {
        if (state == true) {
          state = false;
        } 
        else if (state == false) {
          state = true;
        }
      }
      previousClock = currentClock;
    }

    void setState(boolean set) {
      state = set;
    }

    void reset() {
      state = false;
      currentClock = false;
      previousClock = false;
    }

    boolean getState() {
      return state;
    }
  }
}