Proximity based midi controller

As a part of a major project for a degree a Uni, I am trying to create a midi controller that sends values from two analog distance sensors. Each of the sensors values are mapped to MIDI values from 0-127. As I've never used Arduino or built any projects I have been really hanging on by the seat of my pants thus far, using AI to help me fast track coding as i'm under quite a short time frame. The current circuit and code work quite well, but i'm looking to add a feature and i'm quite stuck on it.

I'd like the midi values being output from the board to hold when I remove my hand from the range of the analog distance sensors. So that I can interact with the controller and leave the controlled parameters as they are before I pull away. I'm trying to avoid using another sensor or switch to activate a hold function. This is because the intended use of the instrument is with both hands, and you will lose one of the sensors values when you shift your hand to the hold button.

Does anyone have any ideas? I'll paste the working code below.

#include <USB-MIDI.h>
USBMIDI_CREATE_DEFAULT_INSTANCE();

// Define constants for the sensor pins and MIDI control parameters
const int sensorPin1 = A0;  // Analog output pin of the first distance sensor connected to A0
const int sensorPin2 = A1;  // Analog output pin of the second distance sensor connected to A1
const int midiControllerNumber1 = 1; // MIDI controller number for the first sensor
const int midiControllerNumber2 = 2; // MIDI controller number for the second sensor
const int midiChannel = 1; // MIDI channel to use
const int midiValueMin = 0; // Minimum MIDI value
const int midiValueMax = 127; // Maximum MIDI value

// Define variables for the moving average filter for sensor 1
const int numReadings = 20; // Number of readings to average
int sensorReadings1[numReadings]; // Array to store sensor 1 readings
int index1 = 0; // Index for storing the current sensor 1 reading
int total1 = 0; // Total sum of sensor 1 readings
int averageReading1 = 0; // Smoothed sensor 1 reading

// Define variables for the moving average filter for sensor 2
int sensorReadings2[numReadings]; // Array to store sensor 2 readings
int index2 = 0; // Index for storing the current sensor 2 reading
int total2 = 0; // Total sum of sensor 2 readings
int averageReading2 = 0; // Smoothed sensor 2 reading

void setup() {
  Serial.begin(9600); // Initialize serial communication at 9600 baud rate
  MIDI.begin(midiChannel); // Initialize MIDI communication
}

void loop() {
  // Read the analog voltage from the first sensor
  int sensorValue1 = analogRead(sensorPin1);

  // Apply moving average filter for sensor 1
  total1 = total1 - sensorReadings1[index1];
  sensorReadings1[index1] = sensorValue1;
  total1 = total1 + sensorReadings1[index1];
  index1 = (index1 + 1) % numReadings;
  averageReading1 = total1 / numReadings;

  // Read the analog voltage from the second sensor
  int sensorValue2 = analogRead(sensorPin2);

  // Apply moving average filter for sensor 2
  total2 = total2 - sensorReadings2[index2];
  sensorReadings2[index2] = sensorValue2;
  total2 = total2 + sensorReadings2[index2];
  index2 = (index2 + 1) % numReadings;
  averageReading2 = total2 / numReadings;

  // Check if the sensor 1 value falls within the desired range
  if (averageReading1 >= 130 && averageReading1 <= 500) {
    // Map the sensor 1 value to MIDI range (20-127)
    int midiValue1 = map(averageReading1, 130, 500, midiValueMin, midiValueMax);

    // Send MIDI Control Change message with the mapped MIDI value for sensor 1
    MIDI.sendControlChange(midiControllerNumber1, midiValue1, midiChannel);

    // Print sensor 1 value and MIDI value to the serial monitor
    Serial.print("Sensor 1 value: ");
    Serial.print(averageReading1);
    Serial.print("\t MIDI value 1: ");
    Serial.println(midiValue1);
  }

  // Check if the sensor 2 value falls within the desired range
  if (averageReading2 >= 130 && averageReading2 <= 500) {
    // Map the sensor 2 value to MIDI range (20-127)
    int midiValue2 = map(averageReading2, 130, 500, midiValueMin, midiValueMax);

    // Send MIDI Control Change message with the mapped MIDI value for sensor 2
    MIDI.sendControlChange(midiControllerNumber2, midiValue2, midiChannel);

    // Print sensor 2 value and MIDI value to the serial monitor
    Serial.print("Sensor 2 value: ");
    Serial.print(averageReading2);
    Serial.print("\t MIDI value 2: ");
    Serial.println(midiValue2);
  }

  // Delay before next reading
  delay(30); // Adjust delay as needed
}

type or paste code here

type or paste code here

But won’t the outputs always then be at the maximum?

How about a foot operated switch?

How about a distance sensor made from a time of flight sensor bouncing off a target on a bearing?

Then it only sends the data when you push it, and that way you can remove your hand at any time.

I can show you a photograph of one I made when I am next on my laptop rather than this iPad.

What sort of Arduino are you using?

Otherwise I can't see how this would actually work without it doing the good stuff you want like the vibrato on the way in to the point where you want to withdraw your hand.

I'm not sure! For example if i'm using the controller with a vibrato effect i'd like to be able to use my hand to move the amount of vibrato say halfway through the range of the sensor. At this point it may be outputting a midi value of 63, which I would then like to pull my hand away and have the output midi value remain at 63.

A foot operated switch would be very useful! I haven't looked into what I would need to do that but it's on the list. In my head i'm just thinking sustain pedal like a piano or synth but i'm not sure what equivalent versions of that would work with the Arduino circuit.

That first suggestion intrigues me, could elaborate on how that works? I am very green with components and how they work sorry. A photograph would be nice if you could!

I'm using an Arduino Leonardo!

One code thing I tried was having a wider range of numbers in the moving average filter, then using the code tried to hold the last midi value output before my hand moved out of range. The thought was that if it was averaging from 10 numbers and only 2 or 3 numbers are dropping from my hand moving away that it would hold a close enough midi value. This didn't work very well as i think it needs a wider range of numbers to average from but the more I add the less precise and reactive the controller itself is.

This is it. It was designed to be used as a Hawaiian Guitar, where sliding the target would show the note in the display. When a "string" was touched or the "strings" strummed the note would sound, but then any further movement would produce a pitch bend on the MIDI notes. The "strings" are brass rods connected to a touch sensor chip. It is also a Bluetooth device but that is beside the point.

The four push buttons are to change the scale being played. I cut the box with my own laser cutter. It was designed as an accessible instrument, for disabled people.

But hopefully you can see how the principle would work for you allowing you to remove your hand and the same degree of tone control would continue until you slid it again. No need for the "strings".

I was thinking of a switch that would immediately freeze the distance-related readings. Because I’d expect any attempts to do so by left and right hand time-based methods (like your post #6, or similar), would at best reduce precision.

But there could of course be many ways to implement the switch itself. Footswitch was the most obvious. Tap to toggle off or on.

This is great! I've looked up some time of flight sensors and will get on to those and have a tinker when they arrive.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.