From bd615bc3344034cd7d2ac874702eeeb03c5dc16b Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Sun, 28 Jun 2015 23:52:50 +0200 Subject: [PATCH] AUDIO: Miles Audio MT32 embedded SysEx support now supports embedded SysEx as well used by 7th guest --- audio/miles.h | 16 ++++++++-- audio/miles_mt32.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 87 insertions(+), 5 deletions(-) diff --git a/audio/miles.h b/audio/miles.h index 50fcae2e275a..f9306069a7ed 100644 --- a/audio/miles.h +++ b/audio/miles.h @@ -49,9 +49,21 @@ namespace Audio { #define MILES_CONTROLLER_REVERB_LEVEL 63 #define MILES_CONTROLLER_RHYTHM_KEY_TIMBRE 58 -// 3 SysEx controllers, each range 14 +// 3 SysEx controllers, each range 5 +// 32-36 for 1st queue +// 37-41 for 2nd queue +// 42-46 for 3rd queue #define MILES_CONTROLLER_SYSEX_RANGE_BEGIN 32 -#define MILES_CONTROLLER_SYSEX_RANGE_END 64 +#define MILES_CONTROLLER_SYSEX_RANGE_END 46 + +#define MILES_CONTROLLER_SYSEX_QUEUE_COUNT 3 +#define MILES_CONTROLLER_SYSEX_QUEUE_SIZE 32 + +#define MILES_CONTROLLER_SYSEX_COMMAND_ADDRESS1 0 +#define MILES_CONTROLLER_SYSEX_COMMAND_ADDRESS2 1 +#define MILES_CONTROLLER_SYSEX_COMMAND_ADDRESS3 2 +#define MILES_CONTROLLER_SYSEX_COMMAND_DATA 3 +#define MILES_CONTROLLER_SYSEX_COMMAND_SEND 4 #define MILES_CONTROLLER_XMIDI_RANGE_BEGIN 110 #define MILES_CONTROLLER_XMIDI_RANGE_END 120 diff --git a/audio/miles_mt32.cpp b/audio/miles_mt32.cpp index 760fcd484e7c..4d1ba66736a2 100644 --- a/audio/miles_mt32.cpp +++ b/audio/miles_mt32.cpp @@ -32,7 +32,6 @@ namespace Audio { // Miles Audio MT32 driver // -// TODO: currently missing: timbre file support (used in 7th Guest) #define MILES_MT32_PATCHES_COUNT 128 #define MILES_MT32_CUSTOMTIMBRE_COUNT 64 @@ -159,6 +158,17 @@ class MidiDriver_Miles_MT32 : public MidiDriver { lastUsedNoteCounter(0) {} }; + struct MilesMT32SysExQueueEntry { + uint32 targetAddress; + byte dataPos; + byte data[MILES_CONTROLLER_SYSEX_QUEUE_SIZE + 1]; // 1 extra byte for terminator + + MilesMT32SysExQueueEntry() : targetAddress(0), + dataPos(0) { + memset(data, 0, sizeof(data)); + } + }; + // stores information about all MIDI channels MidiChannelEntry _midiChannels[MILES_MIDI_CHANNEL_COUNT]; @@ -171,7 +181,10 @@ class MidiDriver_Miles_MT32 : public MidiDriver { MilesMT32InstrumentEntry *_instrumentTablePtr; uint16 _instrumentTableCount; - uint32 _noteCounter; // used to figure out, which timbres are outdated + uint32 _noteCounter; // used to figure out, which timbres are outdated + + // SysEx Queues + MilesMT32SysExQueueEntry _sysExQueues[MILES_CONTROLLER_SYSEX_QUEUE_COUNT]; }; MidiDriver_Miles_MT32::MidiDriver_Miles_MT32(MilesMT32InstrumentEntry *instrumentTablePtr, uint16 instrumentTableCount) { @@ -410,7 +423,64 @@ void MidiDriver_Miles_MT32::controlChange(byte midiChannel, byte controllerNumbe if ((controllerNumber >= MILES_CONTROLLER_SYSEX_RANGE_BEGIN) && (controllerNumber <= MILES_CONTROLLER_SYSEX_RANGE_END)) { // send SysEx - warning("MILES-MT32: embedded SysEx controller %2x, value %2x", controllerNumber, controllerValue); + byte sysExQueueNr = 0; + + // figure out which queue is accessed + controllerNumber -= MILES_CONTROLLER_SYSEX_RANGE_BEGIN; + while (controllerNumber > MILES_CONTROLLER_SYSEX_COMMAND_SEND) { + sysExQueueNr++; + controllerNumber -= (MILES_CONTROLLER_SYSEX_COMMAND_SEND + 1); + } + assert(sysExQueueNr < MILES_CONTROLLER_SYSEX_QUEUE_COUNT); + + byte sysExPos = _sysExQueues[sysExQueueNr].dataPos; + bool sysExSend = false; + + switch(controllerNumber) { + case MILES_CONTROLLER_SYSEX_COMMAND_ADDRESS1: + _sysExQueues[sysExQueueNr].targetAddress &= 0x00FFFF; + _sysExQueues[sysExQueueNr].targetAddress |= (controllerValue << 16); + break; + case MILES_CONTROLLER_SYSEX_COMMAND_ADDRESS2: + _sysExQueues[sysExQueueNr].targetAddress &= 0xFF00FF; + _sysExQueues[sysExQueueNr].targetAddress |= (controllerValue << 8); + break; + case MILES_CONTROLLER_SYSEX_COMMAND_ADDRESS3: + _sysExQueues[sysExQueueNr].targetAddress &= 0xFFFF00; + _sysExQueues[sysExQueueNr].targetAddress |= controllerValue; + break; + case MILES_CONTROLLER_SYSEX_COMMAND_DATA: + if (sysExPos < MILES_CONTROLLER_SYSEX_QUEUE_SIZE) { + // Space left? put current byte into queue + _sysExQueues[sysExQueueNr].data[sysExPos] = controllerValue; + _sysExQueues[sysExQueueNr].dataPos++; + if (sysExPos >= MILES_CONTROLLER_SYSEX_QUEUE_SIZE) { + // overflow? -> send it now + sysExSend = true; + } + } + break; + case MILES_CONTROLLER_SYSEX_COMMAND_SEND: + sysExSend = true; + break; + default: + assert(0); + } + + if (sysExSend) { + if (sysExPos > 0) { + // data actually available? -> send it + _sysExQueues[sysExQueueNr].data[sysExPos] = 0xFF; // put terminator + + // Execute SysEx + MT32SysEx(_sysExQueues[sysExQueueNr].targetAddress, _sysExQueues[sysExQueueNr].data); + + // adjust target address to point at the end of the current data + _sysExQueues[sysExQueueNr].targetAddress += sysExPos; + // reset queue data buffer + _sysExQueues[sysExQueueNr].dataPos = 0; + } + } return; }