LURE: Added MT-32 SysEx loading

This commit is contained in:
NMIError 2020-06-06 13:55:42 +02:00 committed by Thierry Crozat
parent 34aa576744
commit 3d550b8535
6 changed files with 143 additions and 4 deletions

View File

@ -50,7 +50,7 @@ static const AnimRecord anim_screens[] = {
// with a palette in the following resource. Returns true if the introduction
// should be aborted
bool Introduction::showScreen(uint16 screenId, uint16 paletteId, uint16 delaySize) {
bool Introduction::showScreen(uint16 screenId, uint16 paletteId, uint16 delaySize, bool fadeOut) {
Screen &screen = Screen::getReference();
bool isEGA = LureEngine::getReference().isEGA();
screen.screen().loadScreen(screenId);
@ -65,7 +65,7 @@ bool Introduction::showScreen(uint16 screenId, uint16 paletteId, uint16 delaySiz
bool result = interruptableDelay(delaySize);
if (LureEngine::getReference().shouldQuit()) return true;
if (!isEGA)
if (fadeOut && !isEGA)
screen.paletteFadeOut();
return result;
@ -100,10 +100,21 @@ bool Introduction::show() {
// Initial game company and then game screen
for (int ctr = 0; start_screens[ctr]; ++ctr)
for (int ctr = 0; ctr < 3; ++ctr)
if (showScreen(start_screens[ctr], start_screens[ctr] + 1, 5000))
return true;
// Title screen
if (showScreen(start_screens[3], start_screens[3] + 1, 5000, false))
return true;
// TODO Original interpreter flashes a note icon in the lower left corner while doing this
Sound.initCustomTimbres();
// Fade out title screen
if (!isEGA)
screen.paletteFadeOut();
PaletteCollection coll(0x32);
Palette EgaPalette(0x1D);

View File

@ -29,7 +29,7 @@ namespace Lure {
class Introduction {
private:
bool showScreen(uint16 screenId, uint16 paletteId, uint16 delaySize);
bool showScreen(uint16 screenId, uint16 paletteId, uint16 delaySize, bool fadeOut = true);
bool interruptableDelay(uint32 milliseconds);
public:
bool show();

View File

@ -158,6 +158,15 @@ Common::Error LureEngine::go() {
// Play the game
if (!shouldQuit()) {
_screen->empty();
if (Sound.hasNativeMT32()) {
// Initialize Roland MT-32 timbres
Sound.loadSection(ROLAND_MAIN_SYSEX_RESOURCE_ID);
// TODO Original interpreter flashes a note icon in the lower left corner while doing this
Sound.initCustomTimbres();
}
// Play the game
_saveLoadAllowed = true;
Sound.loadSection(Sound.isRoland() ? ROLAND_MAIN_SOUND_RESOURCE_ID : ADLIB_MAIN_SOUND_RESOURCE_ID);

View File

@ -230,6 +230,7 @@ enum CursorType {CURSOR_ARROW = 0, CURSOR_DISK = 1, CURSOR_TIME_START = 2,
// Miscellaneous resources
#define NAMES_RESOURCE_ID 9
#define ROLAND_MAIN_SYSEX_RESOURCE_ID 0xB
#define ROLAND_MAIN_SOUND_RESOURCE_ID 0xC
#define ADLIB_MAIN_SOUND_RESOURCE_ID 0xD
#define ROLAND_INTRO_SOUND_RESOURCE_ID 0x30

View File

@ -143,6 +143,122 @@ void SoundManager::loadSection(uint16 sectionId) {
_driver->setTimerCallback(this, &onTimer);
}
void SoundManager::initCustomTimbres() {
if (!_isRoland || !_nativeMT32 || _driver == NULL)
return;
if (!_soundData)
error("SoundManager::initCustomTimbres - sound section has not been specified");
// Locate timbre data
uint32 headerSize = READ_LE_UINT32(_soundData->data() + 2); // Skip past the number of sounds
uint16 timbreDataHeaderOffset = _soundsTotal * 4 + 2;
if (timbreDataHeaderOffset + 6 > headerSize) {
warning("SoundManager::initCustomTimbres - could not find timbre data header");
return;
}
uint32 timbreDataOffset = READ_LE_UINT32(_soundData->data() + timbreDataHeaderOffset + 2); // Skip past end of header mark
if (timbreDataOffset + 17259 > _soundData->size()) {
warning("SoundManager::initCustomTimbres - timbre data smaller than expected");
return;
}
byte *timbreData = _soundData->data() + timbreDataOffset;
// Send SysExes
// System Area
uint32 address = 0x10 << 14; // 10 00 00
static const uint8 systemAreaSysExLengths[5] = { 1, 3, 9, 9, 1 };
for (int i = 0; i < 5; ++i) {
mt32SysEx(address, timbreData, systemAreaSysExLengths[i]);
address += systemAreaSysExLengths[i];
timbreData += systemAreaSysExLengths[i];
}
// Patch Temporary Area
address = 0x03 << 14; // 03 00 00
int sysexLength = 16;
for (int i = 0; i < 8; ++i) {
mt32SysEx(address, timbreData, sysexLength);
address += sysexLength;
timbreData += sysexLength;
}
// Timbre Memory
address = 0x08 << 14; // 08 00 00
sysexLength = 246;
for (int i = 0; i < 64; ++i) {
mt32SysEx(address, timbreData, sysexLength);
address += 256;
timbreData += sysexLength;
}
// Patch Memory
address = 0x05 << 14; // 05 00 00
sysexLength = 8;
for (int i = 0; i < 128; ++i) {
mt32SysEx(address, timbreData, sysexLength);
address += sysexLength;
timbreData += sysexLength;
}
// Rhythm Part Setup Temporary Area
address = 0x03 << 14 | 0x01 << 7 | 0x10; // 03 01 10
sysexLength = 4;
for (int i = 0; i < 85; ++i) {
mt32SysEx(address, timbreData, sysexLength);
address += sysexLength;
timbreData += sysexLength;
}
}
void SoundManager::mt32SysEx(const uint32 targetAddress, const byte *dataPtr, uint8 length) {
byte sysExMessage[270];
uint16 sysExPos = 0;
byte sysExByte;
uint16 sysExChecksum = 0;
memset(&sysExMessage, 0, sizeof(sysExMessage));
sysExMessage[0] = 0x41; // Roland
sysExMessage[1] = 0x10;
sysExMessage[2] = 0x16; // Model MT32
sysExMessage[3] = 0x12; // Command DT1
sysExChecksum = 0;
sysExMessage[4] = (targetAddress >> 14) & 0x7F;
sysExMessage[5] = (targetAddress >> 7) & 0x7F;
sysExMessage[6] = targetAddress & 0x7F;
for (byte targetAddressByte = 4; targetAddressByte < 7; targetAddressByte++) {
assert(sysExMessage[targetAddressByte] < 0x80); // security check
sysExChecksum -= sysExMessage[targetAddressByte];
}
sysExPos = 7;
for (int i = 0; i < length; ++i) {
sysExByte = *dataPtr++;
assert(sysExPos < sizeof(sysExMessage));
assert(sysExByte < 0x80); // security check
sysExMessage[sysExPos++] = sysExByte;
sysExChecksum -= sysExByte;
}
// Calculate checksum
assert(sysExPos < sizeof(sysExMessage));
sysExMessage[sysExPos++] = sysExChecksum & 0x7F;
_driver->sysEx(sysExMessage, sysExPos);
// Wait the time it takes to send the SysEx data
uint32 delay = (length + 2) * 1000 / 3125;
// Plus an additional delay for the MT-32 rev00
if (_nativeMT32)
delay += 40;
g_system->delayMillis(delay);
}
void SoundManager::bellsBodge() {
debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::bellsBodge");
Resources &res = Resources::getReference();

View File

@ -123,6 +123,7 @@ private:
void musicInterface_TidySounds();
static void onTimer(void *data);
void doTimer();
void mt32SysEx(const uint32 targetAddress, const byte *dataPtr, uint8 length);
public:
SoundManager();
@ -132,6 +133,7 @@ public:
void loadFromStream(Common::ReadStream *stream);
void loadSection(uint16 sectionId);
void initCustomTimbres();
void killSounds();
void addSound(uint8 soundIndex, bool tidyFlag = true);
void addSound2(uint8 soundIndex);