Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add missing MIDI callbacks
  • Loading branch information
PaulStoffregen committed Jan 7, 2018
1 parent 6d49f67 commit bcc87c0
Show file tree
Hide file tree
Showing 2 changed files with 212 additions and 49 deletions.
146 changes: 119 additions & 27 deletions teensy3/usb_midi.c
Expand Up @@ -51,9 +51,20 @@ void (*usb_midi_handleControlChange)(uint8_t ch, uint8_t control, uint8_t value)
void (*usb_midi_handleProgramChange)(uint8_t ch, uint8_t program) = NULL;
void (*usb_midi_handleAfterTouch)(uint8_t ch, uint8_t pressure) = NULL;
void (*usb_midi_handlePitchChange)(uint8_t ch, int pitch) = NULL;
void (*usb_midi_handleSysEx)(const uint8_t *data, uint16_t length, uint8_t complete) = NULL;
void (*usb_midi_handleSysExPartial)(const uint8_t *data, uint16_t length, uint8_t complete) = NULL;
void (*usb_midi_handleSysExComplete)(uint8_t *data, unsigned int size) = NULL;
void (*usb_midi_handleTimeCodeQuarterFrame)(uint8_t data) = NULL;
void (*usb_midi_handleSongPosition)(uint16_t beats) = NULL;
void (*usb_midi_handleSongSelect)(uint8_t songnumber) = NULL;
void (*usb_midi_handleTuneRequest)(void) = NULL;
void (*usb_midi_handleClock)(void) = NULL;
void (*usb_midi_handleStart)(void) = NULL;
void (*usb_midi_handleContinue)(void) = NULL;
void (*usb_midi_handleStop)(void) = NULL;
void (*usb_midi_handleActiveSensing)(void) = NULL;
void (*usb_midi_handleSystemReset)(void) = NULL;
void (*usb_midi_handleRealTimeSystem)(uint8_t rtb) = NULL;
void (*usb_midi_handleTimeCodeQuarterFrame)(uint16_t data) = NULL;


// Maximum number of transmit packets to queue so we don't starve other endpoints for memory
#define TX_PACKET_LIMIT 6
Expand Down Expand Up @@ -157,12 +168,10 @@ void usb_midi_flush_output(void)

