|
|
|
/*
|
|
|
|
MicroDexed
|
|
|
|
|
|
|
|
MicroMDAEPiano is a port of the MDA-EPiano sound engine
|
|
|
|
(https://sourceforge.net/projects/mda-vst/) for the Teensy-3.5/3.6/4.x with audio shield.
|
|
|
|
|
|
|
|
(c)2019-2023 H. Wirtz <wirtz@parasitstudio.de>
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software Foundation,
|
|
|
|
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef MIDI_DEVICES_H
|
|
|
|
#define MIDI_DEVICES_H
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
extern config_t configuration;
|
|
|
|
|
|
|
|
#if defined(MIDI_DEVICE_USB_HOST) || defined(MIDI_DEVICE_USB_HOST_SERIAL)
|
|
|
|
#include <USBHost_t36.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// override default sysex size settings
|
|
|
|
struct MicroDexedSettings : public midi::DefaultSettings {
|
|
|
|
static const bool UseRunningStatus = false;
|
|
|
|
static const bool HandleNullVelocityNoteOnAsNoteOff = true;
|
|
|
|
static const bool Use1ByteParsing = true;
|
|
|
|
static const unsigned SysExMaxSize = 4104;
|
|
|
|
static const bool UseSenderActiveSensing = false;
|
|
|
|
static const bool UseReceiverActiveSensing = false;
|
|
|
|
static const uint16_t SenderActiveSensingPeriodicity = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct CustomBaudRateSettings : public MIDI_NAMESPACE::DefaultSerialSettings {
|
|
|
|
static const long BaudRate = 38400;
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef MIDI_DEVICE_DIN
|
|
|
|
MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, MIDI_DEVICE_DIN, midi_serial, MicroDexedSettings);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(MIDI_DEVICE_USB_HOST) || defined(MIDI_DEVICE_USB_HOST_SERIAL)
|
|
|
|
USBHost usb_host;
|
|
|
|
#endif
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST
|
|
|
|
MIDIDevice midi_usb(usb_host);
|
|
|
|
#endif
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST_SERIAL
|
|
|
|
#if NUM_HUBS_MIDI_DEVICE_USB_HOST_SERIAL < 2
|
|
|
|
USBHub hub1(usb_host);
|
|
|
|
#elif NUM_HUBS_MIDI_DEVICE_USB_HOST_SERIAL < 3
|
|
|
|
USBHub hub2(usb_host);
|
|
|
|
#elif NUM_HUBS_MIDI_DEVICE_USB_HOST_SERIAL < 4
|
|
|
|
USBHub hub3(usb_host);
|
|
|
|
#elif NUM_HUBS_MIDI_DEVICE_USB_HOST_SERIAL < 5
|
|
|
|
USBHub hub4(usb_host);
|
|
|
|
#endif
|
|
|
|
USBSerial_BigBuffer userial(usb_host,1);
|
|
|
|
MIDI_NAMESPACE::SerialMIDI<USBSerial_BigBuffer, CustomBaudRateSettings> serialMIDI(userial);
|
|
|
|
MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<USBSerial_BigBuffer, CustomBaudRateSettings>> usbhost_midi_serial((MIDI_NAMESPACE::SerialMIDI<USBSerial_BigBuffer, CustomBaudRateSettings>&)serialMIDI);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void handleNoteOn(byte inChannel, byte inNumber, byte inVelocity);
|
|
|
|
void handleNoteOff(byte inChannel, byte inNumber, byte inVelocity);
|
|
|
|
void handleControlChange(byte inChannel, byte inData1, byte inData2);
|
|
|
|
void handleAfterTouch(byte inChannel, byte inPressure);
|
|
|
|
void handlePitchBend(byte inChannel, int inPitch);
|
|
|
|
void handleProgramChange(byte inChannel, byte inProgram);
|
|
|
|
void handleAfterTouchPoly(byte inChannel, byte inNumber, byte inVelocity);
|
|
|
|
void handleSystemExclusive(byte *data, uint len);
|
|
|
|
//void handleSystemExclusiveChunk(const byte *data, uint len, bool last);
|
|
|
|
void handleTimeCodeQuarterFrame(byte data);
|
|
|
|
void handleSongSelect(byte inSong);
|
|
|
|
void handleTuneRequest(void);
|
|
|
|
void handleClock(void);
|
|
|
|
void handleStart(void);
|
|
|
|
void handleContinue(void);
|
|
|
|
void handleStop(void);
|
|
|
|
void handleActiveSensing(void);
|
|
|
|
void handleSystemReset(void);
|
|
|
|
//void handleRealTimeSystem(void);
|
|
|
|
void MD_sendControlChange(uint8_t channel, uint8_t cc, uint8_t value);
|
|
|
|
|
|
|
|
#define MIDI_BY_DIN "MIDI_DIN"
|
|
|
|
#define MIDI_BY_USB "USB_MIDI"
|
|
|
|
#define MIDI_BY_USB_HOST "MIDI_USB_HOST"
|
|
|
|
#define MIDI_BY_USB_HOST_SERIAL "MIDI_USB_HOST_SERIAL"
|
|
|
|
|
|
|
|
void handle_generic(byte inChannel, byte inData1, byte inData2, const char *midi_device, midi::MidiType event) {
|
|
|
|
char text[10];
|
|
|
|
|
|
|
|
switch (event) {
|
|
|
|
case midi::NoteOn:
|
|
|
|
handleNoteOn(inChannel, inData1, inData2);
|
|
|
|
strlcpy(text, "NoteOn", sizeof(text));
|
|
|
|
break;
|
|
|
|
case midi::NoteOff:
|
|
|
|
handleNoteOff(inChannel, inData1, inData2);
|
|
|
|
strlcpy(text, "NoteOff", sizeof(text));
|
|
|
|
break;
|
|
|
|
case midi::ControlChange:
|
|
|
|
handleControlChange(inChannel, inData1, inData2);
|
|
|
|
strlcpy(text, "CC", sizeof(text));
|
|
|
|
break;
|
|
|
|
case midi::AfterTouchChannel:
|
|
|
|
handleAfterTouch(inChannel, inData1);
|
|
|
|
strlcpy(text, "Mono AT", sizeof(text));
|
|
|
|
break;
|
|
|
|
case midi::PitchBend:
|
|
|
|
handlePitchBend(inChannel, inData1);
|
|
|
|
strlcpy(text, "PB", sizeof(text));
|
|
|
|
break;
|
|
|
|
case midi::ProgramChange:
|
|
|
|
handleProgramChange(inChannel, inData1);
|
|
|
|
strlcpy(text, "PC", sizeof(text));
|
|
|
|
break;
|
|
|
|
case midi::AfterTouchPoly:
|
|
|
|
handleAfterTouchPoly(inChannel, inData1, inData2);
|
|
|
|
strlcpy(text, "Poly AT", sizeof(text));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.printf_P(PSTR("[%s] %s"), midi_device, text);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// MIDI THRU
|
|
|
|
if (configuration.sys.soft_midi_thru == 1) {
|
|
|
|
#ifdef MIDI_DEVICE_USB
|
|
|
|
if (strcmp(MIDI_BY_USB, midi_device)) {
|
|
|
|
switch (event) {
|
|
|
|
case midi::NoteOn:
|
|
|
|
usbMIDI.sendNoteOn(inData1, inData2, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::NoteOff:
|
|
|
|
usbMIDI.sendNoteOff(inData1, inData2, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::ControlChange:
|
|
|
|
usbMIDI.sendControlChange(inData1, inData2, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::AfterTouchChannel:
|
|
|
|
usbMIDI.sendAfterTouch(inData1, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::PitchBend:
|
|
|
|
usbMIDI.sendPitchBend(inData1, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::ProgramChange:
|
|
|
|
usbMIDI.sendProgramChange(inData1, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::AfterTouchPoly:
|
|
|
|
usbMIDI.sendAfterTouch(inData1, inData2, inChannel);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_USB"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MIDI_DEVICE_DIN
|
|
|
|
if (strcmp(MIDI_BY_DIN, midi_device)) {
|
|
|
|
switch (event) {
|
|
|
|
case midi::NoteOn:
|
|
|
|
midi_serial.sendNoteOn(inData1, inData2, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::NoteOff:
|
|
|
|
midi_serial.sendNoteOff(inData1, inData2, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::ControlChange:
|
|
|
|
midi_serial.sendControlChange(inData1, inData2, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::AfterTouchChannel:
|
|
|
|
midi_serial.sendAfterTouch(inData1, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::PitchBend:
|
|
|
|
midi_serial.sendPitchBend(inData1, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::ProgramChange:
|
|
|
|
midi_serial.sendProgramChange(inData1, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::AfterTouchPoly:
|
|
|
|
midi_serial.sendAfterTouch(inData1, inData2, inChannel);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_DIN"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST
|
|
|
|
if (strcmp(MIDI_BY_USB_HOST, midi_device)) {
|
|
|
|
switch (event) {
|
|
|
|
case midi::NoteOn:
|
|
|
|
midi_usb.sendNoteOn(inData1, inData2, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::NoteOff:
|
|
|
|
midi_usb.sendNoteOff(inData1, inData2, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::ControlChange:
|
|
|
|
midi_usb.sendControlChange(inData1, inData2, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::AfterTouchChannel:
|
|
|
|
midi_usb.sendAfterTouch(inData1, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::PitchBend:
|
|
|
|
midi_usb.sendPitchBend(inData1, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::ProgramChange:
|
|
|
|
midi_usb.sendProgramChange(inData1, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::AfterTouchPoly:
|
|
|
|
midi_usb.sendAfterTouch(inData1, inData2, inChannel);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_USB_HOST"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST_SERIAL
|
|
|
|
if (strcmp(MIDI_BY_USB_HOST_SERIAL, midi_device)) {
|
|
|
|
switch (event) {
|
|
|
|
case midi::NoteOn:
|
|
|
|
usbhost_midi_serial.sendNoteOn(inData1, inData2, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::NoteOff:
|
|
|
|
usbhost_midi_serial.sendNoteOff(inData1, inData2, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::ControlChange:
|
|
|
|
usbhost_midi_serial.sendControlChange(inData1, inData2, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::AfterTouchChannel:
|
|
|
|
usbhost_midi_serial.sendAfterTouch(inData1, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::PitchBend:
|
|
|
|
usbhost_midi_serial.sendPitchBend(inData1, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::ProgramChange:
|
|
|
|
usbhost_midi_serial.sendProgramChange(inData1, inChannel);
|
|
|
|
break;
|
|
|
|
case midi::AfterTouchPoly:
|
|
|
|
usbhost_midi_serial.sendAfterTouch(inData1, inData2, inChannel);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_USB_HOST_SERIAL"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.println();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleSystemExclusive_generic(byte *data, uint len, const char *midi_device) {
|
|
|
|
handleSystemExclusive(data, len);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.printf_P(PSTR("[%s] SysEx"), midi_device);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// MIDI THRU
|
|
|
|
if (configuration.sys.soft_midi_thru == 1) {
|
|
|
|
#ifdef MIDI_DEVICE_USB
|
|
|
|
if (strcmp(MIDI_BY_USB, midi_device)) {
|
|
|
|
usbMIDI.sendSysEx(len, data);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_USB"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MIDI_DEVICE_DIN
|
|
|
|
if (strcmp(MIDI_BY_DIN, midi_device)) {
|
|
|
|
midi_serial.sendSysEx(len, data);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_DIN"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST
|
|
|
|
if (strcmp(MIDI_BY_USB_HOST, midi_device)) {
|
|
|
|
midi_usb.sendSysEx(len, data);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_USB_HOST"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST_SERIAL
|
|
|
|
if (strcmp(MIDI_BY_USB_HOST_SERIAL, midi_device)) {
|
|
|
|
usbhost_midi_serial.sendSysEx(len, data);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_USB_HOST_SERIAL"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.println();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleSystemCommon_generic(byte inData1, const char *midi_device, midi::MidiType event) {
|
|
|
|
char text[10];
|
|
|
|
|
|
|
|
switch (event) {
|
|
|
|
case midi::TimeCodeQuarterFrame:
|
|
|
|
handleTimeCodeQuarterFrame(inData1);
|
|
|
|
strlcpy(text, "TimeCodeQuarterFrame", sizeof(text));
|
|
|
|
break;
|
|
|
|
case midi::SongSelect:
|
|
|
|
handleSongSelect(inData1);
|
|
|
|
strlcpy(text, "SongSelect", sizeof(text));
|
|
|
|
break;
|
|
|
|
case midi::TuneRequest:
|
|
|
|
handleTuneRequest();
|
|
|
|
strlcpy(text, "TuneRequest", sizeof(text));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.printf_P(PSTR("[%s] %s"), midi_device, text);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// MIDI THRU
|
|
|
|
if (configuration.sys.soft_midi_thru == 1) {
|
|
|
|
#ifdef MIDI_DEVICE_USB
|
|
|
|
if (strcmp(MIDI_BY_USB, midi_device)) {
|
|
|
|
switch (event) {
|
|
|
|
case midi::TimeCodeQuarterFrame:
|
|
|
|
usbMIDI.sendTimeCodeQuarterFrame(0xF1, inData1);
|
|
|
|
break;
|
|
|
|
case midi::SongSelect:
|
|
|
|
usbMIDI.sendSongSelect(inData1);
|
|
|
|
break;
|
|
|
|
case midi::TuneRequest:
|
|
|
|
usbMIDI.sendTuneRequest();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_USB"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MIDI_DEVICE_DIN
|
|
|
|
if (strcmp(MIDI_BY_DIN, midi_device)) {
|
|
|
|
switch (event) {
|
|
|
|
case midi::TimeCodeQuarterFrame:
|
|
|
|
midi_serial.sendTimeCodeQuarterFrame(inData1);
|
|
|
|
break;
|
|
|
|
case midi::SongSelect:
|
|
|
|
midi_serial.sendSongSelect(inData1);
|
|
|
|
break;
|
|
|
|
case midi::TuneRequest:
|
|
|
|
midi_serial.sendTuneRequest();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_DIN"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST
|
|
|
|
if (strcmp(MIDI_BY_USB_HOST, midi_device)) {
|
|
|
|
switch (event) {
|
|
|
|
case midi::TimeCodeQuarterFrame:
|
|
|
|
midi_usb.sendTimeCodeQuarterFrame(0xF1, inData1);
|
|
|
|
break;
|
|
|
|
case midi::SongSelect:
|
|
|
|
midi_usb.sendSongSelect(inData1);
|
|
|
|
break;
|
|
|
|
case midi::TuneRequest:
|
|
|
|
midi_usb.sendTuneRequest();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_USB_HOST"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST_SERIAL
|
|
|
|
if (strcmp(MIDI_BY_USB_HOST_SERIAL, midi_device)) {
|
|
|
|
switch (event) {
|
|
|
|
case midi::TimeCodeQuarterFrame:
|
|
|
|
usbhost_midi_serial.sendTimeCodeQuarterFrame(0xF1, inData1);
|
|
|
|
break;
|
|
|
|
case midi::SongSelect:
|
|
|
|
usbhost_midi_serial.sendSongSelect(inData1);
|
|
|
|
break;
|
|
|
|
case midi::TuneRequest:
|
|
|
|
usbhost_midi_serial.sendTuneRequest();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_USB_HOST_SERIAL"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.println();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleRealtime_generic(const char *midi_device, midi::MidiType event) {
|
|
|
|
char text[10];
|
|
|
|
|
|
|
|
switch (event) {
|
|
|
|
case midi::Clock:
|
|
|
|
handleClock();
|
|
|
|
strlcpy(text, "Clock", sizeof(text));
|
|
|
|
break;
|
|
|
|
case midi::Start:
|
|
|
|
handleStart();
|
|
|
|
strlcpy(text, "Start", sizeof(text));
|
|
|
|
break;
|
|
|
|
case midi::Continue:
|
|
|
|
handleContinue();
|
|
|
|
strlcpy(text, "Continue", sizeof(text));
|
|
|
|
break;
|
|
|
|
case midi::Stop:
|
|
|
|
handleStop();
|
|
|
|
strlcpy(text, "Stop", sizeof(text));
|
|
|
|
break;
|
|
|
|
case midi::ActiveSensing:
|
|
|
|
handleActiveSensing();
|
|
|
|
strlcpy(text, "ActiveSensing", sizeof(text));
|
|
|
|
break;
|
|
|
|
case midi::SystemReset:
|
|
|
|
handleSystemReset();
|
|
|
|
strlcpy(text, "SystemReset", sizeof(text));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.printf_P(PSTR("[%s] %s"), midi_device, text);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// MIDI THRU
|
|
|
|
if (configuration.sys.soft_midi_thru == 1) {
|
|
|
|
#ifdef MIDI_DEVICE_USB
|
|
|
|
if (strcmp(MIDI_BY_USB, midi_device)) {
|
|
|
|
usbMIDI.sendRealTime(event);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_USB"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MIDI_DEVICE_DIN
|
|
|
|
if (strcmp(MIDI_BY_DIN, midi_device)) {
|
|
|
|
midi_serial.sendRealTime(event);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_DIN"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST
|
|
|
|
if (strcmp(MIDI_BY_USB_HOST, midi_device)) {
|
|
|
|
midi_usb.sendRealTime(event);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_USB_HOST"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST_SERIAL
|
|
|
|
if (strcmp(MIDI_BY_USB_HOST_SERIAL, midi_device)) {
|
|
|
|
usbhost_midi_serial.sendRealTime(event);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_USB_HOST_SERIAL"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.println();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
///* void handleSystemExclusiveChunk_MIDI_DEVICE_DIN(byte *data, uint len, bool last)
|
|
|
|
|
|
|
|
// void handlRealTimeSystem_generic(byte inRealTime, byte midi_device) {
|
|
|
|
// handleRealTimeSystem();
|
|
|
|
// #ifdef DEBUG
|
|
|
|
// switch(midi_device) {
|
|
|
|
// case MIDI_DIN:
|
|
|
|
// Serial.print(F("[MIDI_DIN] RealTimeSystem"));
|
|
|
|
// break;
|
|
|
|
// case MIDI_USB_HOST:
|
|
|
|
// Serial.print(F("[MIDI_USB_HOST] RealTimeSystem"));
|
|
|
|
// break;
|
|
|
|
// case USB_MIDI:
|
|
|
|
// Serial.print(F("[USB_MIDI] RealTimeSystem"));
|
|
|
|
// break;
|
|
|
|
// }
|
|
|
|
// #endif
|
|
|
|
// if (configuration.sys.soft_midi_thru == 1)
|
|
|
|
// {
|
|
|
|
// #ifdef MIDI_DEVICE_USB
|
|
|
|
// if(midi_device != USB_MIDI) {
|
|
|
|
// usbMIDI.sendRealTime(inRealTime);
|
|
|
|
// #ifdef DEBUG
|
|
|
|
// Serial.print(F(" THRU->MIDI_USB"));
|
|
|
|
// #endif
|
|
|
|
// }
|
|
|
|
// #endif
|
|
|
|
|
|
|
|
// #ifdef MIDI_DEVICE_DIN
|
|
|
|
// if(midi_device != MIDI_DIN) {
|
|
|
|
// midi_serial.sendRealTime((midi::MidiType)inRealTime);
|
|
|
|
// #ifdef DEBUG
|
|
|
|
// Serial.print(F(" THRU->MIDI_DIN"));
|
|
|
|
// #endif
|
|
|
|
// }
|
|
|
|
// #endif
|
|
|
|
|
|
|
|
// #ifdef MIDI_DEVICE_USB_HOST
|
|
|
|
// if(midi_device != MIDI_USB_HOST) {
|
|
|
|
// midi_usb.sendRealTime(inRealTime);
|
|
|
|
// #ifdef DEBUG
|
|
|
|
// Serial.print(F(" THRU->MIDI_USB_HOST"));
|
|
|
|
// #endif
|
|
|
|
// }
|
|
|
|
// #endif
|
|
|
|
// }
|
|
|
|
|
|
|
|
// #ifdef DEBUG
|
|
|
|
// Serial.println();
|
|
|
|
// #endif
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************
|
|
|
|
MIDI_DEVICE_DIN
|
|
|
|
*****************************************/
|
|
|
|
#ifdef MIDI_DEVICE_DIN
|
|
|
|
|
|
|
|
void handleNoteOn_MIDI_DEVICE_DIN(byte inChannel, byte inNoteNumber, byte inVelocity) {
|
|
|
|
handle_generic(inChannel, inNoteNumber, inVelocity, MIDI_BY_DIN, midi::NoteOn);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleNoteOff_MIDI_DEVICE_DIN(byte inChannel, byte inNoteNumber, byte inVelocity) {
|
|
|
|
handle_generic(inChannel, inNoteNumber, inVelocity, MIDI_BY_DIN, midi::NoteOff);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleControlChange_MIDI_DEVICE_DIN(byte inChannel, byte inData1, byte inData2) {
|
|
|
|
handle_generic(inChannel, inData1, inData2, MIDI_BY_DIN, midi::ControlChange);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleAfterTouch_MIDI_DEVICE_DIN(byte inChannel, byte inPressure) {
|
|
|
|
handle_generic(inChannel, inPressure, '\0', MIDI_BY_DIN, midi::AfterTouchChannel);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handlePitchBend_MIDI_DEVICE_DIN(byte inChannel, int inPitch) {
|
|
|
|
handle_generic(inChannel, inPitch, '\0', MIDI_BY_DIN, midi::PitchBend);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleProgramChange_MIDI_DEVICE_DIN(byte inChannel, byte inProgram) {
|
|
|
|
handle_generic(inChannel, inProgram, '\0', MIDI_BY_DIN, midi::ProgramChange);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleAfterTouchPoly_MIDI_DEVICE_DIN(byte inChannel, byte inNoteNumber, byte inVelocity) {
|
|
|
|
handle_generic(inChannel, inNoteNumber, inVelocity, MIDI_BY_DIN, midi::AfterTouchPoly);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleSystemExclusive_MIDI_DEVICE_DIN(byte *data, uint len) {
|
|
|
|
handleSystemExclusive_generic(data, len, MIDI_BY_DIN);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* void handleSystemExclusiveChunk_MIDI_DEVICE_DIN(byte *data, uint len, bool last)
|
|
|
|
{
|
|
|
|
handleSystemExclusiveChunk(data, len, last);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F("[MIDI_DIN] SysExChunk"));
|
|
|
|
#endif
|
|
|
|
if (configuration.sys.soft_midi_thru == 1)
|
|
|
|
{
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST
|
|
|
|
midi_usb.sendSysEx(len, data, last);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_USB_HOST"));
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifdef MIDI_DEVICE_USB
|
|
|
|
usbMIDI.sendSysEx(len, data, last);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_USB"));
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.println();
|
|
|
|
#endif
|
|
|
|
} */
|
|
|
|
|
|
|
|
void handleTimeCodeQuarterFrame_MIDI_DEVICE_DIN(byte data) {
|
|
|
|
handleSystemCommon_generic(data, MIDI_BY_DIN, midi::TimeCodeQuarterFrame);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleSongSelect_MIDI_DEVICE_DIN(byte inSong) {
|
|
|
|
handleSystemCommon_generic(inSong, MIDI_BY_DIN, midi::SongSelect);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleTuneRequest_MIDI_DEVICE_DIN(void) {
|
|
|
|
handleSystemCommon_generic('\0', MIDI_BY_DIN, midi::TuneRequest);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleClock_MIDI_DEVICE_DIN(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_DIN, midi::Clock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleStart_MIDI_DEVICE_DIN(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_DIN, midi::Start);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleContinue_MIDI_DEVICE_DIN(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_DIN, midi::Continue);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleStop_MIDI_DEVICE_DIN(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_DIN, midi::Stop);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleActiveSensing_MIDI_DEVICE_DIN(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_DIN, midi::ActiveSensing);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleSystemReset_MIDI_DEVICE_DIN(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_DIN, midi::SystemReset);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* void handlRealTimeSysteme_MIDI_DEVICE_DIN(byte inRealTime)
|
|
|
|
{
|
|
|
|
handleRealTimeSystem_generic(MIDI_DIN);
|
|
|
|
} */
|
|
|
|
#endif // MIDI_DEVICE_DIN
|
|
|
|
|
|
|
|
/*****************************************
|
|
|
|
MIDI_DEVICE_USB_HOST
|
|
|
|
*****************************************/
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST
|
|
|
|
void handleNoteOn_MIDI_DEVICE_USB_HOST(byte inChannel, byte inNoteNumber, byte inVelocity) {
|
|
|
|
handle_generic(inChannel, inNoteNumber, inVelocity, MIDI_BY_USB_HOST, midi::NoteOn);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleNoteOff_MIDI_DEVICE_USB_HOST(byte inChannel, byte inNoteNumber, byte inVelocity) {
|
|
|
|
handle_generic(inChannel, inNoteNumber, inVelocity, MIDI_BY_USB_HOST, midi::NoteOff);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleControlChange_MIDI_DEVICE_USB_HOST(byte inChannel, byte inData1, byte inData2) {
|
|
|
|
handle_generic(inChannel, inData1, inData2, MIDI_BY_USB_HOST, midi::ControlChange);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleAfterTouch_MIDI_DEVICE_USB_HOST(byte inChannel, byte inPressure) {
|
|
|
|
handle_generic(inChannel, inPressure, '\0', MIDI_BY_USB_HOST, midi::AfterTouchChannel);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handlePitchBend_MIDI_DEVICE_USB_HOST(byte inChannel, int inPitch) {
|
|
|
|
handle_generic(inChannel, inPitch, '\0', MIDI_BY_USB_HOST, midi::PitchBend);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleProgramChange_MIDI_DEVICE_USB_HOST(byte inChannel, byte inProgram) {
|
|
|
|
handle_generic(inChannel, inProgram, '\0', MIDI_BY_USB_HOST, midi::ProgramChange);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleAfterTouchPoly_MIDI_DEVICE_USB_HOST(byte inChannel, byte inNoteNumber, byte inVelocity) {
|
|
|
|
handle_generic(inChannel, inNoteNumber, inVelocity, MIDI_BY_USB_HOST, midi::AfterTouchPoly);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleSystemExclusive_MIDI_DEVICE_USB_HOST(byte *data, uint len) {
|
|
|
|
handleSystemExclusive_generic(data, len, MIDI_BY_USB_HOST);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* void handleSystemExclusiveChunk_MIDI_DEVICE_USB_HOST(byte *data, uint len, bool last)
|
|
|
|
{
|
|
|
|
handleSystemExclusiveChunk(data, len, last);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F("[MIDI_USB_HOST] SysExChunk"));
|
|
|
|
#endif
|
|
|
|
if (configuration.sys.soft_midi_thru == 1)
|
|
|
|
{
|
|
|
|
#ifdef MIDI_DEVICE_DIN
|
|
|
|
midi_serial.sendSysEx(len, data, last);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_DIN"));
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifdef MIDI_DEVICE_USB
|
|
|
|
usbMIDI.sendSysEx(len, data, last);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_USB"));
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.println();
|
|
|
|
#endif
|
|
|
|
} */
|
|
|
|
|
|
|
|
void handleTimeCodeQuarterFrame_MIDI_DEVICE_USB_HOST(midi::DataByte data) {
|
|
|
|
handleSystemCommon_generic(data, MIDI_BY_USB_HOST, midi::TimeCodeQuarterFrame);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleSongSelect_MIDI_DEVICE_USB_HOST(byte inSong) {
|
|
|
|
handleSystemCommon_generic(inSong, MIDI_BY_USB_HOST, midi::SongSelect);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleTuneRequest_MIDI_DEVICE_USB_HOST(void) {
|
|
|
|
handleSystemCommon_generic('\0', MIDI_BY_USB_HOST, midi::TuneRequest);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleClock_MIDI_DEVICE_USB_HOST(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_USB_HOST, midi::Clock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleStart_MIDI_DEVICE_USB_HOST(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_USB_HOST, midi::Start);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleContinue_MIDI_DEVICE_USB_HOST(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_USB_HOST, midi::Continue);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleStop_MIDI_DEVICE_USB_HOST(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_USB_HOST, midi::Stop);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleActiveSensing_MIDI_DEVICE_USB_HOST(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_USB_HOST, midi::ActiveSensing);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleSystemReset_MIDI_DEVICE_USB_HOST(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_USB_HOST, midi::SystemReset);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* void handlRealTimeSystem_MIDI_DEVICE_USB_HOST(midi::MidiType inRealTime)
|
|
|
|
{
|
|
|
|
handleRealTimeSystem_generic(inRealTime, MIDI_USB_HOST);
|
|
|
|
} */
|
|
|
|
|
|
|
|
#endif // MIDI_DEVICE_USB_HOST
|
|
|
|
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST_SERIAL
|
|
|
|
void handleNoteOn_MIDI_DEVICE_USB_HOST_SERIAL(byte inChannel, byte inNoteNumber, byte inVelocity) {
|
|
|
|
handle_generic(inChannel, inNoteNumber, inVelocity, MIDI_BY_USB_HOST_SERIAL, midi::NoteOn);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleNoteOff_MIDI_DEVICE_USB_HOST_SERIAL(byte inChannel, byte inNoteNumber, byte inVelocity) {
|
|
|
|
handle_generic(inChannel, inNoteNumber, inVelocity, MIDI_BY_USB_HOST_SERIAL, midi::NoteOff);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleControlChange_MIDI_DEVICE_USB_HOST_SERIAL(byte inChannel, byte inData1, byte inData2) {
|
|
|
|
handle_generic(inChannel, inData1, inData2, MIDI_BY_USB_HOST_SERIAL, midi::ControlChange);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleAfterTouch_MIDI_DEVICE_USB_HOST_SERIAL(byte inChannel, byte inPressure) {
|
|
|
|
handle_generic(inChannel, inPressure, '\0', MIDI_BY_USB_HOST_SERIAL, midi::AfterTouchChannel);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handlePitchBend_MIDI_DEVICE_USB_HOST_SERIAL(byte inChannel, int inPitch) {
|
|
|
|
handle_generic(inChannel, inPitch, '\0', MIDI_BY_USB_HOST_SERIAL, midi::PitchBend);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleProgramChange_MIDI_DEVICE_USB_HOST_SERIAL(byte inChannel, byte inProgram) {
|
|
|
|
handle_generic(inChannel, inProgram, '\0', MIDI_BY_USB_HOST_SERIAL, midi::ProgramChange);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleAfterTouchPoly_MIDI_DEVICE_USB_HOST_SERIAL(byte inChannel, byte inNoteNumber, byte inVelocity) {
|
|
|
|
handle_generic(inChannel, inNoteNumber, inVelocity, MIDI_BY_USB_HOST_SERIAL, midi::AfterTouchPoly);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleSystemExclusive_MIDI_DEVICE_USB_HOST_SERIAL(byte *data, uint len) {
|
|
|
|
handleSystemExclusive_generic(data, len, MIDI_BY_USB_HOST_SERIAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* void handleSystemExclusiveChunk_MIDI_DEVICE_USB_HOST_SERIAL(byte *data, uint len, bool last)
|
|
|
|
{
|
|
|
|
handleSystemExclusiveChunk(data, len, last);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F("[MIDI_USB_HOST] SysExChunk"));
|
|
|
|
#endif
|
|
|
|
if (configuration.sys.soft_midi_thru == 1)
|
|
|
|
{
|
|
|
|
#ifdef MIDI_DEVICE_DIN
|
|
|
|
midi_serial.sendSysEx(len, data, last);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_DIN"));
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifdef MIDI_DEVICE_USB
|
|
|
|
usbMIDI.sendSysEx(len, data, last);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_USB"));
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.println();
|
|
|
|
#endif
|
|
|
|
} */
|
|
|
|
|
|
|
|
void handleTimeCodeQuarterFrame_MIDI_DEVICE_USB_HOST_SERIAL(midi::DataByte data) {
|
|
|
|
handleSystemCommon_generic(data, MIDI_BY_USB_HOST_SERIAL, midi::TimeCodeQuarterFrame);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleSongSelect_MIDI_DEVICE_USB_HOST_SERIAL(byte inSong) {
|
|
|
|
handleSystemCommon_generic(inSong, MIDI_BY_USB_HOST_SERIAL, midi::SongSelect);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleTuneRequest_MIDI_DEVICE_USB_HOST_SERIAL(void) {
|
|
|
|
handleSystemCommon_generic('\0', MIDI_BY_USB_HOST_SERIAL, midi::TuneRequest);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleClock_MIDI_DEVICE_USB_HOST_SERIAL(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_USB_HOST_SERIAL, midi::Clock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleStart_MIDI_DEVICE_USB_HOST_SERIAL(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_USB_HOST_SERIAL, midi::Start);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleContinue_MIDI_DEVICE_USB_HOST_SERIAL(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_USB_HOST_SERIAL, midi::Continue);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleStop_MIDI_DEVICE_USB_HOST_SERIAL(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_USB_HOST_SERIAL, midi::Stop);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleActiveSensing_MIDI_DEVICE_USB_HOST_SERIAL(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_USB_HOST_SERIAL, midi::ActiveSensing);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleSystemReset_MIDI_DEVICE_USB_HOST_SERIAL(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_USB_HOST_SERIAL, midi::SystemReset);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* void handlRealTimeSystem_MIDI_DEVICE_USB_HOST_SERIAL(midi::MidiType inRealTime)
|
|
|
|
{
|
|
|
|
handleRealTimeSystem_generic(inRealTime, MIDI_USB_HOST);
|
|
|
|
} */
|
|
|
|
#endif // MIDI_DEVICE_USB_HOST_SERIAL
|
|
|
|
|
|
|
|
/*****************************************
|
|
|
|
MIDI_DEVICE_USB
|
|
|
|
*****************************************/
|
|
|
|
#ifdef MIDI_DEVICE_USB
|
|
|
|
void handleNoteOn_MIDI_DEVICE_USB(byte inChannel, byte inNoteNumber, byte inVelocity) {
|
|
|
|
handle_generic(inChannel, inNoteNumber, inVelocity, MIDI_BY_USB, midi::NoteOn);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleNoteOff_MIDI_DEVICE_USB(byte inChannel, byte inNoteNumber, byte inVelocity) {
|
|
|
|
handle_generic(inChannel, inNoteNumber, inVelocity, MIDI_BY_USB, midi::NoteOff);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleControlChange_MIDI_DEVICE_USB(byte inChannel, byte inData1, byte inData2) {
|
|
|
|
handle_generic(inChannel, inData1, inData2, MIDI_BY_USB, midi::ControlChange);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleAfterTouch_MIDI_DEVICE_USB(byte inChannel, byte inPressure) {
|
|
|
|
handle_generic(inChannel, inPressure, '\0', MIDI_BY_USB, midi::AfterTouchChannel);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handlePitchBend_MIDI_DEVICE_USB(byte inChannel, int inPitch) {
|
|
|
|
handle_generic(inChannel, inPitch, '\0', MIDI_BY_USB, midi::PitchBend);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleProgramChange_MIDI_DEVICE_USB(byte inChannel, byte inProgram) {
|
|
|
|
handle_generic(inChannel, inProgram, '\0', MIDI_BY_USB, midi::ProgramChange);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleAfterTouchPoly_MIDI_DEVICE_USB(byte inChannel, byte inNoteNumber, byte inVelocity) {
|
|
|
|
handle_generic(inChannel, inNoteNumber, inVelocity, MIDI_BY_USB, midi::AfterTouchPoly);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleSystemExclusive_MIDI_DEVICE_USB(byte *data, uint len) {
|
|
|
|
handleSystemExclusive_generic(data, len, MIDI_BY_USB);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FLASHMEM void handleSystemExclusiveChunk_MIDI_DEVICE_USB(byte *data, uint len, bool last)
|
|
|
|
{
|
|
|
|
handleSystemExclusiveChunk(data, len, last);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F("[MIDI_USB] SysExChunk"));
|
|
|
|
#endif
|
|
|
|
if (configuration.sys.soft_midi_thru == 1)
|
|
|
|
{
|
|
|
|
#ifdef MIDI_DEVICE_DIN
|
|
|
|
midi_serial.sendSysEx(len, data, last);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_DIN"));
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST
|
|
|
|
midi_usb.sendSysEx(len, data, last);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" THRU->MIDI_USB_HOST"));
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.println();
|
|
|
|
#endif
|
|
|
|
} */
|
|
|
|
|
|
|
|
void handleTimeCodeQuarterFrame_MIDI_DEVICE_USB(midi::DataByte data) {
|
|
|
|
handleSystemCommon_generic(data, MIDI_BY_USB, midi::TimeCodeQuarterFrame);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleSongSelect_MIDI_DEVICE_USB(byte inSong) {
|
|
|
|
handleSystemCommon_generic(inSong, MIDI_BY_USB, midi::SongSelect);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleTuneRequest_MIDI_DEVICE_USB(void) {
|
|
|
|
handleSystemCommon_generic('\0', MIDI_BY_USB, midi::TuneRequest);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleClock_MIDI_DEVICE_USB(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_USB, midi::Clock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleStart_MIDI_DEVICE_USB(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_USB, midi::Start);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleContinue_MIDI_DEVICE_USB(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_USB, midi::Continue);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleStop_MIDI_DEVICE_USB(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_USB, midi::Stop);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleActiveSensing_MIDI_DEVICE_USB(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_USB, midi::ActiveSensing);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleSystemReset_MIDI_DEVICE_USB(void) {
|
|
|
|
handleRealtime_generic(MIDI_BY_USB, midi::SystemReset);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FLASHMEM void handleRealTimeSystem_MIDI_DEVICE_USB(byte inRealTime)
|
|
|
|
{
|
|
|
|
handleRealTimeSystem_generic(inRealTime, USB_MIDI);
|
|
|
|
} */
|
|
|
|
#endif // MIDI_DEVICE_USB
|
|
|
|
|
|
|
|
FLASHMEM void MD_sendControlChange(uint8_t channel, uint8_t cc, uint8_t value) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F("[MD] SendControlChange CH:"));
|
|
|
|
Serial.print(channel, DEC);
|
|
|
|
Serial.print(F(" CC:"));
|
|
|
|
Serial.print(cc);
|
|
|
|
Serial.print(F(" VAL:"));
|
|
|
|
Serial.print(value);
|
|
|
|
#endif
|
|
|
|
#ifdef MIDI_DEVICE_DIN
|
|
|
|
midi_serial.sendControlChange(cc, value, channel);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" MIDI-DIN"));
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST
|
|
|
|
midi_usb.sendControlChange(cc, value, channel);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" MIDI-USB-HOST"));
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifdef MIDI_DEVICE_USB
|
|
|
|
usbMIDI.sendControlChange(cc, value, channel);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(F(" MIDI-USB"));
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.println();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************
|
|
|
|
HELPER FUNCTIONS
|
|
|
|
*****************************************/
|
|
|
|
FLASHMEM void setup_midi_devices(void) {
|
|
|
|
#ifdef MIDI_DEVICE_DIN
|
|
|
|
// Start serial MIDI
|
|
|
|
midi_serial.begin(DEFAULT_MIDI_CHANNEL);
|
|
|
|
midi_serial.setHandleNoteOn(handleNoteOn_MIDI_DEVICE_DIN);
|
|
|
|
midi_serial.setHandleNoteOff(handleNoteOff_MIDI_DEVICE_DIN);
|
|
|
|
midi_serial.setHandleControlChange(handleControlChange_MIDI_DEVICE_DIN);
|
|
|
|
midi_serial.setHandleAfterTouchChannel(handleAfterTouch_MIDI_DEVICE_DIN);
|
|
|
|
midi_serial.setHandlePitchBend(handlePitchBend_MIDI_DEVICE_DIN);
|
|
|
|
midi_serial.setHandleProgramChange(handleProgramChange_MIDI_DEVICE_DIN);
|
|
|
|
midi_serial.setHandleSystemExclusive(handleSystemExclusive_MIDI_DEVICE_DIN);
|
|
|
|
//midi_serial.setHandleSystemExclusiveChunk(handleSystemExclusiveChunk_MIDI_DEVICE_DIN);
|
|
|
|
midi_serial.setHandleTimeCodeQuarterFrame(handleTimeCodeQuarterFrame_MIDI_DEVICE_DIN);
|
|
|
|
midi_serial.setHandleAfterTouchPoly(handleAfterTouchPoly_MIDI_DEVICE_DIN);
|
|
|
|
midi_serial.setHandleSongSelect(handleSongSelect_MIDI_DEVICE_DIN);
|
|
|
|
midi_serial.setHandleTuneRequest(handleTuneRequest_MIDI_DEVICE_DIN);
|
|
|
|
midi_serial.setHandleClock(handleClock_MIDI_DEVICE_DIN);
|
|
|
|
midi_serial.setHandleStart(handleStart_MIDI_DEVICE_DIN);
|
|
|
|
midi_serial.setHandleContinue(handleContinue_MIDI_DEVICE_DIN);
|
|
|
|
midi_serial.setHandleStop(handleStop_MIDI_DEVICE_DIN);
|
|
|
|
midi_serial.setHandleActiveSensing(handleActiveSensing_MIDI_DEVICE_DIN);
|
|
|
|
midi_serial.setHandleSystemReset(handleSystemReset_MIDI_DEVICE_DIN);
|
|
|
|
//midi_serial.setHandleRealTimeSystem(handleRealTimeSystem_MIDI_DEVICE_DIN);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.println(F("MIDI_DEVICE_DIN enabled"));
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// start up USB host
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST
|
|
|
|
usb_host.begin();
|
|
|
|
midi_usb.setHandleNoteOn(handleNoteOn_MIDI_DEVICE_USB_HOST);
|
|
|
|
midi_usb.setHandleNoteOff(handleNoteOff_MIDI_DEVICE_USB_HOST);
|
|
|
|
midi_usb.setHandleControlChange(handleControlChange_MIDI_DEVICE_USB_HOST);
|
|
|
|
midi_usb.setHandleAfterTouchChannel(handleAfterTouch_MIDI_DEVICE_USB_HOST);
|
|
|
|
midi_usb.setHandlePitchChange(handlePitchBend_MIDI_DEVICE_USB_HOST);
|
|
|
|
midi_usb.setHandleProgramChange(handleProgramChange_MIDI_DEVICE_USB_HOST);
|
|
|
|
midi_usb.setHandleSystemExclusive(handleSystemExclusive_MIDI_DEVICE_USB_HOST);
|
|
|
|
//midi_usb.setHandleSystemExclusiveChunk(handleSystemExclusiveChunk_MIDI_DEVICE_USB_HOST);
|
|
|
|
midi_usb.setHandleTimeCodeQuarterFrame(handleTimeCodeQuarterFrame_MIDI_DEVICE_USB_HOST);
|
|
|
|
midi_usb.setHandleAfterTouchPoly(handleAfterTouchPoly_MIDI_DEVICE_USB_HOST);
|
|
|
|
midi_usb.setHandleSongSelect(handleSongSelect_MIDI_DEVICE_USB_HOST);
|
|
|
|
midi_usb.setHandleTuneRequest(handleTuneRequest_MIDI_DEVICE_USB_HOST);
|
|
|
|
midi_usb.setHandleClock(handleClock_MIDI_DEVICE_USB_HOST);
|
|
|
|
midi_usb.setHandleStart(handleStart_MIDI_DEVICE_USB_HOST);
|
|
|
|
midi_usb.setHandleContinue(handleContinue_MIDI_DEVICE_USB_HOST);
|
|
|
|
midi_usb.setHandleStop(handleStop_MIDI_DEVICE_USB_HOST);
|
|
|
|
midi_usb.setHandleActiveSensing(handleActiveSensing_MIDI_DEVICE_USB_HOST);
|
|
|
|
midi_usb.setHandleSystemReset(handleSystemReset_MIDI_DEVICE_USB_HOST);
|
|
|
|
//midi_usb.setHandleRealTimeSystem(handleRealTimeSystem_MIDI_DEVICE_USB_HOST);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.println(F("MIDI_DEVICE_USB_HOST enabled."));
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST_SERIAL
|
|
|
|
usb_host.begin();
|
|
|
|
userial.begin(USB_HOST_SERIAL_BAUD, USB_HOST_SERIAL_FORMAT);
|
|
|
|
usbhost_midi_serial.setHandleNoteOn(handleNoteOn_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
usbhost_midi_serial.setHandleNoteOff(handleNoteOff_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
usbhost_midi_serial.setHandleControlChange(handleControlChange_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
usbhost_midi_serial.setHandleAfterTouchChannel(handleAfterTouch_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
usbhost_midi_serial.setHandlePitchBend(handlePitchBend_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
usbhost_midi_serial.setHandleProgramChange(handleProgramChange_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
usbhost_midi_serial.setHandleSystemExclusive(handleSystemExclusive_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
//usbhost_midi_serial.setHandleSystemExclusiveChunk(handleSystemExclusiveChunk_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
usbhost_midi_serial.setHandleTimeCodeQuarterFrame(handleTimeCodeQuarterFrame_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
usbhost_midi_serial.setHandleAfterTouchPoly(handleAfterTouchPoly_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
usbhost_midi_serial.setHandleSongSelect(handleSongSelect_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
usbhost_midi_serial.setHandleTuneRequest(handleTuneRequest_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
usbhost_midi_serial.setHandleClock(handleClock_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
usbhost_midi_serial.setHandleStart(handleStart_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
usbhost_midi_serial.setHandleContinue(handleContinue_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
usbhost_midi_serial.setHandleStop(handleStop_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
usbhost_midi_serial.setHandleActiveSensing(handleActiveSensing_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
usbhost_midi_serial.setHandleSystemReset(handleSystemReset_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
//usbhost_midi_serial.setHandleRealTimeSystem(handleRealTimeSystem_MIDI_DEVICE_USB_HOST_SERIAL);
|
|
|
|
|
|
|
|
usbhost_midi_serial.begin(MIDI_CHANNEL_OMNI);
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.println(F("MIDI_DEVICE_USB_HOST_SERIAL enabled."));
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// check for onboard USB-MIDI
|
|
|
|
#ifdef MIDI_DEVICE_USB
|
|
|
|
usbMIDI.begin();
|
|
|
|
usbMIDI.setHandleNoteOn(handleNoteOn_MIDI_DEVICE_USB);
|
|
|
|
usbMIDI.setHandleNoteOff(handleNoteOff_MIDI_DEVICE_USB);
|
|
|
|
usbMIDI.setHandleControlChange(handleControlChange_MIDI_DEVICE_USB);
|
|
|
|
usbMIDI.setHandleAfterTouchChannel(handleAfterTouch_MIDI_DEVICE_USB);
|
|
|
|
usbMIDI.setHandlePitchChange(handlePitchBend_MIDI_DEVICE_USB);
|
|
|
|
usbMIDI.setHandleProgramChange(handleProgramChange_MIDI_DEVICE_USB);
|
|
|
|
usbMIDI.setHandleSystemExclusive(handleSystemExclusive_MIDI_DEVICE_USB);
|
|
|
|
//usbMIDI.setHandleSystemExclusiveChunk(handleSystemExclusiveChunk_MIDI_DEVICE_USB);
|
|
|
|
usbMIDI.setHandleTimeCodeQuarterFrame(handleTimeCodeQuarterFrame_MIDI_DEVICE_USB);
|
|
|
|
usbMIDI.setHandleAfterTouchPoly(handleAfterTouchPoly_MIDI_DEVICE_USB);
|
|
|
|
usbMIDI.setHandleSongSelect(handleSongSelect_MIDI_DEVICE_USB);
|
|
|
|
usbMIDI.setHandleTuneRequest(handleTuneRequest_MIDI_DEVICE_USB);
|
|
|
|
usbMIDI.setHandleClock(handleClock_MIDI_DEVICE_USB);
|
|
|
|
usbMIDI.setHandleStart(handleStart_MIDI_DEVICE_USB);
|
|
|
|
usbMIDI.setHandleContinue(handleContinue_MIDI_DEVICE_USB);
|
|
|
|
usbMIDI.setHandleStop(handleStop_MIDI_DEVICE_USB);
|
|
|
|
usbMIDI.setHandleActiveSensing(handleActiveSensing_MIDI_DEVICE_USB);
|
|
|
|
usbMIDI.setHandleSystemReset(handleSystemReset_MIDI_DEVICE_USB);
|
|
|
|
//usbMIDI.setHandleRealTimeSystem(handleRealTimeSystem_MIDI_DEVICE_USB);
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.println(F("MIDI_DEVICE_USB enabled."));
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
FLASHMEM void check_midi_devices(void) {
|
|
|
|
#ifdef MIDI_DEVICE_DIN
|
|
|
|
midi_serial.read();
|
|
|
|
#endif
|
|
|
|
#ifdef MIDI_DEVICE_USB
|
|
|
|
usbMIDI.read();
|
|
|
|
#endif
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST
|
|
|
|
usb_host.Task();
|
|
|
|
midi_usb.read();
|
|
|
|
#endif
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST_SERIAL
|
|
|
|
usb_host.Task();
|
|
|
|
usbhost_midi_serial.read();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
FLASHMEM void send_sysex_voice(uint8_t midi_channel, uint8_t *data) {
|
|
|
|
uint8_t checksum = 0;
|
|
|
|
uint8_t vd[161];
|
|
|
|
|
|
|
|
// Send SYSEX data also via MIDI
|
|
|
|
//vd[0] = 0xF0; // SysEx start
|
|
|
|
vd[0] = 0x43; // ID=Yamaha
|
|
|
|
vd[1] = midi_channel; // Sub-status and MIDI channel
|
|
|
|
vd[2] = 0x00; // Format number (0=1 voice)
|
|
|
|
vd[3] = 0x01; // Byte count MSB
|
|
|
|
vd[4] = 0x1B; // Byte count LSB
|
|
|
|
for (uint8_t n = 0; n < 155; n++) {
|
|
|
|
checksum -= data[n];
|
|
|
|
vd[5 + n] = data[n];
|
|
|
|
}
|
|
|
|
vd[160] = checksum & 0x7f; // Checksum
|
|
|
|
//vd[162] = 0xF7; // SysEx end
|
|
|
|
|
|
|
|
#ifdef MIDI_DEVICE_DIN
|
|
|
|
midi_serial.sendSysEx(161, vd); // Send to DIN MIDI
|
|
|
|
#endif
|
|
|
|
#ifdef MIDI_DEVICE_USB
|
|
|
|
usbMIDI.sendSysEx(161, vd); // Send to USB MIDI
|
|
|
|
#endif
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST
|
|
|
|
midi_usb.sendSysEx(161, vd); // Send to USB-HOST MIDI
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
FLASHMEM void send_sysex_bank(uint8_t midi_channel, uint8_t *bank_data) {
|
|
|
|
#ifdef MIDI_DEVICE_DIN
|
|
|
|
midi_serial.sendSysEx(4104, bank_data); // Send to DIN MIDI
|
|
|
|
#endif
|
|
|
|
#ifdef MIDI_DEVICE_USB
|
|
|
|
// Sysex bank dump is splitted due to Windows USB driver limitations
|
|
|
|
usbMIDI.sendSysEx(2048, bank_data, true); // Send to USB MIDI
|
|
|
|
delay(50);
|
|
|
|
usbMIDI.sendSysEx(2048, bank_data + 2048, true);
|
|
|
|
delay(50);
|
|
|
|
usbMIDI.sendSysEx(8, bank_data + 4096, true);
|
|
|
|
#endif
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST
|
|
|
|
midi_usb.sendSysEx(4104, bank_data); // Send to USB-HOST MIDI
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
FLASHMEM void send_sysex_param(uint8_t midi_channel, uint8_t var, uint8_t val, uint8_t param_group) {
|
|
|
|
uint8_t s[5];
|
|
|
|
|
|
|
|
s[0] = 0x43; // ID=Yamaha
|
|
|
|
s[1] = midi_channel; // Sub-status and MIDI channel
|
|
|
|
s[2] = (param_group & 5) << 2; // Format number (0=1 voice)
|
|
|
|
if (param_group == 0) {
|
|
|
|
s[2] |= 1;
|
|
|
|
s[3] = var & 0x7f;
|
|
|
|
} else {
|
|
|
|
s[3] = var & 0x7f;
|
|
|
|
}
|
|
|
|
s[4] = val & 0x7f;
|
|
|
|
|
|
|
|
#ifdef MIDI_DEVICE_DIN
|
|
|
|
midi_serial.sendSysEx(5, s); // Send to DIN MIDI
|
|
|
|
#endif
|
|
|
|
#ifdef MIDI_DEVICE_USB
|
|
|
|
usbMIDI.sendSysEx(5, s); // Send to USB MIDI
|
|
|
|
#endif
|
|
|
|
#ifdef MIDI_DEVICE_USB_HOST
|
|
|
|
midi_usb.sendSysEx(5, s); // Send to USB-HOST MIDI
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // MIDI_DEVICES_H
|