scummvm/engines/sci/sound/drivers/midi.cpp
athrxx 037eec3144 SCI: implement SCI0 midi driver track initialization
I put this in an separate commit to make it easier to review/revert. I've tried to make this as minimum invasive as possible. That's why I put this in place of the former call to onNewSound().

SCI_0_LATE sound drivers (probably also SCI_0_EARLY, but I don't know that) do some midi track initialization, mostly resetting certain values and assigning voices (hardware channels) to midi parts. The information for this comes from the track header.

The SCI0 version of the PC-98 sound driver relies on this code. The driver checks the channel flags with two different masks and assigns different sound channel types accordingly. This can't be done with the 0x4B event. Using the 0x4B event is sort of counter intuitive anyway, since only some of the SCI0 drivers even support that event.

It seems that the only driver making use of onNewSound() was MT-32. I've adapted the driver to my changes, although I am quite sure that the sound will be unaffected. The only thing that the MT-32 driver does with the header information is checking whether a midi part should play or not and assign exactly one timbre (with exactly the same number) to that part if required.
2019-04-02 20:45:35 +03:00

1235 lines
38 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "sci/sci.h"
#include "common/config-manager.h"
#include "common/file.h"
#include "common/memstream.h"
#include "common/system.h"
#include "audio/mididrv.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 {
#ifdef ENABLE_SCI32
static const byte defaultSci32GMPatch[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E,
0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E,
0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E,
0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E,
0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E,
0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E,
0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E,
0x7F, 0x00, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26,
0x27, 0x27, 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E,
0x2F, 0x2F, 0x30, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36,
0x37, 0x37, 0x38, 0x38, 0x39, 0x39, 0x3A, 0x3A, 0x3B, 0x3B, 0x3C, 0x3C, 0x3D, 0x3D, 0x3E, 0x3E,
0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E,
0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E,
0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E,
0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E,
0x7F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E,
0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E,
0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E,
0x3F, 0x40, 0x41, 0x42, 0x42, 0x43, 0x43, 0x44, 0x44, 0x45, 0x45, 0x46, 0x46, 0x47, 0x47, 0x48,
0x48, 0x49, 0x49, 0x4A, 0x4A, 0x4B, 0x4B, 0x4C, 0x4C, 0x4D, 0x4D, 0x4E, 0x4E, 0x4F, 0x4F, 0x50,
0x50, 0x51, 0x51, 0x52, 0x52, 0x53, 0x53, 0x54, 0x54, 0x55, 0x55, 0x56, 0x56, 0x57, 0x57, 0x58,
0x58, 0x59, 0x59, 0x5A, 0x5A, 0x5B, 0x5B, 0x5C, 0x5C, 0x5D, 0x5D, 0x5E, 0x5E, 0x5F, 0x5F, 0x60,
0x60, 0x00, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26,
0x27, 0x27, 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E,
0x2F, 0x2F, 0x30, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36,
0x37, 0x37, 0x38, 0x38, 0x39, 0x39, 0x3A, 0x3A, 0x3B, 0x3B, 0x3C, 0x3C, 0x3D, 0x3D, 0x3E, 0x3E,
0x3F, 0x40, 0x41, 0x42, 0x42, 0x43, 0x43, 0x44, 0x44, 0x45, 0x45, 0x46, 0x46, 0x47, 0x47, 0x48,
0x48, 0x49, 0x49, 0x4A, 0x4A, 0x4B, 0x4B, 0x4C, 0x4C, 0x4D, 0x4D, 0x4E, 0x4E, 0x4F, 0x4F, 0x50,
0x50, 0x51, 0x51, 0x52, 0x52, 0x53, 0x53, 0x54, 0x54, 0x55, 0x55, 0x56, 0x56, 0x57, 0x57, 0x58,
0x58, 0x59, 0x59, 0x5A, 0x5A, 0x5B, 0x5B, 0x5C, 0x5C, 0x5D, 0x5D, 0x5E, 0x5E, 0x5F, 0x5F, 0x60,
0x60, 0x9B, 0x00, 0xF0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7F, 0x00, 0x41, 0xF7, 0xB0, 0x65,
0x00, 0x64, 0x00, 0x06, 0x0C, 0x26, 0x00, 0xB1, 0x65, 0x00, 0x64, 0x00, 0x06, 0x0C, 0x26, 0x00,
0xB2, 0x65, 0x00, 0x64, 0x00, 0x06, 0x0C, 0x26, 0x00, 0xB3, 0x65, 0x00, 0x64, 0x00, 0x06, 0x0C,
0x26, 0x00, 0xB4, 0x65, 0x00, 0x64, 0x00, 0x06, 0x0C, 0x26, 0x00, 0xB5, 0x65, 0x00, 0x64, 0x00,
0x06, 0x0C, 0x26, 0x00, 0xB6, 0x65, 0x00, 0x64, 0x00, 0x06, 0x0C, 0x26, 0x00, 0xB7, 0x65, 0x00,
0x64, 0x00, 0x06, 0x0C, 0x26, 0x00, 0xB8, 0x65, 0x00, 0x64, 0x00, 0x06, 0x0C, 0x26, 0x00, 0xB9,
0x65, 0x00, 0x64, 0x00, 0x06, 0x0C, 0x26, 0x00, 0xBA, 0x65, 0x00, 0x64, 0x00, 0x06, 0x0C, 0x26,
0x00, 0xBB, 0x65, 0x00, 0x64, 0x00, 0x06, 0x0C, 0x26, 0x00, 0xBC, 0x65, 0x00, 0x64, 0x00, 0x06,
0x0C, 0x26, 0x00, 0xBD, 0x65, 0x00, 0x64, 0x00, 0x06, 0x0C, 0x26, 0x00, 0xBE, 0x65, 0x00, 0x64,
0x00, 0x06, 0x0C, 0x26, 0x00, 0xBF, 0x65, 0x00, 0x64, 0x00, 0x06, 0x0C, 0x26, 0x00
};
#endif
Mt32ToGmMapList *Mt32dynamicMappings = NULL;
class MidiPlayer_Midi : public MidiPlayer {
public:
enum {
kVoices = 32,
kReverbConfigNr = 11,
kMaxSysExSize = 264
};
enum Mt32Type {
kMt32TypeNone,
kMt32TypeReal,
kMt32TypeEmulated
};
MidiPlayer_Midi(SciVersion version);
virtual ~MidiPlayer_Midi();
int open(ResourceManager *resMan) override;
void close() override;
void send(uint32 b) override;
void sysEx(const byte *msg, uint16 length) override;
bool hasRhythmChannel() const override { return true; }
byte getPlayId() const override;
int getPolyphony() const override {
if (g_sci && g_sci->_features->useAltWinGMSound())
return 16;
else
return kVoices;
}
int getFirstChannel() const override;
int getLastChannel() const override;
void setVolume(byte volume) override;
int getVolume() override;
void setReverb(int8 reverb) override;
void playSwitch(bool play) override;
virtual void initTrack(SciSpan<const byte> &) override;
private:
bool isMt32GmPatch(const SciSpan<const byte> &data);
void readMt32GmPatch(const SciSpan<const byte> &data);
void readMt32Patch(const SciSpan<const byte> &data);
void readMt32DrvData();
void mapMt32ToGm(const SciSpan<const byte> &data);
uint8 lookupGmInstrument(const char *iname);
uint8 lookupGmRhythmKey(const char *iname);
uint8 getGmInstrument(const Mt32ToGmMap &Mt32Ins);
void sendMt32SysEx(const uint32 addr, Common::SeekableReadStream &data, const int len, bool noDelay);
void sendMt32SysEx(const uint32 addr, const SciSpan<const byte> &data, bool noDelay);
void setMt32Volume(byte volume);
void resetMt32();
void noteOn(int channel, int note, int velocity);
void setPatch(int channel, int patch);
void controlChange(int channel, int control, int value);
struct Channel {
byte mappedPatch;
byte patch;
int velocityMapIdx;
bool playing;
int8 keyShift;
int8 volAdjust;
uint8 pan;
uint8 hold;
uint8 volume;
Channel() : mappedPatch(MIDI_UNMAPPED), patch(MIDI_UNMAPPED), velocityMapIdx(0), playing(false),
keyShift(0), volAdjust(0), pan(0x40), hold(0), volume(0x7f) { }
};
Mt32Type _mt32Type;
bool _useMT32Track;
bool _hasReverb;
bool _playSwitch;
int _masterVolume;
byte _reverbConfig[kReverbConfigNr][3];
int8 _defaultReverb;
Channel _channels[16];
uint8 _percussionMap[128];
int8 _keyShift[128];
int8 _volAdjust[128];
uint8 _patchMap[128];
uint8 _velocityMapIdx[128];
uint8 _velocityMap[4][128];
// These are extensions used for our own MT-32 to GM mapping
uint8 _pitchBendRange[128];
uint8 _percussionVelocityScale[128];
byte _goodbyeMsg[20];
byte _sysExBuf[kMaxSysExSize];
};
MidiPlayer_Midi::MidiPlayer_Midi(SciVersion version) : MidiPlayer(version), _playSwitch(true), _masterVolume(15), _mt32Type(kMt32TypeNone), _hasReverb(false), _defaultReverb(-1), _useMT32Track(true) {
MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI);
_driver = MidiDriver::createMidi(dev);
if (MidiDriver::getMusicType(dev) == MT_MT32 || ConfMan.getBool("native_mt32")) {
if (MidiDriver::getDeviceString(dev, MidiDriver::kDriverId) == "mt32") {
_mt32Type = kMt32TypeEmulated;
} else {
_mt32Type = kMt32TypeReal;
}
}
_sysExBuf[0] = 0x41;
_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) {
uint8 patch = _channels[channel].mappedPatch;
assert(channel <= 15);
assert(note <= 127);
assert(velocity <= 127);
if (channel == MIDI_RHYTHM_CHANNEL) {
if (_percussionMap[note] == MIDI_UNMAPPED) {
debugC(kDebugLevelSound, "[Midi] Percussion instrument %i is unmapped", note);
return;
}
note = _percussionMap[note];
// Scale velocity;
velocity = velocity * _percussionVelocityScale[note] / 127;
} else if (patch >= 128) {
if (patch == MIDI_UNMAPPED)
return;
// Map to rhythm
channel = MIDI_RHYTHM_CHANNEL;
note = patch - 128;
// Scale velocity;
velocity = velocity * _percussionVelocityScale[note] / 127;
} else {
int8 keyshift = _channels[channel].keyShift;
int shiftNote = note + keyshift;
if (keyshift > 0) {
while (shiftNote > 127)
shiftNote -= 12;
} else {
while (shiftNote < 0)
shiftNote += 12;
}
note = shiftNote;
// We assume that velocity 0 maps to 0 (for note off)
int mapIndex = _channels[channel].velocityMapIdx;
assert(velocity <= 127);
velocity = _velocityMap[mapIndex][velocity];
}
_channels[channel].playing = true;
_driver->send(0x90 | channel, note, velocity);
}
void MidiPlayer_Midi::controlChange(int channel, int control, int value) {
assert(channel <= 15);
switch (control) {
case 0x07:
_channels[channel].volume = value;
if (!_playSwitch)
return;
value += _channels[channel].volAdjust;
if (value > 0x7f)
value = 0x7f;
if (value < 0)
value = 1;
value *= _masterVolume;
if (value != 0) {
value /= 15;
if (value == 0)
value = 1;
}
break;
case 0x0a:
_channels[channel].pan = value;
break;
case 0x40:
_channels[channel].hold = value;
break;
case 0x4b: // voice mapping
break;
case 0x4e: // velocity
break;
case 0x7b:
_channels[channel].playing = false;
default:
break;
}
_driver->send(0xb0 | channel, control, value);
}
void MidiPlayer_Midi::setPatch(int channel, int patch) {
bool resetVol = false;
assert(channel <= 15);
if ((channel == MIDI_RHYTHM_CHANNEL) || (_channels[channel].patch == patch))
return;
_channels[channel].patch = patch;
_channels[channel].velocityMapIdx = _velocityMapIdx[patch];
if (_channels[channel].mappedPatch == MIDI_UNMAPPED)
resetVol = true;
_channels[channel].mappedPatch = _patchMap[patch];
if (_patchMap[patch] == MIDI_UNMAPPED) {
debugC(kDebugLevelSound, "[Midi] Channel %i set to unmapped patch %i", channel, patch);
_driver->send(0xb0 | channel, 0x7b, 0);
_driver->send(0xb0 | channel, 0x40, 0);
return;
}
if (_patchMap[patch] >= 128) {
// Mapped to rhythm, don't send channel commands
return;
}
if (_channels[channel].keyShift != _keyShift[patch]) {
_channels[channel].keyShift = _keyShift[patch];
_driver->send(0xb0 | channel, 0x7b, 0);
_driver->send(0xb0 | channel, 0x40, 0);
resetVol = true;
}
if (resetVol || (_channels[channel].volAdjust != _volAdjust[patch])) {
_channels[channel].volAdjust = _volAdjust[patch];
controlChange(channel, 0x07, _channels[channel].volume);
}
uint8 bendRange = _pitchBendRange[patch];
if (bendRange != MIDI_UNMAPPED)
_driver->setPitchBendRange(channel, bendRange);
_driver->send(0xc0 | channel, _patchMap[patch], 0);
// Send a pointless command to work around a firmware bug in common
// USB-MIDI cables. If the first MIDI command in a USB packet is a
// Cx or Dx command, the second command in the packet is dropped
// somewhere.
// FIXME: consider putting a workaround in the MIDI backend drivers
// instead.
// Known to be affected: alsa, coremidi
// Known *not* to be affected: windows (only seems to send one MIDI
// command per USB packet even if the device allows larger packets).
_driver->send(0xb0 | channel, 0x0a, _channels[channel].pan);
}
void MidiPlayer_Midi::send(uint32 b) {
byte command = b & 0xf0;
byte channel = b & 0xf;
byte op1 = (b >> 8) & 0x7f;
byte op2 = (b >> 16) & 0x7f;
// 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 (_version == SCI_VERSION_0_EARLY) {
if (channel < 1 || channel > 9)
return;
}
switch (command) {
case 0x80:
noteOn(channel, op1, 0);
break;
case 0x90:
noteOn(channel, op1, op2);
break;
case 0xb0:
controlChange(channel, op1, op2);
break;
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;
default:
warning("Ignoring MIDI event %02x", command);
}
}
// We return 1 for mt32, because if we remap channels to 0 for mt32, those won't get played at all
// NOTE: SSCI uses channels 1 through 8 for General MIDI as well, in the drivers I checked
int MidiPlayer_Midi::getFirstChannel() const {
if (_mt32Type != kMt32TypeNone)
return 1;
return 0;
}
int MidiPlayer_Midi::getLastChannel() const {
if (_mt32Type != kMt32TypeNone)
return 8;
return 15;
}
void MidiPlayer_Midi::setVolume(byte volume) {
_masterVolume = volume;
if (!_playSwitch)
return;
for (uint i = 1; i < 10; i++) {
if (_channels[i].volume != 0xff)
controlChange(i, 0x07, _channels[i].volume & 0x7f);
}
}
int MidiPlayer_Midi::getVolume() {
return _masterVolume;
}
void MidiPlayer_Midi::setReverb(int8 reverb) {
assert(reverb < kReverbConfigNr);
if (_hasReverb && _reverb != reverb) {
sendMt32SysEx(0x100001, SciSpan<const byte>(_reverbConfig[reverb], 3), true);
}
_reverb = reverb;
}
void MidiPlayer_Midi::playSwitch(bool play) {
_playSwitch = play;
if (play)
setVolume(_masterVolume);
else {
for (uint i = 1; i < 10; i++)
_driver->send(0xb0 | i, 7, 0);
}
}
void MidiPlayer_Midi::initTrack(SciSpan<const byte> &header) {
if (_version > SCI_VERSION_0_LATE)
return;
if (_defaultReverb >= 0)
// SCI0 in combination with MT-32 requires a reset of the reverb to
// the default value that is present in either the MT-32 patch data
// or MT32.DRV itself.
setReverb(_defaultReverb);
/* TODO: I have no idea what SCI_VERSION_0_EARLY games do here.
Therefore the extra code is restricted to SCI_VERSION_0_LATE for now.*/
if (_version == SCI_VERSION_0_EARLY)
return;
uint8 caps = header.getInt8At(0);
if (caps != 0 && caps != 2)
return;
uint8 readPos = 3;
byte msg[9];
uint8 flags = 0;
for (int i = 1; i < 9; ++i) {
readPos++;
flags = header.getInt8At(readPos++);
msg[i - 1] = (flags & 1) ? i : 0x10;
}
flags = header.getInt8At(readPos);
msg[8] = (flags & 0x80) ? 9 : 0x10;
// assign channels
Sci::SciSpan<const byte> s(msg, 9);
sendMt32SysEx(0x10000D, s, false);
}
bool MidiPlayer_Midi::isMt32GmPatch(const SciSpan<const byte> &data) {
uint32 size = data.size();
// WORKAROUND: Some Mac games (e.g. LSL5) may have an extra byte at the
// end, so compensate for that here - bug #6725.
if (size == 16890)
size--;
// Need at least 1153 + 2 bytes for a GM patch. Check readMt32GmPatch()
// below for more info.
if (size < 1153 + 2)
return false;
// The maximum number of bytes for an MT-32 patch is 16889. The maximum
// number of timbres is 64, which leads us to:
// 491 + 1 + 64 * 246 + 653 = 16889
if (size > 16889)
return true;
bool isMt32 = false;
bool isMt32Gm = false;
// First, check for a GM patch. The presence of MIDI data after the
// initial 1153 + 2 bytes indicates a GM patch
if (data.getUint16LEAt(1153) + 1155U == size)
isMt32Gm = true;
// Now check for a regular MT-32 patch. Check readMt32Patch() below for
// more info.
// 491 = 20 + 20 + 20 + 2 + 1 + 11 + 3 * 11 + 256 + 128
byte timbresNr = data[491];
uint pos = 492 + 246 * timbresNr;
// Patches 49-96
if (size >= pos + 386 && data.getUint16BEAt(pos) == 0xabcd)
pos += 386; // 256 + 128 + 2
// Rhythm key map + partial reserve
if (size >= pos + 267 && data.getUint16BEAt(pos) == 0xdcba)
pos += 267; // 256 + 9 + 2
if (size == pos)
isMt32 = true;
if (isMt32 == isMt32Gm)
error("Failed to detect MT-32 patch format");
return isMt32Gm;
}
void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, Common::SeekableReadStream &stream, int len, bool noDelay = false) {
if (len + 8 > kMaxSysExSize) {
warning("SysEx message exceed maximum size; ignoring");
return;
}
uint16 chk = 0;
_sysExBuf[4] = (addr >> 16) & 0xff;
_sysExBuf[5] = (addr >> 8) & 0xff;
_sysExBuf[6] = addr & 0xff;
stream.read(_sysExBuf + 7, len);
for (int i = 4; i < 7 + len; i++)
chk -= _sysExBuf[i];
_sysExBuf[7 + len] = chk & 0x7f;
if (noDelay)
_driver->sysEx(_sysExBuf, len + 8);
else
sysEx(_sysExBuf, len + 8);
}
void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, const SciSpan<const byte> &buf, bool noDelay = false) {
Common::MemoryReadStream stream(buf.toStream());
sendMt32SysEx(addr, stream, buf.size(), noDelay);
}
void MidiPlayer_Midi::readMt32Patch(const SciSpan<const byte> &data) {
// MT-32 patch contents:
// - 0-19 after-SysEx message
// - 20-39 before-SysEx message
// - 40-59 goodbye SysEx message
// - 60-61 volume
// - 62 reverb
// - 63-73 reverb Sysex message
// - 74-106 [3 * 11] reverb data
// - 107-490 [256 + 128] patches 1-48
// --> total: 491 bytes
// - 491 number of timbres (64 max)
// - 492..n [246 * number of timbres] timbre data
// - n-n+1 flag (0xabcd)
// - n+2-n+385 [256 + 128] patches 49-96
// - n+386-n+387 flag (0xdcba)
// - n+388-n+643 rhythm key map
// - n+644-n+652 partial reserve
Common::MemoryReadStream stream(data.toStream());
// Send before-SysEx text
stream.seek(20);
sendMt32SysEx(0x200000, stream, 20);
// Save goodbye message
assert(sizeof(_goodbyeMsg) == 20);
stream.read(_goodbyeMsg, 20);
const uint8 volume = MIN<uint16>(stream.readUint16LE(), 100);
setMt32Volume(volume);
// Reverb default only used in (roughly) SCI0/SCI01
_defaultReverb = stream.readSByte();
_hasReverb = true;
// Skip reverb SysEx message
stream.seek(11, SEEK_CUR);
// Read reverb data (stored vertically - patch #3117434)
for (int j = 0; j < 3; ++j) {
for (int i = 0; i < kReverbConfigNr; i++) {
_reverbConfig[i][j] = stream.readByte();
}
}
// Patches 1-48
sendMt32SysEx(0x50000, stream, 256);
sendMt32SysEx(0x50200, stream, 128);
// Timbres
const uint8 timbresNr = stream.readByte();
for (int i = 0; i < timbresNr; i++)
sendMt32SysEx(0x80000 + (i << 9), stream, 246);
uint16 flag = stream.readUint16BE();
if (!stream.eos() && flag == 0xabcd) {
// Patches 49-96
sendMt32SysEx(0x50300, stream, 256);
sendMt32SysEx(0x50500, stream, 128);
flag = stream.readUint16BE();
}
if (!stream.eos() && flag == 0xdcba) {
// Rhythm key map
sendMt32SysEx(0x30110, stream, 256);
// Partial reserve
sendMt32SysEx(0x100004, stream, 9);
}
// Send after-SysEx text
stream.seek(0);
sendMt32SysEx(0x200000, stream, 20);
// Send the mystery SysEx
Common::MemoryReadStream mystery((const byte *)"\x16\x16\x16\x16\x16\x16", 6);
sendMt32SysEx(0x52000a, mystery, 6);
}
void MidiPlayer_Midi::readMt32GmPatch(const SciSpan<const byte> &data) {
// GM patch contents:
// - 128 bytes patch map
// - 128 bytes key shift
// - 128 bytes volume adjustment
// - 128 bytes percussion map
// - 1 byte volume adjust for the rhythm channel
// - 128 bytes velocity map IDs
// - 512 bytes velocity map
// --> total: 1153 bytes
data.subspan(0, sizeof(_patchMap)).unsafeCopyDataTo(_patchMap);
data.subspan(128, sizeof(_keyShift)).unsafeCopyDataTo(_keyShift);
data.subspan(256, sizeof(_volAdjust)).unsafeCopyDataTo(_volAdjust);
data.subspan(384, sizeof(_percussionMap)).unsafeCopyDataTo(_percussionMap);
_channels[MIDI_RHYTHM_CHANNEL].volAdjust = data[512];
data.subspan(513, sizeof(_velocityMapIdx)).unsafeCopyDataTo(_velocityMapIdx);
data.subspan(641, sizeof(_velocityMap)).unsafeCopyDataTo(_velocityMap);
uint16 midiSize = data.getUint16LEAt(1153);
if (midiSize > 0) {
if (data.size() < midiSize + 1155U)
error("Failed to read MIDI data");
const SciSpan<const byte> midi = data.subspan(1155, midiSize);
byte command = 0;
uint i = 0;
while (i < midiSize) {
byte op1, op2;
if (midi[i] & 0x80)
command = midi[i++];
switch (command & 0xf0) {
case 0xf0: {
const byte *sysExStart = midi.getUnsafeDataAt(i, midiSize - i);
const byte *sysExEnd = (const byte *)memchr(sysExStart, 0xf7, midiSize - i);
if (!sysExEnd)
error("Failed to find end of sysEx");
int len = sysExEnd - sysExStart;
sysEx(sysExStart, len);
i += len + 1; // One more for the 0xf7
break;
}
case 0x80:
case 0x90:
case 0xa0:
case 0xb0:
case 0xe0:
if (i + 1 >= midiSize)
error("MIDI command exceeds data size");
op1 = midi[i++];
op2 = midi[i++];
_driver->send(command, op1, op2);
break;
case 0xc0:
case 0xd0:
if (i >= midiSize)
error("MIDI command exceeds data size");
op1 = midi[i++];
_driver->send(command, op1, 0);
break;
default:
error("Failed to find MIDI command byte");
}
}
}
}
void MidiPlayer_Midi::readMt32DrvData() {
Common::File f;
if (f.open("MT32.DRV")) {
int size = f.size();
// Skip before-SysEx text
if (size == 1773 || size == 1759 || size == 1747) // XMAS88 / KQ4 early (0.000.253 / 0.000.274)
f.seek(0x59);
else if (size == 2771) // LSL2 early
f.seek(0x29);
else
error("Unknown MT32.DRV size (%d)", size);
// Skip 2 extra 0 bytes in some drivers
if (f.readUint16LE() != 0)
f.seek(-2, SEEK_CUR);
// Send before-SysEx text
sendMt32SysEx(0x200000, f, 20);
if (size != 2271) {
// Send after-SysEx text (SSCI sends this before every song).
// There aren't any SysEx calls in old drivers, so this can
// be sent right after the before-SysEx text.
sendMt32SysEx(0x200000, f, 20);
} else {
// Skip the after-SysEx text in the newer patch version, we'll send
// it after the SysEx messages are sent.
f.skip(20);
}
// Save goodbye message. This isn't a C string, so it may not be
// nul-terminated.
f.read(_goodbyeMsg, 20);
// Set volume
byte volume = CLIP<uint16>(f.readUint16LE(), 0, 100);
setMt32Volume(volume);
if (size == 2771) {
// MT32.DRV in LSL2 early contains more data, like a normal patch
_defaultReverb = f.readByte();
_hasReverb = true;
// Skip reverb SysEx message
f.skip(11);
// Read reverb data (stored vertically - patch #3117434)
for (int j = 0; j < 3; ++j) {
for (int i = 0; i < kReverbConfigNr; i++) {
_reverbConfig[i][j] = f.readByte();
}
}
f.skip(2235); // skip driver code
// Patches 1-48
sendMt32SysEx(0x50000, f, 256);
sendMt32SysEx(0x50200, f, 128);
// Send the after-SysEx text
f.seek(0x3d);
sendMt32SysEx(0x200000, f, 20);
} else {
byte reverbSysEx[13];
// This old driver should have a full reverb SysEx
if ((f.read(reverbSysEx, 13) != 13) || (reverbSysEx[0] != 0xf0) || (reverbSysEx[12] != 0xf7))
error("Error reading MT32.DRV");
// Send reverb SysEx
sysEx(reverbSysEx + 1, 11);
_hasReverb = false;
f.seek(0x29);
// Read AdLib->MT-32 patch map
for (int i = 0; i < 48; i++) {
_patchMap[i] = f.readByte();
}
}
f.close();
} else {
error("Failed to open MT32.DRV");
}
}
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;
}
uint8 MidiPlayer_Midi::getGmInstrument(const Mt32ToGmMap &Mt32Ins) {
if (Mt32Ins.gmInstr == MIDI_MAPPED_TO_RHYTHM)
return Mt32Ins.gmRhythmKey + 0x80;
else
return Mt32Ins.gmInstr;
}
void MidiPlayer_Midi::mapMt32ToGm(const SciSpan<const byte> &data) {
// FIXME: Clean this up
int memtimbres, patches;
uint8 group, number, keyshift, /*finetune,*/ bender_range;
SciSpan<const byte> patchpointer;
uint32 pos;
int i;
for (i = 0; i < 128; i++) {
_patchMap[i] = getGmInstrument(Mt32PresetTimbreMaps[i]);
_pitchBendRange[i] = 12;
}
for (i = 0; i < 128; i++)
_percussionMap[i] = Mt32PresetRhythmKeymap[i];
memtimbres = data[0x1eb];
pos = 0x1ec + memtimbres * 0xf6;
if (data.size() > pos && data.getUint16BEAt(pos) == 0xabcd) {
patches = 96;
pos += 2 + 8 * 48;
} else {
patches = 48;
}
debugC(kDebugLevelSound, "[MT32-to-GM] %d MT-32 Patches detected", patches);
debugC(kDebugLevelSound, "[MT32-to-GM] %d MT-32 Memory Timbres", memtimbres);
debugC(kDebugLevelSound, "\n[MT32-to-GM] Mapping patches..");
for (i = 0; i < patches; i++) {
Common::String name;
if (i < 48)
patchpointer = data.subspan(0x6b + 8 * i);
else
patchpointer = data.subspan(0x1ec + 8 * (i - 48) + memtimbres * 0xf6 + 2);
group = patchpointer[0];
number = patchpointer[1];
keyshift = patchpointer[2];
//finetune = patchpointer[3];
bender_range = patchpointer[4];
debugCN(kDebugLevelSound, " [%03d] ", i);
switch (group) {
case 1:
number += 64;
// Fall through
case 0:
_patchMap[i] = getGmInstrument(Mt32PresetTimbreMaps[number]);
debugCN(kDebugLevelSound, "%s -> ", Mt32PresetTimbreMaps[number].name);
break;
case 2:
if (number < memtimbres) {
name = data.getStringAt(0x1ec + number * 0xf6, 10);
_patchMap[i] = lookupGmInstrument(name.c_str());
debugCN(kDebugLevelSound, "%s -> ", name.c_str());
} else {
_patchMap[i] = 0xff;
debugCN(kDebugLevelSound, "[Invalid] -> ");
}
break;
case 3:
_patchMap[i] = getGmInstrument(Mt32RhythmTimbreMaps[number]);
debugCN(kDebugLevelSound, "%s -> ", Mt32RhythmTimbreMaps[number].name);
break;
default:
break;
}
if (_patchMap[i] == MIDI_UNMAPPED) {
debugC(kDebugLevelSound, "[Unmapped]");
} else {
#ifndef REDUCE_MEMORY_USAGE
if (_patchMap[i] >= 128) {
debugC(kDebugLevelSound, "%s [Rhythm]", GmPercussionNames[_patchMap[i] - 128]);
} else {
debugC(kDebugLevelSound, "%s", GmInstrumentNames[_patchMap[i]]);
}
#endif
}
_keyShift[i] = CLIP<uint8>(keyshift, 0, 48) - 24;
_pitchBendRange[i] = CLIP<uint8>(bender_range, 0, 24);
}
if (data.size() > pos && data.getUint16BEAt(pos) == 0xdcba) {
debugC(kDebugLevelSound, "\n[MT32-to-GM] Mapping percussion..");
for (i = 0; i < 64; i++) {
number = data[pos + 4 * i + 2];
byte ins = i + 24;
debugCN(kDebugLevelSound, " [%03d] ", ins);
if (number < 64) {
Common::String name = data.getStringAt(0x1ec + number * 0xf6, 10);
debugCN(kDebugLevelSound, "%s -> ", name.c_str());
_percussionMap[ins] = lookupGmRhythmKey(name.c_str());
} else {
if (number < 94) {
debugCN(kDebugLevelSound, "%s -> ", Mt32RhythmTimbreMaps[number - 64].name);
_percussionMap[ins] = Mt32RhythmTimbreMaps[number - 64].gmRhythmKey;
} else {
debugCN(kDebugLevelSound, "[Key %03i] -> ", number);
_percussionMap[ins] = MIDI_UNMAPPED;
}
}
#ifndef REDUCE_MEMORY_USAGE
if (_percussionMap[ins] == MIDI_UNMAPPED)
debugC(kDebugLevelSound, "[Unmapped]");
else
debugC(kDebugLevelSound, "%s", GmPercussionNames[_percussionMap[ins]]);
#endif
_percussionVelocityScale[ins] = data[pos + 4 * i + 3] * 127 / 100;
}
}
}
void MidiPlayer_Midi::setMt32Volume(byte volume) {
Common::MemoryReadStream s(&volume, 1);
sendMt32SysEx(0x100016, s, 1);
}
void MidiPlayer_Midi::resetMt32() {
Common::MemoryReadStream s((const byte *)"\x01\x00", 2);
sendMt32SysEx(0x7f0000, s, 2, true);
if (_mt32Type != kMt32TypeEmulated) {
// This seems to require a longer delay than usual
g_sci->sleep(150);
}
}
int MidiPlayer_Midi::open(ResourceManager *resMan) {
assert(resMan != NULL);
int retval = _driver->open();
if (retval != 0) {
warning("Failed to open MIDI driver");
return retval;
}
// By default use no mapping
for (uint i = 0; i < 128; i++) {
_percussionMap[i] = i;
_patchMap[i] = i;
_velocityMap[0][i] = i;
_velocityMap[1][i] = i;
_velocityMap[2][i] = i;
_velocityMap[3][i] = i;
_keyShift[i] = 0;
_volAdjust[i] = 0;
_velocityMapIdx[i] = 0;
_pitchBendRange[i] = MIDI_UNMAPPED;
_percussionVelocityScale[i] = 127;
}
Resource *res = nullptr;
if (g_sci && g_sci->_features->useAltWinGMSound()) {
res = resMan->findResource(ResourceId(kResourceTypePatch, 4), false);
if (!res || !isMt32GmPatch(*res)) {
// Don't do any mapping when a Windows alternative track is selected
// and no MIDI patch is available
_useMT32Track = false;
return 0;
}
}
if (_mt32Type != kMt32TypeNone) {
// MT-32
resetMt32();
res = resMan->findResource(ResourceId(kResourceTypePatch, 1), false);
if (res) {
if (isMt32GmPatch(*res)) {
readMt32GmPatch(*res);
// Note that _goodbyeMsg is not zero-terminated
memcpy(_goodbyeMsg, " ScummVM ", 20);
} else {
readMt32Patch(*res);
}
} else {
// Early SCI0 games have the sound bank embedded in the MT-32 driver
readMt32DrvData();
}
} else {
// General MIDI
res = resMan->findResource(ResourceId(kResourceTypePatch, 4), false);
if (res && isMt32GmPatch(*res)) {
// There is a GM patch
readMt32GmPatch(*res);
if (g_sci && g_sci->_features->useAltWinGMSound()) {
// Always use the GM track if an alternative GM Windows soundtrack is selected
_useMT32Track = false;
} else {
// Detect the format of patch 1, so that we know what play mask to use
res = resMan->findResource(ResourceId(kResourceTypePatch, 1), false);
if (!res)
_useMT32Track = false;
else
_useMT32Track = !isMt32GmPatch(*res);
// Check if the songs themselves have a GM track
if (!_useMT32Track) {
if (!resMan->isGMTrackIncluded())
_useMT32Track = true;
}
}
#ifdef ENABLE_SCI32
} else if (getSciVersion() >= SCI_VERSION_2) {
readMt32GmPatch(SciSpan<const byte>(defaultSci32GMPatch, sizeof(defaultSci32GMPatch)));
_useMT32Track = false;
#endif
} else {
// No GM patch found, map instruments using MT-32 patch
warning("Game has no native support for General MIDI, applying auto-mapping");
// TODO: The MT-32 <-> GM mapping hasn't been worked on for SCI1 games. Throw
// a warning to the user
if (getSciVersion() >= SCI_VERSION_1_EGA_ONLY)
warning("The automatic mapping for General MIDI hasn't been worked on for "
"SCI1 games. Music might sound wrong or broken. Please choose another "
"music driver for this game (e.g. AdLib or MT-32) if you are "
"experiencing issues with music");
// Modify velocity map to make low velocity notes a little louder
for (uint i = 1; i < 0x40; i++) {
_velocityMap[0][i] = 0x20 + (i - 1) / 2;
_velocityMap[1][i] = 0x20 + (i - 1) / 2;
_velocityMap[2][i] = 0x20 + (i - 1) / 2;
_velocityMap[3][i] = 0x20 + (i - 1) / 2;
}
res = resMan->findResource(ResourceId(kResourceTypePatch, 1), false);
if (res) {
if (!isMt32GmPatch(*res)) {
mapMt32ToGm(*res);
} else {
if (getSciVersion() < SCI_VERSION_3) {
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 = %u)", res->size());
}
}
} else {
// Early SCI0 games have the sound bank embedded in the MT-32 driver
// No MT-32 patch present, try to read from MT32.DRV
Common::File f;
if (f.open("MT32.DRV")) {
int size = f.size();
assert(size >= 70);
f.seek(0x29);
// Read AdLib->MT-32 patch map
for (int i = 0; i < 48; i++)
_patchMap[i] = getGmInstrument(Mt32PresetTimbreMaps[f.readByte() & 0x7f]);
}
}
}
}
return 0;
}
void MidiPlayer_Midi::close() {
if (_mt32Type != kMt32TypeNone) {
// Send goodbye message
sendMt32SysEx(0x200000, SciSpan<const byte>(_goodbyeMsg, 20), true);
}
_driver->close();
}
void MidiPlayer_Midi::sysEx(const byte *msg, uint16 length) {
_driver->sysEx(msg, length);
if (_mt32Type != kMt32TypeEmulated) {
// 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 (_mt32Type == kMt32TypeReal)
delay += 40;
g_system->updateScreen();
g_sci->sleep(delay);
}
}
byte MidiPlayer_Midi::getPlayId() const {
switch (_version) {
case SCI_VERSION_0_EARLY:
case SCI_VERSION_0_LATE:
return 0x01;
default:
if (_mt32Type != kMt32TypeNone)
return 0x0c;
else
return _useMT32Track ? 0x0c : 0x07;
}
}
MidiPlayer *MidiPlayer_Midi_create(SciVersion version) {
return new MidiPlayer_Midi(version);
}
} // End of namespace Sci