How to use Analog input to increment value by single step?

Hi,

I am working on a project called laser mouse instrument. It is based on laser harp and LOMAK(laser operated mouse and keyboard)
I use laser and LDRs to trigger midi signals

I shift through the array using inputs 8-11, but I am getting very large increments instead of single steps.

Is there any way I can use analog input increment by single step?

Thank You

#include <SoftwareSerial.h>

boolean notePlaying[8];  //note states array: keeps track of whether a MIDI note is "on" or "off"

int ldrNoteUp=8;
int ldrNoteDown=9;

int ldrScaleUp=10;
int ldrScaleDown=11;



int scales[7][8]={
             {0,2,4,5,7,9,11,12}, // major
             {0,2,3,5,7,9,10,12},// minor
             {0,2,5,7,9,12,14,17}, // pentatonic
             {0,7,12,19,24,31,36}, //5th arpeggio
             {0,4,7,12,16,19,24}, //3th arpeggio
             {0,4,7,11,12,16,19,23}, // major 3rd,5th,major 7th arpeggio
             {0,3,5,6,7,10,12,15} //Blues
               };
int scale=0;

int ledPins[] = {22,23,24,25,26,27,28,29};

int beginNote=60;                                  //starting note value (default middle C)

int threshold=100;                                //value which analogRead() must cross for a midi note to be triggered

      

SoftwareSerial midiSerial(2, 3);
void setup(){
 //  Set MIDI baud rate:
   Serial.begin(9600);
     midiSerial.begin(31250);
 }
 


void loop() { 
 for(int i=0;i<8;i++){   
   
   if((analogRead(i)>threshold)&&(notePlaying[i]==false)){ 
         int note=beginNote+scales[scale][i];
         midiMessage(0x90, note, 120); 
         digitalWrite(ledPins[i], HIGH);                          
         notePlaying[i]=true;  
                                      
   }
   
   if((analogRead(i)<threshold)&&(notePlaying[i]==true)) {    
         int note=beginNote+scales[scale][i];
         midiMessage(0x80, note, 0);
         digitalWrite(ledPins[i], LOW);
         notePlaying[i]=false;   
                                         
     }
 }
 if ((analogRead(ldrNoteUp)>100)&&(beginNote<100)){beginNote+=1;}
 Serial.print("beginNote: ");
 Serial.println(beginNote); 

   
 if ((analogRead(ldrNoteDown)>100)&&(beginNote>0)){beginNote-=1;}
 if ((analogRead(ldrScaleUp)>100)&&(scale<8)){scale+=1;}
 if ((analogRead(ldrScaleDown)>100)&&(scale>0)){scale-=1;}
}





