Last active
December 11, 2023 08:44
-
-
Save cowboy/9c9ea9151a330e1e4552e76292a12bf4 to your computer and use it in GitHub Desktop.
USB MIDI device -> filter -> DIN MIDI out - for Teensy LC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// To give your project a unique name, this code must be | |
// placed into a .c file (its own tab). It can not be in | |
// a .cpp file or your main sketch (the .ino file). | |
#include "usb_names.h" | |
// Edit these lines to create your own name. The length must | |
// match the number of characters in your custom name. | |
#define MIDI_NAME {'R','e','n','a','m','e',' ','M','e',' ','D','u','d','e'} | |
#define MIDI_NAME_LEN 14 | |
// Do not change this part. This exact format is required by USB. | |
struct usb_string_descriptor_struct usb_string_product_name = { | |
2 + MIDI_NAME_LEN * 2, | |
3, | |
MIDI_NAME | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// =============================================================== | |
// USB MIDI device -> filter -> DIN MIDI out - for Teensy LC | |
// =============================================================== | |
// Settings: | |
// Tools > USB Type to "MIDI" | |
#include <MIDI.h> // access to serial (5 pin DIN) MIDI | |
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, downstreamDinMIDI); | |
// ===================== | |
// LED BASICS | |
// ===================== | |
int LED_OTHER = 17; | |
int LED_HOST_ACTIVITY = 20; | |
void blink(int count) { | |
int delay_ms = 100; | |
for (int i = 0; i < count; i++) { | |
digitalWrite(LED_OTHER, HIGH); | |
delay(delay_ms); | |
digitalWrite(LED_OTHER, LOW); | |
delay(delay_ms); | |
} | |
} | |
// ===================== | |
// SETUP | |
// ===================== | |
void setup() { | |
downstreamDinMIDI.begin(MIDI_CHANNEL_OMNI); | |
pinMode(LED_OTHER, OUTPUT); | |
pinMode(LED_HOST_ACTIVITY, OUTPUT); | |
blink(3); | |
} | |
// ===================== | |
// CLOCK LOGIC | |
// ===================== | |
// Assume 4/4 time | |
int BEATS_PER_MEASURE = 4; | |
int PPQN = 24; | |
int MAX_PULSES = BEATS_PER_MEASURE * PPQN; | |
bool clockRunning = false; | |
int clockCounter = 0; | |
void updateClock() { | |
if (clockCounter % PPQN == 0) { | |
digitalWriteFast(LED_OTHER, HIGH); | |
} else if (clockCounter % (PPQN / 2) == 0) { | |
digitalWriteFast(LED_OTHER, LOW); | |
} | |
int currentBeat = clockCounter / PPQN; | |
if (++clockCounter >= MAX_PULSES) { | |
clockCounter = 0; | |
} | |
} | |
void startClock() { | |
clockCounter = 0; | |
clockRunning = true; | |
} | |
void stopClock() { | |
clockCounter = 0; | |
clockRunning = false; | |
digitalWriteFast(LED_OTHER, LOW); | |
} | |
// ===================== | |
// LED MIDI ACTIVITY | |
// ===================== | |
// Different types of MIDI messages should display for different lengths of time | |
const int MIDI_MESSAGE_NONE = 0; | |
const int MIDI_MESSAGE_DEFAULT = 1; | |
const int MIDI_MESSAGE_CLOCK = 2; | |
const uint8_t ledTimeMap[3] = { | |
0, // MIDI_MESSAGE_NONE | |
15, // MIDI_MESSAGE_DEFAULT | |
1 // MIDI_MESSAGE_CLOCK | |
}; | |
// Keep track of the current MIDI message type | |
int hostCurrentMessageType = MIDI_MESSAGE_NONE; | |
// A variable to know how long the LED has been turned on | |
elapsedMillis hostActivityLedTime; | |
// ===================== | |
// RUN LOOP | |
// ===================== | |
void loop() { | |
bool hostActivity = false; | |
// Read messages the PC (upstream host) sends and forward them to devices | |
if (usbMIDI.read()) { | |
byte type = usbMIDI.getType(); | |
byte data1 = usbMIDI.getData1(); | |
byte data2 = usbMIDI.getData2(); | |
byte channel = usbMIDI.getChannel(); | |
const uint8_t *sys = usbMIDI.getSysExArray(); | |
byte cable = usbMIDI.getCable(); | |
hostActivity = sendToDownstreamDevice(type, data1, data2, channel, sys, cable); | |
} | |
// Flash LED on activity | |
if (hostActivity) { | |
digitalWriteFast(LED_HOST_ACTIVITY, HIGH); | |
hostActivityLedTime = 0; | |
} | |
if (hostCurrentMessageType != MIDI_MESSAGE_NONE && hostActivityLedTime > ledTimeMap[hostCurrentMessageType]) { | |
hostCurrentMessageType = MIDI_MESSAGE_NONE; | |
digitalWriteFast(LED_HOST_ACTIVITY, LOW); | |
} | |
} | |
// ===================== | |
// HANDLE MIDI MESSAGES | |
// ===================== | |
// Send data from the upstream host (eg. computer) to the downstream MIDI device (eg. controller) | |
bool sendToDownstreamDevice(byte type, byte data1, byte data2, byte channel, const uint8_t *sysexarray, byte cable) { | |
int prevMessageType = hostCurrentMessageType; | |
hostCurrentMessageType = MIDI_MESSAGE_DEFAULT; | |
if (type != usbMIDI.SystemExclusive) { | |
// Handle clock and MMC messages | |
if (type == usbMIDI.Clock) { | |
hostCurrentMessageType = prevMessageType == MIDI_MESSAGE_NONE ? MIDI_MESSAGE_CLOCK : prevMessageType; | |
updateClock(); | |
} else if (type == usbMIDI.Start || type == usbMIDI.Continue) { | |
startClock(); | |
} else if (type == usbMIDI.Stop) { | |
stopClock(); | |
} | |
downstreamDinMIDI.send(type, data1, data2, channel); | |
// if (type == usbMIDI.Clock) { | |
// return false; | |
// } | |
} | |
else { | |
unsigned int SysExLength = data1 + data2 * 256; | |
downstreamDinMIDI.sendSysEx(SysExLength, sysexarray, true); | |
} | |
return true; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment