aboutsummaryrefslogtreecommitdiff
path: root/scumm
diff options
context:
space:
mode:
authorEugene Sandulenko2005-04-13 00:11:49 +0000
committerEugene Sandulenko2005-04-13 00:11:49 +0000
commitbdbd56406c20dfa7425a71de22999cc92065ce77 (patch)
tree0b3cc6d6c63ecac48ac9fed8170004a00cab195d /scumm
parent3536cd0aa2d9ade01d7f5bf0c19c6a573739a398 (diff)
downloadscummvm-rg350-bdbd56406c20dfa7425a71de22999cc92065ce77.tar.gz
scummvm-rg350-bdbd56406c20dfa7425a71de22999cc92065ce77.tar.bz2
scummvm-rg350-bdbd56406c20dfa7425a71de22999cc92065ce77.zip
Patches #1164217 "Updated GS Support + Percussion Remapping Patch" and
#1181750 "Updated Native MIDI documentation". Thanks _tom a lot. svn-id: r17571
Diffstat (limited to 'scumm')
-rw-r--r--scumm/imuse.cpp165
-rw-r--r--scumm/imuse.h1
-rw-r--r--scumm/imuse_internal.h3
-rw-r--r--scumm/scumm.cpp5
-rw-r--r--scumm/scumm.h1
5 files changed, 172 insertions, 3 deletions
diff --git a/scumm/imuse.cpp b/scumm/imuse.cpp
index 2f12865ff1..1777eb5247 100644
--- a/scumm/imuse.cpp
+++ b/scumm/imuse.cpp
@@ -46,6 +46,8 @@ namespace Scumm {
IMuseInternal::IMuseInternal() :
_native_mt32(false),
+_enable_gs(false),
+_sc55(false),
_midi_adlib(0),
_midi_native(0),
_base_sounds(0),
@@ -1071,11 +1073,24 @@ uint32 IMuseInternal::property(int prop, uint32 value) {
case IMuse::PROP_NATIVE_MT32:
_native_mt32 = (value > 0);
- Instrument::nativeMT32(value > 0);
- if (value > 0 && _midi_native)
+ Instrument::nativeMT32(_native_mt32);
+ if (_midi_native && _native_mt32)
initMT32(_midi_native);
break;
+ case IMuse::PROP_GS:
+ _enable_gs = (value > 0);
+
+ // If True Roland MT-32 is not selected, run in GM or GS mode.
+ // If it is selected, change the Roland GS synth to MT-32 mode.
+ if (_midi_native && !_native_mt32)
+ initGM(_midi_native);
+ else if (_midi_native && _native_mt32 && _enable_gs) {
+ _sc55 = true;
+ initGM(_midi_native);
+ }
+ break;
+
case IMuse::PROP_LIMIT_PLAYERS:
if (value > 0 && value <= ARRAYSIZE(_players))
_player_limit = (int) value;
@@ -1171,12 +1186,156 @@ void IMuseInternal::initMT32(MidiDriver *midi) {
midi->sysEx(buffer, 31);
g_system->delayMillis (250);
- // Setup rythm part
+ // Map percussion to notes 24 - 34 without reverb
memcpy(&buffer[4], "\x03\x01\x10\x40\x64\x07\x00\x4a\x64\x06\x00\x41\x64\x07\x00\x4b\x64\x08\x00\x45\x64\x06\x00\x44\x64\x0b\x00\x51\x64\x05\x00\x43\x64\x08\x00\x50\x64\x07\x00\x42\x64\x03\x00\x4c\x64\x07\x00\x44", 48);
midi->sysEx(buffer, 52);
g_system->delayMillis (250);
}
+void IMuseInternal::initGM(MidiDriver *midi) {
+ byte buffer[11];
+
+ // General MIDI System On message
+ // Resets all GM devices to default settings
+ memcpy(&buffer[0], "\xF0\x7E\x7F\x09\x01\xF7", 6);
+ midi->sysEx(buffer, 6);
+ debug(2, "GM SysEx: GM System On");
+ g_system->delayMillis (200);
+
+ if (_enable_gs) {
+
+ // All GS devices recognize the GS Reset command,
+ // even with Roland's ID. It is impractical to
+ // support other manufacturers' devices for
+ // further GS settings, as there are limitless
+ // numbers of them out there that would each
+ // require individual SysEx commands with unique IDs.
+
+ // Roland GS SysEx ID
+ memcpy(&buffer[0], "\xF0\x41\x10\x42\x12", 5);
+
+ // GS Reset
+ memcpy(&buffer[5], "\x40\x00\x7F\x00\x41\xF7", 6);
+ midi->sysEx(buffer, 11);
+ debug(2, "GS SysEx: GS Reset");
+ g_system->delayMillis (200);
+
+ if (_sc55) {
+
+ // This mode is for GS devices that support an MT-32-compatible
+ // Map, such as the Roland Sound Canvas line of modules. It
+ // will allow them to work with True MT-32 mode, but will
+ // obviously still ignore MT-32 SysEx (and thus custom
+ // instruments).
+
+ // Set Channels 1-16 to SC-55 Map, then CM-64/32L Variation
+ for (int i = 0; i < 16; ++i) {
+ midi->send(( 127 << 16) | (0 << 8) | (0xB0 | i));
+ midi->send(( 1 << 16) | (32 << 8) | (0xB0 | i));
+ midi->send(( 0 << 16) | (0 << 8) | (0xC0 | i));
+ }
+ debug(2, "GS Program Change: CM-64/32L Map Selected");
+
+ // Set Percussion Channel to SC-55 Map (CC#32, 01H), then
+ // Switch Drum Map to CM-64/32L (MT-32 Compatible Drums)
+ midi->getPercussionChannel()->controlChange(0, 0);
+ midi->getPercussionChannel()->controlChange(32, 1);
+ midi->send (127 << 8 | 0xC0 | 9);
+ debug(2, "GS Program Change: Drum Map is CM-64/32L");
+
+ }
+
+ // Set Master Chorus to 0. The MT-32 has no chorus capability.
+ memcpy(&buffer[5], "\x40\x01\x3A\x00\x05\xF7", 6);
+ midi->sysEx(buffer, 11);
+ debug(2, "GS SysEx: Master Chorus Level is 0");
+
+ // Set Channels 1-16 Reverb to 64, which is the
+ // equivalent of MT-32 default Reverb Level 5
+ for (int i = 0; i < 16; ++i)
+ midi->send(( 64 << 16) | (91 << 8) | (0xB0 | i));
+ debug(2, "GM Controller 91 Change: Channels 1-16 Reverb Level is 64");
+
+ // Set Channels 1-16 Pitch Bend Sensitivity to
+ // 12 semitones; then lock the RPN by setting null.
+ for (int i = 0; i < 16; ++i) {
+ midi->send(( 0 << 16) | (100 << 8) | (0xB0 | i));
+ midi->send(( 0 << 16) | (101 << 8) | (0xB0 | i));
+ midi->send(( 12 << 16) | (6 << 8) | (0xB0 | i));
+ midi->send(( 0 << 16) | (38 << 8) | (0xB0 | i));
+ midi->send(( 127 << 16) | (100 << 8) | (0xB0 | i));
+ midi->send(( 127 << 16) | (101 << 8) | (0xB0 | i));
+ }
+ debug(2, "GM Controller 6 Change: Channels 1-16 Pitch Bend Sensitivity is 12 semitones");
+
+ // Set channels 1-16 Mod. LFO1 Pitch Depth to 4
+ memcpy(&buffer[5], "\x40\x20\x04\x04\x18\xF7", 6);
+ midi->sysEx(buffer, 11);
+ memcpy(&buffer[5], "\x40\x21\x04\x04\x17\xF7", 6);
+ midi->sysEx(buffer, 11);
+ memcpy(&buffer[5], "\x40\x22\x04\x04\x16\xF7", 6);
+ midi->sysEx(buffer, 11);
+ memcpy(&buffer[5], "\x40\x23\x04\x04\x15\xF7", 6);
+ midi->sysEx(buffer, 11);
+ memcpy(&buffer[5], "\x40\x24\x04\x04\x14\xF7", 6);
+ midi->sysEx(buffer, 11);
+ memcpy(&buffer[5], "\x40\x25\x04\x04\x13\xF7", 6);
+ midi->sysEx(buffer, 11);
+ memcpy(&buffer[5], "\x40\x26\x04\x04\x12\xF7", 6);
+ midi->sysEx(buffer, 11);
+ memcpy(&buffer[5], "\x40\x27\x04\x04\x11\xF7", 6);
+ midi->sysEx(buffer, 11);
+ memcpy(&buffer[5], "\x40\x28\x04\x04\x10\xF7", 6);
+ midi->sysEx(buffer, 11);
+ memcpy(&buffer[5], "\x40\x29\x04\x04\x0F\xF7", 6);
+ midi->sysEx(buffer, 11);
+ memcpy(&buffer[5], "\x40\x2A\x04\x04\x0E\xF7", 6);
+ midi->sysEx(buffer, 11);
+ memcpy(&buffer[5], "\x40\x2B\x04\x04\x0D\xF7", 6);
+ midi->sysEx(buffer, 11);
+ memcpy(&buffer[5], "\x40\x2C\x04\x04\x0C\xF7", 6);
+ midi->sysEx(buffer, 11);
+ memcpy(&buffer[5], "\x40\x2D\x04\x04\x0B\xF7", 6);
+ midi->sysEx(buffer, 11);
+ memcpy(&buffer[5], "\x40\x2E\x04\x04\x0A\xF7", 6);
+ midi->sysEx(buffer, 11);
+ memcpy(&buffer[5], "\x40\x2F\x04\x04\x09\xF7", 6);
+ midi->sysEx(buffer, 11);
+ debug(2, "GS SysEx: Channels 1-16 Mod. LFO1 Pitch Depth Level is 4");
+
+ // Set Percussion Channel Expression to 80
+ midi->getPercussionChannel()->controlChange(11, 80);
+ debug(2, "GM Controller 11 Change: Percussion Channel Expression Level is 80");
+
+ // Turn off Percussion Channel Rx. Expression so that
+ // Expression cannot be modified. I don't know why, but
+ // Roland does it this way.
+ memcpy(&buffer[5], "\x40\x10\x0E\x00\x22\xF7", 6);
+ midi->sysEx(buffer, 11);
+ debug(2, "GS SysEx: Percussion Channel Rx. Expression is OFF");
+
+ // Change Reverb Character to 0. I don't think this
+ // sounds most like MT-32, but apparently Roland does.
+ memcpy(&buffer[5], "\x40\x01\x31\x00\x0E\xF7", 6);
+ midi->sysEx(buffer, 11);
+ debug(2, "GS SysEx: Reverb Character is 0");
+
+ // Change Reverb Pre-LF to 4, which is similar to
+ // what MT-32 reverb does.
+ memcpy(&buffer[5], "\x40\x01\x32\x04\x09\xF7", 6);
+ midi->sysEx(buffer, 11);
+ debug(2, "GS SysEx: Reverb Pre-LF is 4");
+
+ // Change Reverb Time to 106; the decay on Hall 2
+ // Reverb is too fast compared to the MT-32's
+ memcpy(&buffer[5], "\x40\x01\x34\x6A\x21\xF7", 6);
+ midi->sysEx(buffer, 11);
+ debug(2, "GS SysEx: Reverb Time is 106");
+
+ }
+
+}
+
void IMuseInternal::init_queue() {
_queue_adding = false;
_queue_pos = 0;
diff --git a/scumm/imuse.h b/scumm/imuse.h
index a9da34247b..cb78db7b5f 100644
--- a/scumm/imuse.h
+++ b/scumm/imuse.h
@@ -52,6 +52,7 @@ public:
enum {
PROP_TEMPO_BASE,
PROP_NATIVE_MT32,
+ PROP_GS,
PROP_LIMIT_PLAYERS,
PROP_RECYCLE_PLAYERS,
PROP_DIRECT_PASSTHROUGH
diff --git a/scumm/imuse_internal.h b/scumm/imuse_internal.h
index 04414ead08..a0e05db9fb 100644
--- a/scumm/imuse_internal.h
+++ b/scumm/imuse_internal.h
@@ -346,6 +346,8 @@ class IMuseInternal {
protected:
bool _native_mt32;
+ bool _enable_gs;
+ bool _sc55;
MidiDriver *_midi_adlib;
MidiDriver *_midi_native;
@@ -392,6 +394,7 @@ protected:
void handle_marker(uint id, byte data);
int get_channel_volume(uint a);
void initMidiDriver(MidiDriver *midi);
+ void initGM(MidiDriver *midi);
void initMT32(MidiDriver *midi);
void init_players();
void init_parts();
diff --git a/scumm/scumm.cpp b/scumm/scumm.cpp
index 98d968a8c7..bacc0a1020 100644
--- a/scumm/scumm.cpp
+++ b/scumm/scumm.cpp
@@ -1672,6 +1672,10 @@ void ScummEngine_v99he::scummInit() {
void ScummEngine::setupMusic(int midi) {
_midiDriver = MidiDriver::detectMusicDriver(midi);
_native_mt32 = (ConfMan.getBool("native_mt32") || (_midiDriver == MD_MT32));
+ if ((_gameId == GID_TENTACLE) || (_gameId == GID_SAMNMAX))
+ _enable_gs = false;
+ else
+ _enable_gs = ConfMan.getBool("enable_gs");
#ifndef __GP32__ //ph0x FIXME, "quick dirty hack"
/* Bind the mixer to the system => mixer will be invoked
@@ -1720,6 +1724,7 @@ void ScummEngine::setupMusic(int midi) {
if (ConfMan.hasKey("tempo"))
_imuse->property(IMuse::PROP_TEMPO_BASE, ConfMan.getInt("tempo"));
_imuse->property(IMuse::PROP_NATIVE_MT32, _native_mt32);
+ _imuse->property(IMuse::PROP_GS, _enable_gs);
if (_features & GF_HUMONGOUS || midi == MDT_TOWNS) {
_imuse->property(IMuse::PROP_LIMIT_PLAYERS, 1);
_imuse->property(IMuse::PROP_RECYCLE_PLAYERS, 1);
diff --git a/scumm/scumm.h b/scumm/scumm.h
index b8e2ed8e11..fd80ab2118 100644
--- a/scumm/scumm.h
+++ b/scumm/scumm.h
@@ -1111,6 +1111,7 @@ protected:
int _tempMusic;
int _saveSound;
bool _native_mt32;
+ bool _enable_gs;
int _midi;
int _midiDriver; // Use the MD_ values from mididrv.h
bool _copyProtection;