Sharp IR sensor to MIDI. Tutorial? Help.

I´m working with a project involving my Arduino UNO, a Sharp IR sensor (4-30 cm) and my "KORG volca keys" synthesizer. I want to use the sensor to control my synthesizer with MIDI-signals.

I have earlier succeed doing this ^^ using an Ultra sonic sensor. But now I am looking for a tutorial or some help with doing the same thing but this time using the IR sensor.

I'm a totally newbie so I appreciate all advises and help I can get 8)

I have earlier succeed doing this ^^ using an Ultra sonic sensor.

Good.

But now I am looking for a tutorial or some help with doing the same thing but this time using the IR sensor.

Why?

Just substitute one for the other.

Post the code where you have tried this and it didn't work.

Grumpy_Mike:
Good.
Why?

Just substitute one for the other.

Post the code where you have tried this and it didn't work.

I thought maybe the IR sensor is more reliable? I want the sensor (ultrasonic or IR) to convert the shape of spinning objects into soundloops. But when I have tried this using the Ultra sonic sensor I experience that maybe that type of distance measurement sensor is not accurate or "quick" enough? But this is just my guesses and thoughts. The soundloops that were created by the Ultra sonic sensor reading the spinning objects were not consistent enough.

To be honest the codes I have tried is way off I believe. So I think I have to start over from scratch.
But maybe there is an easy way to just use the code from the Ultra sonic sensor-project and replace some parts of it with IR-sensor codes instead?

This is the code I used to get the Ultra sonic sensor to translate spinning objects to midi-signals:

// MIDI THEREMIN
// Moritz Simon Geist
// www.sonicrobots.com
// v.1.0 14 March 2014
////////////////////////////////
// This sketch uses an HC-SR04 Ultrasonic Sensor and produces an MIDI out signal, according to the measured distance form a object
// Be sure to include the latest MIDI Library (here 4.0)
// Arduino Playground - MIDILibrary
//
// Wiring: Ping pin from the HC-SR04 Ultrasonic Sensor --> arduino Pin 13,
// Echo pin from HC-SR04 Ultrasonic Sensor --> Arduino PIN 12
// MIDI-Out --> TX according to this sketch http://arduino.cc/en/uploads/Tutorial/MIDI_schem.png

#include <MIDI.h>
int pingPin = 13;
int inPin = 12;
long duration;
int cm_new = 20;
int cm_old = 20;
int sens = 5; // sensivity range when to launch a new note

void setup() {

Serial.begin(31250); // MIDI Begin
pinMode(pingPin, OUTPUT); // setup the Pins
pinMode(inPin, INPUT); // setup the Pins

}

void loop()
{

// The PING is triggered by a HIGH pulse of 2 or more microseconds.
// Give a short LOW pulse beforehand to ensure a clean HIGH pulse:

digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(10);
digitalWrite(pingPin, LOW);
duration = pulseIn(inPin, HIGH); // the singal from the Sensor is measured. The length of the pulse describes the distance form an object to the sensor.

cm_new = map(constrain(duration, 20, 3000), 50, 2000, 96, 48); // contrain --> set a threshold to cut values of the sensor that are to far away of to short (20 .. 3000) MAP --> Map the sensor range to a note values vom 96 (A high C) to 48 (a low C)

if (cm_new != cm_old) // only if a new sensor value is detected, a new nite will be send. IF the object stays stable infront of the sensor, no note will be send.
{
MIDI.sendNoteOff(cm_old,0,1); // Stop the old note
MIDI.sendNoteOn(cm_new,127,1); // Send a new Note (pitch , velocity 127, on channel 1)
cm_old = cm_new;
}
delay(30); // for staiblity
}

ALWAYS ALWAYS ALWAYS use code tags when posting code. The icon to click is to the left of quote icon.

This might set you going. It uses two IR sensors one connected to the A0 and the other A1 in the normal volume and pitch theremin. It uses pitch bend to glide the note while it is playing. If this is not want you want you can modify it from here.

// MIDI THEREMIN
// by Mike Cook
// v.1.0 03 March 2015
////////////////////////////////

#include <MIDI.h>
boolean playing = false;
const byte channel = 0;
const byte baseNote = 72;

void setup() {

  Serial.begin(31250); // MIDI Begin
  pinMode(pingPin, OUTPUT); // setup the Pins
  pinMode(inPin, INPUT); // setup the Pins

}
 

