LDR to Arduino to MIDI, URGENT!

Hi, we're new to the forum, sorry our first post is under such urgent circumstances!
We're trying to use photo-resistors to trigger midi notes however we've stumbled upon a few problems.

Ideally we need the LDR (photo-resistor) circuit to act more like a switch (simply triggering note-on values) rather than churning out continuous controller messages.
Having set up the LDR to divide the voltage between the +5v pin and ground (giving a continuous input value at analog pin 0), we want to create a statement which essentially says:
When the value at analog-0 goes above a set threshold, we want to trigger a single note on message.
We have studied every similar Arduino sketch we could find, however nothing seems to quite work out right for us.
We're getting very little in the way of note-on messages, lots of changes in midi channel, nothing consistent. basically... it's a complete mess.
We can be relatively flexible in terms of what the messages being transmitted are, as long as we get 2 clearly defined messages (which we can later transform into what we need in logic).

Internet findings that come 'closest' to success.

Circuit in use:
http://itp.nyu.edu/physcomp/Labs/MIDIOutput

Arduino code in use:
// by Tubedogg 12/2006; fabian at tubedogg.de

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1165833586

//This program reads up to 6 analog sensors / potentiometers ans converts the data to Midi-Controller messages
// define Switchpin:
#define switchPin 10
// define LED:
#define LEDpin 13

// Variables

// define variables for the controller data
int AnalogValue[6] = {0,0,0,0,0,0};

// define the "lastValue" variables
int lastAnalogValue[6] = {0,0,0,0,0,0};

// select the midi Controller Number for each input
int midiCCselect[6] = {1,2,3,4,5,6};

// select threshold for each analog input
int thresh[6] = {1,1,1,1,1,1};

// select number of desired analog inputs (max 6)
int input_no = 6;

void setup() {
// set the states of the I/O pins:
pinMode(switchPin, INPUT);
pinMode(LEDpin, OUTPUT);
// Set MIDI baud rate:
Serial.begin(31250);

}

// main program loop
void loop() {

for(int i=0;i<input_no;i++){

AnalogValue = (analogRead(i))/8; // read the value from the analog input and divide by 8 for range 0-127

  • // check if value is greater than defined threshold (good for resistive touchpads etc)*
    if ( AnalogValue >thresh ) {
    * // check if analog input has changed*
    if ( AnalogValue != lastAnalogValue ) {
    * //send control change on cc#i*
    midiCC(0xB0, midiCCselect_, AnalogValue*);
    // update lastAnalogValue variable*

    lastAnalogValue = AnalogValue*;*
    * //End if*
    * }
    //End if*

    * }*_

//End for
}
//End Loop
}
// This function sends a Midi CC.
void midiCC(char CC_data, char c_num, char c_val){
Serial.print(CC_data, BYTE);
Serial.print(c_num, BYTE);
Serial.print(c_val, BYTE);
}
We realise this code is for continuous controllers, however we're pretty sure it should be a simple case of setting up a threshold which splits the continuous data into an on/off message (of some kind, doesnt really matter if it's note data)
Apologies again for the urgency of this post, we're trying to get a piece complete for exhibition very soon and we cant seem to get past this point!
Any 'light' you can shed on your LDR problems would be greatly appreciated.
All the best,
HalGG :cry:

Your thresholds look low to me, but I don't know what sort of values you're expecting.

What sort of values does this print:

const int input_no = 6;

void setup() 
{
  Serial.begin (9600);
}

// main program loop
void loop() 
{
  for(int i = 0; i < input_no; i++) {
    Serial.print (i);
    Serial.print (" ");
    Serial.prinln (analogRead (i)/ 8);
  }
  delay (100);
}

BTW, please don't cross-post the same problem - it just wastes people's time.
Also, when posting code, please use the "#" (Code) button on the posting editor's toolbar.

Hi Groove, thanks a lot for your reply and apologies for the duplicate post. Having entered your code we got the following results through Logic and Serial Monitor. What do you make of them?

Thanks in advance


Click for full size - Uploaded with plasq's Skitch

Having set up the LDR to divide the voltage between the +5v pin and ground (giving a continuous input value at analog pin 0), we want to create a statement which essentially says:

How have you done this? It looks like you have just connected the LDR up without any pull up or pull down resistor.

This project does something very similar to what you are trying to do:-
http://www.thebox.myzen.co.uk/Hardware/MIDI_Footsteps.html

Thanks for the input.

Picking apart the web a hand full of sites quote:
The arduino has built-in pullup resistor. That seems worth a mention.
Comment by Josiah — August 9, 2009 @ 7:33 pm

http://www.google.co.uk/imgres?imgurl=http://www.roguescience.org/wordpress/images/pullupdown.png&imgrefurl=http://roguescience.org/wordpress/%3Fpage_id%3D11&usg=__nTZbRC_UVVKpnuRLKCBloeJNao0=&h=681&w=476&sz=22&hl=en&start=6&sig2=nLBKcNEGvWCCStZu2-s_-A&um=1&itbs=1&tbnid=v-YYt4T9J6EFDM:&tbnh=139&tbnw=97&prev=/images%3Fq%3Dpull%2Bup%2Bpull%2Bdown%2Bresistor%26um%3D1%26hl%3Den%26safe%3Doff%26sa%3DG%26tbs%3Disch:1&ei=WtchTIS8OMqjOOOUoN8P

Am I being misled?

Can a variable resistor [50k-100k] make up for the absence?

Thanks again for the link. Attempting to make sense of the schematic as I type.

No, you're not being misled, you're just not using the built-in pullups.

Can a variable resistor [50k-100k] make up for the absence?

Why variable?

Apologies Grumpy_Mike. Unsure in which site to side with I started to consider I'd need a another component to make up for the pull up - pull down until Groove cleared that one up. Thanks.

New question, can there be a particular reason why Tubedogg removed or purposely left out the internal pull down - up command?
In Tubedogg's original where might pull down etc benefit our situation? I keep getting corrected by Arduino to the point I have no code left.

//This program reads up to 6 analog sensors / potentiometers ans converts the data to Midi-Controller messages
// define Switchpin:
#define switchPin 10
//  define LED:
#define LEDpin 13

// Variables

// define variables for the controller data
int AnalogValue[6] = {0,0,0,0,0,0};    

// define the "lastValue" variables
int lastAnalogValue[6] = {0,0,0,0,0,0};

// select the midi Controller Number for each input
int midiCCselect[6] = {1,2,3,4,5,6};

// select threshold for each analog input  
int thresh[6] = {1,1,1,1,1,1};  

// select number of desired analog inputs (max 6)
int input_no = 6;

void setup() {
//  set the states of the I/O pins:
pinMode(switchPin, INPUT);
pinMode(LEDpin, OUTPUT);
//  Set MIDI baud rate:
Serial.begin(31250);

}

// main program loop
void loop() {

for(int i=0;i<input_no;i++){

        AnalogValue[i] = (analogRead(i))/8;    // read the value from the analog input and divide by 8 for range 0-127
    // check if value is greater than defined threshold (good for resistive touchpads etc)
    if ( AnalogValue [i]>thresh[i] ) {
          // check if analog input has changed
          if ( AnalogValue[i] != lastAnalogValue[i] ) {

          //send control change on cc#i
          midiCC(0xB0, midiCCselect[i], AnalogValue[i]);
          // update lastAnalogValue variable
          lastAnalogValue[i] = AnalogValue[i];

          //End if
          }
      //End if
    }
 

//End for
}


//End Loop
}



// This function sends a Midi CC.
void midiCC(char CC_data, char c_num, char c_val){
Serial.print(CC_data, BYTE);
Serial.print(c_num, BYTE);
Serial.print(c_val, BYTE);

}

Thanks again for the support so far.

an there be a particular reason why Tubedogg removed or purposely left out the internal pull down - up command?

There is no internal pull down resistor so that is a good reason for leaving it out.
The internal pull up resistor is ill defined and can be any value between 20K and 50K, it is useful for digital input pins but I am not sure they work when the pin is in analogue mode. You are better to put an external resistor into the circuit because then you can have it the value you need not the value you have. Look at the pull up arrangements on my MIDI footsteps, that contains some circuit protection as well.

