/*
ESP32
https://www.mouser.com/ProductDetail/Espressif-Systems/ESP32-DevKitC-32D
Pinout
ESP SparkFun Shield
GND GND (jumper all grounds together for Shield)
16 2
17 3
4 4
RX RX
TX TX
5V +5V
3V3 3.3V
*/
#define WOKWI
#include <Adafruit_NeoPixel.h>
#define RXD2 16 // was 2, not needed
#define TXD2 18 // was 3 MIDI-In
/* Digital pins for LEDs */
#define PIN0 22 // don't use, actually D1 - GPIO8, retrace other pin on PCB
#define PIN1 32 // JP2
#define PIN2 33 // JP3
#define PIN3 27 // JP4
#define PIN4 13 // JP5
//#define note 0 //The MIDI note value to be played
//#define resetMIDI 4 //Reset line
//#define instrument 0
#define NUMPIXELS 14
Adafruit_NeoPixel pixels0 (NUMPIXELS, PIN0, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel pixels1 (NUMPIXELS, PIN1, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel pixels2 (NUMPIXELS, PIN2, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel pixels3 (NUMPIXELS, PIN3, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel pixels4 (NUMPIXELS, PIN4, NEO_GRB + NEO_KHZ800);
byte note = 0; //The MIDI note value to be played
byte resetMIDI = 4; //Reset line
int instrument = 0;
// X Y
// 1: 2, 15
// 2: 4, 0
// 3: 35, 34
// 4: 26, 25
// 5: 12, 14
const byte PinX [] = { 2, 4, 35, 26, 12 };
const byte PinY [] = { 15, 0, 34, 25, 14 };
const int N = sizeof(PinX);
int xLast [N];
int yLast [N];
int i [N];
boolean lightLED[N];
boolean toneIsActive[N];
unsigned long msecLast [N];
unsigned long msecLastLED [N];
const unsigned long PeriodLED = 200;
const unsigned long PeriodBEL = 50;
unsigned long msec;
char s [80];
// -----------------------------------------------------------------------------
void setup ()
{
Serial.begin (115200);
//Setup soft serial for MIDI control
Serial2.begin(31250, SERIAL_8N1, RXD2, TXD2);
for (int n = 0; n < N; n++)
{
xLast [n] = analogRead (PinX [n]);
yLast [n] = analogRead (PinY [n]);
toneIsActive[n] = false;
lightLED[n] = false;
msecLast[n] = 0;
msecLastLED[n] = 0;
}
pixels0.begin ();
pixels1.begin ();
pixels2.begin ();
pixels3.begin ();
pixels4.begin ();
//Reset
pinMode(resetMIDI, OUTPUT);
digitalWrite(resetMIDI, LOW);
delay(100);
digitalWrite(resetMIDI, HIGH);
delay(100);
talkMIDI(0xB0, 0x07, 120); //0xB0 is channel message, set channel volume to near max (127)
}
// -----------------------------------------------------------------------------
//Send a MIDI note-on message. Like pressing a piano key
//channel ranges from 0-15
void noteOn(byte channel, byte note, byte attack_velocity) {
talkMIDI( (0x90 | channel), note, attack_velocity);
}
//Send a MIDI note-off message. Like releasing a piano key
void noteOff(byte channel, byte note, byte release_velocity) {
talkMIDI( (0x80 | channel), note, release_velocity);
}
//Plays a MIDI note. Doesn't check to see that cmd is greater than 127, or that data values are less than 127
void talkMIDI(byte cmd, byte data1, byte data2) {
Serial2.write(cmd);
Serial2.write(data1);
//Some commands only have one data byte. All cmds less than 0xBn have 2 data bytes
//(sort of: http://253.ccarh.org/handout/midiprotocol/)
if ( (cmd & 0xF0) <= 0xB0)
Serial2.write(data2);
}
// -----------------------------------------------------------------------------
void update ( int n, Adafruit_NeoPixel * pixels )
{
int x;
int y;
if (!toneIsActive[n]) {
x = analogRead (PinX [n]);
y = analogRead (PinY [n]);
#ifdef WOKWI
if (abs (x - xLast [n]) > 45)
#else
if (abs (x - xLast [n]) > 45 || abs (y - yLast [n]) > 45)
#endif
{
talkMIDI(0xB0, 0, 0x00); //Default bank GM1
talkMIDI(0xC0, 98, 0); //Set instrument number. 0xC0 is a 1 data byte command
msecLast [n] = msec;
//Note on channel 1 (0x90), some note value (note), middle velocity (0x45):
noteOn(0, 98, 60);
toneIsActive[n] = true;
xLast [n] = x;
yLast [n] = y;
}
}
if (toneIsActive[n]){
if (msec - msecLast [n] >= PeriodBEL)
{
//Turn off the note with a given off/release velocity
noteOff(0, 98, 15000);
toneIsActive[n] = false;
lightLED[n] = true;
}
}
if (lightLED[n] && msec - msecLastLED[n] > PeriodLED)
{
msecLastLED[n] = msec;
if (i [n] >= NUMPIXELS)
{
i [n] = 0; // reset i at max value
pixels->clear (); // Set all pixel colors to 'off'
lightLED[n] = false;
} else
{
pixels->setPixelColor (i [n],
pixels->Color (150 - i [n] * 20, i [n] * 20, 0));
i [n]++;
}
pixels->show ();
}
}
// -----------------------------------------------------------------------------
void loop ()
{
msec = millis ();
update (0, & pixels0);
update (1, & pixels1);
update (2, & pixels2);
update (3, & pixels3);
update (4, & pixels4);
}