void loop(){
  int av1 = 1027 - analogRead(0);
  int av2 = 1027 - analogRead(1);
  if(av1 <870 && av2 < 870){
     if(!playing)noteOn();
     else {
          trackNote(av2,av1);
     }
  }
  else {
    if(playing) noteOff();
  }
}

void noteOff(){
  playing= false;
  // note off + sustain off
  noteSend(0x80,baseNote,127);
  controlSend(64, 0);
}
void noteOn(){
 // note on + sustain on
  noteSend(0x90,baseNote,127);
  controlSend(64, 127);
  playing = true;
}

 void noteSend(byte cmd, byte data1, byte data2) {
  cmd = cmd | channel;
  Serial.write(cmd);
  Serial.write(data1);
  Serial.write(data2);
}

int trackNote(int freq, int volume){
  int pb = 0x2000 - (435 - freq);
  sendPB(pb);
  int vel = volume>> 3;
   controlSend(7, vel);
}

void controlSend(byte CCnumber, byte CCdata) {
  byte CCchannel = channel | 0xB0; // convert to Controller message
  Serial.write(CCchannel);
  Serial.write(CCnumber);
  Serial.write(CCdata);
}

void sendPB(int pb){ // send pitch bend message
  Serial.write( (byte)0xE0 | channel);
  Serial.write( pb & (byte)0x7f);
  Serial.write( (pb>>7) & (byte)0x7f);
}

Thank you so much for taking time to help me!
It looks great. I will try it later today.

And I promise. I will ALWAYS use code tags from now on!

Grumpy_Mike:
This might set you going. It uses two IR sensors one connected to the A0 and the other A1 in the normal volume and pitch theremin. It uses pitch bend to glide the note while it is playing. If this is not want you want you can modify it from here.

I copied your code and have now wired it up. But I have some concerns (of course).

I have connected one IR sensor to "A0" and the other one to "A1". I have connected the MIDI to "Digital PIN 1".
But I´m wondering about the "PingPin" and the "InPin". How can I connect the IR sensors to them, when the sensors doesn´t have a "PinPing" (unlike the Ultra sonic sensor) ? And what should the code look like concerning the PingPin and the InPin?

I guess I lack some significant knowledge here.
When I hold both of my hands over the two different IR sensors the synthesizer plays just one note.

I´m really glad that you´re willing to help me on the way :slight_smile:

But I´m wondering about the "PingPin" and the "InPin". How can I connect the IR sensors to them, when the sensors doesn´t have a "PinPing" (unlike the Ultra sonic sensor) ?

You don't do anything with them, you are not using the ultra sonic sensor so there is no need for code or wiring for them.

When I hold both of my hands over the two different IR sensors the synthesizer plays just one note.

Is your sound module capable of reproducing pitch bend information?

Grumpy_Mike:
You don't do anything with them, you are not using the ultra sonic sensor so there is no need for code or wiring for them.
Is your sound module capable of reproducing pitch bend information?

Oh. I see. Then I just delete that from the code.

Aha. Maybe the pitch bend is a problem. I Don't now right now if my synth (Korg Volca Keys) is cabable of that. Maybe not. I'll check it up.

If it's not. Is it possible to just delete that part of the code?

If it's not. Is it possible to just delete that part of the code?

Yes but you will have to replace it with something because the pitch bend is how that code produces diffrent ( sliding ) notes, like a real theremin.

Grumpy_Mike:
Yes but you will have to replace it with something because the pitch bend is how that code produces diffrent ( sliding ) notes, like a real theremin.

Ok!

By the way. I just checked your web-page. Impressive projects and CV!
This Arduino-project is a part of my final Design Bachelor Thesis. I study design in Gothenburg and I'm also working as an artist. But I´m new to this "electronic world". It´s tougher than I thought!

Grumpy_Mike:
Is your sound module capable of reproducing pitch bend information?

My "Volca keys" should be able to handle the pitch bend information. But I only get on tone when I hold my hands over the Sharp Ir sensors. Any thoughts about what´s wrong?

I have connected the sensors to A0 and A1. The midi is connected to digital Pin 1.
This is what the code looks like at the moment:

// MIDI THEREMIN
// by Mike Cook
// v.1.0 03 March 2015
////////////////////////////////

#include <MIDI.h>
boolean playing = false;
const byte channel = 0;
const byte baseNote = 72;



void setup() {

  Serial.begin(31250); // MIDI Begin


}
 