I keep getting corrected by Arduino to the point I have no code left.

Can you explain that please?

Thanks for the patience. It's easy to tell I couldn't be more amateur.

Trying to apply Grumpy_Mikes suggestion of a pull up and Grooves link to the necessary coding. I attempted to apply it to Tubedoggs current code. Arduino kept spotting errors. Can it even be applied or should I pursue other alternatives?

Well I would suggest you go with my code because it does almost exactly what you want. That is there is a threshold that when it is exceeded sends a MIDI note on and when it drops below it plus some hysteresis sends a MIDI note off.

If the arduino spots errors then that means that the code is way out. These are called compile errors and is only the first step in getting a program to do what you want. Just because something compiles doesn't mean it will work.

Can I find the coding on the stepper link? All that was accessible to me was the schematics to the stepper circuit.

Is it possible to link me to your suggested coding from this thread?

Cheers again.

It's on the web page but here it is directly:-
http://www.thebox.myzen.co.uk/Hardware/MIDI_Footsteps_files/Footsteps%20Software.zip

Great thanks for the link, we've been through the code, however, we cannot isolate what is relevant to our circuit and what we are trying to achieve. What would you suggest in terms of simplicity. We simply need a single midi note on/off, no velocity etc and we have no need to multiplex our sensors.
We're trying to keep this as simple as possible, would another way of creating a 'switch' from the LDR be to use a funtion like:

map (analogRead(rangePot), 0, 1023, 0, 1);

and then use the mapped value as a 'virtual' switch?
ie, when the value is '0', it will trigger a note-off message and when '1', a note-on will be triggered.

This doesn't solve our problem of constant streaming of data, however I think it's possibly the simplest way of transforming the LDR into a 'switch'

Apologies again for the stupidity that we're displaying here,it's safe to say we're out of our depth!!
Your help is greatly appreciated!!
Cheers
HalGG

We simply need a single midi note on/off, no velocity etc

You have to have velocity otherwise the MIDI protocol doesn't work. You don't need it and neither do I so you set it to a constant.

we have no need to multiplex our sensors.

so are you using all the analogue inputs?

Don't use the map function that will not help you here as you have no hysteresis.
Have you set the threshold to the values you are getting from your sensor?

Have a look at this, a quick hack to remove the multiplexing stuff:-

/* Midi read analogue - Mike Cook Feb 2010
 *
 * ----------------- 
 * send MIDI serial data, for multiplexed pressure pad sensors
 * 
 * 
###############################################################################################

HARDWARE NOTE:
The MIDI Socket is connected to arduino TX through a PNP transistor to invert the MIDI signal.

 *  Output MIDI CC values from 16 to 32 (depending on what sensor is triggered) 
    with a value of 0 or 127 depending if the sansor returns
    a number greater than or less than that held in the threshold variable.

################################################################################################
*/
// Includes
#include <avr/pgmspace.h>
#define midiChannel (byte)0
// Variable definations
int currentState[6]; // current state of sensors
int lastState[6];    // the last state of the sensors
int threshold = 0x90;  // sets the threshold value in deciding if a sensor is pressd.
int lastLedVal;
char control[6] = { 16, 17, 18, 19, 20, 21};



// #define MIDI_TEST   // un comment for a test to format the data for the seril monitor

// Start of code
void setup() {
   lastLedVal = 0;

    doSensorScan();                                        // get initial states
   saveCurrentState();

 //  Setup serial / MIDI
#ifdef MIDI_TEST
     Serial.begin(9600);    // Debug speed
#else
     Serial.begin(31250);       // MIDI speed
#endif
}

//********************* MAIN LOOP ***********************************

void loop() {
    doSensorScan();
    lookForChange();
    saveCurrentState();
 //   delay(400);
    } // end loop function
    
//********************* Functions *********************************** 

void doSensorScan() {  // look at all the sensors
 for(int i=0; i<6; i++){
   currentState[i] = analogRead(i); // read a/d values
 }  
}

void saveCurrentState(){  // save the current state for next time
  for(int i=0; i<6; i++){
    lastState[i] = currentState[i];
  }
}

