minikbd/midi-dials/Src/usbd_midi_if.c
2020-04-01 00:40:03 +02:00

480 lines
12 KiB
C

/**
******************************************************************************
* @file : usbd_midi_if.c
* @brief :
******************************************************************************
(CC at)2016 by D.F.Mac. @TripArts Music
******************************************************************************
Modified by keshikan (www.keshikan.net) 2018
The license is (CC BY 4.0), and takes over from original usbd_midi_if.h/c.
See also original source code page.
https://github.com/mimuz/mimuz-tuch/blob/master/STM32/
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbd_midi_if.h"
#include "stm32f0xx_hal.h"
// basic midi rx/tx functions
static uint16_t MIDI_DataRx(uint8_t *msg, uint16_t length);
static uint16_t MIDI_DataTx(uint8_t *msg, uint16_t length);
// for Cure Series
#define MIDI_BUFFER_SIZ (512)//FIFO buffer byte size for midi message buffer
RingBufferU8 rbuf_usb_rx[MIDI_OUT_JACK_NUM]; //for input from USB
RingBufferU8 rbuf_jack_rx[MIDI_IN_JACK_NUM]; //for input from MIDI-IN jack
//for receiving midi data from jack
MidiAnalysisStatus analyzed_status[MIDI_IN_JACK_NUM];
MIDIEvent midi_event[MIDI_IN_JACK_NUM]; //received midi data
uint8_t rx_midi_msg[MIDI_IN_JACK_NUM];
FUNC_STATUS midiInit()
{
uint32_t i,j;
for(i=0; i<MIDI_OUT_JACK_NUM; i++){
if(BUFFER_SUCCESS != cureRingBufferU8Init(&rbuf_usb_rx[i], MIDI_BUFFER_SIZ))
{
return FUNC_ERROR;
}
}
for(i=0; i<MIDI_IN_JACK_NUM; i++){
if(BUFFER_SUCCESS != cureRingBufferU8Init(&rbuf_jack_rx[i], MIDI_BUFFER_SIZ))
{
return FUNC_ERROR;
}
}
//Init RX
for(i=0; i<MIDI_IN_JACK_NUM; i++){
rx_midi_msg[i] = 0x00;
analyzed_status[i].data_idx = 0;
midi_event[i].length = 0;
for(j=0; j<MIDI_SENDDATA_MAX; j++){
midi_event[i].midi_byte[j] = 0x00;
}
}
return FUNC_SUCCESS;
}
FUNC_STATUS midiGetFromUsbRx(uint8_t cable_num, uint8_t* dat)
{
if(BUFFER_SUCCESS != cureRingBufferU8Dequeue(&rbuf_usb_rx[cable_num], dat))
{
return FUNC_ERROR;
}
return FUNC_SUCCESS;
}
FUNC_STATUS midiGetFromJackRx(uint8_t cable_num)
{
if(BUFFER_SUCCESS != cureRingBufferU8Dequeue(&rbuf_jack_rx[cable_num], &rx_midi_msg[cable_num]))
{
return FUNC_ERROR;
}
return FUNC_SUCCESS;
}
FUNC_STATUS midiSetFromJackRx(uint8_t cable_num, uint8_t* dat)
{
if(BUFFER_SUCCESS != cureRingBufferU8Enqueue(&rbuf_jack_rx[cable_num], dat))
{
return FUNC_ERROR;
}
return FUNC_SUCCESS;
}
bool isUsbRxBufEmpty(uint8_t cable_num)
{
if( 0 != _cureRingBufferU8GetUsedSize(&rbuf_usb_rx[cable_num]) ){
return false;
}
return true;
}
bool isJackRxBufEmpty(uint8_t cable_num)
{
if( 0 != _cureRingBufferU8GetUsedSize(&rbuf_jack_rx[cable_num]) ){
return false;
}
return true;
}
bool isRxBufEmpty()
{
uint32_t i;
for(i=0; i<MIDI_OUT_JACK_NUM; i++){
if(0 != _cureRingBufferU8GetUsedSize(&rbuf_usb_rx[i]))
{
return false;
}
}
for(i=0; i<MIDI_IN_JACK_NUM; i++){
if(0 != _cureRingBufferU8GetUsedSize(&rbuf_jack_rx[i]))
{
return false;
}
}
return true;
}
USBD_MIDI_ItfTypeDef USBD_Interface_fops_FS =
{
MIDI_DataRx,
MIDI_DataTx
};
static uint16_t MIDI_DataRx(uint8_t *msg, uint16_t length){
uint16_t cnt;
uint16_t msgs = length / 4;
uint16_t chk = length % 4;
uint8_t u8b;
uint8_t midi_size;
if(0 != chk)
{
return 0;
}
for(uint32_t cnt_msgs = 0; cnt_msgs < msgs; cnt_msgs++){
uint8_t cable_num = (msg[0 + 4*cnt_msgs] & 0xF0) >> 4;
uint8_t code_idx_num = msg[0 + 4*cnt_msgs] & 0x0F;
switch (code_idx_num) {
//not defined
case 0x0:
case 0x1:
midi_size = 0;
break;
//1byte message
case 0x5:
case 0xF:
midi_size = 1;
break;
//2byte message
case 0x2:
case 0x6:
case 0xC:
case 0xD:
midi_size = 2;
break;
//3byte message
case 0x3:
case 0x4:
case 0x7:
case 0x8:
case 0x9:
case 0xA:
case 0xB:
case 0xE:
midi_size = 3;
break;
default:
midi_size = 0;
break;
}
for(cnt = 0;cnt < midi_size;cnt ++){
u8b = *(msg + 4*cnt_msgs + cnt + 1);
cureRingBufferU8Enqueue(&rbuf_usb_rx[cable_num], &u8b);
}
}
return 0;
}
void sendMidiMessage(uint8_t *msg, uint16_t size){
if(size == 4){
// APP_Rx_Buffer[0] = msg[0];
// APP_Rx_Buffer[1] = msg[1];
// APP_Rx_Buffer[2] = msg[2];
// APP_Rx_Buffer[3] = msg[3];
// USBD_MIDI_SendData(&hUsbDeviceFS, APP_Rx_Buffer, size);
MIDI_DataTx(msg, size);
}
}
static uint16_t MIDI_DataTx(uint8_t *msg, uint16_t length){
uint32_t i = 0;
while (i < length) {
APP_Rx_Buffer[APP_Rx_ptr_in] = *(msg + i);
APP_Rx_ptr_in++;
i++;
if (APP_Rx_ptr_in == APP_RX_DATA_SIZE) {
APP_Rx_ptr_in = 0;
}
}
return USBD_OK;
}
bool midiEventIsGenerated(uint8_t cable_num)
{
uint8_t upper_half_byte= (rx_midi_msg[cable_num]) & 0xF0;
if( upper_half_byte & 0x80 ){//0x80-0xFF:status byte
switch(upper_half_byte){
case 0xF0://0xF0-0xFF:system message
switch(rx_midi_msg[cable_num]){
case 0xF0://SysEx Start
analyzed_status[cable_num].data_idx = 0;
midi_event[cable_num].midi_byte[ analyzed_status[cable_num].data_idx++ ] = rx_midi_msg[cable_num];
analyzed_status[cable_num].type = MSG_SYSEX;
analyzed_status[cable_num].stat = WAIT_SYSTEM_DATA;
break;
case 0xF7://SysEx End
midi_event[cable_num].midi_byte[ analyzed_status[cable_num].data_idx++ ] = rx_midi_msg[cable_num];
midi_event[cable_num].length = analyzed_status[cable_num].data_idx;
analyzed_status[cable_num].stat = END_ANALYSIS;
break;
case 0xF2://Song Position
midi_event[cable_num].midi_byte[0] = rx_midi_msg[cable_num];
analyzed_status[cable_num].type = MSG_THREE_BYTE;
analyzed_status[cable_num].stat = WAIT_DATA1;
break;
case 0xF1://Time Code
case 0xF3://Song Select
midi_event[cable_num].midi_byte[0] = rx_midi_msg[cable_num];
analyzed_status[cable_num].type = MSG_TWO_BYTE;
analyzed_status[cable_num].stat = WAIT_DATA1;
break;
case 0xF4://Undefined
case 0xF5://Undefined
case 0xF6://Tune request
case 0xF8://Timing clock
case 0xF9://Undefined
case 0xFA://Start
case 0xFB://Continue
case 0xFC://Stop
case 0xFD://Undefined
case 0xFE://Active Sensing
case 0xFF://Reset
midi_event[cable_num].midi_byte[0] = rx_midi_msg[cable_num];
midi_event[cable_num].length = 1;
analyzed_status[cable_num].type = MSG_ONE_BYTE;
analyzed_status[cable_num].stat = END_ANALYSIS;
break;
}
analyzed_status[cable_num].is_system_common = true;
break;
case 0x80://Note Off
case 0x90://Note On
case 0xA0://Polyphonic key-pressure
case 0xB0://ControlChange
case 0xE0://PitchBend
midi_event[cable_num].midi_byte[0] = rx_midi_msg[cable_num];
analyzed_status[cable_num].type = MSG_THREE_BYTE;
analyzed_status[cable_num].stat = WAIT_DATA1;
analyzed_status[cable_num].is_system_common = false;
break;
case 0xC0://Program Change
case 0xD0://Channel pressure
midi_event[cable_num].midi_byte[0] = rx_midi_msg[cable_num];
analyzed_status[cable_num].type = MSG_TWO_BYTE;
analyzed_status[cable_num].stat = WAIT_DATA1;
analyzed_status[cable_num].is_system_common = false;
break;
default:
analyzed_status[cable_num].type = MSG_NOTHING;
analyzed_status[cable_num].stat = START_ANALYSIS;
analyzed_status[cable_num].is_system_common = false;
break;
}
}else{//0x00-0x7F:data byte
switch(analyzed_status[cable_num].stat){
case WAIT_DATA1:
midi_event[cable_num].midi_byte[1] = rx_midi_msg[cable_num];
if(MSG_THREE_BYTE == analyzed_status[cable_num].type ){
analyzed_status[cable_num].stat = WAIT_DATA2;
}else if( MSG_TWO_BYTE == analyzed_status[cable_num].type ){
midi_event[cable_num].length = 2;
analyzed_status[cable_num].stat = END_ANALYSIS;
}else{
analyzed_status[cable_num].stat = START_ANALYSIS;
}
break;
case WAIT_DATA2:
if(MSG_THREE_BYTE == analyzed_status[cable_num].type ){
midi_event[cable_num].midi_byte[2] = rx_midi_msg[cable_num];
midi_event[cable_num].length = 3;
analyzed_status[cable_num].stat = END_ANALYSIS;
}else{
analyzed_status[cable_num].stat = START_ANALYSIS;
}
break;
case WAIT_SYSTEM_DATA:
midi_event[cable_num].midi_byte[ analyzed_status[cable_num].data_idx++ ] = rx_midi_msg[cable_num];
if(analyzed_status[cable_num].data_idx > (MIDI_SENDDATA_MAX - 1) ){
analyzed_status[cable_num].stat = END_ANALYSIS;
}
break;
case END_ANALYSIS://running status:When status byte is omitted.
midi_event[cable_num].midi_byte[1] = rx_midi_msg[cable_num];
if(MSG_THREE_BYTE == analyzed_status[cable_num].type){
analyzed_status[cable_num].stat = WAIT_DATA2;
}else if(MSG_TWO_BYTE == analyzed_status[cable_num].type){
midi_event[cable_num].length = 2;
analyzed_status[cable_num].stat = END_ANALYSIS;
}
break;
case START_ANALYSIS:
break;
default:
break;
}
}
if(END_ANALYSIS == analyzed_status[cable_num].stat){
return true;
}else{
return false;
}
}
void midiGenerateUsbPacket(uint8_t cable_num)
{
uint8_t msg_buf[4] = {0x00,0x00,0x00,0x00};
uint32_t cnt_remain=0, cnt_length;
switch(analyzed_status[cable_num].type){
case MSG_ONE_BYTE:
//byte 0: cable number + code index number
msg_buf[0] = (cable_num << 4) + ((midi_event[cable_num].midi_byte[0] & 0xF0) >> 4);
sendMidiMessage(msg_buf,4);
break;
case MSG_TWO_BYTE:
case MSG_THREE_BYTE:
//byte 0: cable number + code index number
if(analyzed_status[cable_num].is_system_common){
msg_buf[0] = (cable_num << 4) + midi_event[cable_num].length;
}else{
msg_buf[0] = (cable_num << 4) + ((midi_event[cable_num].midi_byte[0] & 0xF0) >> 4);
}
//byte 1-3
for(uint32_t i=0; i<midi_event[cable_num].length; i++){
msg_buf[i+1] = midi_event[cable_num].midi_byte[i];
}
sendMidiMessage(msg_buf,4);
break;
case MSG_SYSEX:
for(cnt_length = 0; cnt_length < midi_event[cable_num].length; cnt_length++){
if( 0xF7 !=midi_event[cable_num].midi_byte[cnt_length] ){
if(2 == cnt_remain){
msg_buf[3] = midi_event[cable_num].midi_byte[cnt_length];
msg_buf[0] = (cable_num << 4) + 0x4; //SysEx starts or continues
sendMidiMessage(msg_buf,4);
}else{
msg_buf[1 + cnt_remain] = midi_event[cable_num].midi_byte[cnt_length];
}
}else{
switch (cnt_remain) {
case 0:
msg_buf[0] = (cable_num << 4) + 0x5; //SysEx ends with following single byte
msg_buf[1] = 0xF7;
msg_buf[2] = msg_buf[3] = 0x00;
sendMidiMessage(msg_buf,4);
break;
case 1:
msg_buf[0] = (cable_num << 4) + 0x6; //SysEx ends with following two bytes.
msg_buf[2] = 0xF7;
msg_buf[3] = 0x00;
sendMidiMessage(msg_buf,4);
break;
case 2:
msg_buf[0] = (cable_num << 4) + 0x7; //SysEx ends with following three bytes.
msg_buf[3] = 0xF7;
sendMidiMessage(msg_buf,4);
break;
default:
break;
}
}
cnt_remain++;
if(cnt_remain >=3){
cnt_remain = 0;
}
}
break;
default:
break;
}
USBD_MIDI_SendPacket();
}
void midiProcess(){
for(uint32_t cable_num=0; cable_num<MIDI_IN_JACK_NUM; cable_num++){
while( FUNC_SUCCESS == midiGetFromJackRx(cable_num) ){
if( midiEventIsGenerated(cable_num) ){// Generate MIDI event from UART buffer.
//Analyze MIDI Message.
midiGenerateUsbPacket(cable_num);
}
}
}
}