void loop(){
  int av1 = 1027 - analogRead(0);
  int av2 = 1027 - analogRead(1);
  if(av1 <870 && av2 < 870){
     if(!playing)noteOn();
     else {
          trackNote(av2,av1);
     }
  }
  else {
    if(playing) noteOff();
  }
}

void noteOff(){
  playing= false;
  // note off + sustain off
  noteSend(0x80,baseNote,127);
  controlSend(64, 0);
}
void noteOn(){
 // note on + sustain on
  noteSend(0x90,baseNote,127);
  controlSend(64, 127);
  playing = true;
}

 void noteSend(byte cmd, byte data1, byte data2) {
  cmd = cmd | channel;
  Serial.write(cmd);
  Serial.write(data1);
  Serial.write(data2);
}

int trackNote(int freq, int volume){
  int pb = 0x2000 - (435 - freq);
  sendPB(pb);
  int vel = volume>> 3;
   controlSend(7, vel);
}

void controlSend(byte CCnumber, byte CCdata) {
  byte CCchannel = channel | 0xB0; // convert to Controller message
  Serial.write(CCchannel);
  Serial.write(CCnumber);
  Serial.write(CCdata);
}

void sendPB(int pb){ // send pitch bend message
  Serial.write( (byte)0xE0 | channel);
  Serial.write( pb & (byte)0x7f);
  Serial.write( (pb>>7) & (byte)0x7f);
}

But I only get on tone when I hold my hands over the Sharp Ir sensors. Any thoughts about what´s wrong?

In which case the object you are trying to read the range of has not got enough reflectivity in the IR to work with the sensor. You could try painting it white or sticking some white paper over it.

The volume sensor gates the sound so if that is not being triggered within the range you will get no sound. If you don't want that to happen then change the software.

Grumpy_Mike:
In which case the object you are trying to read the range of has not got enough reflectivity in the IR to work with the sensor. You could try painting it white or sticking some white paper over it.

Hello again. I am not getting the IR-sensors to work properly, I don't know why.
But. I would like to use your code with my Ultra-sonic-sensor instead.

Can you help me with what I should erase and what I should add to get your code to work with me Ultra-sonic-sensor? Would be amazing!

/Robert

Just one sensor?
What do you want it to do?
The code has one sensor acting as a volume gate and the other as the pitch bend if so how do you want it to work with regards to note on / off and pitch bend?

Grumpy_Mike:
Just one sensor?
What do you want it to do?
The code has one sensor acting as a volume gate and the other as the pitch bend if so how do you want it to work with regards to note on / off and pitch bend?

Yes. Just one ultrasonic sensor to play different tones (with pitch bend) depending on the distance of the object in front of it. Like a theremin but without the volume-parameter.
I have now tried a simple pitchbend code on my volca keys and it can handle that kind of information!

Try this:-

// 
// by Mike Cook
// v.1.1 07 March 2015
////////////////////////////////

#include <MIDI.h>
boolean playing = false;
const byte channel = 0;
const byte baseNote = 72;



void setup() {

  Serial.begin(31250); // MIDI Begin
  noteOn();
}
 

void loop(){
  int av1 = // put the ultrasonic measurement here
  trackNote(av1);
}

void noteOff(){
  playing= false;
  // note off + sustain off
  noteSend(0x80,baseNote,127);
  controlSend(64, 0);
}
void noteOn(){
 // note on + sustain on
  noteSend(0x90,baseNote,127);
  controlSend(64, 127);
  playing = true;
}

 void noteSend(byte cmd, byte data1, byte data2) {
  cmd = cmd | channel;
  Serial.write(cmd);
  Serial.write(data1);
  Serial.write(data2);
}

int trackNote(int freq){
  int pb = 0x2000 - (435 - freq);
  sendPB(pb);
  int vel = volume>> 3;
   controlSend(7, vel);
}

void controlSend(byte CCnumber, byte CCdata) {
  byte CCchannel = channel | 0xB0; // convert to Controller message
  Serial.write(CCchannel);
  Serial.write(CCnumber);
  Serial.write(CCdata);
}

void sendPB(int pb){ // send pitch bend message
  Serial.write( (byte)0xE0 | channel);
  Serial.write( pb & (byte)0x7f);
  Serial.write( (pb>>7) & (byte)0x7f);
}

Note that some voices decay after the first note on. Choose a voice that sustains as long as the note on remains in force.

Grumpy_Mike:
Note that some voices decay after the first note on. Choose a voice that sustains as long as the note on remains in force.

Thank you so much.
But I get this error:
__

