Sending MIDI on Event Change using MPR121 Capacitive Touch

Hi
Please can someone assist me in the correct midi commands to use in place of a pushbutton so when one of the Capacitive touch pins (1 to 12) are touched, it will send a equivalent midi command to play a note say middle C or a variation of that for the other 12 pins.
Using an Arduino leonardo.

Im using the MPR121 basic test code and also want to include the The Control Surface library:Control_Surface.h

Code:

/*********************************************************
This is a library for the MPR121 12-channel Capacitive touch sensor

Designed specifically to work with the MPR121 Breakout in the Adafruit shop
----> https://www.adafruit.com/products/

These sensors use I2C communicate, at least 2 pins are required
to interface

Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!

Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
**********************************************************/

#include <Wire.h>
#include “Adafruit_MPR121.h”
#include <Control_Surface.h> // Include the Control Surface library

// Instantiate a MIDI over USB interface
USBMIDI_Interface midi;

const uint8_t velocity = 0b1111111; // Maximum velocity (0b1111111 = 0x7F = 127)
const uint8_t C4 = 60; // Note number 60 is defined as middle C in the MIDI specification

#ifndef _BV
#define _BV(bit) (1 << (bit))
#endif

// You can have up to 4 on one i2c bus but one is enough for testing!
Adafruit_MPR121 cap = Adafruit_MPR121();

// Keeps track of the last pins touched
// so we know when buttons are ‘released’
uint16_t lasttouched = 0;
uint16_t currtouched = 0;

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

while (!Serial) { // needed to keep leonardo/micro from starting too fast!
delay(10);
}

Serial.println(“Adafruit MPR121 Capacitive Touch sensor test”);

// Default address is 0x5A, if tied to 3.3V its 0x5B
// If tied to SDA its 0x5C and if SCL then 0x5D
if (!cap.begin(0x5A)) {
Serial.println(“MPR121 not found, check wiring?”);
while (1);
}
Serial.println(“MPR121 found!”);
}

void loop() {
// Get the currently touched pads
currtouched = cap.touched();

for (uint8_t i=0; i<12; i++) {
// it if is touched and wasnt touched before, alert!
if ((currtouched & _BV(i)) && !(lasttouched & _BV(i)) ) {
Serial.print(i); Serial.println(" touched");

}
// if it was touched and now isnt, alert!
if (!(currtouched & _BV(i)) && (lasttouched & _BV(i)) ) {
Serial.print(i); Serial.println(" released");
}
}

// reset our state
lasttouched = currtouched;

// comment out this line for detailed data from the sensor!
return;

// debugging info, what
Serial.print("\t\t\t\t\t\t\t\t\t\t\t\t\t 0x"); Serial.println(cap.touched(), HEX);
Serial.print(“Filt: “);
for (uint8_t i=0; i<12; i++) {
Serial.print(cap.filteredData(i)); Serial.print(”\t”);
}
Serial.println();
Serial.print(“Base: “);
for (uint8_t i=0; i<12; i++) {
Serial.print(cap.baselineData(i)); Serial.print(”\t”);
}
Serial.println();

// put a delay so it isn’t overwhelming
delay(100);

// Refresh the button (check whether the button’s state has changed since last time, if so, send it over MIDI)
Control_Surface.refresh();
}

See this example: Send-MIDI-Notes.ino

Pieter

yep thats what I have used to test but not seeing any midi being sent ?

