scummvm/engines/sci/sound/drivers/midi.cpp

1444 lines
44 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 "audio/mt32gm.h"
#include "sci/resource/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,
kMt32TypeD110
};
MidiPlayer_Midi(SciVersion version);
~MidiPlayer_Midi() override;
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;
void initTrack(SciSpan<const byte> &) override;
const char *reportMissingFiles() override { return _missingFiles; }
private:
bool isMt32GmPatch(const SciSpan<const byte> &data);
void readMt32GmPatch(const SciSpan<const byte> &data);
void readMt32Patch(const SciSpan<const byte> &data);
void readMt32DrvData();
bool readD110DrvData();
bool readD110SysEx();
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;
uint _mt32LCDSize;
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[32];
byte _sysExBuf[kMaxSysExSize];
const char *_missingFiles;
};
MidiPlayer_Midi::MidiPlayer_Midi(SciVersion version) : MidiPlayer(version), _playSwitch(true), _masterVolume(15), _mt32Type(kMt32TypeNone), _mt32LCDSize(20), _hasReverb(false), _defaultReverb(-1), _useMT32Track(true), _missingFiles(nullptr) {
MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI);
_driver = MidiDriver::createMidi(dev);
if (ConfMan.getInt("midi_mode") == kMidiModeD110) {
_mt32Type = kMt32TypeD110;
_mt32LCDSize = 32;
} else 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);
bool standard_midi_controller = true;
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
// this is an internal Sierra command, and shouldn't be sent to the real MIDI driver - fixing #11409
standard_midi_controller = false;
break;
case 0x4e: // velocity
break;
case 0x7b:
_channels[channel].playing = false;
default:
break;
}
if (standard_midi_controller)
_driver->send(0xb0 | channel, control, value);
}
void MidiPlayer_Midi::setPatch(int channel, int patch) {
bool resetVol = false;
assert(channel <= 15);
// No need to do anything if a patch change is sent on the rhythm channel of an MT-32
// or if the requested patch is the same as the current patch.
if ((_mt32Type != kMt32TypeNone && channel == MIDI_RHYTHM_CHANNEL) || (_channels[channel].patch == patch))
return;
int patchToSend;
if (channel != MIDI_RHYTHM_CHANNEL) {
_channels[channel].patch = patch;
_channels[channel].velocityMapIdx = _velocityMapIdx[patch];
if (_channels[channel].mappedPatch == MIDI_UNMAPPED)
resetVol = true;
_channels[channel].mappedPatch = patchToSend = _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);
} else {
// A patch change on the rhythm channel of a Roland GS device indicates a drumkit change.
// Some GM devices support the GS drumkits as well.
// Apply drumkit fallback to correct invalid drumkit numbers.
patchToSend = patch < 128 ? MidiDriver_MT32GM::GS_DRUMKIT_FALLBACK_MAP[patch] : 0;
_channels[channel].patch = patchToSend;
debugC(kDebugLevelSound, "[Midi] Selected drumkit %i (requested %i)", patchToSend, patch);
}
_driver->send(0xc0 | channel, patchToSend, 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 {
return 1;
}
int MidiPlayer_Midi::getLastChannel() const {
return 8;
}
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);
uint8 caps = header.getInt8At(0);
if (caps != 0 && (_version == SCI_VERSION_0_EARLY || caps != 2))
return;
uint8 readPos = 1;
uint8 flags = 0;
byte msg[9];
memset(msg, 0x10, 9);
if (_version == SCI_VERSION_0_EARLY) {
uint8 writePos = 0;
for (int i = 0; i < 16; ++i) {
flags = header.getInt8At(readPos++);
if (flags & 8) {
// If both flags 1 and 8 are set this will make the driver assign that channel to MT32 part 9.
// This suggests that any one channel could be the rhythm channel. I don't know whether this has any practical relevance.
// A channel not flagged with 8 can also be assigned to MT-32 part 9 if it just happens to be the last channel. This is how
// it is done in the tracks that I have seen so far. Flag 8 without flag 1 is the control channel (not handled in the driver).
if (flags & 1) {
if (i < 11) {
msg[8] = i;
writePos++;
}
} else {
debugC(9, kDebugLevelSound, "MidiPlayer_Midi::initTrack(): Control channel found: 0x%.02x", i);
}
} else if (i < 11 && (flags & 1)) {
assert(writePos < 9);
msg[writePos++] = i;
}
}
} else {
readPos = 3;
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
debugC(5, kDebugLevelSound, "MidiPlayer_Midi::initTrack(): Channels assigned to MT-32 parts: 0x%.02x 0x%.02x 0x%.02x 0x%.02x 0x%.02x 0x%.02x 0x%.02x 0x%.02x 0x%.02x", msg[0], msg[1], msg[2], msg[3], msg[4], msg[5], msg[6], msg[7], msg[8]);
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(_mt32LCDSize);
sendMt32SysEx(0x200000, stream, _mt32LCDSize);
// Save goodbye message
assert(sizeof(_goodbyeMsg) >= _mt32LCDSize);
stream.read(_goodbyeMsg, _mt32LCDSize);
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 - trac #9261)
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, _mt32LCDSize);
if (_mt32Type != kMt32TypeD110) {
// 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 - trac #9261)
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");
}
}
bool MidiPlayer_Midi::readD110DrvData() {
const char *fileName;
// Only one driver is known to exist
switch (g_sci->getGameId()) {
case GID_KQ4:
fileName = "DKQ4.DRV";
break;
default:
error("No D-110 driver is known to exist for this game");
}
Common::File f;
if (!f.open(fileName)) {
_missingFiles = fileName;
return false;
}
if (f.size() != 3500)
error("Unknown '%s' size (%d)", fileName, (int)f.size());
f.seek(42);
// Send before-SysEx text
sendMt32SysEx(0x200000, f, 32);
// Timbres
f.seek(2761);
sendMt32SysEx(0x50000, f, 256);
sendMt32SysEx(0x50200, f, 128);
// Rhythm
sendMt32SysEx(0x30110, f, 256);
sendMt32SysEx(0x30310, f, 84);
f.seek(75);
// Send after-SysEx text
sendMt32SysEx(0x200000, f, 32);
f.read(_goodbyeMsg, 32);
byte reverbSysEx[13];
f.read(reverbSysEx, 13);
sysEx(reverbSysEx + 1, 11);
_hasReverb = false;
if (f.err() || f.eos())
error("Error reading '%s'", fileName);
f.close();
return true;
}
bool MidiPlayer_Midi::readD110SysEx() {
// These patches contain SysEx messages that were meant to be sent to the
// device with a 3rd party tool before starting the game with MT-32 music.
// In order to prevent the MT-32 patches from interfering with the
// D-110/D-10/D-20 patches, these SysEx use unit #18. The user would be
// required to change the unit number on their device. Since we can avoid
// sending the MT-32 patch, we override the unit number back to 17 here.
// The D-110 versions of these patches use Patch Memory at 0x060000,
// which is not available on the D-10/D-20. Additionally, this method
// requires user interaction on the device between SysEx upload and
// starting the game. We therefore use the D-20 patches instead.
// Patches for later games (using patch 4 format with GENMIDI.DRV) appear
// to have been distributed on the Sierra BBS in file GEND110.EXE. So far
// this file has not been recovered.
// Note: there was also aftermarket support for E-mu Proteus 1/2, but those
// files appear to have been lost in the mists of time as well.
const char *fileName;
switch (g_sci->getGameId()) {
case GID_KQ5:
fileName = "KQ5D20";
break;
case GID_QFG2:
fileName = "QFG2D20";
break;
default:
error("No aftermarket D-110 patch is known to exist for this game");
}
Common::File sysExFile;
if (!sysExFile.open(fileName)) {
_missingFiles = fileName;
return false;
}
byte sysExBuf[kMaxSysExSize + 2];
while (true) {
byte b = sysExFile.readByte();
if (sysExFile.err())
error("Error reading '%s'", fileName);
if (sysExFile.eos())
break;
if (b != 0xf0)
error("Unexpected data found in SysEx file '%s'", fileName);
uint sysExLen = 0;
sysExBuf[sysExLen++] = b;
while (sysExLen < ARRAYSIZE(sysExBuf) && b != 0xf7) {
b = sysExFile.readByte();
sysExBuf[sysExLen++] = b;
}
if (b != 0xf7 || sysExLen < 10)
error("SysEx has invalid size in SysEx file '%s'", fileName);
// Use unit #17
sysExBuf[2] = 0x10;
sysEx(sysExBuf + 1, sysExLen - 2);
}
// The D-10/D-20 have fixed MIDI channel assignments, so we need to set the D-110
// manually here
Common::MemoryReadStream s((const byte *)"\x01\x02\x03\x04\x05\x06\x07\x08\x09", 9);
sendMt32SysEx(0x10000d, s, 9);
memcpy(_goodbyeMsg, " ScummVM ", 32);
return true;
}
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 == kMt32TypeD110) {
// D-110, no reset SysEx exists
for (uint i = 0; i < MIDI_CHANNELS; ++i) {
_driver->send(0xb0 | i, 0x7b, 0); // All notes off
_driver->send(0xb0 | i, 0x79, 0); // Reset all controllers
}
if (getSciVersion() == SCI_VERSION_0_EARLY) {
if (!readD110DrvData())
return MidiDriver::MERR_DEVICE_NOT_AVAILABLE;
} else if (getSciVersion() == SCI_VERSION_0_LATE) {
res = resMan->findResource(ResourceId(kResourceTypePatch, 0), false);
if (!res) {
_missingFiles = "PATCH.000";
return MidiDriver::MERR_DEVICE_NOT_AVAILABLE;
}
readMt32Patch(*res);
} else {
if (!readD110SysEx())
return MidiDriver::MERR_DEVICE_NOT_AVAILABLE;
}
} else 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, _mt32LCDSize), true);
}
_driver->setTimerCallback(NULL, NULL);
_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