void printCurrentSatae(){   // for debugging use
  Serial.print(" one ");
   for(int i=0; i<3; i++){
    Serial.print(currentState[i], HEX);
   Serial.print(" ");
   }
   Serial.println(" ");
     Serial.print(" two ");
      for(int i=0; i<3; i++){
    Serial.print(currentState[i+8], HEX);
   Serial.print(" ");
   }
}

// the value of threshold determins the on / off point
void lookForChange(){
  int ledVal = 0;
  int ledMask = 1;
  for(int i=0; i<6; i++){
    if(currentState[i] < threshold) ledVal |= ledMask;   // add a 1 in the position of sensors under threshold
     ledMask = ledMask << 1;
   }
   if(lastLedVal != ledVal) {   // something has changed
   ledMask = 1;
     for(int i=0; i<6; i++){
       if((ledMask & ledVal) != (ledMask & lastLedVal)){
         if((ledMask & ledVal) == 0) {
           // note off
           controlSend(0xB0, control[i], 0x00);   // turn off control message
         }
         else{
           // note on
           controlSend(0xB0, control[i], 0x7f);  // turn on control message
         }
       }
       ledMask = ledMask << 1;
     }

   }
   lastLedVal = ledVal;        // record current state of LEDs and MIDI notes / messages
}

//  plays a MIDI note

#ifdef MIDI_TEST
// This is a test so format data for viewing in the serial monitor
 void controlSend(char cmd, char data1, char data2) {
  cmd = cmd | char(midiChannel);  // merge channel number
  Serial.print(((cmd >> 4) & 0xf), HEX);  // to prevent leading Fs being displayed
  Serial.print((cmd & 0xf), HEX);
  Serial.print(" ");
  Serial.print(data1, HEX);
  Serial.print(" ");
  Serial.println(data2, HEX);
  
}
//  change the voice
 void programChange(char cmd, char data1) {
   cmd = cmd | char(midiChannel);  // merge channel number
   Serial.print(((cmd >> 4) & 0xf), HEX);  // to prevent leading Fs being displayed
   Serial.print((cmd & 0xf), HEX);
   Serial.print(" ");
   Serial.println(data1, HEX);
}
#else
  // no test so send the stuff out to MIDI
 void controlSend(char cmd, char data1, char data2) {
  cmd = cmd | char(midiChannel);  // merge channel number
  Serial.print(cmd, BYTE);
  Serial.print(data1, BYTE);
  Serial.print(data2, BYTE);
}
//  change the voice
 void programChange(char cmd, char data1) {
  cmd = cmd | char(midiChannel);  // merge channel number
  Serial.print(cmd, BYTE);
  Serial.print(data1, BYTE);
}
#endif

//  change the bank
void bankChange(char cmd, char data1) {
  Serial.print(0xB0 | char(midiChannel), BYTE);  // control change
  Serial.print(cmd, BYTE);
  Serial.print(data1, BYTE);
}

Grumpy_Mike thanks again.
Is there a chance in adapting the coding around whats provided in the link below? Again it's about simplicity and getting the most out of what little equipment and time we have!

http://www.arduino.cc/playground/Learning/PhotoResistor

halGG

Yes that input system will work with the code I posted.

You need to see what sort of change you are getting by putting the code into debug mode and printing the outputs. Then go and change the threshold value in the code to half way between the values you want.
The code sends CC events, it is easy to change that to note on / note off event number (0x80 and 0x90) in the calls to controlSend() (the first parameter)

Hi Mike,
Thanks again for the help, it's beginning to feel like we're back on target (although probably a long way off still!)
We were just wondering what the reason behind inverting the midi output is? We don't have a PNP transistor to hand, only NPN's which is frustrating, is it actually necessary to invert it or would we be able to just hook it up like the midi output here

Cheers mike!
HalGG

Applying Grumpy_Mikes code with Arduino Playground - PhotoResistor circuit alongside a parallel circuit connecting the midi in and arduino together:
Skitch | Evernote

Recorded threshold values. A covered LRD = 1-3, concentrated light on LRD = 1002-1003

Thanks again,
HalGG