In the void loop section Ive put:
for (uint8_t i=0; i<12; i++) {
// it if is touched and wasnt touched before, alert!
if ((currtouched & _BV(i)) && !(lasttouched & _BV(i)) ) {
Serial.print(i); Serial.println(" touched");

midi.sendNoteOn(noteAddress, velocity);

Does it print anything to the serial monitor?

Please update the Control Surface library, you're at least 680 commits behind the latest version. A lot has changes since then.

yes it prints the touched and untouched events.

Im using a download from the 20/01/2020.

what if any calls should be put in the void.loop ie:
Control_Surface.loop();
midi.update();

maybe Im missing something there?

wayro:
// Refresh the button (check whether the button's state has changed since last time, if so, send it over MIDI)
Control_Surface.refresh();
}

The refresh method was removed a long time ago.

The loop should only have Control_Surface.loop(). It'll call midi.update internally. But calling it twice shouldn't be an issue.

How do you know that it doesn't send any MIDI? What software did you use to verify this?

Please post your full code, but before you do, please read the forum rules and use code tags.

I am looking at the serial monitor - would this not show any midi output?
the updated code is :

/*********************************************************
This is a library for the MPR121 12-channel Capacitive touch sensor

Designed specifically to work with the MPR121 Breakout in the Adafruit shop
----> https://www.adafruit.com/products/

These sensors use I2C communicate, at least 2 pins are required
to interface

Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!

Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
**********************************************************/

#include <Wire.h>
#include “Adafruit_MPR121.h”
#include <Control_Surface.h> // Include the Control Surface library

// Instantiate a MIDI over USB interface
USBMIDI_Interface midi;

const uint8_t velocity = 0b1111111; // Maximum velocity (0b1111111 = 0x7F = 127)
const uint8_t C4 = 60; // Note number 60 is defined as middle C in the MIDI specification

using namespace MIDI_Notes;

// MIDI address of the note to send
const MIDICNChannelAddress noteAddress = {note(C, 4), CHANNEL_1};

#ifndef _BV
#define _BV(bit) (1 << (bit))
#endif

// You can have up to 4 on one i2c bus but one is enough for testing!
Adafruit_MPR121 cap = Adafruit_MPR121();

// Keeps track of the last pins touched
// so we know when buttons are ‘released’
uint16_t lasttouched = 0;
uint16_t currtouched = 0;

void setup() {
midi.begin();
//Control_Surface.begin(); // Initialize Control Surface
Serial.begin(9600);

while (!Serial) { // needed to keep leonardo/micro from starting too fast!
delay(10);
}

Serial.println(“Adafruit MPR121 Capacitive Touch sensor test”);

// Default address is 0x5A, if tied to 3.3V its 0x5B
// If tied to SDA its 0x5C and if SCL then 0x5D
if (!cap.begin(0x5A)) {
Serial.println(“MPR121 not found, check wiring?”);
while (1);
}
Serial.println(“MPR121 found!”);
}

void loop() {

midi.update();
// Get the currently touched pads
currtouched = cap.touched();

for (uint8_t i=0; i<12; i++) {
// it if is touched and wasnt touched before, alert!
if ((currtouched & _BV(i)) && !(lasttouched & _BV(i)) ) {
Serial.print(i); Serial.println(" touched");

midi.sendNoteOn(noteAddress, velocity);

}
// if it was touched and now isnt, alert!
if (!(currtouched & _BV(i)) && (lasttouched & _BV(i)) ) {
Serial.print(i); Serial.println(" released");

midi.sendNoteOff(noteAddress, velocity);

}
}

// reset our state
lasttouched = currtouched;

}

PieterP:
Please post your full code, but before you do, please read the forum rules and use code tags.

wayro:
I am looking at the serial monitor - would this not show any midi output?

No, MIDI output is sent as MIDI over USB. You need a MIDI monitor or a DAW to see the MIDI messages.
Alternatively, use the USBDebugMIDI_Interface instead of the USBMIDI_Interface.

I have midi-ox and nothing showing there

are you happy with the code?
Im assuming that when one of the sensor pins is touched its firing off that midi command?
in the serial monitor it shows touched or released

Yes, the code looks fine. Did you try USBDebugMIDI_Interface?

using USBDebugMIDI_Interface

serial monitor shows:
2 touched
Note On Channel: 1 Data 1: 0x3c Data 2: 0x7f Cable: 0
2 released
Note Off Channel: 1 Data 1: 0x3c Data 2: 0x7f Cable: 0
4 touched
Note On Channel: 1 Data 1: 0x3c Data 2: 0x7f Cable: 0
4 released
Note Off Channel: 1 Data 1: 0x3c Data 2: 0x7f Cable: 0

Then the USBMIDI_Interface should work as well. Did you select the right settings in midi-ox? (I’ve never used it.)

think I figured it out
the const is incorrect - please advise correct syntax
const MIDICNChannelAddress noteAddress = {note(C, 4), CHANNEL_1};

wayro:
think I figured it out
the const is incorrect - please advise correct syntax
const MIDICNChannelAddress noteAddress = {note(C, 4), CHANNEL_1};

What do you mean? The const is correct, and shouldn’t have anything to do with whether it’s sending MIDI or not.

I tested the following code on touch event:
for (int note = 53; note <= 55; note ++) {

midi.sendNoteOn(note, velocity);
delay(1000); // Wait 1000 milliseconds.

midi.sendNoteOff(note, velocity);
}

this worked perfectly, the only variable that changed is this code uses “note” whereas the original code uses “noteAddress” which doesnt work?

I have noted that no midi get sent unless I open the serial monitor?
How do I ensure that the midi get sent when the event occurs without having to open the serial monitor?

Are you sure the const makes a difference? Because it really shouldn't, and could indicate another problem is hiding somewhere in the sketch or in a library.

Your sketch waits for the Serial connection to be opened before it starts. Get rid of these lines in your setup:

  while (!Serial) { // needed to keep leonardo/micro from starting too fast!
    delay(10);
  }

correct the const wasnt the issue it was the serial connection waiting to be opened, Ive taken that out and it seems to be fine now.
thanks for the help.
Im going to try it now with a DAW to see if this works