Schoo Project-Arduino Midi Drumpads

I was wondering how you changed each drum pad to a different sound in a midi drum project. I have mine working, I have 4 pads and I'm using fl studio 12, hairless midi, and loop midi. I have to get a school project done quickly so I'm hoping for a quick response. Currently all pads work but they're just a variation of the same note. Like snare would be c5 and each other pad would play a different variation and pitch of that note. Here is the code that I tried to change. Could someone to help to where like each pad would be a different item, snare, bass drum, hi hat, and clap or something.

I have an arduino UNO and 4 piezos wired starting at A0 to A3. I have the other analog inputs grounded from a previous build but I dont think that'd effect it.

Here is the code: Thanks in advance anyone who can help a newbie for a school project

//Piezo defines
#define NUM_PIEZOS 4
#define SNARE_THRESHOLD 30     //anything < TRIGGER_THRESHOLD is treated as 0
#define LTOM_THRESHOLD 30
#define RTOM_THRESHOLD 30
#define LCYM_THRESHOLD 100
#define RCYM_THRESHOLD 100
#define KICK_THRESHOLD 50
#define START_SLOT 0     //first analog slot of piezos

//MIDI note defines for each trigger
#define SNARE_NOTE 70
#define LTOM_NOTE 71
#define RTOM_NOTE 72
#define LCYM_NOTE 73
#define RCYM_NOTE 74
#define KICK_NOTE 75

//MIDI defines
#define NOTE_ON_CMD 0x90
#define NOTE_OFF_CMD 0x80
#define MAX_MIDI_VELOCITY 127

//MIDI baud rate
#define SERIAL_RATE 115200

//Program defines
//ALL TIME MEASURED IN MILLISECONDS
#define SIGNAL_BUFFER_SIZE 100
#define PEAK_BUFFER_SIZE 30
#define MAX_TIME_BETWEEN_PEAKS 20
#define MIN_TIME_BETWEEN_NOTES 50

//map that holds the mux slots of the piezos
unsigned short slotMap[NUM_PIEZOS];

//map that holds the respective note to each piezo
unsigned short noteMap[NUM_PIEZOS];

//map that holds the respective threshold to each piezo
unsigned short thresholdMap[NUM_PIEZOS];

//Ring buffers to store analog signal and peaks
short currentSignalIndex[NUM_PIEZOS];
short currentPeakIndex[NUM_PIEZOS];
unsigned short signalBuffer[NUM_PIEZOS][SIGNAL_BUFFER_SIZE];
unsigned short peakBuffer[NUM_PIEZOS][PEAK_BUFFER_SIZE];

boolean noteReady[NUM_PIEZOS];
unsigned short noteReadyVelocity[NUM_PIEZOS];
boolean isLastPeakZeroed[NUM_PIEZOS];

unsigned long lastPeakTime[NUM_PIEZOS];
unsigned long lastNoteTime[NUM_PIEZOS];

void setup()
{
Serial.begin(SERIAL_RATE);

//initialize globals
for(short i=0; i<NUM_PIEZOS; ++i)
{
  currentSignalIndex[i] = 0;
  currentPeakIndex[i] = 0;
  memset(signalBuffer[i],0,sizeof(signalBuffer[i]));
  memset(peakBuffer[i],0,sizeof(peakBuffer[i]));
  noteReady[i] = false;
  noteReadyVelocity[i] = 0;
  isLastPeakZeroed[i] = true;
  lastPeakTime[i] = 0;
  lastNoteTime[i] = 0;    
  slotMap[i] = START_SLOT + i;
}

thresholdMap[0] = KICK_THRESHOLD;
thresholdMap[1] = RTOM_THRESHOLD;
thresholdMap[2] = RCYM_THRESHOLD;
thresholdMap[3] = LCYM_THRESHOLD;
thresholdMap[4] = SNARE_THRESHOLD;
thresholdMap[5] = LTOM_THRESHOLD;  

noteMap[0] = KICK_NOTE;
noteMap[1] = RTOM_NOTE;
noteMap[2] = RCYM_NOTE;
noteMap[3] = LCYM_NOTE;
noteMap[4] = SNARE_NOTE;
noteMap[5] = LTOM_NOTE;  
}

void loop()
{
unsigned long currentTime = millis();

for(short i=0; i<NUM_PIEZOS; ++i)
{
  //get a new signal from analog read
  unsigned short newSignal = analogRead(slotMap[i]);
  signalBuffer[i][currentSignalIndex[i]] = newSignal;
  
  //if new signal is 0
  if(newSignal < thresholdMap[i])
  {
    if(!isLastPeakZeroed[i] && (currentTime - lastPeakTime[i]) > MAX_TIME_BETWEEN_PEAKS)
    {
      recordNewPeak(i,0);
    }
    else
    {
      //get previous signal
      short prevSignalIndex = currentSignalIndex[i]-1;
      if(prevSignalIndex < 0) prevSignalIndex = SIGNAL_BUFFER_SIZE-1;        
      unsigned short prevSignal = signalBuffer[i][prevSignalIndex];
      
      unsigned short newPeak = 0;
      
      //find the wave peak if previous signal was not 0 by going
      //through previous signal values until another 0 is reached
      while(prevSignal >= thresholdMap[i])
      {
        if(signalBuffer[i][prevSignalIndex] > newPeak)
        {
          newPeak = signalBuffer[i][prevSignalIndex];        
        }
        
        //decrement previous signal index, and get previous signal
        prevSignalIndex--;
        if(prevSignalIndex < 0) prevSignalIndex = SIGNAL_BUFFER_SIZE-1;
        prevSignal = signalBuffer[i][prevSignalIndex];
      }
      
      if(newPeak > 0)
      {
        recordNewPeak(i, newPeak);
      }
    }

  }
      
  currentSignalIndex[i]++;
  if(currentSignalIndex[i] == SIGNAL_BUFFER_SIZE) currentSignalIndex[i] = 0;
}
}

