aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Kiewitz2015-06-30 16:05:01 +0200
committerMartin Kiewitz2015-06-30 16:05:01 +0200
commitf7ac1e944a273923735f1a79335cd043040b2c6a (patch)
treeab95bc02b58b3f5667c4931a0c344ac6a905ed45
parent4ff695524a71b81cdd682e33c44c5dac361a6130 (diff)
downloadscummvm-rg350-f7ac1e944a273923735f1a79335cd043040b2c6a.tar.gz
scummvm-rg350-f7ac1e944a273923735f1a79335cd043040b2c6a.tar.bz2
scummvm-rg350-f7ac1e944a273923735f1a79335cd043040b2c6a.zip
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
-rw-r--r--audio/midiparser.h3
-rw-r--r--audio/midiparser_xmidi.cpp49
-rw-r--r--audio/miles.h2
-rw-r--r--audio/miles_mt32.cpp86
4 files changed, 126 insertions, 14 deletions
diff --git a/audio/midiparser.h b/audio/midiparser.h
index 9c10462cd7..2cca56b14c 100644
--- a/audio/midiparser.h
+++ b/audio/midiparser.h
@@ -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(); }
};
diff --git a/audio/midiparser_xmidi.cpp b/audio/midiparser_xmidi.cpp
index 95aa5d72f3..8742d7aad1 100644
--- a/audio/midiparser_xmidi.cpp
+++ b/audio/midiparser_xmidi.cpp
@@ -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);
}
diff --git a/audio/miles.h b/audio/miles.h
index f9306069a7..08586233fc 100644
--- a/audio/miles.h
+++ b/audio/miles.h
@@ -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
diff --git a/audio/miles_mt32.cpp b/audio/miles_mt32.cpp
index 889dad3bc5..d28006e772 100644
--- a/audio/miles_mt32.cpp
+++ b/audio/miles_mt32.cpp
@@ -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