aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/sound/drivers/midi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/sound/drivers/midi.cpp')
-rw-r--r--engines/sci/sound/drivers/midi.cpp130
1 files changed, 102 insertions, 28 deletions
diff --git a/engines/sci/sound/drivers/midi.cpp b/engines/sci/sound/drivers/midi.cpp
index 8ba7a6a352..ed3a1e25d2 100644
--- a/engines/sci/sound/drivers/midi.cpp
+++ b/engines/sci/sound/drivers/midi.cpp
@@ -27,16 +27,21 @@
#include "common/config-manager.h"
#include "common/file.h"
+#include "common/memstream.h"
#include "sound/fmopl.h"
#include "sound/softsynth/emumidi.h"
#include "sci/resource.h"
+#include "sci/engine/features.h"
+#include "sci/sound/drivers/gm_names.h"
#include "sci/sound/drivers/mididriver.h"
#include "sci/sound/drivers/map-mt32-to-gm.h"
namespace Sci {
+Mt32ToGmMapList *Mt32dynamicMappings = NULL;
+
class MidiPlayer_Midi : public MidiPlayer {
public:
enum {
@@ -54,12 +59,17 @@ public:
void sysEx(const byte *msg, uint16 length);
bool hasRhythmChannel() const { return true; }
byte getPlayId() const;
- int getPolyphony() const { return kVoices; }
+ int getPolyphony() const {
+ if (g_sci && g_sci->_features->useAltWinGMSound())
+ return 16;
+ else
+ return kVoices;
+ }
int getFirstChannel() const;
int getLastChannel() const;
void setVolume(byte volume);
int getVolume();
- void setReverb(byte reverb);
+ void setReverb(int8 reverb);
void playSwitch(bool play);
private:
@@ -131,10 +141,21 @@ MidiPlayer_Midi::MidiPlayer_Midi(SciVersion version) : MidiPlayer(version), _pla
_sysExBuf[1] = 0x10;
_sysExBuf[2] = 0x16;
_sysExBuf[3] = 0x12;
+
+ Mt32dynamicMappings = new Mt32ToGmMapList();
}
MidiPlayer_Midi::~MidiPlayer_Midi() {
delete _driver;
+
+ const Mt32ToGmMapList::iterator end = Mt32dynamicMappings->end();
+ for (Mt32ToGmMapList::iterator it = Mt32dynamicMappings->begin(); it != end; ++it) {
+ delete[] (*it).name;
+ (*it).name = 0;
+ }
+
+ Mt32dynamicMappings->clear();
+ delete Mt32dynamicMappings;
}
void MidiPlayer_Midi::noteOn(int channel, int note, int velocity) {
@@ -304,8 +325,10 @@ void MidiPlayer_Midi::send(uint32 b) {
// In early SCI0, we may also get events for AdLib rhythm channels.
// While an MT-32 would ignore those with the default channel mapping,
// we filter these out for the benefit of other MIDI devices.
- if (channel < 1 || channel > 9)
- return;
+ if (_version == SCI_VERSION_0_EARLY) {
+ if (channel < 1 || channel > 9)
+ return;
+ }
switch (command) {
case 0x80:
@@ -320,6 +343,10 @@ void MidiPlayer_Midi::send(uint32 b) {
case 0xc0:
setPatch(channel, op1);
break;
+ // The original MIDI driver from sierra ignores aftertouch completely, so should we
+ case 0xa0: // Polyphonic key pressure (aftertouch)
+ case 0xd0: // Channel pressure (aftertouch)
+ break;
case 0xe0:
_driver->send(b);
break;
@@ -358,10 +385,13 @@ int MidiPlayer_Midi::getVolume() {
return _masterVolume;
}
-void MidiPlayer_Midi::setReverb(byte reverb) {
- _reverb = CLIP<byte>(reverb, 0, kReverbConfigNr - 1);
- if (_hasReverb)
- sendMt32SysEx(0x100001, _reverbConfig[_reverb], 3, true);
+void MidiPlayer_Midi::setReverb(int8 reverb) {
+ assert(reverb < kReverbConfigNr);
+
+ if (_hasReverb && (_reverb != reverb))
+ sendMt32SysEx(0x100001, _reverbConfig[reverb], 3, true);
+
+ _reverb = reverb;
}
void MidiPlayer_Midi::playSwitch(bool play) {
@@ -420,9 +450,9 @@ void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, Common::SeekableReadStrea
_sysExBuf[7 + i] = str->readByte();
for (int i = 4; i < 7 + len; i++)
- chk += _sysExBuf[i];
+ chk -= _sysExBuf[i];
- _sysExBuf[7 + len] = 128 - chk % 128;
+ _sysExBuf[7 + len] = chk & 0x7f;
if (noDelay)
_driver->sysEx(_sysExBuf, len + 8);
@@ -450,17 +480,18 @@ void MidiPlayer_Midi::readMt32Patch(const byte *data, int size) {
setMt32Volume(volume);
// Reverb default only used in (roughly) SCI0/SCI01
- _reverb = str->readByte();
+ byte reverb = str->readByte();
+
_hasReverb = true;
// Skip reverb SysEx message
str->seek(11, SEEK_CUR);
- // Read reverb data
- for (int i = 0; i < kReverbConfigNr; i++) {
- _reverbConfig[i][0] = str->readByte();
- _reverbConfig[i][1] = str->readByte();
- _reverbConfig[i][2] = str->readByte();
+ // Read reverb data (stored vertically - patch #3117434)
+ for (int j = 0; j < 3; ++j) {
+ for (int i = 0; i < kReverbConfigNr; i++) {
+ _reverbConfig[i][j] = str->readByte();
+ }
}
// Patches 1-48
@@ -488,6 +519,10 @@ void MidiPlayer_Midi::readMt32Patch(const byte *data, int size) {
sendMt32SysEx(0x100004, str, 9);
}
+ // Reverb for SCI0
+ if (_version <= SCI_VERSION_0_LATE)
+ setReverb(reverb);
+
// Send after-SysEx text
str->seek(0);
sendMt32SysEx(0x200000, str, 20);
@@ -615,22 +650,40 @@ void MidiPlayer_Midi::readMt32DrvData() {
byte MidiPlayer_Midi::lookupGmInstrument(const char *iname) {
int i = 0;
+ if (Mt32dynamicMappings != NULL) {
+ const Mt32ToGmMapList::iterator end = Mt32dynamicMappings->end();
+ for (Mt32ToGmMapList::iterator it = Mt32dynamicMappings->begin(); it != end; ++it) {
+ if (scumm_strnicmp(iname, (*it).name, 10) == 0)
+ return getGmInstrument((*it));
+ }
+ }
+
while (Mt32MemoryTimbreMaps[i].name) {
if (scumm_strnicmp(iname, Mt32MemoryTimbreMaps[i].name, 10) == 0)
return getGmInstrument(Mt32MemoryTimbreMaps[i]);
i++;
}
+
return MIDI_UNMAPPED;
}
byte MidiPlayer_Midi::lookupGmRhythmKey(const char *iname) {
int i = 0;
+ if (Mt32dynamicMappings != NULL) {
+ const Mt32ToGmMapList::iterator end = Mt32dynamicMappings->end();
+ for (Mt32ToGmMapList::iterator it = Mt32dynamicMappings->begin(); it != end; ++it) {
+ if (scumm_strnicmp(iname, (*it).name, 10) == 0)
+ return (*it).gmRhythmKey;
+ }
+ }
+
while (Mt32MemoryTimbreMaps[i].name) {
if (scumm_strnicmp(iname, Mt32MemoryTimbreMaps[i].name, 10) == 0)
return Mt32MemoryTimbreMaps[i].gmRhythmKey;
i++;
}
+
return MIDI_UNMAPPED;
}
@@ -801,6 +854,16 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {
Resource *res = NULL;
+ if (g_sci && g_sci->_features->useAltWinGMSound()) {
+ res = resMan->findResource(ResourceId(kResourceTypePatch, 4), 0);
+ if (!(res && isMt32GmPatch(res->data, res->size))) {
+ // Don't do any mapping when a Windows alternative track is selected
+ // and no MIDI patch is available
+ _useMT32Track = false;
+ return 0;
+ }
+ }
+
if (_isMt32) {
// MT-32
resetMt32();
@@ -825,17 +888,22 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {
// There is a GM patch
readMt32GmPatch(res->data, res->size);
- // Detect the format of patch 1, so that we know what play mask to use
- res = resMan->findResource(ResourceId(kResourceTypePatch, 1), 0);
- if (!res)
+ if (g_sci && g_sci->_features->useAltWinGMSound()) {
+ // Always use the GM track if an alternative GM Windows soundtrack is selected
_useMT32Track = false;
- else
- _useMT32Track = !isMt32GmPatch(res->data, res->size);
+ } else {
+ // Detect the format of patch 1, so that we know what play mask to use
+ res = resMan->findResource(ResourceId(kResourceTypePatch, 1), 0);
+ if (!res)
+ _useMT32Track = false;
+ else
+ _useMT32Track = !isMt32GmPatch(res->data, res->size);
- // Check if the songs themselves have a GM track
- if (!_useMT32Track) {
- if (!resMan->isGMTrackIncluded())
- _useMT32Track = true;
+ // Check if the songs themselves have a GM track
+ if (!_useMT32Track) {
+ if (!resMan->isGMTrackIncluded())
+ _useMT32Track = true;
+ }
}
} else {
// No GM patch found, map instruments using MT-32 patch
@@ -861,10 +929,16 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {
res = resMan->findResource(ResourceId(kResourceTypePatch, 1), 0);
if (res) {
- if (!isMt32GmPatch(res->data, res->size))
+ if (!isMt32GmPatch(res->data, res->size)) {
mapMt32ToGm(res->data, res->size);
- else
- error("MT-32 patch has wrong type");
+ } else {
+ if (getSciVersion() <= SCI_VERSION_2_1) {
+ error("MT-32 patch has wrong type");
+ } else {
+ // Happens in the SCI3 interactive demo of Lighthouse
+ warning("TODO: Ignoring new SCI3 type of MT-32 patch for now (size = %d)", res->size);
+ }
+ }
} else {
// No MT-32 patch present, try to read from MT32.DRV
Common::File f;