*/
// Includes
#include <avr/pgmspace.h>
#define midiChannel (byte)0
// Variable definations
int currentState[6]; // current state of sensors
int lastState[6];    // the last state of the sensors
int threshold = 0x40;  // sets the threshold value in deciding if a sensor is pressd.
int lastLedVal;
char control[6] = { 16, 17, 18, 19, 20, 21};



// #define MIDI_TEST   // un comment for a test to format the data for the seril monitor

// Start of code
void setup() {
   lastLedVal = 0;

    doSensorScan();                                        // get initial states
   saveCurrentState();

 //  Setup serial / MIDI
#ifdef MIDI_TEST
     Serial.begin(9600);    // Debug speed
#else
     Serial.begin(31250);       // MIDI speed
#endif
}

//********************* MAIN LOOP ***********************************

void loop() {
    doSensorScan();
    lookForChange();
    saveCurrentState();
 //   delay(400);
    } // end loop function

//********************* Functions ***********************************

void doSensorScan() {  // look at all the sensors
 for(int i=0; i<6; i++){
   currentState[i] = analogRead(i); // read a/d values
 }
}

void saveCurrentState(){  // save the current state for next time
  for(int i=0; i<6; i++){
    lastState[i] = currentState[i];
  }
}

void printCurrentSatae(){   // for debugging use
  Serial.print(" one ");
   for(int i=0; i<3; i++){
    Serial.print(currentState[i], HEX);
   Serial.print(" ");
   }
   Serial.println(" ");
     Serial.print(" two ");
      for(int i=0; i<3; i++){
    Serial.print(currentState[i+8], HEX);
   Serial.print(" ");
   }
}

// the value of threshold determins the on / off point
void lookForChange(){
  int ledVal = 0;
  int ledMask = 1;
  for(int i=0; i<6; i++){
    if(currentState[i] < threshold) ledVal |= ledMask;   // add a 1 in the position of sensors under threshold
     ledMask = ledMask << 1;
   }
   if(lastLedVal != ledVal) {   // something has changed
   ledMask = 1;
     for(int i=0; i<6; i++){
       if((ledMask & ledVal) != (ledMask & lastLedVal)){
         if((ledMask & ledVal) == 0) {
           // note off
           controlSend(0x90, control[i], 0x00);   // turn off control message
         }
         else{
           // note on
           controlSend(0x0, control[i], 0x7f);  // turn on control message
         }
       }
       ledMask = ledMask << 1;
     }

   }
   lastLedVal = ledVal;        // record current state of LEDs and MIDI notes / messages
}

//  plays a MIDI note

#ifdef MIDI_TEST
// This is a test so format data for viewing in the serial monitor
 void controlSend(char cmd, char data1, char data2) {
  cmd = cmd | char(midiChannel);  // merge channel number
  Serial.print(((cmd >> 4) & 0xf), HEX);  // to prevent leading Fs being displayed
  Serial.print((cmd & 0xf), HEX);
  Serial.print(" ");
  Serial.print(data1, HEX);
  Serial.print(" ");
  Serial.println(data2, HEX);

}
//  change the voice
 void programChange(char cmd, char data1) {
   cmd = cmd | char(midiChannel);  // merge channel number
   Serial.print(((cmd >> 4) & 0xf), HEX);  // to prevent leading Fs being displayed
   Serial.print((cmd & 0xf), HEX);
   Serial.print(" ");
   Serial.println(data1, HEX);
}
#else
  // no test so send the stuff out to MIDI
 void controlSend(char cmd, char data1, char data2) {
  cmd = cmd | char(midiChannel);  // merge channel number
  Serial.print(cmd, BYTE);
  Serial.print(data1, BYTE);
  Serial.print(data2, BYTE);
}
//  change the voice
 void programChange(char cmd, char data1) {
  cmd = cmd | char(midiChannel);  // merge channel number
  Serial.print(cmd, BYTE);
  Serial.print(data1, BYTE);
}
#endif

//  change the bank
void bankChange(char cmd, char data1) {
  Serial.print(0xB0 | char(midiChannel), BYTE);  // control change
  Serial.print(cmd, BYTE);
  Serial.print(data1, BYTE);
}