sketch_mar07f.ino: In function 'int trackNote(int)':
sketch_mar07f.ino:50:13: error: 'volume' was not declared in this scope
__

How can I declare the volume?

How can I declare the volume?

Don't you are not controlling the volume are you? Just delete volume related code.

Grumpy_Mike:
Try this:-

// 

// by Mike Cook
// v.1.1 07 March 2015
////////////////////////////////

#include <MIDI.h>
boolean playing = false;
const byte channel = 0;
const byte baseNote = 72;

void setup() {

Serial.begin(31250); // MIDI Begin
  noteOn();
}

void loop(){
  int av1 = // put the ultrasonic measurement here
  trackNote(av1);
}

void noteOff(){
  playing= false;
  // note off + sustain off
  noteSend(0x80,baseNote,127);
  controlSend(64, 0);
}
void noteOn(){
// note on + sustain on
  noteSend(0x90,baseNote,127);
  controlSend(64, 127);
  playing = true;
}

void noteSend(byte cmd, byte data1, byte data2) {
  cmd = cmd | channel;
  Serial.write(cmd);
  Serial.write(data1);
  Serial.write(data2);
}

int trackNote(int freq){
  int pb = 0x2000 - (435 - freq);
  sendPB(pb);
  int vel = volume>> 3;
  controlSend(7, vel);
}

void controlSend(byte CCnumber, byte CCdata) {
  byte CCchannel = channel | 0xB0; // convert to Controller message
  Serial.write(CCchannel);
  Serial.write(CCnumber);
  Serial.write(CCdata);
}

void sendPB(int pb){ // send pitch bend message
  Serial.write( (byte)0xE0 | channel);
  Serial.write( pb & (byte)0x7f);
  Serial.write( (pb>>7) & (byte)0x7f);
}

In your code you say " put the ultrasonic measurement here".
I am not sure what part of the code I have been using that is the "ultrasonic measurement". Wich part should I copy/paste from this code?:

// MIDI THEREMIN
// Moritz Simon Geist
// www.sonicrobots.com
// v.1.0 14 March 2014
////////////////////////////////
// This sketch uses an HC-SR04 Ultrasonic Sensor and produces an MIDI out signal, according to the measured distance form a object
// Be sure to include the latest MIDI Library  (here 4.0)
// http://playground.arduino.cc/Main/MIDILibrary#.UyNutYUn2Hs
//
// Wiring: Ping pin from the HC-SR04 Ultrasonic Sensor --> arduino Pin 13, 
// Echo pin from HC-SR04 Ultrasonic Sensor --> Arduino PIN 12
// MIDI-Out --> TX according to this sketch http://arduino.cc/en/uploads/Tutorial/MIDI_schem.png

#include <MIDI.h>
int pingPin = 13;
int inPin = 12;
long duration;
int cm_new = 20;
int cm_old = 20;
int sens = 5; // sensivity range when to launch a new  note

void setup() {

  Serial.begin(31250); // MIDI Begin
  pinMode(pingPin, OUTPUT); // setup the Pins
  pinMode(inPin, INPUT); // setup the Pins

}
 
void loop()
{


// The PING is triggered by a HIGH pulse of 2 or more microseconds.
// Give a short LOW pulse beforehand to ensure a clean HIGH pulse:

digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(10);
digitalWrite(pingPin, LOW);
duration = pulseIn(inPin, HIGH); // the singal from the Sensor is measured. The length of the pulse describes the distance form an object to the sensor.
 
cm_new = map(constrain(duration, 20, 3000), 50, 2000, 96, 48); // contrain --> set a threshold to cut values of the sensor that are to far away of to short (20 .. 3000) MAP --> Map the sensor range to a note values vom 96 (A high C) to 48 (a low C)

if (cm_new != cm_old) // only if a new sensor value is detected, a new nite will be send. IF the object stays stable infront of the sensor, no note will be send.
{
 MIDI.sendNoteOff(cm_old,0,1);   // Stop the old note
 MIDI.sendNoteOn(cm_new,127,1);  // Send a new Note (pitch , velocity 127, on channel 1)
cm_old = cm_new;
}
delay(30); // for staiblity
}

I am not sure what part of the code I have been using that is the "ultrasonic measurement".

Are you actually reading the code? You read it like words. Each line does one job. You must try and understand what these lines say.

Come on, I think you can guess which lines pulse the ping sensor and measure the returned pulse. If you are lost look at the comments in your code, that tells you.

For the theory look at this:-
How an Ultrasonic distance sensor works