Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1a7a893

Browse filesBrowse files
EleotleCramme-no-devlucasssvazP-R-O-C-H-Y
authored
Add USB MIDI support to libraries/USB (espressif#8166)
* Added USBMIDI support to libraries/USB * Added MIDI examples to libraries/USB * Added missing newline at end of file to MidiController.ino * Added USBMIDI.cpp to CMake file * Fix narrowing conversion warning in USBMIDI.cpp * Fix incomplete initializers warning in USBMIDI.cpp * Apply suggestions from code review Co-authored-by: Lucas Saavedra Vaz <lucassvaz@yahoo.com.br> * add skip files for C6+H2 * remove already patched workaroud for bug * move #define to top of file --------- Co-authored-by: Me No Dev <me-no-dev@users.noreply.github.com> Co-authored-by: Lucas Saavedra Vaz <lucas.vaz@espressif.com> Co-authored-by: Jan Procházka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Co-authored-by: Lucas Saavedra Vaz <lucassvaz@yahoo.com.br>
1 parent 374280c commit 1a7a893
Copy full SHA for 1a7a893
Expand file treeCollapse file tree

23 files changed

+555
-0
lines changed

‎CMakeLists.txt

Copy file name to clipboardExpand all lines: CMakeLists.txt
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ set(LIBRARY_SRCS
115115
libraries/Update/src/Updater.cpp
116116
libraries/Update/src/HttpsOTAUpdate.cpp
117117
libraries/USB/src/USBHID.cpp
118+
libraries/USB/src/USBMIDI.cpp
118119
libraries/USB/src/USBHIDMouse.cpp
119120
libraries/USB/src/USBHIDKeyboard.cpp
120121
libraries/USB/src/USBHIDGamepad.cpp

‎libraries/USB/examples/MIDI/MidiController/.skip.esp32

Copy file name to clipboardExpand all lines: libraries/USB/examples/MIDI/MidiController/.skip.esp32
Whitespace-only changes.

‎libraries/USB/examples/MIDI/MidiController/.skip.esp32c3

Copy file name to clipboardExpand all lines: libraries/USB/examples/MIDI/MidiController/.skip.esp32c3
Whitespace-only changes.

‎libraries/USB/examples/MIDI/MidiController/.skip.esp32c6

Copy file name to clipboardExpand all lines: libraries/USB/examples/MIDI/MidiController/.skip.esp32c6
Whitespace-only changes.

‎libraries/USB/examples/MIDI/MidiController/.skip.esp32h2

Copy file name to clipboardExpand all lines: libraries/USB/examples/MIDI/MidiController/.skip.esp32h2
Whitespace-only changes.
+118Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
This is an example of a Simple MIDI Controller using an ESP32 with a native USB support stack (S2, S3,
3+
etc.).
4+
5+
For a hookup guide and more information on reading the ADC, please see:
6+
https://randomnerdtutorials.com/esp32-adc-analog-read-arduino-ide/ (Note: This sketch uses GPIO05)
7+
8+
For best results, it is recommended to add an extra offset resistor between VCC and the potentiometer.
9+
(For a standard 10kOhm potentiometer, 3kOhm - 4kOhm will do.)
10+
11+
View this sketch in action on YouTube: https://youtu.be/Y9TLXs_3w1M
12+
*/
13+
#if ARDUINO_USB_MODE
14+
#warning This sketch should be used when USB is in OTG mode
15+
void setup() {}
16+
void loop() {}
17+
#else
18+
19+
#include <math.h>
20+
21+
#include "USB.h"
22+
#include "USBMIDI.h"
23+
USBMIDI MIDI;
24+
25+
#define MIDI_NOTE_C4 64
26+
27+
#define MIDI_CC_CUTOFF 74
28+
29+
///// ADC & Controller Input Handling /////
30+
31+
#define CONTROLLER_PIN 5
32+
33+
// ESP32 ADC needs a ton of smoothing
34+
#define SMOOTHING_VALUE 1000
35+
static double controllerInputValue = 0;
36+
37+
void updateControllerInputValue() {
38+
controllerInputValue =
39+
(controllerInputValue * (SMOOTHING_VALUE - 1) + analogRead(CONTROLLER_PIN)) / SMOOTHING_VALUE;
40+
}
41+
42+
void primeControllerInputValue() {
43+
for (int i = 0; i < SMOOTHING_VALUE; i++) {
44+
updateControllerInputValue();
45+
}
46+
}
47+
48+
uint16_t readControllerValue() {
49+
// Lower ADC input amplitude to get a stable value
50+
return round(controllerInputValue / 12);
51+
}
52+
53+
///// Button Handling /////
54+
55+
#define BUTTON_PIN 0
56+
57+
// Simple button state transition function with debounce
58+
// (See also: https://tinyurl.com/simple-debounce)
59+
#define PRESSED 0xff00
60+
#define RELEASED 0xfe1f
61+
uint16_t getButtonEvent() {
62+
static uint16_t state = 0;
63+
state = (state << 1) | digitalRead(BUTTON_PIN) | 0xfe00;
64+
return state;
65+
}
66+
67+
///// Arduino Hooks /////
68+
69+
void setup() {
70+
Serial.begin(115200);
71+
MIDI.begin();
72+
USB.begin();
73+
74+
primeControllerInputValue();
75+
}
76+
77+
void loop() {
78+
uint16_t newControllerValue = readControllerValue();
79+
static uint16_t lastControllerValue = 0;
80+
81+
// Auto-calibrate the controller range
82+
static uint16_t maxControllerValue = 0;
83+
static uint16_t minControllerValue = 0xFFFF;
84+
85+
if (newControllerValue < minControllerValue) {
86+
minControllerValue = newControllerValue;
87+
}
88+
if (newControllerValue > maxControllerValue) {
89+
maxControllerValue = newControllerValue;
90+
}
91+
92+
// Send update if the controller value has changed
93+
if (lastControllerValue != newControllerValue) {
94+
lastControllerValue = newControllerValue;
95+
96+
// Can't map if the range is zero
97+
if (minControllerValue != maxControllerValue) {
98+
MIDI.controlChange(MIDI_CC_CUTOFF,
99+
map(newControllerValue, minControllerValue, maxControllerValue, 0, 127));
100+
}
101+
}
102+
103+
updateControllerInputValue();
104+
105+
// Hook Button0 to a MIDI note so that we can observe
106+
// the CC effect without the need for a MIDI keyboard.
107+
switch (getButtonEvent()) {
108+
case PRESSED:
109+
MIDI.noteOn(MIDI_NOTE_C4, 64);
110+
break;
111+
case RELEASED:
112+
MIDI.noteOff(MIDI_NOTE_C4, 0);
113+
break;
114+
default:
115+
break;
116+
}
117+
}
118+
#endif /* ARDUINO_USB_MODE */

‎libraries/USB/examples/MIDI/MidiInterface/.skip.esp32

Copy file name to clipboardExpand all lines: libraries/USB/examples/MIDI/MidiInterface/.skip.esp32
Whitespace-only changes.

‎libraries/USB/examples/MIDI/MidiInterface/.skip.esp32c3

Copy file name to clipboardExpand all lines: libraries/USB/examples/MIDI/MidiInterface/.skip.esp32c3
Whitespace-only changes.

‎libraries/USB/examples/MIDI/MidiInterface/.skip.esp32c6

Copy file name to clipboardExpand all lines: libraries/USB/examples/MIDI/MidiInterface/.skip.esp32c6
Whitespace-only changes.

‎libraries/USB/examples/MIDI/MidiInterface/.skip.esp32h2

Copy file name to clipboardExpand all lines: libraries/USB/examples/MIDI/MidiInterface/.skip.esp32h2
Whitespace-only changes.
+70Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
This is an example of using an ESP32 with a native USB support stack (S2, S3, etc.) as a Serial MIDI to
3+
USB MIDI bridge (AKA "A MIDI Interface").
4+
5+
View this sketch in action on YouTube: https://youtu.be/BXG5i55I9s0
6+
7+
Receiving and decoding USB MIDI 1.0 packets is a more advanced topic than sending MIDI over USB,
8+
please refer to the other examples in this library for a more basic example of sending MIDI over USB.
9+
10+
This example should still be self explanatory, please refer to the USB MIDI 1.0 specification (the spec)
11+
for a more in-depth explanation of the packet format.
12+
13+
For the spec please visit: https://www.midi.org/specifications-old/item/usb-midi-1-0-specification
14+
15+
Note: Because ESP32 works at VCC=3.3v normal schematics for Serial MIDI connections will not suffice,
16+
Please refer to the Updated MIDI 1.1 Electrical Specification [1] for information on how to hookup
17+
Serial MIDI for 3.3v devices.
18+
19+
[1] - https://www.midi.org/specifications/midi-transports-specifications/5-pin-din-electrical-specs
20+
*/
21+
#if ARDUINO_USB_MODE
22+
#warning This sketch should be used when USB is in OTG mode
23+
void setup() {}
24+
void loop() {}
25+
#else
26+
27+
#include "USB.h"
28+
#include "USBMIDI.h"
29+
USBMIDI MIDI;
30+
31+
#define MIDI_RX 39
32+
#define MIDI_TX 40
33+
34+
void setup() {
35+
// USBCDC Serial
36+
Serial.begin(115200);
37+
38+
// HW UART Serial
39+
Serial1.begin(31250, SERIAL_8N1, MIDI_RX, MIDI_TX);
40+
41+
MIDI.begin();
42+
USB.begin();
43+
}
44+
45+
void loop() {
46+
// MIDI Serial 1.0 to USB MIDI 1.0
47+
if (Serial1.available()) {
48+
byte data = Serial1.read();
49+
MIDI.write(data);
50+
}
51+
52+
// USB MIDI 1.0 to MIDI Serial 1.0
53+
midiEventPacket_t midi_packet_in = {0};
54+
// See Chapter 4: USB-MIDI Event Packets (page 16) of the spec.
55+
int8_t cin_to_midix_size[16] = {-1, -1, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1};
56+
57+
if (MIDI.readPacket(&midi_packet_in)) {
58+
midi_code_index_number_t code_index_num = MIDI_EP_HEADER_CIN_GET(midi_packet_in.header);
59+
int8_t midix_size = cin_to_midix_size[code_index_num];
60+
61+
// We skip Misc and Cable Events for simplicity
62+
if (code_index_num >= 0x2) {
63+
for (int i = 0; i < midix_size; i++) {
64+
Serial1.write(((uint8_t *)&midi_packet_in)[i + 1]);
65+
}
66+
Serial1.flush();
67+
}
68+
}
69+
}
70+
#endif /* ARDUINO_USB_MODE */

‎libraries/USB/examples/MIDI/MidiMusicBox/.skip.esp32

Copy file name to clipboardExpand all lines: libraries/USB/examples/MIDI/MidiMusicBox/.skip.esp32
Whitespace-only changes.

‎libraries/USB/examples/MIDI/MidiMusicBox/.skip.esp32c3

Copy file name to clipboardExpand all lines: libraries/USB/examples/MIDI/MidiMusicBox/.skip.esp32c3
Whitespace-only changes.

‎libraries/USB/examples/MIDI/MidiMusicBox/.skip.esp32c6

Copy file name to clipboardExpand all lines: libraries/USB/examples/MIDI/MidiMusicBox/.skip.esp32c6
Whitespace-only changes.

‎libraries/USB/examples/MIDI/MidiMusicBox/.skip.esp32h2

Copy file name to clipboardExpand all lines: libraries/USB/examples/MIDI/MidiMusicBox/.skip.esp32h2
Whitespace-only changes.
+59Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
This is an example of a MIDI Music Box using an ESP32 with a native USB support stack (S2, S3, etc.).
3+
4+
Every time the button on the ESP32 board (attached to pin 0) is pressed the next note of a melody is
5+
played. It is up to the user to get the timing of the button presses right.
6+
7+
One simple way of running this sketch is to download the Pianoteq evaluation version, because upon
8+
application start it automatically listens to the first MIDI Input on Channel 1, which is the case,
9+
if the ESP32 is the only MIDI device attached.
10+
11+
View this sketch in action on YouTube: https://youtu.be/JFrc-wSmcus
12+
*/
13+
#if ARDUINO_USB_MODE
14+
#warning This sketch should be used when USB is in OTG mode
15+
void setup() {}
16+
void loop() {}
17+
#else
18+
19+
#include "USB.h"
20+
#include "USBMIDI.h"
21+
USBMIDI MIDI;
22+
23+
#define END_OF_SONG 255
24+
uint8_t notes[] = {END_OF_SONG, 71, 76, 79, 78, 76, 83, 81, 78, 76, 79, 78, 75, 77, 71};
25+
uint8_t noteIndex = 0; // From 0 to sizeof(notes)
26+
#define SONG_LENGTH (sizeof(notes) - 1) // END_OF_SONG does not attribute to the length.
27+
28+
#define BUTTON_PIN 0
29+
30+
// Simple button press check with debounce
31+
// (See also: https://tinyurl.com/simple-debounce)
32+
bool isButtonPressed() {
33+
static uint16_t state = 0;
34+
state = (state << 1) | digitalRead(BUTTON_PIN) | 0xfe00;
35+
return (state == 0xff00);
36+
}
37+
38+
void setup() {
39+
Serial.begin(115200);
40+
// Make the BUTTON_PIN an input:
41+
pinMode(BUTTON_PIN, INPUT_PULLUP);
42+
43+
MIDI.begin();
44+
USB.begin();
45+
}
46+
47+
void loop() {
48+
if (isButtonPressed()) {
49+
// Stop current note
50+
MIDI.noteOff(notes[noteIndex]);
51+
52+
// Play next note
53+
noteIndex = noteIndex < SONG_LENGTH ? noteIndex + 1 : 0;
54+
if (notes[noteIndex] != END_OF_SONG) {
55+
MIDI.noteOn(notes[noteIndex], 64);
56+
}
57+
}
58+
}
59+
#endif /* ARDUINO_USB_MODE */

‎libraries/USB/examples/MIDI/ReceiveMidi/.skip.esp32

Copy file name to clipboardExpand all lines: libraries/USB/examples/MIDI/ReceiveMidi/.skip.esp32
Whitespace-only changes.

‎libraries/USB/examples/MIDI/ReceiveMidi/.skip.esp32c3

Copy file name to clipboardExpand all lines: libraries/USB/examples/MIDI/ReceiveMidi/.skip.esp32c3
Whitespace-only changes.

‎libraries/USB/examples/MIDI/ReceiveMidi/.skip.esp32c6

Copy file name to clipboardExpand all lines: libraries/USB/examples/MIDI/ReceiveMidi/.skip.esp32c6
Whitespace-only changes.

‎libraries/USB/examples/MIDI/ReceiveMidi/.skip.esp32h2

Copy file name to clipboardExpand all lines: libraries/USB/examples/MIDI/ReceiveMidi/.skip.esp32h2
Whitespace-only changes.
+104Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
This is an example of receiving USB MIDI 1.0 messages using an ESP32 with a native USB support stack
3+
(S2, S3, etc.).
4+
5+
Receiving and decoding USB MIDI 1.0 packets is a more advanced topic than sending MIDI over USB,
6+
please refer to the other examples in this library for a more basic example of sending MIDI over USB.
7+
8+
This example should still be self explanatory, please refer to the USB MIDI 1.0 specification (the spec)
9+
for a more in-depth explanation of the packet format.
10+
11+
For the spec please visit: https://www.midi.org/specifications-old/item/usb-midi-1-0-specification
12+
*/
13+
#if ARDUINO_USB_MODE
14+
#warning This sketch should be used when USB is in OTG mode
15+
void setup() {}
16+
void loop() {}
17+
#else
18+
19+
#include "USB.h"
20+
#include "USBMIDI.h"
21+
USBMIDI MIDI;
22+
23+
void setup() {
24+
Serial.begin(115200);
25+
26+
MIDI.begin();
27+
USB.begin();
28+
}
29+
30+
void loop() {
31+
midiEventPacket_t midi_packet_in = {0};
32+
33+
if (MIDI.readPacket(&midi_packet_in)) {
34+
printDetails(midi_packet_in);
35+
}
36+
}
37+
38+
void printDetails(midiEventPacket_t &midi_packet_in) {
39+
// See Chapter 4: USB-MIDI Event Packets (page 16) of the spec.
40+
uint8_t cable_num = MIDI_EP_HEADER_CN_GET(midi_packet_in.header);
41+
midi_code_index_number_t code_index_num = MIDI_EP_HEADER_CIN_GET(midi_packet_in.header);
42+
43+
Serial.println("Received a USB MIDI packet:");
44+
Serial.println(".----.-----.--------.--------.--------.");
45+
Serial.println("| CN | CIN | STATUS | DATA 0 | DATA 1 |");
46+
Serial.println("+----+-----+--------+--------+--------+");
47+
Serial.printf("| %d | %X | %X | %X | %X |\n", cable_num, code_index_num,
48+
midi_packet_in.byte1, midi_packet_in.byte2, midi_packet_in.byte3);
49+
Serial.println("'----'-----'--------.--------'--------'\n");
50+
Serial.print("Description: ");
51+
52+
switch (code_index_num) {
53+
case MIDI_CIN_MISC:
54+
Serial.println("This a Miscellaneous event");
55+
break;
56+
case MIDI_CIN_CABLE_EVENT:
57+
Serial.println("This a Cable event");
58+
break;
59+
case MIDI_CIN_SYSCOM_2BYTE: // 2 byte system common message e.g MTC, SongSelect
60+
case MIDI_CIN_SYSCOM_3BYTE: // 3 byte system common message e.g SPP
61+
Serial.println("This a System Common (SysCom) event");
62+
break;
63+
case MIDI_CIN_SYSEX_START: // SysEx starts or continue
64+
case MIDI_CIN_SYSEX_END_1BYTE: // SysEx ends with 1 data, or 1 byte system common message
65+
case MIDI_CIN_SYSEX_END_2BYTE: // SysEx ends with 2 data
66+
case MIDI_CIN_SYSEX_END_3BYTE: // SysEx ends with 3 data
67+
Serial.println("This a system exclusive (SysEx) event");
68+
break;
69+
case MIDI_CIN_NOTE_ON:
70+
Serial.printf("This a Note-On event of Note %d with a Velocity of %d\n",
71+
midi_packet_in.byte2, midi_packet_in.byte3);
72+
break;
73+
case MIDI_CIN_NOTE_OFF:
74+
Serial.printf("This a Note-Off event of Note %d with a Velocity of %d\n",
75+
midi_packet_in.byte2, midi_packet_in.byte3);
76+
break;
77+
case MIDI_CIN_POLY_KEYPRESS:
78+
Serial.printf("This a Poly Aftertouch event for Note %d and Value %d\n",
79+
midi_packet_in.byte2, midi_packet_in.byte3);
80+
break;
81+
case MIDI_CIN_CONTROL_CHANGE:
82+
Serial.printf("This a Control Change/Continuous Controller (CC) event of Controller %d "
83+
"with a Value of %d\n",
84+
midi_packet_in.byte2, midi_packet_in.byte3);
85+
break;
86+
case MIDI_CIN_PROGRAM_CHANGE:
87+
Serial.printf("This a Program Change event with a Value of %d\n", midi_packet_in.byte2);
88+
break;
89+
case MIDI_CIN_CHANNEL_PRESSURE:
90+
Serial.printf("This a Channel Pressure event with a Value of %d\n", midi_packet_in.byte2);
91+
break;
92+
case MIDI_CIN_PITCH_BEND_CHANGE:
93+
Serial.printf("This a Pitch Bend Change event with a Value of %d\n",
94+
((uint16_t)midi_packet_in.byte2) << 7 | midi_packet_in.byte3);
95+
break;
96+
case MIDI_CIN_1BYTE_DATA:
97+
Serial.printf("This an embedded Serial MIDI event byte with Value %X\n",
98+
midi_packet_in.byte1);
99+
break;
100+
}
101+
102+
Serial.println();
103+
}
104+
#endif /* ARDUINO_USB_MODE */

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.