void recordNewPeak(short slot, short newPeak)
{
isLastPeakZeroed[slot] = (newPeak == 0);

unsigned long currentTime = millis();
lastPeakTime[slot] = currentTime;

//new peak recorded (newPeak)
peakBuffer[slot][currentPeakIndex[slot]] = newPeak;

//1 of 3 cases can happen:
// 1) note ready - if new peak >= previous peak
// 2) note fire - if new peak < previous peak and previous peak was a note ready
// 3) no note - if new peak < previous peak and previous peak was NOT note ready

//get previous peak
short prevPeakIndex = currentPeakIndex[slot]-1;
if(prevPeakIndex < 0) prevPeakIndex = PEAK_BUFFER_SIZE-1;        
unsigned short prevPeak = peakBuffer[slot][prevPeakIndex];
 
if(newPeak > prevPeak && (currentTime - lastNoteTime[slot])>MIN_TIME_BETWEEN_NOTES)
{
  noteReady[slot] = true;
  if(newPeak > noteReadyVelocity[slot])
    noteReadyVelocity[slot] = newPeak;
}
else if(newPeak < prevPeak && noteReady[slot])
{
  noteFire(noteMap[slot], noteReadyVelocity[slot]);
  noteReady[slot] = false;
  noteReadyVelocity[slot] = 0;
  lastNoteTime[slot] = currentTime;
}

currentPeakIndex[slot]++;
if(currentPeakIndex[slot] == PEAK_BUFFER_SIZE) currentPeakIndex[slot] = 0;  
}

void noteFire(unsigned short note, unsigned short velocity)
{
if(velocity > MAX_MIDI_VELOCITY)
  velocity = MAX_MIDI_VELOCITY;

midiNoteOn(note, velocity);
midiNoteOff(note, velocity);
}

void midiNoteOn(byte note, byte midiVelocity)
{
Serial.write(NOTE_ON_CMD);
Serial.write(note);
Serial.write(midiVelocity);
}

void midiNoteOff(byte note, byte midiVelocity)
{
Serial.write(NOTE_OFF_CMD);
Serial.write(note);
Serial.write(midiVelocity);
}

sketch_apr20a.ino (5.5 KB)

Read the how to use the forum and correct that post to post code correctly.

To get the MIDI to produce different percussion sounds send over channel 13 as this is the percussion channels for most MIDI sound generators, look up what yours is.

How do I edit my post?

Select More:Modify at the lower right of the box.

Give it a few minutes, its says I cant modify the code, that I've hit the limit

Time limit? That goes away after so many posts.
Size limit? Reply, and click "Attachments and other options" to attach the .ino file if it's too big.

What length data do you get with
short and unsigned short?
I've not seen those before.

I'm not quite sure, I borrowed the code from another project and was trying to modify it to my own needs

I borrowed the code

So you are going to give it back?

Do you understand any of it?

What is your MIDI sound generator?

I'm using fl studio and the ASIO4ALL driver. And sort of, but not really. It works as far as putting out a sound of drums that I can customize for different sounds. They all send the same note but a different tone of that note.
A0=D#6
A1= C6
A2=D6
A3=C#6

A's being our 4 piezoes connected to the analog connections on our arduino uno.
A4 and 5 are grounded.

Read reply #1 again.
Have you tried this?
Do you understand this?

No, not at all

MIDI is send over 16 channels. Channel 10 is normally reserved for percussion. See:-

You are sending stuff on channel 0, so you can never get the percussion set with that.

You need to send stuff on channel 10, to do this change your code to:-

void midiNoteOn(byte note, byte midiVelocity)
{
Serial.write(NOTE_ON_CMD + 9);
Serial.write(note);
Serial.write(midiVelocity);
}

void midiNoteOff(byte note, byte midiVelocity)
{
Serial.write(NOTE_OFF_CMD + 9);
Serial.write(note);
Serial.write(midiVelocity);
}

I would also skip sending the note off as the percussion drum set does not need it and it will only cut notes short because you have no delay between on and off.
Percussion notes are from note 35 to note 81 although some sound generators might have things for other notes as well.

So in short, get rid of this?:

void midiNoteOff(byte note, byte midiVelocity)
{
Serial.write(NOTE_OFF_CMD + 9);
Serial.write(note);
Serial.write(midiVelocity);
}

the second part of what you said. I will try that soon, just putting so final touches on the setup

Even sent over channel 10, fl studio still plays the same instrument for each pad just a slightly different tone. I cant figure out how to make each pad a different tone. Like snare, kick, etc. I now have 6 pads instead of 4. Is that something I have to do with the software or in the arduino code?

Is that something I have to do with the software

Yes.

or in the arduino code?

No apart from sending it on the right channel.

Even sent over channel 10, fl studio still plays the same instrument for each pad just a slightly different tone.

Then there are three possibilities:-

  1. You are not doing what you think. Use a MIDI monitor program to check that stuff is on channel 10.
  2. Your software is not GM MIDI compatible and there is no percussion kit on channel 10.
  3. Some other program change message is needed with your software.