void static sysex_byte(uint8_t b)
{
// when buffer is full, send another chunk to handler.
if (usb_midi_msg_sysex_len == USB_MIDI_SYSEX_MAX) {
if (usb_midi_handleSysEx) {
(*usb_midi_handleSysEx)(usb_midi_msg_sysex, usb_midi_msg_sysex_len, 0);
usb_midi_msg_sysex_len = 0;
}
if (usb_midi_handleSysExPartial && usb_midi_msg_sysex_len >= USB_MIDI_SYSEX_MAX) {
// when buffer is full, send another chunk to partial handler.
(*usb_midi_handleSysExPartial)(usb_midi_msg_sysex, usb_midi_msg_sysex_len, 0);
usb_midi_msg_sysex_len = 0;
}
if (usb_midi_msg_sysex_len < USB_MIDI_SYSEX_MAX) {
usb_midi_msg_sysex[usb_midi_msg_sysex_len++] = b;
Expand Down Expand Up @@ -299,6 +308,80 @@ int usb_midi_read(uint32_t channel)
usb_midi_msg_data2 = (n >> 24);
return 1;
}
if (type1 == 0x02 || type1 == 0x03 || (type1 == 0x05 && type2 == 0x0F)) {
// system common or system realtime message
uint8_t type;
system_common_or_realtime:
type = n >> 8;
switch (type) {
case 0xF1: // TimeCodeQuarterFrame
if (usb_midi_handleTimeCodeQuarterFrame) {
(*usb_midi_handleTimeCodeQuarterFrame)(n >> 16);
}
break;
case 0xF2: // SongPosition
if (usb_midi_handleSongPosition) {
(*usb_midi_handleSongPosition)(n >> 16);
}
break;
case 0xF3: // SongSelect
if (usb_midi_handleSongSelect) {
(*usb_midi_handleSongSelect)(n >> 16);
}
break;
case 0xF6: // TuneRequest
if (usb_midi_handleTuneRequest) {
(*usb_midi_handleTuneRequest)();
}
break;
case 0xF8: // Clock
if (usb_midi_handleClock) {
(*usb_midi_handleClock)();
} else if (usb_midi_handleRealTimeSystem) {
(*usb_midi_handleRealTimeSystem)(0xF8);
}
break;
case 0xFA: // Start
if (usb_midi_handleStart) {
(*usb_midi_handleStart)();
} else if (usb_midi_handleRealTimeSystem) {
(*usb_midi_handleRealTimeSystem)(0xFA);
}
break;
case 0xFB: // Continue
if (usb_midi_handleContinue) {
(*usb_midi_handleContinue)();
} else if (usb_midi_handleRealTimeSystem) {
(*usb_midi_handleRealTimeSystem)(0xFB);
}
break;
case 0xFC: // Stop
if (usb_midi_handleStop) {
(*usb_midi_handleStop)();
} else if (usb_midi_handleRealTimeSystem) {
(*usb_midi_handleRealTimeSystem)(0xFC);
}
break;
case 0xFE: // ActiveSensing
if (usb_midi_handleActiveSensing) {
(*usb_midi_handleActiveSensing)();
} else if (usb_midi_handleRealTimeSystem) {
(*usb_midi_handleRealTimeSystem)(0xFE);
}
break;
case 0xFF: // SystemReset
if (usb_midi_handleSystemReset) {
(*usb_midi_handleSystemReset)();
} else if (usb_midi_handleRealTimeSystem) {
(*usb_midi_handleRealTimeSystem)(0xFF);
}
break;
default:
return 0; // unknown message, ignore it
}
usb_midi_msg_type = type;
goto return_message;
}
if (type1 == 0x04) {
sysex_byte(n >> 8);
sysex_byte(n >> 16);
Expand All @@ -309,39 +392,48 @@ int usb_midi_read(uint32_t channel)
sysex_byte(n >> 8);
if (type1 >= 0x06) sysex_byte(n >> 16);
if (type1 == 0x07) sysex_byte(n >> 24);
usb_midi_msg_data1 = usb_midi_msg_sysex_len;
usb_midi_msg_data2 = usb_midi_msg_sysex_len >> 8;
uint16_t len = usb_midi_msg_sysex_len;
usb_midi_msg_data1 = len;
usb_midi_msg_data2 = len >> 8;
usb_midi_msg_sysex_len = 0;
usb_midi_msg_type = 7; // 7 = Sys Ex
if (usb_midi_handleSysEx)
(*usb_midi_handleSysEx)(usb_midi_msg_sysex, usb_midi_msg_data1, 1);
if (usb_midi_handleSysExPartial) {
(*usb_midi_handleSysExPartial)(usb_midi_msg_sysex, len, 1);
} else if (usb_midi_handleSysExComplete) {
(*usb_midi_handleSysExComplete)(usb_midi_msg_sysex, len);
}
return 1;
}
if (type1 == 0x0F) {
// TODO: does this need to be a full MIDI parser?
// What software actually uses this message type in practice?
uint8_t b = n >> 8;
if (b >= 0xF8) {
// From Sebastian Tomczak, seb.tomczak at gmail.com
// http://little-scale.blogspot.com/2011/08/usb-midi-game-boy-sync-for-16.html
goto system_common_or_realtime;
}
if (usb_midi_msg_sysex_len > 0) {
// From David Sorlien, dsorlien at gmail.com, http://axe4live.wordpress.com
// OSX sometimes uses Single Byte Unparsed to
// send bytes in the middle of a SYSEX message.
sysex_byte(n >> 8);
} else {
// From Sebastian Tomczak, seb.tomczak at gmail.com
// http://little-scale.blogspot.com/2011/08/usb-midi-game-boy-sync-for-16.html
usb_midi_msg_type = 8;
if (usb_midi_handleRealTimeSystem)
(*usb_midi_handleRealTimeSystem)(n >> 8);
goto return_message;
}
//} else {
// usb_midi_msg_type = 8;
// if (usb_midi_handleRealTimeSystem)
// (*usb_midi_handleRealTimeSystem)(n >> 8);
// goto return_message;
//}
}
if (type1 == 0x02) {
// From Timm Schlegelmilch, karg.music at gmail.com
// http://karg-music.blogspot.de/2015/06/receiving-midi-time-codes-over-usb-with.html
usb_midi_msg_type = 9;
if (usb_midi_handleTimeCodeQuarterFrame)
(*usb_midi_handleTimeCodeQuarterFrame)(n >> 16);
return 1;
}
//if (type1 == 0x02) {
// From Timm Schlegelmilch, karg.music at gmail.com
// http://karg-music.blogspot.de/2015/06/receiving-midi-time-codes-over-usb-with.html
// usb_midi_msg_type = 9;
// if (usb_midi_handleTimeCodeQuarterFrame)
// (*usb_midi_handleTimeCodeQuarterFrame)(n >> 16);
// return 1;
//}
return 0;
}

Expand Down
115 changes: 93 additions & 22 deletions teensy3/usb_midi.h
Expand Up @@ -87,9 +87,19 @@ extern void (*usb_midi_handleControlChange)(uint8_t ch, uint8_t control, uint8_t
extern void (*usb_midi_handleProgramChange)(uint8_t ch, uint8_t program);
extern void (*usb_midi_handleAfterTouch)(uint8_t ch, uint8_t pressure);
extern void (*usb_midi_handlePitchChange)(uint8_t ch, int pitch);
extern void (*usb_midi_handleSysEx)(const uint8_t *data, uint16_t length, uint8_t complete);
extern void (*usb_midi_handleSysExPartial)(const uint8_t *data, uint16_t length, uint8_t complete);
extern void (*usb_midi_handleSysExComplete)(uint8_t *data, unsigned int size);
extern void (*usb_midi_handleTimeCodeQuarterFrame)(uint8_t data);
extern void (*usb_midi_handleSongPosition)(uint16_t beats);
extern void (*usb_midi_handleSongSelect)(uint8_t songnumber);
extern void (*usb_midi_handleTuneRequest)(void);
extern void (*usb_midi_handleClock)(void);
extern void (*usb_midi_handleStart)(void);
extern void (*usb_midi_handleContinue)(void);
extern void (*usb_midi_handleStop)(void);
extern void (*usb_midi_handleActiveSensing)(void);
extern void (*usb_midi_handleSystemReset)(void);
extern void (*usb_midi_handleRealTimeSystem)(uint8_t rtb);
extern void (*usb_midi_handleTimeCodeQuarterFrame)(uint16_t data);

#ifdef __cplusplus
}
Expand Down Expand Up @@ -252,55 +262,116 @@ class usb_midi_class
bool read(uint8_t channel=0) __attribute__((always_inline)) {
return usb_midi_read(channel);
};
inline uint8_t getType(void) __attribute__((always_inline)) {
uint8_t getType(void) __attribute__((always_inline)) {
return usb_midi_msg_type;
};
inline uint8_t getCable(void) __attribute__((always_inline)) {
uint8_t getCable(void) __attribute__((always_inline)) {
return usb_midi_msg_cable;
};
inline uint8_t getChannel(void) __attribute__((always_inline)) {
uint8_t getChannel(void) __attribute__((always_inline)) {
return usb_midi_msg_channel;
};
inline uint8_t getData1(void) __attribute__((always_inline)) {
uint8_t getData1(void) __attribute__((always_inline)) {
return usb_midi_msg_data1;
};
inline uint8_t getData2(void) __attribute__((always_inline)) {
uint8_t getData2(void) __attribute__((always_inline)) {
return usb_midi_msg_data2;
};
inline uint8_t * getSysExArray(void) __attribute__((always_inline)) {
uint8_t * getSysExArray(void) __attribute__((always_inline)) {
return usb_midi_msg_sysex;
};
inline void setHandleNoteOff(void (*fptr)(uint8_t channel, uint8_t note, uint8_t velocity)) {
void setHandleNoteOff(void (*fptr)(uint8_t channel, uint8_t note, uint8_t velocity)) {
// type: 0x80 NoteOff
usb_midi_handleNoteOff = fptr;
};
inline void setHandleNoteOn(void (*fptr)(uint8_t channel, uint8_t note, uint8_t velocity)) {
void setHandleNoteOn(void (*fptr)(uint8_t channel, uint8_t note, uint8_t velocity)) {
// type: 0x90 NoteOn
usb_midi_handleNoteOn = fptr;
};
inline void setHandleVelocityChange(void (*fptr)(uint8_t channel, uint8_t note, uint8_t velocity)) {
void setHandleVelocityChange(void (*fptr)(uint8_t channel, uint8_t note, uint8_t velocity)) {
// type: 0xA0 AfterTouchPoly
usb_midi_handleVelocityChange = fptr;
};
inline void setHandleControlChange(void (*fptr)(uint8_t channel, uint8_t control, uint8_t value)) {
void setHandleAfterTouchPoly(void (*fptr)(uint8_t channel, uint8_t note, uint8_t pressure)) {
// type: 0xA0 AfterTouchPoly
usb_midi_handleVelocityChange = fptr;
};
void setHandleControlChange(void (*fptr)(uint8_t channel, uint8_t control, uint8_t value)) {
// type: 0xB0 ControlChange
usb_midi_handleControlChange = fptr;
};
inline void setHandleProgramChange(void (*fptr)(uint8_t channel, uint8_t program)) {
void setHandleProgramChange(void (*fptr)(uint8_t channel, uint8_t program)) {
// type: 0xC0 ProgramChange
usb_midi_handleProgramChange = fptr;
};
inline void setHandleAfterTouch(void (*fptr)(uint8_t channel, uint8_t pressure)) {
void setHandleAfterTouch(void (*fptr)(uint8_t channel, uint8_t pressure)) {
// type: 0xD0 AfterTouchChannel
usb_midi_handleAfterTouch = fptr;
};
inline void setHandlePitchChange(void (*fptr)(uint8_t channel, int pitch)) {
void setHandleAfterTouchChannel(void (*fptr)(uint8_t channel, uint8_t pressure)) {
// type: 0xD0 AfterTouchChannel
usb_midi_handleAfterTouch = fptr;
};
void setHandlePitchChange(void (*fptr)(uint8_t channel, int pitch)) {
// type: 0xE0 PitchBend
usb_midi_handlePitchChange = fptr;
};
inline void setHandleSysEx(void (*fptr)(const uint8_t *data, uint16_t length, bool complete)) {
usb_midi_handleSysEx = (void (*)(const uint8_t *, uint16_t, uint8_t))fptr;
void setHandleSysEx(void (*fptr)(const uint8_t *data, uint16_t length, bool complete)) {
// type: 0xF0 SystemExclusive - multiple calls for message bigger than buffer
usb_midi_handleSysExPartial = (void (*)(const uint8_t *, uint16_t, uint8_t))fptr;
}
inline void setHandleRealTimeSystem(void (*fptr)(uint8_t realtimebyte)) {
usb_midi_handleRealTimeSystem = fptr;
};
inline void setHandleTimeCodeQuarterFrame(void (*fptr)(uint16_t data)) {
void setHandleSystemExclusive(void (*fptr)(const uint8_t *data, uint16_t length, bool complete)) {
// type: 0xF0 SystemExclusive - multiple calls for message bigger than buffer
usb_midi_handleSysExPartial = (void (*)(const uint8_t *, uint16_t, uint8_t))fptr;
}
void setHandleSystemExclusive(void (*fptr)(uint8_t *data, unsigned int size)) {
// type: 0xF0 SystemExclusive - single call, message larger than buffer is truncated
usb_midi_handleSysExComplete = fptr;
}
void setHandleTimeCodeQuarterFrame(void (*fptr)(uint8_t data)) {
// type: 0xF1 TimeCodeQuarterFrame
usb_midi_handleTimeCodeQuarterFrame = fptr;
};
private:
void setHandleSongPosition(void (*fptr)(uint16_t beats)) {
// type: 0xF2 SongPosition
usb_midi_handleSongPosition = fptr;
}
void setHandleSongSelect(void (*fptr)(uint8_t songnumber)) {
// type: 0xF3 SongSelect
usb_midi_handleSongSelect = fptr;
}
void setHandleTuneRequest(void (*fptr)(void)) {
// type: 0xF6 TuneRequest
usb_midi_handleTuneRequest = fptr;
}
void setHandleClock(void (*fptr)(void)) {
// type: 0xF8 Clock
usb_midi_handleClock = fptr;
}
void setHandleStart(void (*fptr)(void)) {
// type: 0xFA Start
usb_midi_handleStart = fptr;
}
void setHandleContinue(void (*fptr)(void)) {
// type: 0xFB Continue
usb_midi_handleContinue = fptr;
}
void setHandleStop(void (*fptr)(void)) {
// type: 0xFC Stop
usb_midi_handleStop = fptr;
}
void setHandleActiveSensing(void (*fptr)(void)) {
// type: 0xFE ActiveSensing
usb_midi_handleActiveSensing = fptr;
}
void setHandleSystemReset(void (*fptr)(void)) {
// type: 0xFF SystemReset
usb_midi_handleSystemReset = fptr;
}
void setHandleRealTimeSystem(void (*fptr)(uint8_t realtimebyte)) {
// type: 0xF8-0xFF - if more specific handler not configured
usb_midi_handleRealTimeSystem = fptr;
};
};

extern usb_midi_class usbMIDI;
Expand Down

0 comments on commit bcc87c0

Please sign in to comment.