MIDI controller triggering random notes

Hey,

Ive been trying to make this MIDI percussion thing with ChatGPT as i dont know how to code but i think we have reached stalemate and require some actual brains to move on.

Here is the circuit im currently working with: (the round black thing is supposed to be a piezo sensor)

Im using Arduino UNO R4 Minima connected to my laptop via USB.
On the laptop ive been using Arduino IDE (obviously), loopMIDI and Hairless MIDI to make a virtual MIDI cable.

I have tried using 2 somewhat different codes.
This is what we were initially working on starting from scratch.

#include <MIDI.h>

// Define constants and variables
const int thresholdBase = 100;  // Base threshold for detecting a hit
const int debounceDelay = 50;   // Delay in milliseconds to debounce the hit
const int analogPin = A0;       // Analog pin connected to the sensor
const float alpha = 0.1;        // Low-pass filter constant
int threshold = thresholdBase;  // Dynamic threshold
float filteredValue = 0;        // Low-pass filter output
unsigned long lastHitTime = 0;  // Timestamp of the last hit

// Create a MIDI object
MIDI_CREATE_DEFAULT_INSTANCE();

void setup() {
  Serial.begin(115200);
  MIDI.begin(MIDI_CHANNEL_OMNI);  // Initialize MIDI communication
}

void loop() {
  int sensorValue = analogRead(analogPin);

  // Apply low-pass filter
  filteredValue = alpha * sensorValue + (1 - alpha) * filteredValue;

  // Log the filtered sensor value
  Serial.print("Filtered sensor value: ");
  Serial.println(filteredValue);

  if (filteredValue > threshold) {
    unsigned long currentTime = millis();
    if (currentTime - lastHitTime > debounceDelay) {
      Serial.println("Hit detected!");
      int velocity = map(filteredValue, threshold, 1023, 1, 127);  // Map sensor value to MIDI velocity

      // Log the mapped velocity
      Serial.print("Mapped velocity: ");
      Serial.println(velocity);

      sendMIDI(60, velocity);  // Send MIDI note with velocity

      // Dynamic threshold adjustment
      threshold = thresholdBase + (filteredValue - thresholdBase) / 2;

      lastHitTime = currentTime;
    }
  } else {
    // Gradually reset threshold to base value
    threshold = max(thresholdBase, threshold - 1);
  }

  delay(10);  // Short delay to prevent overwhelming the serial buffer
}

void sendMIDI(byte note, byte velocity) {
  Serial.print("Sending MIDI note: ");
  Serial.print(note);
  Serial.print(", Velocity: ");
  Serial.println(velocity);

  MIDI.sendNoteOn(note, velocity, 1);  // Send Note On message
  MIDI.sendNoteOff(note, 0, 1);         // Send Note Off message

  Serial.println("MIDI note off sent");
  delay(10);  // Short delay to ensure message is sent completely
}

Serial Monitor is constantly spamming low filtered sensor values and when i tap on the piezo its detecting multiple hits (like 4-5) with varying velocities over 350ms or so.

Hairless MIDI is spamming "Error: got unexpected data byte 0x(followed by a random number and/or letter)" when i turn on the Serial <-> MIDI Bridge and after the initial tap it keeps spamming random midi notes with random velocities.

I couldnt get it better than this so i asked it to adapt the code i previously had success with on Arduino NANO to Arduino UNO and this was the best we could do with it. (before more problems got introduced)

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

#define LED 2
#define PIEZO_PIN A0
#define MIDI_CHANNEL 10
#define NOTE_NUMBER 10
#define THRESHOLD 50
#define DEBOUNCE_TIME 200  // Debounce time in milliseconds

int lastValue = 0;
unsigned long lastHitTime = 0;

void setup() {
  Serial.begin(115200);
  MIDI.begin(MIDI_CHANNEL_OMNI);
  pinMode(LED, OUTPUT);
  pinMode(PIEZO_PIN, INPUT);
  Serial.println("Setup complete");
}

