home

Image scanning sequencer


This sequencer scans images, and plays the image as midi notes.

It uses LDRs to measure the gray-scale of specific point of a image, and triggers midi notes from a selected threshold. When the threshold is reached the velocity will be set by the darkness at that point. the darker point the higher the velocity will be.

The sequencer plays the notes as a arpeggiator, i chose for this playback method because i dont have a midi device that can play 24 keys at the same time.. There are 2 different arpeggio modes. One rearranges the playback sequence to the active notes velocitys. And the second mode changes the arpeggio playback speed to the amount of notes that are active. If this mode is not selected the playback speed is set by a potentiometer. These modes can also be combined.

The sequencer has 24 LDRs that are read into 3 ADC ports of the arduino, via 3 4051 ics.

The image that i used for the midi sequence in the demo movie below, is a modified version of Treatise by Cornelius Cardew. And the instrument used to play the melody is a micro modular.

I also made script in PHP that generates images that can be played back on the sequencer. The script can be found here. (It is a smaller version then the one i printed, but every time it reloads it will be different).
A smaller version of this image is shown below..



I also added a script, so the scanner can be used to scan images.. You can see a example in the picture and demo movie below.
The scripts to scan images can be found here.
//Image Scan Sequencer, by: Gijs Gieskes 2008
//Copyleft: This is a free work, you can copy, distribute, and modify it
//under the terms of the Free Art License:
//http://artlibre.org/licence/lal/en/

//MIDI 
byte setNoteOn = 0x90;
byte setNoteOff= 0x80;

byte pitch = 65;
int velocity = 0;

int arpegiator = 0;
long prevMillis = 0;
byte stateArrCounter = 0;
byte arpCounter = 0;
byte prevPitch = 0;
boolean enableNoteOff = true;
boolean rearangeYesNo = false;
boolean arpegiatorYesNo = false;

boolean read11 = HIGH;
int noteOnRange = 0;

//multiplex variables
int multiArray[3][8] = {
                     {0,0,0,0,0,0,0,0},
                     {0,0,0,0,0,0,0,0},
                     {0,0,0,0,0,0,0,0}
                     };
                  
byte stateArray[3][24]= {
                      {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                      {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                      {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
                      };

void setup() {
  DDRB = DDRB | B00000111;  // 10, 9, 8 zijn outputs
  
  pinMode(11, INPUT);
  digitalWrite(11, HIGH);

  //baut reet:
  Serial.begin(31250);
  //Serial.begin(9600);
}

void loop() {
    
    //read multiplexor inputs
    readAnalogs();
    
    switcher();
    
    //bepaalt de hoeveelheid noten die gespeelt worden in de arpegio.
    stateArrCounter = 0;
    
    //modify/organize recieved data
    for(byte i=0; i<3; i++){
      for(byte j=0; j<8; j++){
        int avals = multiArray[i][j];
        velocity = (noteOnRange - avals);                 //inverse
        velocity = map(velocity, 0, noteOnRange, 0, 127); //bazeer de velocity op de noteOnRange.
        velocity = constrain(velocity, 0, 127);           //voor de zekerheid..
        
        if(avals <= noteOnRange){
          stateArray[0][stateArrCounter] = setNoteOn;
          stateArray[1][stateArrCounter] = pitch;
          stateArray[2][stateArrCounter] = velocity;
          stateArrCounter++;
        }else{
          stateArray[0][stateArrCounter] = setNoteOff;
        }

        pitch++;
      }
    }
    //als er weinig noten zijn word de arpegiator speed hoger.
    if(arpegiatorYesNo == true){
      arpegiator = (stateArrCounter*16)+10;
    }
    //re-organize and send data as arpegio
    if(millis() - prevMillis > arpegiator) {
       prevMillis = millis();
       
       if(rearangeYesNo == true){
         rearangeToVel();  //reanrange notes to velocity
       }
       
       arpCounter++;
       if(arpCounter >= stateArrCounter){arpCounter = 0;}
       
       byte arpOnOff = stateArray[0][arpCounter];
       byte arpInPitch = stateArray[1][arpCounter];
       byte arpInVel = stateArray[2][arpCounter];
       
       if(arpInPitch != prevPitch){
         sendMIDI(setNoteOn, arpInPitch, arpInVel);
       }
       
       if(arpCounter == 0 && arpOnOff == setNoteOff && enableNoteOff == true){
         sendMIDI(setNoteOff, arpInPitch, 0);                                     
         enableNoteOff = false;                                                  //set note off once
       }
       
       if(arpInPitch != prevPitch){                                              //turn off the last played note 
         sendMIDI(setNoteOff, prevPitch, 0);
         enableNoteOff = true;                                                   //set note off once 
       }

       prevPitch = arpInPitch;
    }
    
    //just some delay
    delay(8);
}

//http://itp.nyu.edu/physcomp/Labs/MIDIOutput
void sendMIDI(char sb, char data1, char data2) {
  Serial.print(sb, BYTE);
  Serial.print(data1, BYTE);
  Serial.print(data2, BYTE);
}

//lees de multiplex LDRs in
void readAnalogs(){
  for(byte i=0; i<8; i++){
    PORTB &= B11111000;
    PORTB |= i;                         //schijf naar poort 10,9,8 
    delayMicroseconds(3);               //geef de multiplexor de teid om te schakelen..
    multiArray[0][i] = analogRead(0);
    multiArray[1][i] = analogRead(1);
    multiArray[2][i] = analogRead(2);
  }
}

//http://www.arduino.cc/playground/Main/DigitalSmooth
void rearangeToVel(){
  boolean done = 0;                // flag to know when were done sorting    
  byte temp0 = 0;
  byte temp1 = 0;
  byte temp2 = 0;
  while(done != 1){        // simple swap sort, sorts numbers from lowest to highest
    done = 1;
    for (byte j = 0; j < (stateArrCounter - 1); j++){
      if (stateArray[2][j] > stateArray[2][j + 1]){     // numbers are out of order - swap
        temp0 = stateArray[0][j + 1];
        temp1 = stateArray[1][j + 1];
        temp2 = stateArray[2][j + 1];
        stateArray[0][j+1] =  stateArray[0][j] ;
        stateArray[1][j+1] =  stateArray[1][j] ;
        stateArray[2][j+1] =  stateArray[2][j] ;
        stateArray[0][j] = temp0;
        stateArray[1][j] = temp1;
        stateArray[2][j] = temp2;
        done = 0;
      }
    }
  }
}

void switcher(){
  read11 = digitalRead(11);
  int Aread4T = analogRead(4);
  int Aread5T = analogRead(5);
  if(read11 == LOW){
    if(Aread4T < 512){
      noteOnRange = Aread5T/2;
      pitch = 65;
    }else{
      //switch to select different types of playback (rearange to vel and vel dendant speed).
      if(Aread5T < 255){
        rearangeYesNo = true;
        arpegiatorYesNo = false;
      }else if(Aread5T < 512 && Aread5T >= 255){
        rearangeYesNo = false;
        arpegiatorYesNo = true;
      }else if(Aread5T < 765 && Aread5T >= 512){
        rearangeYesNo = false;
        arpegiatorYesNo = false;
      }else{
        rearangeYesNo = true;
        arpegiatorYesNo = true;
      }
      pitch = 65;
    }
  }else{
    pitch = (Aread5T/10)+1;
    arpegiator = ((1023 - Aread4T)/2)+1;
  }
}

image-scanner
image-scans
schematics
hand-held-scanner
edited-treatise-partituur

Copy "ilovegijs" here: (it stops spam bots)
Put your here:
1977 B.C. till 2010 © Gijs Gieskes - about