void midiMessage(int commandByte, int data1Byte, int data2Byte) {
 //if(midiMode){
   midiSerial.write(commandByte);
   midiSerial.write(data1Byte);
   midiSerial.write(data2Byte);

   Serial.print("Command byte: ");
   Serial.print(commandByte);
   Serial.print(", data1Byte: ");
   Serial.print(data1Byte);
   Serial.print(", data2Byte: ");
   Serial.println(data2Byte);

Hello,

can you please advise if there is a way get single step increments for beginNote and scale at pins 8-11?

Thank You.

#include <SoftwareSerial.h>

boolean notePlaying[8];  //note states array: keeps track of whether a MIDI note is "on" or "off"

int ldrNoteUp=8;
int ldrNoteDown=9;

int ldrScaleUp=10;
int ldrScaleDown=11;



int scales[7][8]={
            {0,2,4,5,7,9,11,12}, // major
            {0,2,3,5,7,9,10,12},// minor
            {0,2,5,7,9,12,14,17}, // pentatonic
            {0,7,12,19,24,31,36}, //5th arpeggio
            {0,4,7,12,16,19,24}, //3th arpeggio
            {0,4,7,11,12,16,19,23}, // major 3rd,5th,major 7th arpeggio
            {0,3,5,6,7,10,12,15} //Blues
              };
int scale=0;

int ledPins[] = {22,23,24,25,26,27,28,29};

int beginNote=60;                                  //starting note value (default middle C)

int threshold=100;                                //value which analogRead() must cross for a midi note to be triggered

     

SoftwareSerial midiSerial(2, 3);
void setup(){
//  Set MIDI baud rate:
  Serial.begin(9600);
    midiSerial.begin(31250);
}



void loop() { 
for(int i=0;i<8;i++){   
  
  if((analogRead(i)>threshold)&&(notePlaying[i]==false)){ 
        int note=beginNote+scales[scale][i];
        midiMessage(0x90, note, 120); 
        digitalWrite(ledPins[i], HIGH);                          
        notePlaying[i]=true;  

        Serial.print("beginNote:");
        Serial.print(beginNote);
        Serial.print(" ,scale:");
        Serial.println(scale);                                         
  }
  
  if((analogRead(i)<threshold)&&(notePlaying[i]==true)) {    
        int note=beginNote+scales[scale][i];
        midiMessage(0x80, note, 0);
        digitalWrite(ledPins[i], LOW);
        notePlaying[i]=false;   
                                        
    }
}
if ((analogRead(ldrNoteUp)>100)&&(beginNote<100)){beginNote+=1;}
Serial.print("beginNote: ");
Serial.println(beginNote); 

  
if ((analogRead(ldrNoteDown)>100)&&(beginNote>0)){beginNote-=1;}
if ((analogRead(ldrScaleUp)>100)&&(scale<8)){scale+=1;}
if ((analogRead(ldrScaleDown)>100)&&(scale>0)){scale-=1;}
}





void midiMessage(int commandByte, int data1Byte, int data2Byte) {
//if(midiMode){
  midiSerial.write(commandByte);
  midiSerial.write(data1Byte);
  midiSerial.write(data2Byte);

  Serial.print("Command byte: ");
  Serial.print(commandByte);
  Serial.print(", data1Byte: ");
  Serial.print(data1Byte);
  Serial.print(", data2Byte: ");
  Serial.println(data2Byte);

Please read these two posts:

How to use this forum - please read.
and
Read this before posting a programming question …
You have posted code without using code tags. The code tags make the code look

like this

when posting source code files. It makes it easier to read, and can be copied with a single mouse click. Also, if you don’t do it, some of the character sequences in the code can be misinterpred by the forum code as italics or funny emoticons like the little guy with the sunglasses above.
If you have already posted without using code tags, open your message and select “modify” from the pull down menu labelled, “More”, at the lower left corner of the message. Highlight your code by selecting it (it turns blue), and then click on the “</>” icon at the upper left hand corner. Click on the “Save” button.

Do you see that half your code is in italics and you have a smilie face? Please use code tags.

You get large increments because you use a single threshold and an analogue reading can oscillate arround that threshold.

Use some hysteresis and have a different threshold for going up than you do for going down.

Read the rules, use code tags.

Thank you.

Hi, sorry bout the formatting.

@Grumpy_Mike:

I think I get large increments because the note and scale are being incremented as many as long as the loop keeps counting. I've tried to use delay, but its not feasible option. And using millis just delayed the reading and still produced the same increments. The difference between threshold is nearly 300 so I dont believe adjusting will solve. Do you have any idea how I could use the sensor just to trigger, not count the time length?

Thanx a lot for your help

What Arduino board are you using?

The Uno only has 6 analog inputs A0 to A5

...R

Mega

here is a general way to do it.

if the old setting is not the same as the current setting setting_flag=HIGH

if setting_flag==HIGH increment once setting_flag=LOW

...

current_setting = old setting; } // end of void loop

The difference between threshold is nearly 300 so I dont believe adjusting will solve.

Not on the code you posted it isn't. Have you got it the right way.

dave-in-nj is quite right though, you only want to increment when you turn the note on, not every time through the loop.

@dave-in-nj: yes, I am trying to rewrite the code that way, but I think i used something similar yesterday, when I tried to implement debounce using millis, but didn't quite work, but i'll give it another shot. Thanx a lot for suggestion

@Grumpy_Mike: Hi Mike. I think I need to clarify, what I meant by 300 value: The LDRs are in dark tubes so in idle state the value is around 4-10, when they get hit by laser it rises to roughly 300, picked 100 threshold to keep enough slack for most light conditions and still have plenty of overhead room for trigger. That's basically lazy way to avoid writing code for calibration....

The setup: The 8 LDR's trigger notes fine, as long as the laser is shining on the they play note. Problems is the the additional 4 LDRs I want to use for scrolling up/down the array and shifting beginNote. They need to trigger only once and add +1 at single event, once triggered the scale and beginNote stays the same so doesnt effect the response of 8 notes only changes the position in array.

Thanx again

when they get hit by laser it rises to roughly 300, picked 100 threshold to keep enough slack for most light conditions and still have plenty of overhead room for trigger.

No, what happens is when the signal rises it does not rise instantaneously it can dither around the threshold mark. So use a threshold of say 200 for going up and 100 for goinf down.

@Grumpy_Mike: Hi, I actually can pushed the threshold to 300 and the increments are much slower, but if the sensors gets direct hit from the beam, it will jump up the same way as before. Even when I look at the serial monitor the values for beginNote count really fast.

Is this the same project as in your other Thread?

If so, please ask the moderator to merge the Threads so all the info is in one place.

...R

I wasn’t sure the title of thread was right, I have contacted the moderator.

Still no progress with the problem though :frowning:

Threads merged.

Sigh!

currentRead = analogRead(ldrNoteDown);
if( currentRead>100)&&(beginNote>0) && lastRead < 100){beginNote-=1;}
lastRead = currentRead;

Apply this technique to all variables that you only want to change on an edge not a level.

Sorted :slight_smile:

if ((analogRead(i) < threshold) && (notePlaying[i] == true)) {
      int note = beginNote + scales[scale][i];
      midiMessage(0x80, note, 0);
      digitalWrite(ledPins[i], LOW);
      notePlaying[i] = false;

    }

thanx for help everybody