void noteOn(byte pitch, byte velocity) {
  MIDI.sendNoteOn(pitch, velocity, MIDI_CHANNEL);
  Serial.print("MIDI note on, Note: ");
  Serial.print(pitch);
  Serial.print(", Velocity: ");
  Serial.println(velocity);
}

void noteOff(byte pitch) {
  MIDI.sendNoteOff(pitch, 0, MIDI_CHANNEL);
}

void loop() {
  int sensorValue = analogRead(PIEZO_PIN);

  if (sensorValue > THRESHOLD && (millis() - lastHitTime) > DEBOUNCE_TIME) {
    int velocity = map(sensorValue, THRESHOLD, 1023, 1, 127);
    if (velocity > 127) velocity = 127;
    noteOn(NOTE_NUMBER, velocity);
    digitalWrite(LED, HIGH);
    delay(10);  // Light up LED for visual feedback
    digitalWrite(LED, LOW);
    lastHitTime = millis();
  }

  delay(10);  // Short delay to prevent overwhelming the loop
}

On Serial Monitor i was getting pretty accurate readings though it seemed to register each tap on the piezo twice with varying velocities.

On Hairless MIDI i got a bunch of seemingly random unintended notes with random velocities after each tap (though they followed the same pattern and velocities were mostly the same also).

I dont know if this is relevant but may be worth mentioning that i currently have the piezo loose (but stable) on a wooden table and sometimes between fairly firm foam pads.

I appreciate if anyone bothers to take a look and share their thoughts.
Thank you!

Well first off that circuit will not do anything. It appears to be a buzzer, or microphone feeding into an analogue input. This is not going to produce enough voltage to produce any reading from the analogue input.

Ill also include some pictures of the Serial Monitor and Hairless MIDI to better show whats going on.

This is of the Serial Monitor running the first code (values getting higher when i tapped on it):

Hairless MIDI running the first code initially:

Hairless MIDI running the first code after tapping it:

Its a piezo sensor, sorry. I could find it in the app i was using, probably should have specified.

Serial Monitor with second code:

Hairless MIDI with second code:

I don't know what you mean by that can you explain please.

Because it seems to be an integral part of your code you code can not possibly work.

I did a lot of experimenting with the UNO R4 Minima when it first came out. And I got it to work with the Minima, but not the R4 Wi-Fi.
Here is the sketch I used:-

/*
How to use the MIDI.h Libiary on a Uno R4 Minima
*/

#include <MIDI.h>

// Simple tutorial on how to receive and send MIDI messages.
// Here, when receiving any message on channel 4, the Arduino
// will blink a led and play back a note for 1 second.

MIDI_CREATE_DEFAULT_INSTANCE();

void setup()
{   
    pinMode(LED_BUILTIN, OUTPUT);
    /* correction for WIFI board to switch the USB back to the RA4M1
       this also requires resetting the WIFI board by unplugging and replugging
       the board from the USB, or cycling the power from it
    */ 
    pinMode(21, OUTPUT);
    digitalWrite(21, LOW);
    MIDI.begin(4);                      // Launch MIDI and listen to channel 4
    Serial.begin(115200); // HAIRLESS DEFAULT SPEED
}

void loop()
{
    if (MIDI.read())                    // If we have received a message
    {
        MIDI.sendNoteOn(42, 127, 1);    // Send a Note (pitch 42, velo 127 on channel 1)
        MIDI.sendNoteOn(54, 127, 1);
        digitalWrite(LED_BUILTIN, HIGH);
        delay(500);		            // Wait for a second
        MIDI.sendNoteOff(42, 0, 1);     // Stop the note
        MIDI.sendNoteOff(54, 127, 1);
        digitalWrite(LED_BUILTIN, LOW);
        delay(500);
    }
}

Make sure that hairless is set to the default speed on your machine. It sounds like it is not.

Piezos, as i understand it generate voltage when they receive some force. I thought they were called something else in the TinkerCad app i was using but after checking it again i found that they are called piezo there, just look different to what i have. Piezos are what ive seen most DIY Arduino drum projects use and theyve made it work.

