mirror of
https://github.com/libretro/scummvm.git
synced 2024-11-27 11:20:40 +00:00
AUDIO: XMIDI: implement support for TIMB chunk
implement support for TIMB chunk inside XMIDI-parser (forwarding of data to driver) implement actual support for TIMB chunk inside Miles Audio MT32 driver
This commit is contained in:
parent
4ff695524a
commit
f7ac1e944a
@ -370,6 +370,7 @@ public:
|
||||
|
||||
public:
|
||||
typedef void (*XMidiCallbackProc)(byte eventData, void *refCon);
|
||||
typedef void (*XMidiNewTimbreListProc)(MidiDriver_BASE *driver, const byte *timbreListPtr, uint32 timbreListSize);
|
||||
|
||||
MidiParser();
|
||||
virtual ~MidiParser() { allNotesOff(); }
|
||||
@ -395,7 +396,7 @@ public:
|
||||
static void defaultXMidiCallback(byte eventData, void *refCon);
|
||||
|
||||
static MidiParser *createParser_SMF();
|
||||
static MidiParser *createParser_XMIDI(XMidiCallbackProc proc = defaultXMidiCallback, void *refCon = 0);
|
||||
static MidiParser *createParser_XMIDI(XMidiCallbackProc proc = defaultXMidiCallback, void *refCon = 0, XMidiNewTimbreListProc newTimbreListProc = NULL, MidiDriver_BASE *newTimbreListDriver = NULL);
|
||||
static MidiParser *createParser_QT();
|
||||
static void timerCallback(void *data) { ((MidiParser *) data)->onTimer(); }
|
||||
};
|
||||
|
@ -43,6 +43,22 @@ protected:
|
||||
XMidiCallbackProc _callbackProc;
|
||||
void *_callbackData;
|
||||
|
||||
// TODO:
|
||||
// This should possibly get cleaned up at some point, but it's very tricks.
|
||||
// We need to support XMIDI TIMB for 7th guest, which uses
|
||||
// Miles Audio drivers. The MT32 driver needs to get the TIMB chunk, so that it
|
||||
// can install all required timbres before the song starts playing.
|
||||
// But we can't easily implement this directly like for example creating
|
||||
// a special Miles Audio class for usage in this XMIDI-class, because other engines use this
|
||||
// XMIDI-parser but w/o using Miles Audio drivers.
|
||||
XMidiNewTimbreListProc _newTimbreListProc;
|
||||
MidiDriver_BASE *_newTimbreListDriver;
|
||||
|
||||
byte *_tracksTimbreList[120]; ///< Timbre-List for each track.
|
||||
uint32 _tracksTimbreListSize[120]; ///< Size of the Timbre-List for each track.
|
||||
byte *_activeTrackTimbreList;
|
||||
uint32 _activeTrackTimbreListSize;
|
||||
|
||||
protected:
|
||||
uint32 readVLQ2(byte * &data);
|
||||
void parseNextEvent(EventInfo &info);
|
||||
@ -53,7 +69,17 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
MidiParser_XMIDI(XMidiCallbackProc proc, void *data) : _callbackProc(proc), _callbackData(data), _loopCount(-1) {}
|
||||
MidiParser_XMIDI(XMidiCallbackProc proc, void *data, XMidiNewTimbreListProc newTimbreListProc, MidiDriver_BASE *newTimbreListDriver) {
|
||||
_callbackProc = proc;
|
||||
_callbackData = data;
|
||||
_loopCount = -1;
|
||||
_newTimbreListProc = newTimbreListProc;
|
||||
_newTimbreListDriver = newTimbreListDriver;
|
||||
memset(_tracksTimbreList, 0, sizeof(_tracksTimbreList));
|
||||
memset(_tracksTimbreListSize, 0, sizeof(_tracksTimbreListSize));
|
||||
_activeTrackTimbreList = NULL;
|
||||
_activeTrackTimbreListSize = 0;
|
||||
}
|
||||
~MidiParser_XMIDI() { }
|
||||
|
||||
bool loadMusic(byte *data, uint32 size);
|
||||
@ -322,11 +348,16 @@ bool MidiParser_XMIDI::loadMusic(byte *data, uint32 size) {
|
||||
// Skip this.
|
||||
pos += 4;
|
||||
} else if (!memcmp(pos, "TIMB", 4)) {
|
||||
// Custom timbres?
|
||||
// We don't support them.
|
||||
// Read the length, skip it, and hope there was nothing there.
|
||||
// Custom timbres
|
||||
// chunk data is as follows:
|
||||
// UINT16LE timbre count (amount of custom timbres used by this track)
|
||||
// BYTE patchId
|
||||
// BYTE bankId
|
||||
// * timbre count
|
||||
pos += 4;
|
||||
len = read4high(pos);
|
||||
_tracksTimbreList[tracksRead] = pos; // Skip the length bytes
|
||||
_tracksTimbreListSize[tracksRead] = len;
|
||||
pos += (len + 1) & ~1;
|
||||
} else if (!memcmp(pos, "EVNT", 4)) {
|
||||
// Ahh! What we're looking for at last.
|
||||
@ -350,6 +381,12 @@ bool MidiParser_XMIDI::loadMusic(byte *data, uint32 size) {
|
||||
resetTracking();
|
||||
setTempo(500000);
|
||||
setTrack(0);
|
||||
_activeTrackTimbreList = _tracksTimbreList[0];
|
||||
_activeTrackTimbreListSize = _tracksTimbreListSize[0];
|
||||
|
||||
if (_newTimbreListProc)
|
||||
_newTimbreListProc(_newTimbreListDriver, _activeTrackTimbreList, _activeTrackTimbreListSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -360,6 +397,6 @@ void MidiParser::defaultXMidiCallback(byte eventData, void *data) {
|
||||
warning("MidiParser: defaultXMidiCallback(%d)", eventData);
|
||||
}
|
||||
|
||||
MidiParser *MidiParser::createParser_XMIDI(XMidiCallbackProc proc, void *data) {
|
||||
return new MidiParser_XMIDI(proc, data);
|
||||
MidiParser *MidiParser::createParser_XMIDI(XMidiCallbackProc proc, void *data, XMidiNewTimbreListProc newTimbreListProc, MidiDriver_BASE *newTimbreListDriver) {
|
||||
return new MidiParser_XMIDI(proc, data, newTimbreListProc, newTimbreListDriver);
|
||||
}
|
||||
|
@ -75,6 +75,8 @@ extern MidiDriver *MidiDriver_Miles_AdLib_create(const Common::String instrument
|
||||
|
||||
extern MidiDriver *MidiDriver_Miles_MT32_create(const Common::String instrumentDataFilename);
|
||||
|
||||
extern void MidiDriver_Miles_MT32_processXMIDITimbreChunk(MidiDriver_BASE *driver, const byte *timbreListPtr, uint32 timbreListSize);
|
||||
|
||||
} // End of namespace Audio
|
||||
|
||||
#endif // AUDIO_MILES_MIDIDRIVER_H
|
||||
|
@ -36,6 +36,9 @@ namespace Audio {
|
||||
#define MILES_MT32_PATCHES_COUNT 128
|
||||
#define MILES_MT32_CUSTOMTIMBRE_COUNT 64
|
||||
|
||||
#define MILES_MT32_TIMBREBANK_STANDARD_ROLAND 0
|
||||
#define MILES_MT32_TIMBREBANK_MELODIC_MODULE 127
|
||||
|
||||
#define MILES_MT32_PATCHDATA_COMMONPARAMETER_SIZE 14
|
||||
#define MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE 58
|
||||
#define MILES_MT32_PATCHDATA_PARTIALPARAMETERS_COUNT 4
|
||||
@ -111,6 +114,7 @@ protected:
|
||||
int _baseFreq;
|
||||
|
||||
public:
|
||||
void processXMIDITimbreChunk(const byte *timbreListPtr, uint32 timbreListSize);
|
||||
|
||||
private:
|
||||
void resetMT32();
|
||||
@ -327,6 +331,7 @@ void MidiDriver_Miles_MT32::MT32SysEx(const uint32 targetAddress, const byte *da
|
||||
delay += 40;
|
||||
|
||||
g_system->delayMillis(delay);
|
||||
g_system->updateScreen();
|
||||
}
|
||||
|
||||
// MIDI messages can be found at http://www.midi.org/techspecs/midimessages.php
|
||||
@ -550,11 +555,6 @@ void MidiDriver_Miles_MT32::setupPatch(byte patchBank, byte patchId) {
|
||||
if (patchBank) {
|
||||
// non-built-in bank
|
||||
int16 customTimbreId = searchCustomTimbre(patchBank, patchId);
|
||||
if (customTimbreId < 0) {
|
||||
// currently not loaded, try to install it
|
||||
// Miles Audio didn't do this here, I'm not exactly sure when it called the install code
|
||||
customTimbreId = installCustomTimbre(patchBank, patchId);
|
||||
}
|
||||
if (customTimbreId >= 0) {
|
||||
// now available? -> use this timbre
|
||||
writePatchTimbre(patchId, 2, customTimbreId); // Group MEMORY
|
||||
@ -571,11 +571,54 @@ void MidiDriver_Miles_MT32::setupPatch(byte patchBank, byte patchId) {
|
||||
}
|
||||
}
|
||||
|
||||
void MidiDriver_Miles_MT32::processXMIDITimbreChunk(const byte *timbreListPtr, uint32 timbreListSize) {
|
||||
uint16 timbreCount = 0;
|
||||
uint32 expectedSize = 0;
|
||||
const byte *timbreListSeeker = timbreListPtr;
|
||||
|
||||
if (timbreListSize < 2) {
|
||||
warning("MILES-MT32: XMIDI-TIMB chunk - not enough bytes in chunk");
|
||||
return;
|
||||
}
|
||||
|
||||
timbreCount = READ_LE_UINT16(timbreListPtr);
|
||||
expectedSize = timbreCount * 2;
|
||||
if (expectedSize > timbreListSize) {
|
||||
warning("MILES-MT32: XMIDI-TIMB chunk - size mismatch");
|
||||
return;
|
||||
}
|
||||
|
||||
timbreListSeeker += 2;
|
||||
|
||||
while (timbreCount) {
|
||||
const byte patchId = *timbreListSeeker++;
|
||||
const byte patchBank = *timbreListSeeker++;
|
||||
int16 customTimbreId = 0;
|
||||
|
||||
switch (patchBank) {
|
||||
case MILES_MT32_TIMBREBANK_STANDARD_ROLAND:
|
||||
case MILES_MT32_TIMBREBANK_MELODIC_MODULE:
|
||||
// ignore those 2 banks
|
||||
break;
|
||||
|
||||
default:
|
||||
// Check, if this timbre was already loaded
|
||||
customTimbreId = searchCustomTimbre(patchBank, patchId);
|
||||
|
||||
if (customTimbreId < 0) {
|
||||
// currently not loaded, try to install it
|
||||
installCustomTimbre(patchBank, patchId);
|
||||
}
|
||||
}
|
||||
timbreCount--;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
int16 MidiDriver_Miles_MT32::installCustomTimbre(byte patchBank, byte patchId) {
|
||||
switch(patchBank) {
|
||||
case 0: // Standard Roland MT32 bank
|
||||
case 127: // Reserved for melodic mode
|
||||
case MILES_MT32_TIMBREBANK_STANDARD_ROLAND: // Standard Roland MT32 bank
|
||||
case MILES_MT32_TIMBREBANK_MELODIC_MODULE: // Reserved for melodic mode
|
||||
return -1;
|
||||
default:
|
||||
break;
|
||||
@ -641,6 +684,25 @@ int16 MidiDriver_Miles_MT32::installCustomTimbre(byte patchBank, byte patchId) {
|
||||
uint32 targetAddressPartial3 = targetAddress + 0x000102;
|
||||
uint32 targetAddressPartial4 = targetAddress + 0x00013C;
|
||||
|
||||
#if 0
|
||||
byte parameterData[MILES_MT32_PATCHDATA_TOTAL_SIZE + 1];
|
||||
uint16 parameterDataPos = 0;
|
||||
|
||||
memcpy(parameterData, instrumentPtr->commonParameter, MILES_MT32_PATCHDATA_COMMONPARAMETER_SIZE);
|
||||
parameterDataPos += MILES_MT32_PATCHDATA_COMMONPARAMETER_SIZE;
|
||||
memcpy(parameterData + parameterDataPos, instrumentPtr->partialParameters[0], MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE);
|
||||
parameterDataPos += MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE;
|
||||
memcpy(parameterData + parameterDataPos, instrumentPtr->partialParameters[1], MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE);
|
||||
parameterDataPos += MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE;
|
||||
memcpy(parameterData + parameterDataPos, instrumentPtr->partialParameters[2], MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE);
|
||||
parameterDataPos += MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE;
|
||||
memcpy(parameterData + parameterDataPos, instrumentPtr->partialParameters[3], MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE);
|
||||
parameterDataPos += MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE;
|
||||
parameterData[parameterDataPos] = MILES_MT32_SYSEX_TERMINATOR;
|
||||
|
||||
MT32SysEx(targetAddressCommon, parameterData);
|
||||
#endif
|
||||
|
||||
// upload common parameter data
|
||||
MT32SysEx(targetAddressCommon, instrumentPtr->commonParameter);
|
||||
// upload partial parameter data
|
||||
@ -649,6 +711,8 @@ int16 MidiDriver_Miles_MT32::installCustomTimbre(byte patchBank, byte patchId) {
|
||||
MT32SysEx(targetAddressPartial3, instrumentPtr->partialParameters[2]);
|
||||
MT32SysEx(targetAddressPartial4, instrumentPtr->partialParameters[3]);
|
||||
|
||||
setupPatch(patchBank, patchId);
|
||||
|
||||
return customTimbreId;
|
||||
}
|
||||
|
||||
@ -806,4 +870,12 @@ MidiDriver *MidiDriver_Miles_MT32_create(const Common::String instrumentDataFile
|
||||
return new MidiDriver_Miles_MT32(instrumentTablePtr, instrumentTableCount);
|
||||
}
|
||||
|
||||
void MidiDriver_Miles_MT32_processXMIDITimbreChunk(MidiDriver_BASE *driver, const byte *timbreListPtr, uint32 timbreListSize) {
|
||||
MidiDriver_Miles_MT32 *driverMT32 = dynamic_cast<MidiDriver_Miles_MT32 *>(driver);
|
||||
|
||||
if (driverMT32) {
|
||||
driverMT32->processXMIDITimbreChunk(timbreListPtr, timbreListSize);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Audio
|
||||
|
Loading…
Reference in New Issue
Block a user