Skip to content

Commit

Permalink
Improve USB MIDI Implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
DatanoiseTV committed Sep 13, 2024
1 parent fe71053 commit 7cde60e
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 60 deletions.
51 changes: 23 additions & 28 deletions include/midi_input_usb.h
Original file line number Diff line number Diff line change
@@ -1,38 +1,33 @@
#ifndef __MIDI_INPUT_USB__H__
#define __MIDI_INPUT_USB__H__
#ifndef MIDI_INPUT_USB_H
#define MIDI_INPUT_USB_H

#include <functional>
#include <stdint.h>

#include "pico/stdlib.h"
#include "hardware/uart.h"
#include "project_config.h"
#include "tusb.h"

class MIDIInputUSB
{
class MIDIInputUSB {
public:
MIDIInputUSB() {

}

void process();

// Callback setters
void setNoteOnCallback(void (*callback)(uint8_t, uint8_t, uint8_t));
void setNoteOffCallback(void (*callback)(uint8_t, uint8_t, uint8_t));
void setCCCallback(void (*callback)(uint8_t, uint8_t, uint8_t));
void setPitchBendCallback(void (*callback)(uint16_t, uint8_t));
void setAftertouchCallback(void (*callback)(uint8_t, uint8_t));
void setChannelPressureCallback(void (*callback)(uint8_t, uint8_t));

private:
const char MIDICH = 1;

char MIDIRunningStatus;
char MIDINote;
char MIDILevel;

void (*MIDINoteOnCallback)(uint8_t, uint8_t, uint8_t);
void (*MIDINoteOffCallback)(uint8_t, uint8_t, uint8_t);
void (*MIDICCCallback)(uint8_t, uint8_t, uint8_t);

void midi_task();
// MIDI processing function
void process();

private:
// Callback function pointers using std::function for flexibility
std::function<void(uint8_t, uint8_t, uint8_t)> MIDINoteOnCallback = nullptr;
std::function<void(uint8_t, uint8_t, uint8_t)> MIDINoteOffCallback = nullptr;
std::function<void(uint8_t, uint8_t, uint8_t)> MIDICCCallback = nullptr;
std::function<void(uint16_t, uint8_t)> MIDIPitchBendCallback = nullptr;
std::function<void(uint8_t, uint8_t)> MIDIAftertouchCallback = nullptr;
std::function<void(uint8_t, uint8_t)> MIDIChannelPressureCallback = nullptr;

// Helper function for parsing pitch bend data
uint16_t parsePitchBend(const uint8_t* packet);
};

#endif // __MIDI_INPUT_USB_H__
#endif // MIDI_INPUT_USB_H
100 changes: 68 additions & 32 deletions src/midi_input_usb.cpp
Original file line number Diff line number Diff line change
@@ -1,55 +1,91 @@
#include "midi_input_usb.h"
#include "tusb.h" // Assuming you're using TinyUSB

void MIDIInputUSB::setNoteOnCallback(void (*callback)(uint8_t, uint8_t, uint8_t))
{
// Setters for the various MIDI callbacks
void MIDIInputUSB::setNoteOnCallback(void (*callback)(uint8_t, uint8_t, uint8_t)) {
MIDINoteOnCallback = callback;
}

void MIDIInputUSB::setNoteOffCallback(void (*callback)(uint8_t, uint8_t, uint8_t))
{
void MIDIInputUSB::setNoteOffCallback(void (*callback)(uint8_t, uint8_t, uint8_t)) {
MIDINoteOffCallback = callback;
}

void MIDIInputUSB::setCCCallback(void (*callback)(uint8_t, uint8_t, uint8_t))
{
void MIDIInputUSB::setCCCallback(void (*callback)(uint8_t, uint8_t, uint8_t)) {
MIDICCCallback = callback;
}

void MIDIInputUSB::process()
{
void MIDIInputUSB::setPitchBendCallback(void (*callback)(uint16_t, uint8_t)) {
MIDIPitchBendCallback = callback;
}

void MIDIInputUSB::setAftertouchCallback(void (*callback)(uint8_t, uint8_t)) {
MIDIAftertouchCallback = callback;
}

void MIDIInputUSB::setChannelPressureCallback(void (*callback)(uint8_t, uint8_t)) {
MIDIChannelPressureCallback = callback;
}

// Helper function to parse pitch bend data
uint16_t MIDIInputUSB::parsePitchBend(const uint8_t* packet) {
// Combine the two data bytes into a 14-bit pitch bend value
return (packet[2] << 7) | packet[1];
}

void MIDIInputUSB::process() {
uint8_t packet[4];
while (tud_midi_available())
{

while (tud_midi_available()) {
tud_midi_stream_read(packet, 3);

#ifdef DEBUG_MIID
#ifdef DEBUG_MIDI
printf("%02X %02X %02X %02X\n", packet[0], packet[1], packet[2], packet[3]);
#endif

if (packet[0] >> 4 == 0x8 || packet[0] >> 4 == 0x9)
{
if (packet[0] >> 4 == 0x8)
{
if (MIDINoteOffCallback != NULL)
{
MIDINoteOffCallback(packet[1], packet[2], packet[0] & 0xF);
uint8_t status = packet[0] >> 4;
uint8_t channel = packet[0] & 0xF;

switch (status) {
case 0x8: // Note Off
if (MIDINoteOffCallback != nullptr) {
MIDINoteOffCallback(packet[1], packet[2], channel);
}
}
else if(packet[0] >> 4 == 0x9)
{
if (MIDINoteOnCallback != NULL)
{
MIDINoteOnCallback(packet[1], packet[2], packet[0] & 0xF);
break;

case 0x9: // Note On
if (MIDINoteOnCallback != nullptr) {
MIDINoteOnCallback(packet[1], packet[2], channel);
}
}
break;

}
else if (packet[0] >> 4 == 0xB)
{
if (MIDICCCallback != NULL)
{
MIDICCCallback(packet[1], packet[2], packet[0] & 0xF);
}
case 0xB: // Control Change
if (MIDICCCallback != nullptr) {
MIDICCCallback(packet[1], packet[2], channel);
}
break;

case 0xE: // Pitch Bend
if (MIDIPitchBendCallback != nullptr) {
uint16_t pitchBendValue = parsePitchBend(packet);
MIDIPitchBendCallback(pitchBendValue, channel);
}
break;

case 0xA: // Polyphonic Aftertouch
if (MIDIAftertouchCallback != nullptr) {
MIDIAftertouchCallback(packet[1], packet[2]);
}
break;

case 0xD: // Channel Pressure (Aftertouch)
if (MIDIChannelPressureCallback != nullptr) {
MIDIChannelPressureCallback(packet[1], channel);
}
break;

default:
// Handle other types of MIDI messages if needed
break;
}
}
}

0 comments on commit 7cde60e

Please sign in to comment.