Testing the code you provided i couldnt get any response from serial monitor or the Hairless MIDI. My baud rate in both these always matched the code which was usually 115200.

How did you test this?
Do you know what it is supposed to do?

It is a version of the very first example in the MIDI Library examples. It takes in a MIDI note on channel 4 and in responce to this sends out a pair of notes, and flashes the built in LED.

So how did you test this? I can see no evidence of you configuring Hairless to send in anything.

But have you checked what hairless is **actually ** set to?

So let me assume you have even less information of how to code than I thought you had.
So this code will send out random MIDI notes. Please note it does not use the MIDI library at all. But it does require Hairless to be configured correctly and working.

// Simple example of how to send a MIDI messages on an Arduino R4.
// When sending it will blink a led and play back a random note for 0.3 second.
// Note that the random numbers set might be outside the range of the
// MIDI sound module. This code requires that you have the Hairless app
// running on your computer. Or a MIDI interface connected to pin 1

void setup()
{
    Serial.begin(115200); // for Hairless
    Serial1.begin(31250); // external output pin - MIDI baud rate
    delay(2000);
    pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  int val, vel;
  vel = random(36,110);
  val = random(30,100);
    digitalWrite(LED_BUILTIN, HIGH);
    noteSend(0x90, val, vel);
    delay(300);
    digitalWrite(LED_BUILTIN, LOW);
    noteSend(0x80, val, 0);
   delay(1000);
    } // end loop function


//  plays a MIDI note
 void noteSend(char cmd, char data1, char data2) {
  // first the internal connection
  Serial.write(cmd);
  Serial.write(data1);
  Serial.write(data2);
  // now the serial output on the board
  Serial1.write(cmd);
  Serial1.write(data1);
  Serial1.write(data2);

}

Now back to your code which as I say can't possibly work for a number of reasons.

First of all are you hitting the piezo with some kind of stick?

And this is surprising because?

Have you ever looked at the sort of signal you get from hitting a sensor like this using your circuit?

Note here that the input sensitivity of the scope is 5V per division, so that gives a peak voltage of about 45V you are feeding directly into your Arduino. This, over time, will destroy any Arduino input you feed into.
Notice also there is a smaller secondary peak of signal after the massive initial one. This is due to the reverberation of the initial hit causing a secondary one.

So first you need to stop this massive initial voltage which you have done by using that large resistor and relying on the ESD diodes in the processor. But then you go and spoil the signal by having a capacitor across it so remove that.

It is worth remembering that large language models of AI have exactly zero actual intelligence and should never be trusted to tell you anything that you have not got the skills to spot are wrong.

I suppose it came up with the total nonsense which is:-

You are much better off at looking at some real projects that people have made, and see how difficult what you are trying to do actually is.

Youre right, i didnt really understand what its supposed to do. I didnt try to send in a MIDI note.

Im not sure what you mean by that. The only way i know how to configure the baud rate there is like this:
Kuvatõmmis 2024-06-11 163246

Regarding the code you sent, it works and does exactly what you said it would.

No, im just tapping on it with my finger.

Ive looked at the serial plotter tool (though im not sure if thats the right thing as it doesnt have as much info as your program does). This is what it looks like in there using my first code:

Yea, im starting to realize that lol.

Yes I used an oscilloscope, where as a serial plotter only looks at the samples you have taken, so there is a lot of difference.

That is odd because this is exactly how my version of hairless is configured, and the only time I have seen it throwing errors is if there is a miss match between configurations. Now In am using a Mac, I am assuming you are using a PC.

If so I wonder if the PC can actually cope with 8 bits, no parity and one stop bit? I wonder if it uses just the closest it can cope with. Of course you would need to look at the serial communication with an oscilloscope to find this out.

The other thing that could be giving you trouble is adding a de-bounce feature. It is the last thing you need with this kind of circuit.

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