mirror of
https://github.com/libretro/scummvm.git
synced 2025-03-05 01:38:36 +00:00
LURE: Added MT-32 SysEx loading
This commit is contained in:
parent
34aa576744
commit
3d550b8535
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user