aboutsummaryrefslogtreecommitdiff
path: root/engines/sherlock
diff options
context:
space:
mode:
authorMartin Kiewitz2015-06-27 22:43:32 +0200
committerMartin Kiewitz2015-06-27 22:44:39 +0200
commit0655839a4ff2a3805919c0b9bfa8f035d015e641 (patch)
tree2708550c323fac08ba6062b869389905ff21a0c8 /engines/sherlock
parent9cfe5c12968bdb53fb552615a354180b04778e29 (diff)
downloadscummvm-rg350-0655839a4ff2a3805919c0b9bfa8f035d015e641.tar.gz
scummvm-rg350-0655839a4ff2a3805919c0b9bfa8f035d015e641.tar.bz2
scummvm-rg350-0655839a4ff2a3805919c0b9bfa8f035d015e641.zip
COMMON: move Miles Audio AdLib+MT32 to common
- remove Miles Audio from Sherlock engine - put Miles Audio into common audio (namespace Audio) - Miles Audio is used at least by the engines TINSEL, GROOVIE, TOLTECS, SAGA and KYRA This way it can be used by the other engines
Diffstat (limited to 'engines/sherlock')
-rw-r--r--engines/sherlock/module.mk2
-rw-r--r--engines/sherlock/music.cpp9
-rw-r--r--engines/sherlock/tattoo/drivers/tattoo_adlib.cpp1137
-rw-r--r--engines/sherlock/tattoo/drivers/tattoo_mididriver.h69
-rw-r--r--engines/sherlock/tattoo/drivers/tattoo_mt32.cpp437
5 files changed, 5 insertions, 1649 deletions
diff --git a/engines/sherlock/module.mk b/engines/sherlock/module.mk
index 704b8d2639..e592baa5f5 100644
--- a/engines/sherlock/module.mk
+++ b/engines/sherlock/module.mk
@@ -19,8 +19,6 @@ MODULE_OBJS = \
scalpel/scalpel_talk.o \
scalpel/scalpel_user_interface.o \
scalpel/settings.o \
- tattoo/drivers/tattoo_adlib.o \
- tattoo/drivers/tattoo_mt32.o \
tattoo/tattoo.o \
tattoo/tattoo_fixed_text.o \
tattoo/tattoo_journal.o \
diff --git a/engines/sherlock/music.cpp b/engines/sherlock/music.cpp
index 948794a5a6..f72eaf71c3 100644
--- a/engines/sherlock/music.cpp
+++ b/engines/sherlock/music.cpp
@@ -25,7 +25,8 @@
#include "sherlock/sherlock.h"
#include "sherlock/music.h"
#include "sherlock/scalpel/drivers/mididriver.h"
-#include "sherlock/tattoo/drivers/tattoo_mididriver.h"
+// for Miles Audio (Sherlock Holmes 2)
+#include "audio/miles.h"
// for 3DO digital music
#include "audio/decoders/aiff.h"
@@ -269,14 +270,14 @@ Music::Music(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
// SAMPLE.AD -> regular AdLib instrument data
// SAMPLE.OPL -> OPL-3 instrument data
// although in case of Rose Tattoo both files are exactly the same
- _midiDriver = MidiDriver_Miles_AdLib_create("SAMPLE.AD", "SAMPLE.OPL");
+ _midiDriver = Audio::MidiDriver_Miles_AdLib_create("SAMPLE.AD", "SAMPLE.OPL");
break;
case MT_MT32:
- _midiDriver = MidiDriver_Miles_MT32_create("SAMPLE.MT");
+ _midiDriver = Audio::MidiDriver_Miles_MT32_create("SAMPLE.MT");
break;
case MT_GM:
if (ConfMan.getBool("native_mt32")) {
- _midiDriver = MidiDriver_Miles_MT32_create("SAMPLE.MT");
+ _midiDriver = Audio::MidiDriver_Miles_MT32_create("SAMPLE.MT");
_musicType = MT_MT32;
}
break;
diff --git a/engines/sherlock/tattoo/drivers/tattoo_adlib.cpp b/engines/sherlock/tattoo/drivers/tattoo_adlib.cpp
deleted file mode 100644
index cfc9786546..0000000000
--- a/engines/sherlock/tattoo/drivers/tattoo_adlib.cpp
+++ /dev/null
@@ -1,1137 +0,0 @@
-/* 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 "sherlock/sherlock.h"
-#include "sherlock/tattoo/drivers/tattoo_mididriver.h"
-
-#include "common/file.h"
-#include "common/system.h"
-#include "common/textconsole.h"
-
-#include "audio/fmopl.h"
-#include "audio/softsynth/emumidi.h"
-
-namespace Sherlock {
-
-// Miles Audio supported the following things:
-// regular AdLib OPL card
-// Dual-OPL2 <-- we don't do this atm
-// OPL3 <-- we do support this, but there is no support for 4-op voices atm
-
-#define MILES_ADLIB_VIRTUAL_FMVOICES_COUNT_MAX 20
-#define MILES_ADLIB_PHYSICAL_FMVOICES_COUNT_MAX 18
-
-#define MILES_ADLIB_PERCUSSION_BANK 127
-
-#define MILES_ADLIB_STEREO_PANNING_THRESHOLD_LEFT 27
-#define MILES_ADLIB_STEREO_PANNING_THRESHOLD_RIGHT 100
-
-enum kMilesAdLibUpdateFlags {
- kMilesAdLibUpdateFlags_None = 0,
- kMilesAdLibUpdateFlags_Reg_20 = 1 << 0,
- kMilesAdLibUpdateFlags_Reg_40 = 1 << 1,
- kMilesAdLibUpdateFlags_Reg_60 = 1 << 2, // register 0x6x + 0x8x
- kMilesAdLibUpdateFlags_Reg_C0 = 1 << 3,
- kMilesAdLibUpdateFlags_Reg_E0 = 1 << 4,
- kMilesAdLibUpdateFlags_Reg_A0 = 1 << 5, // register 0xAx + 0xBx
- kMilesAdLibUpdateFlags_Reg_All = 0x3F
-};
-
-uint16 milesAdLibOperator1Register[MILES_ADLIB_PHYSICAL_FMVOICES_COUNT_MAX] = {
- 0x0000, 0x0001, 0x0002, 0x0008, 0x0009, 0x000A, 0x0010, 0x0011, 0x0012,
- 0x0100, 0x0101, 0x0102, 0x0108, 0x0109, 0x010A, 0x0110, 0x0111, 0x0112
-};
-
-uint16 milesAdLibOperator2Register[MILES_ADLIB_PHYSICAL_FMVOICES_COUNT_MAX] = {
- 0x0003, 0x0004, 0x0005, 0x000B, 0x000C, 0x000D, 0x0013, 0x0014, 0x0015,
- 0x0103, 0x0104, 0x0105, 0x010B, 0x010C, 0x010D, 0x0113, 0x0114, 0x0115
-};
-
-uint16 milesAdLibChannelRegister[MILES_ADLIB_PHYSICAL_FMVOICES_COUNT_MAX] = {
- 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
- 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, 0x0108
-};
-
-struct InstrumentEntry {
- byte bankId;
- byte patchId;
- int16 transposition;
- byte reg20op1;
- byte reg40op1;
- byte reg60op1;
- byte reg80op1;
- byte regE0op1;
- byte reg20op2;
- byte reg40op2;
- byte reg60op2;
- byte reg80op2;
- byte regE0op2;
- byte regC0;
-};
-
-// hardcoded, dumped from ADLIB.MDI
-uint16 milesAdLibFrequencyLookUpTable[] = {
- 0x02B2, 0x02B4, 0x02B7, 0x02B9, 0x02BC, 0x02BE, 0x02C1, 0x02C3, 0x02C6, 0x02C9, 0x02CB, 0x02CE,
- 0x02D0, 0x02D3, 0x02D6, 0x02D8, 0x02DB, 0x02DD, 0x02E0, 0x02E3, 0x02E5, 0x02E8, 0x02EB, 0x02ED,
- 0x02F0, 0x02F3, 0x02F6, 0x02F8, 0x02FB, 0x02FE, 0x0301, 0x0303, 0x0306, 0x0309, 0x030C, 0x030F,
- 0x0311, 0x0314, 0x0317, 0x031A, 0x031D, 0x0320, 0x0323, 0x0326, 0x0329, 0x032B, 0x032E, 0x0331,
- 0x0334, 0x0337, 0x033A, 0x033D, 0x0340, 0x0343, 0x0346, 0x0349, 0x034C, 0x034F, 0x0352, 0x0356,
- 0x0359, 0x035C, 0x035F, 0x0362, 0x0365, 0x0368, 0x036B, 0x036F, 0x0372, 0x0375, 0x0378, 0x037B,
- 0x037F, 0x0382, 0x0385, 0x0388, 0x038C, 0x038F, 0x0392, 0x0395, 0x0399, 0x039C, 0x039F, 0x03A3,
- 0x03A6, 0x03A9, 0x03AD, 0x03B0, 0x03B4, 0x03B7, 0x03BB, 0x03BE, 0x03C1, 0x03C5, 0x03C8, 0x03CC,
- 0x03CF, 0x03D3, 0x03D7, 0x03DA, 0x03DE, 0x03E1, 0x03E5, 0x03E8, 0x03EC, 0x03F0, 0x03F3, 0x03F7,
- 0x03FB, 0x03FE, 0xFE01, 0xFE03, 0xFE05, 0xFE07, 0xFE08, 0xFE0A, 0xFE0C, 0xFE0E, 0xFE10, 0xFE12,
- 0xFE14, 0xFE16, 0xFE18, 0xFE1A, 0xFE1C, 0xFE1E, 0xFE20, 0xFE21, 0xFE23, 0xFE25, 0xFE27, 0xFE29,
- 0xFE2B, 0xFE2D, 0xFE2F, 0xFE31, 0xFE34, 0xFE36, 0xFE38, 0xFE3A, 0xFE3C, 0xFE3E, 0xFE40, 0xFE42,
- 0xFE44, 0xFE46, 0xFE48, 0xFE4A, 0xFE4C, 0xFE4F, 0xFE51, 0xFE53, 0xFE55, 0xFE57, 0xFE59, 0xFE5C,
- 0xFE5E, 0xFE60, 0xFE62, 0xFE64, 0xFE67, 0xFE69, 0xFE6B, 0xFE6D, 0xFE6F, 0xFE72, 0xFE74, 0xFE76,
- 0xFE79, 0xFE7B, 0xFE7D, 0xFE7F, 0xFE82, 0xFE84, 0xFE86, 0xFE89, 0xFE8B, 0xFE8D, 0xFE90, 0xFE92,
- 0xFE95, 0xFE97, 0xFE99, 0xFE9C, 0xFE9E, 0xFEA1, 0xFEA3, 0xFEA5, 0xFEA8, 0xFEAA, 0xFEAD, 0xFEAF
-};
-
-// hardcoded, dumped from ADLIB.MDI
-uint16 milesAdLibVolumeSensitivityTable[] = {
- 82, 85, 88, 91, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127
-};
-
-
-class MidiDriver_Miles_AdLib : public MidiDriver_Emulated {
-public:
- MidiDriver_Miles_AdLib(Audio::Mixer *mixer, InstrumentEntry *instrumentTablePtr, uint16 instrumentTableCount);
- virtual ~MidiDriver_Miles_AdLib();
-
- // MidiDriver
- int open();
- void close();
- void send(uint32 b);
- MidiChannel *allocateChannel() { return NULL; }
- MidiChannel *getPercussionChannel() { return NULL; }
-
- // AudioStream
- bool isStereo() const { return _modeStereo; }
- int getRate() const { return _mixer->getOutputRate(); }
- int getPolyphony() const { return _modePhysicalFmVoicesCount; }
- bool hasRhythmChannel() const { return false; }
-
- // MidiDriver_Emulated
- void generateSamples(int16 *buf, int len);
-
- void setVolume(byte volume);
- virtual uint32 property(int prop, uint32 param);
-
-private:
- bool _modeOPL3;
- byte _modePhysicalFmVoicesCount;
- byte _modeVirtualFmVoicesCount;
- bool _modeStereo;
-
- // Structure to hold information about current status of MIDI Channels
- struct MidiChannelEntry {
- byte currentPatchBank;
- const InstrumentEntry *currentInstrumentPtr;
- uint16 currentPitchBender;
- byte currentPitchRange;
- byte currentVoiceProtection;
-
- byte currentVolume;
- byte currentVolumeExpression;
-
- byte currentPanning;
-
- byte currentModulation;
- byte currentSustain;
-
- byte currentActiveVoicesCount;
-
- MidiChannelEntry() : currentPatchBank(0),
- currentInstrumentPtr(NULL),
- currentPitchBender(MILES_PITCHBENDER_DEFAULT),
- currentVoiceProtection(0),
- currentVolume(0), currentVolumeExpression(0),
- currentPanning(0),
- currentModulation(0),
- currentSustain(0),
- currentActiveVoicesCount(0) { }
- };
-
- // Structure to hold information about current status of virtual FM Voices
- struct VirtualFmVoiceEntry {
- bool inUse;
- byte actualMidiChannel;
-
- const InstrumentEntry *currentInstrumentPtr;
-
- bool isPhysical;
- byte physicalFmVoice;
-
- uint16 currentPriority;
-
- byte currentOriginalMidiNote;
- byte currentNote;
- int16 currentTransposition;
- byte currentVelocity;
-
- bool sustained;
-
- VirtualFmVoiceEntry(): inUse(false),
- actualMidiChannel(0),
- currentInstrumentPtr(NULL),
- isPhysical(false), physicalFmVoice(0),
- currentPriority(0),
- currentOriginalMidiNote(0),
- currentNote(0),
- currentTransposition(0),
- currentVelocity(0),
- sustained(false) { }
- };
-
- // Structure to hold information about current status of physical FM Voices
- struct PhysicalFmVoiceEntry {
- bool inUse;
- byte virtualFmVoice;
-
- byte currentB0hReg;
-
- PhysicalFmVoiceEntry(): inUse(false),
- virtualFmVoice(0),
- currentB0hReg(0) { }
- };
-
- OPL::OPL *_opl;
- int _masterVolume;
-
- // stores information about all MIDI channels (not the actual OPL FM voice channels!)
- MidiChannelEntry _midiChannels[MILES_MIDI_CHANNEL_COUNT];
-
- // stores information about all virtual OPL FM voices
- VirtualFmVoiceEntry _virtualFmVoices[MILES_ADLIB_VIRTUAL_FMVOICES_COUNT_MAX];
-
- // stores information about all physical OPL FM voices
- PhysicalFmVoiceEntry _physicalFmVoices[MILES_ADLIB_PHYSICAL_FMVOICES_COUNT_MAX];
-
- // holds all instruments
- InstrumentEntry *_instrumentTablePtr;
- uint16 _instrumentTableCount;
-
- bool circularPhysicalAssignment;
- byte circularPhysicalAssignmentFmVoice;
-
-protected:
- void onTimer();
-
-private:
- void resetData();
- void resetAdLib();
- void resetAdLibOperatorRegisters(byte baseRegister, byte value);
- void resetAdLibFMVoiceChannelRegisters(byte baseRegister, byte value);
-
- void setRegister(int reg, int value);
-
- int16 searchFreeVirtualFmVoiceChannel();
- int16 searchFreePhysicalFmVoiceChannel();
-
- void noteOn(byte midiChannel, byte note, byte velocity);
- void noteOff(byte midiChannel, byte note);
-
- void prioritySort();
-
- void releaseFmVoice(byte virtualFmVoice);
-
- void updatePhysicalFmVoice(byte virtualFmVoice, bool keyOn, uint16 registerUpdateFlags);
-
- void controlChange(byte midiChannel, byte controllerNumber, byte controllerValue);
- void programChange(byte midiChannel, byte patchId);
-
- const InstrumentEntry *searchInstrument(byte bankId, byte patchId);
-
- void pitchBendChange(byte MIDIchannel, byte parameter1, byte parameter2);
-};
-
-MidiDriver_Miles_AdLib::MidiDriver_Miles_AdLib(Audio::Mixer *mixer, InstrumentEntry *instrumentTablePtr, uint16 instrumentTableCount)
- : MidiDriver_Emulated(mixer), _masterVolume(15), _opl(0) {
-
- _instrumentTablePtr = instrumentTablePtr;
- _instrumentTableCount = instrumentTableCount;
-
- // Set up for OPL3, we will downgrade in case we can't create OPL3 emulator
- // regular AdLib (OPL2) card
- _modeOPL3 = true;
- _modeVirtualFmVoicesCount = 20;
- _modePhysicalFmVoicesCount = 18;
- _modeStereo = true;
-
- // Older Miles Audio drivers did not do a circular assign for physical FM-voices
- // Sherlock Holmes 2 used the circular assign
- circularPhysicalAssignment = true;
- // this way the first circular physical FM-voice search will start at FM-voice 0
- circularPhysicalAssignmentFmVoice = MILES_ADLIB_PHYSICAL_FMVOICES_COUNT_MAX;
-
- resetData();
-}
-
-MidiDriver_Miles_AdLib::~MidiDriver_Miles_AdLib() {
- delete[] _instrumentTablePtr; // is created in factory MidiDriver_Miles_AdLib_create()
-}
-
-int MidiDriver_Miles_AdLib::open() {
- int rate = _mixer->getOutputRate();
-
- if (_modeOPL3) {
- // Try to create OPL3 first
- _opl = OPL::Config::create(OPL::Config::kOpl3);
- }
- if (!_opl) {
- // not created yet, downgrade to OPL2
- _modeOPL3 = false;
- _modeVirtualFmVoicesCount = 16;
- _modePhysicalFmVoicesCount = 9;
- _modeStereo = false;
-
- _opl = OPL::Config::create(OPL::Config::kOpl2);
- }
-
- if (!_opl) {
- // We still got nothing -> can't do anything anymore
- return -1;
- }
-
- _opl->init(rate);
-
- MidiDriver_Emulated::open();
-
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, _mixer->kMaxChannelVolume, 0, DisposeAfterUse::NO);
-
- resetAdLib();
-
- return 0;
-}
-
-void MidiDriver_Miles_AdLib::close() {
- _mixer->stopHandle(_mixerSoundHandle);
-
- delete _opl;
-}
-
-void MidiDriver_Miles_AdLib::setVolume(byte volume) {
- _masterVolume = volume;
- //renewNotes(-1, true);
-}
-
-void MidiDriver_Miles_AdLib::onTimer() {
-}
-
-void MidiDriver_Miles_AdLib::resetData() {
- memset(_midiChannels, 0, sizeof(_midiChannels));
- memset(_virtualFmVoices, 0, sizeof(_virtualFmVoices));
- memset(_physicalFmVoices, 0, sizeof(_physicalFmVoices));
-
- for (byte midiChannel = 0; midiChannel < MILES_MIDI_CHANNEL_COUNT; midiChannel++) {
- _midiChannels[midiChannel].currentPitchBender = MILES_PITCHBENDER_DEFAULT;
- _midiChannels[midiChannel].currentPitchRange = 12;
- // Miles Audio 2: hardcoded pitch range as a global (not channel specific), set to 12
- // Miles Audio 3: pitch range per MIDI channel
- _midiChannels[midiChannel].currentVolumeExpression = 127;
- }
-
-}
-
-void MidiDriver_Miles_AdLib::resetAdLib() {
- if (_modeOPL3) {
- setRegister(0x105, 1); // enable OPL3
- setRegister(0x104, 0); // activate 18 2-operator FM-voices
- }
-
- setRegister(0x01, 0x20); // enable waveform control on both operators
- setRegister(0x04, 0xE0); // Timer control
-
- setRegister(0x08, 0); // select FM music mode
- setRegister(0xBD, 0); // disable Rhythm
-
- // reset FM voice instrument data
- resetAdLibOperatorRegisters(0x20, 0);
- resetAdLibOperatorRegisters(0x60, 0);
- resetAdLibOperatorRegisters(0x80, 0);
- resetAdLibFMVoiceChannelRegisters(0xA0, 0);
- resetAdLibFMVoiceChannelRegisters(0xB0, 0);
- resetAdLibFMVoiceChannelRegisters(0xC0, 0);
- resetAdLibOperatorRegisters(0xE0, 0);
- resetAdLibOperatorRegisters(0x40, 0x3F);
-}
-
-void MidiDriver_Miles_AdLib::resetAdLibOperatorRegisters(byte baseRegister, byte value) {
- byte physicalFmVoice = 0;
-
- for (physicalFmVoice = 0; physicalFmVoice < _modePhysicalFmVoicesCount; physicalFmVoice++) {
- setRegister(baseRegister + milesAdLibOperator1Register[physicalFmVoice], value);
- setRegister(baseRegister + milesAdLibOperator2Register[physicalFmVoice], value);
- }
-}
-
-void MidiDriver_Miles_AdLib::resetAdLibFMVoiceChannelRegisters(byte baseRegister, byte value) {
- byte physicalFmVoice = 0;
-
- for (physicalFmVoice = 0; physicalFmVoice < _modePhysicalFmVoicesCount; physicalFmVoice++) {
- setRegister(baseRegister + milesAdLibChannelRegister[physicalFmVoice], value);
- }
-}
-
-// MIDI messages can be found at http://www.midi.org/techspecs/midimessages.php
-void MidiDriver_Miles_AdLib::send(uint32 b) {
- byte command = b & 0xf0;
- byte channel = b & 0xf;
- byte op1 = (b >> 8) & 0xff;
- byte op2 = (b >> 16) & 0xff;
-
- switch (command) {
- case 0x80:
- noteOff(channel, op1);
- break;
- case 0x90:
- noteOn(channel, op1, op2);
- break;
- case 0xb0: // Control change
- controlChange(channel, op1, op2);
- break;
- case 0xc0: // Program Change
- programChange(channel, op1);
- break;
- case 0xa0: // Polyphonic key pressure (aftertouch)
- case 0xd0: // Channel pressure (aftertouch)
- // Aftertouch doesn't seem to be implemented in the Sherlock Holmes adlib driver
- break;
- case 0xe0:
- pitchBendChange(channel, op1, op2);
- break;
- case 0xf0: // SysEx
- warning("MILES-ADLIB: SysEx: %x", b);
- break;
- default:
- warning("MILES-ADLIB: Unknown event %02x", command);
- }
-}
-
-void MidiDriver_Miles_AdLib::generateSamples(int16 *data, int len) {
- if (_modeStereo)
- len *= 2;
-
- _opl->readBuffer(data, len);
-}
-
-int16 MidiDriver_Miles_AdLib::searchFreeVirtualFmVoiceChannel() {
- for (byte virtualFmVoice = 0; virtualFmVoice < _modeVirtualFmVoicesCount; virtualFmVoice++) {
- if (!_virtualFmVoices[virtualFmVoice].inUse)
- return virtualFmVoice;
- }
- return -1;
-}
-
-int16 MidiDriver_Miles_AdLib::searchFreePhysicalFmVoiceChannel() {
- if (!circularPhysicalAssignment) {
- // Older assign logic
- for (byte physicalFmVoice = 0; physicalFmVoice < _modePhysicalFmVoicesCount; physicalFmVoice++) {
- if (!_physicalFmVoices[physicalFmVoice].inUse)
- return physicalFmVoice;
- }
- } else {
- // Newer one
- // Remembers last physical FM-voice and searches from that spot
- byte physicalFmVoice = circularPhysicalAssignmentFmVoice;
- for (byte physicalFmVoiceCount = 0; physicalFmVoiceCount < _modePhysicalFmVoicesCount; physicalFmVoiceCount++) {
- physicalFmVoice++;
- if (physicalFmVoice >= _modePhysicalFmVoicesCount)
- physicalFmVoice = 0;
- if (!_physicalFmVoices[physicalFmVoice].inUse) {
- circularPhysicalAssignmentFmVoice = physicalFmVoice;
- return physicalFmVoice;
- }
- }
- }
- return -1;
-}
-
-void MidiDriver_Miles_AdLib::noteOn(byte midiChannel, byte note, byte velocity) {
- const InstrumentEntry *instrumentPtr = NULL;
-
- if (velocity == 0) {
- noteOff(midiChannel, note);
- return;
- }
-
- if (midiChannel == 9) {
- // percussion channel
- // search for instrument according to given note
- instrumentPtr = searchInstrument(MILES_ADLIB_PERCUSSION_BANK, note);
- } else {
- // directly get instrument of channel
- instrumentPtr = _midiChannels[midiChannel].currentInstrumentPtr;
- }
- if (!instrumentPtr) {
- warning("MILES-ADLIB: noteOn: invalid instrument");
- return;
- }
-
- //warning("Note On: channel %d, note %d, velocity %d, instrument %d/%d", midiChannel, note, velocity, instrumentPtr->bankId, instrumentPtr->patchId);
-
- // look for free virtual FM voice
- int16 virtualFmVoice = searchFreeVirtualFmVoiceChannel();
-
- if (virtualFmVoice == -1) {
- // Out of virtual voices, can't do anything about it
- return;
- }
-
- // Scale back velocity
- velocity = (velocity & 0x7F) >> 3;
- velocity = milesAdLibVolumeSensitivityTable[velocity];
-
- if (midiChannel != 9) {
- _virtualFmVoices[virtualFmVoice].currentNote = note;
- _virtualFmVoices[virtualFmVoice].currentTransposition = instrumentPtr->transposition;
- } else {
- // Percussion channel
- _virtualFmVoices[virtualFmVoice].currentNote = instrumentPtr->transposition;
- _virtualFmVoices[virtualFmVoice].currentTransposition = 0;
- }
-
- _virtualFmVoices[virtualFmVoice].inUse = true;
- _virtualFmVoices[virtualFmVoice].actualMidiChannel = midiChannel;
- _virtualFmVoices[virtualFmVoice].currentOriginalMidiNote = note;
- _virtualFmVoices[virtualFmVoice].currentInstrumentPtr = instrumentPtr;
- _virtualFmVoices[virtualFmVoice].currentVelocity = velocity;
- _virtualFmVoices[virtualFmVoice].isPhysical = false;
- _virtualFmVoices[virtualFmVoice].sustained = false;
- _virtualFmVoices[virtualFmVoice].currentPriority = 32767;
-
- int16 physicalFmVoice = searchFreePhysicalFmVoiceChannel();
- if (physicalFmVoice == -1) {
- // None found
- // go through priorities and reshuffle voices
- prioritySort();
- return;
- }
-
- // Another voice active on this MIDI channel
- _midiChannels[midiChannel].currentActiveVoicesCount++;
-
- // Mark virtual FM-Voice as being connected to physical FM-Voice
- _virtualFmVoices[virtualFmVoice].isPhysical = true;
- _virtualFmVoices[virtualFmVoice].physicalFmVoice = physicalFmVoice;
-
- // Mark physical FM-Voice as being connected to virtual FM-Voice
- _physicalFmVoices[physicalFmVoice].inUse = true;
- _physicalFmVoices[physicalFmVoice].virtualFmVoice = virtualFmVoice;
-
- // Update the physical FM-Voice
- updatePhysicalFmVoice(virtualFmVoice, true, kMilesAdLibUpdateFlags_Reg_All);
-}
-
-void MidiDriver_Miles_AdLib::noteOff(byte midiChannel, byte note) {
- //warning("Note Off: channel %d, note %d", midiChannel, note);
-
- // Search through all virtual FM-Voices for current midiChannel + note
- for (byte virtualFmVoice = 0; virtualFmVoice < _modeVirtualFmVoicesCount; virtualFmVoice++) {
- if (_virtualFmVoices[virtualFmVoice].inUse) {
- if ((_virtualFmVoices[virtualFmVoice].actualMidiChannel == midiChannel) && (_virtualFmVoices[virtualFmVoice].currentOriginalMidiNote == note)) {
- // found one
- if (_midiChannels[midiChannel].currentSustain >= 64) {
- _virtualFmVoices[virtualFmVoice].sustained = true;
- continue;
- }
- //
- releaseFmVoice(virtualFmVoice);
- }
- }
- }
-}
-
-void MidiDriver_Miles_AdLib::prioritySort() {
- byte virtualFmVoice = 0;
- uint16 virtualPriority = 0;
- uint16 virtualPriorities[MILES_ADLIB_VIRTUAL_FMVOICES_COUNT_MAX];
- uint16 virtualFmVoicesCount = 0;
- byte midiChannel = 0;
-
- memset(&virtualPriorities, 0, sizeof(virtualPriorities));
-
- //warning("prioritysort");
-
- // First calculate priorities for all virtual FM voices, that are in use
- for (virtualFmVoice = 0; virtualFmVoice < _modeVirtualFmVoicesCount; virtualFmVoice++) {
- if (_virtualFmVoices[virtualFmVoice].inUse) {
- virtualFmVoicesCount++;
-
- midiChannel = _virtualFmVoices[virtualFmVoice].actualMidiChannel;
- if (_midiChannels[midiChannel].currentVoiceProtection >= 64) {
- // Voice protection enabled
- virtualPriority = 0xFFFF;
- } else {
- virtualPriority = _virtualFmVoices[virtualFmVoice].currentPriority;
- }
- byte currentActiveVoicesCount = _midiChannels[midiChannel].currentActiveVoicesCount;
- if (virtualPriority >= currentActiveVoicesCount) {
- virtualPriority -= _midiChannels[midiChannel].currentActiveVoicesCount;
- } else {
- virtualPriority = 0; // overflow, should never happen
- }
- virtualPriorities[virtualFmVoice] = virtualPriority;
- }
- }
-
- //
- while (virtualFmVoicesCount) {
- uint16 unvoicedHighestPriority = 0;
- byte unvoicedHighestFmVoice = 0;
- uint16 voicedLowestPriority = 65535;
- byte voicedLowestFmVoice = 0;
-
- for (virtualFmVoice = 0; virtualFmVoice < _modeVirtualFmVoicesCount; virtualFmVoice++) {
- if (_virtualFmVoices[virtualFmVoice].inUse) {
- virtualPriority = virtualPriorities[virtualFmVoice];
- if (!_virtualFmVoices[virtualFmVoice].isPhysical) {
- // currently not physical, so unvoiced
- if (virtualPriority >= unvoicedHighestPriority) {
- unvoicedHighestPriority = virtualPriority;
- unvoicedHighestFmVoice = virtualFmVoice;
- }
- } else {
- // currently physical, so voiced
- if (virtualPriority <= voicedLowestPriority) {
- voicedLowestPriority = virtualPriority;
- voicedLowestFmVoice = virtualFmVoice;
- }
- }
- }
- }
-
- if (unvoicedHighestPriority < voicedLowestPriority)
- break; // We are done
-
- if (unvoicedHighestPriority == 0)
- break;
-
- // Safety checks
- assert(_virtualFmVoices[voicedLowestFmVoice].isPhysical);
- assert(!_virtualFmVoices[unvoicedHighestFmVoice].isPhysical);
-
- // Steal this physical voice
- byte physicalFmVoice = _virtualFmVoices[voicedLowestFmVoice].physicalFmVoice;
-
- //warning("MILES-ADLIB: stealing physical FM-Voice %d from virtual FM-Voice %d for virtual FM-Voice %d", physicalFmVoice, voicedLowestFmVoice, unvoicedHighestFmVoice);
- //warning("priority old %d, priority new %d", unvoicedHighestPriority, voicedLowestPriority);
-
- releaseFmVoice(voicedLowestFmVoice);
-
- // Get some data of the unvoiced highest priority virtual FM Voice
- midiChannel = _virtualFmVoices[unvoicedHighestFmVoice].actualMidiChannel;
-
- // Another voice active on this MIDI channel
- _midiChannels[midiChannel].currentActiveVoicesCount++;
-
- // Mark virtual FM-Voice as being connected to physical FM-Voice
- _virtualFmVoices[unvoicedHighestFmVoice].isPhysical = true;
- _virtualFmVoices[unvoicedHighestFmVoice].physicalFmVoice = physicalFmVoice;
-
- // Mark physical FM-Voice as being connected to virtual FM-Voice
- _physicalFmVoices[physicalFmVoice].inUse = true;
- _physicalFmVoices[physicalFmVoice].virtualFmVoice = unvoicedHighestFmVoice;
-
- // Update the physical FM-Voice
- updatePhysicalFmVoice(unvoicedHighestFmVoice, true, kMilesAdLibUpdateFlags_Reg_All);
-
- virtualFmVoicesCount--;
- }
-}
-
-void MidiDriver_Miles_AdLib::releaseFmVoice(byte virtualFmVoice) {
- // virtual Voice not actually played? -> exit
- if (!_virtualFmVoices[virtualFmVoice].isPhysical) {
- _virtualFmVoices[virtualFmVoice].inUse = false;
- return;
- }
-
- byte midiChannel = _virtualFmVoices[virtualFmVoice].actualMidiChannel;
- byte physicalFmVoice = _virtualFmVoices[virtualFmVoice].physicalFmVoice;
-
- // stop note from playing
- updatePhysicalFmVoice(virtualFmVoice, false, kMilesAdLibUpdateFlags_Reg_A0);
-
- // this virtual FM voice isn't physical anymore
- _virtualFmVoices[virtualFmVoice].isPhysical = false;
- _virtualFmVoices[virtualFmVoice].inUse = false;
-
- // Remove physical FM-Voice from being active
- _physicalFmVoices[physicalFmVoice].inUse = false;
-
- // One less voice active on this MIDI channel
- assert(_midiChannels[midiChannel].currentActiveVoicesCount);
- _midiChannels[midiChannel].currentActiveVoicesCount--;
-}
-
-void MidiDriver_Miles_AdLib::updatePhysicalFmVoice(byte virtualFmVoice, bool keyOn, uint16 registerUpdateFlags) {
- byte midiChannel = _virtualFmVoices[virtualFmVoice].actualMidiChannel;
-
- if (!_virtualFmVoices[virtualFmVoice].isPhysical) {
- // virtual FM-Voice has no physical FM-Voice assigned? -> ignore
- return;
- }
-
- byte physicalFmVoice = _virtualFmVoices[virtualFmVoice].physicalFmVoice;
- const InstrumentEntry *instrumentPtr = _virtualFmVoices[virtualFmVoice].currentInstrumentPtr;
-
- uint16 op1Reg = milesAdLibOperator1Register[physicalFmVoice];
- uint16 op2Reg = milesAdLibOperator2Register[physicalFmVoice];
- uint16 channelReg = milesAdLibChannelRegister[physicalFmVoice];
-
- uint16 compositeVolume = 0;
-
- if (registerUpdateFlags & kMilesAdLibUpdateFlags_Reg_40) {
- // Calculate new volume
- byte midiVolume = _midiChannels[midiChannel].currentVolume;
- byte midiVolumeExpression = _midiChannels[midiChannel].currentVolumeExpression;
- compositeVolume = midiVolume * midiVolumeExpression * 2;
-
- compositeVolume = compositeVolume >> 8; // get upmost 8 bits
- if (compositeVolume)
- compositeVolume++; // round up in case result wasn't 0
-
- compositeVolume = compositeVolume * _virtualFmVoices[virtualFmVoice].currentVelocity * 2;
- compositeVolume = compositeVolume >> 8; // get upmost 8 bits
- if (compositeVolume)
- compositeVolume++; // round up in case result wasn't 0
- }
-
- if (registerUpdateFlags & kMilesAdLibUpdateFlags_Reg_20) {
- // Amplitude Modulation / Vibrato / Envelope Generator Type / Keyboard Scaling Rate / Modulator Frequency Multiple
- byte reg20op1 = instrumentPtr->reg20op1;
- byte reg20op2 = instrumentPtr->reg20op2;
-
- if (_midiChannels[midiChannel].currentModulation >= 64) {
- // set bit 6 (Vibrato)
- reg20op1 |= 0x40;
- reg20op2 |= 0x40;
- }
- setRegister(0x20 + op1Reg, reg20op1);
- setRegister(0x20 + op2Reg, reg20op2);
- }
-
- if (registerUpdateFlags & kMilesAdLibUpdateFlags_Reg_40) {
- // Volume (Level Key Scaling / Total Level)
- byte reg40op1 = instrumentPtr->reg40op1;
- byte reg40op2 = instrumentPtr->reg40op2;
-
- uint16 volumeOp1 = (~reg40op1) & 0x3F;
- uint16 volumeOp2 = (~reg40op2) & 0x3F;
-
- if (instrumentPtr->regC0 & 1) {
- // operator 2 enabled
- // scale volume factor
- volumeOp1 = (volumeOp1 * compositeVolume) / 127;
- // 2nd operator always scaled
- }
-
- volumeOp2 = (volumeOp2 * compositeVolume) / 127;
-
- volumeOp1 = (~volumeOp1) & 0x3F; // negate it, so we get the proper value for the register
- volumeOp2 = (~volumeOp2) & 0x3F; // ditto
- reg40op1 = (reg40op1 & 0xC0) | volumeOp1; // keep "scaling level" and merge in our volume
- reg40op2 = (reg40op2 & 0xC0) | volumeOp2;
-
- setRegister(0x40 + op1Reg, reg40op1);
- setRegister(0x40 + op2Reg, reg40op2);
- }
-
- if (registerUpdateFlags & kMilesAdLibUpdateFlags_Reg_60) {
- // Attack Rate / Decay Rate
- // Sustain Level / Release Rate
- byte reg60op1 = instrumentPtr->reg60op1;
- byte reg60op2 = instrumentPtr->reg60op2;
- byte reg80op1 = instrumentPtr->reg80op1;
- byte reg80op2 = instrumentPtr->reg80op2;
-
- setRegister(0x60 + op1Reg, reg60op1);
- setRegister(0x60 + op2Reg, reg60op2);
- setRegister(0x80 + op1Reg, reg80op1);
- setRegister(0x80 + op2Reg, reg80op2);
- }
-
- if (registerUpdateFlags & kMilesAdLibUpdateFlags_Reg_E0) {
- // Waveform Select
- byte regE0op1 = instrumentPtr->regE0op1;
- byte regE0op2 = instrumentPtr->regE0op2;
-
- setRegister(0xE0 + op1Reg, regE0op1);
- setRegister(0xE0 + op2Reg, regE0op2);
- }
-
- if (registerUpdateFlags & kMilesAdLibUpdateFlags_Reg_C0) {
- // Feedback / Algorithm
- byte regC0 = instrumentPtr->regC0;
-
- if (_modeOPL3) {
- // Panning for OPL3
- byte panning = _midiChannels[midiChannel].currentPanning;
-
- if (panning <= MILES_ADLIB_STEREO_PANNING_THRESHOLD_LEFT) {
- regC0 |= 0x10; // left speaker only
- } else if (panning >= MILES_ADLIB_STEREO_PANNING_THRESHOLD_RIGHT) {
- regC0 |= 0x20; // right speaker only
- } else {
- regC0 |= 0x30; // center
- }
- }
-
- setRegister(0xC0 + channelReg, regC0);
- }
-
- if (registerUpdateFlags & kMilesAdLibUpdateFlags_Reg_A0) {
- // Frequency / Key-On
- // Octave / F-Number / Key-On
- if (!keyOn) {
- // turn off note
- byte regB0 = _physicalFmVoices[physicalFmVoice].currentB0hReg & 0x1F; // remove bit 5 "key on"
- setRegister(0xB0 + channelReg, regB0);
-
- } else {
- // turn on note, calculate frequency, octave...
- int16 pitchBender = _midiChannels[midiChannel].currentPitchBender;
- byte pitchRange = _midiChannels[midiChannel].currentPitchRange;
- int16 currentNote = _virtualFmVoices[virtualFmVoice].currentNote;
- int16 physicalNote = 0;
- int16 halfTone = 0;
- uint16 frequency = 0;
- uint16 frequencyIdx = 0;
- byte octave = 0;
-
- pitchBender -= 0x2000;
- pitchBender = pitchBender >> 5; // divide by 32
- pitchBender = pitchBender * pitchRange; // pitchrange 12: now +0x0C00 to -0xC00
- // difference between Miles Audio 2 + 3
- // Miles Audio 2 used a pitch range of 12, which was basically hardcoded
- // Miles Audio 3 used an array, which got set by control change events
-
- currentNote += _virtualFmVoices->currentTransposition;
-
- // Normalize note
- currentNote -= 24;
- do {
- currentNote += 12;
- } while (currentNote < 0);
- currentNote += 12;
-
- do {
- currentNote -= 12;
- } while (currentNote > 95);
-
- // combine note + pitchbender, also adjust by 8 for rounding
- currentNote = (currentNote << 8) + pitchBender + 8;
-
- currentNote = currentNote >> 4; // get actual note
-
- // Normalize
- currentNote -= (12 * 16);
- do {
- currentNote += (12 * 16);
- } while (currentNote < 0);
-
- currentNote += (12 * 16);
- do {
- currentNote -= (12 * 16);
- } while (currentNote > ((96 * 16) - 1));
-
- physicalNote = currentNote >> 4;
-
- halfTone = physicalNote % 12; // remainder of physicalNote / 12
-
- frequencyIdx = (halfTone << 4) + (currentNote & 0x0F);
- assert(frequencyIdx < sizeof(milesAdLibFrequencyLookUpTable));
- frequency = milesAdLibFrequencyLookUpTable[frequencyIdx];
-
- octave = (physicalNote / 12) - 1;
-
- if (frequency & 0x8000)
- octave++;
-
- if (octave & 0x80) {
- octave++;
- frequency = frequency >> 1;
- }
-
- byte regA0 = frequency & 0xFF;
- byte regB0 = ((frequency >> 8) & 0x03) | (octave << 2) | 0x20;
-
- setRegister(0xA0 + channelReg, regA0);
- setRegister(0xB0 + channelReg, regB0);
-
- _physicalFmVoices[physicalFmVoice].currentB0hReg = regB0;
- }
- }
-
- //warning("end of update voice");
-}
-
-void MidiDriver_Miles_AdLib::controlChange(byte midiChannel, byte controllerNumber, byte controllerValue) {
- uint16 registerUpdateFlags = kMilesAdLibUpdateFlags_None;
-
- switch (controllerNumber) {
- case MILES_CONTROLLER_SELECT_PATCH_BANK:
- _midiChannels[midiChannel].currentPatchBank = controllerValue;
- break;
-
- case MILES_CONTROLLER_PROTECT_VOICE:
- _midiChannels[midiChannel].currentVoiceProtection = controllerValue;
- break;
-
- case MILES_CONTROLLER_PROTECT_TIMBRE:
- // It seems that this can get ignored, because we don't cache timbres at all
- break;
-
- case MILES_CONTROLLER_MODULATION:
- _midiChannels[midiChannel].currentModulation = controllerValue;
- registerUpdateFlags = kMilesAdLibUpdateFlags_Reg_20;
- break;
-
- case MILES_CONTROLLER_VOLUME:
- _midiChannels[midiChannel].currentVolume = controllerValue;
- registerUpdateFlags = kMilesAdLibUpdateFlags_Reg_40;
- break;
-
- case MILES_CONTROLLER_EXPRESSION:
- _midiChannels[midiChannel].currentVolumeExpression = controllerValue;
- registerUpdateFlags = kMilesAdLibUpdateFlags_Reg_40;
- break;
-
- case MILES_CONTROLLER_PANNING:
- _midiChannels[midiChannel].currentPanning = controllerValue;
- if (_modeStereo) {
- // Update register only in case we are in stereo mode
- registerUpdateFlags = kMilesAdLibUpdateFlags_Reg_C0;
- }
- break;
-
- case MILES_CONTROLLER_SUSTAIN:
- _midiChannels[midiChannel].currentSustain = controllerValue;
- if (controllerValue < 64) {
- // release sustain TODO
- }
- break;
-
- case MILES_CONTROLLER_PITCH_RANGE:
- // Miles Audio 3 feature
- _midiChannels[midiChannel].currentPitchRange = controllerValue;
- break;
-
- case MILES_CONTROLLER_RESET_ALL:
- _midiChannels[midiChannel].currentSustain = 0;
- // release sustain TODO
- _midiChannels[midiChannel].currentModulation = 0;
- _midiChannels[midiChannel].currentVolumeExpression = 127;
- _midiChannels[midiChannel].currentPitchBender = MILES_PITCHBENDER_DEFAULT;
- registerUpdateFlags = kMilesAdLibUpdateFlags_Reg_20 | kMilesAdLibUpdateFlags_Reg_40 | kMilesAdLibUpdateFlags_Reg_A0;
- break;
-
- case MILES_CONTROLLER_ALL_NOTES_OFF:
- for (byte virtualFmVoice = 0; virtualFmVoice < _modeVirtualFmVoicesCount; virtualFmVoice++) {
- if (_virtualFmVoices[virtualFmVoice].inUse) {
- // used
- if (_virtualFmVoices[virtualFmVoice].actualMidiChannel == midiChannel) {
- // by our current MIDI channel -> noteOff
- noteOff(midiChannel, _virtualFmVoices[virtualFmVoice].currentNote);
- }
- }
- }
- break;
-
- default:
- //warning("MILES-ADLIB: Unsupported control change %d", controllerNumber);
- break;
- }
-
- if (registerUpdateFlags) {
- for (byte virtualFmVoice = 0; virtualFmVoice < _modeVirtualFmVoicesCount; virtualFmVoice++) {
- if (_virtualFmVoices[virtualFmVoice].inUse) {
- // used
- if (_virtualFmVoices[virtualFmVoice].actualMidiChannel == midiChannel) {
- // by our current MIDI channel -> update
- updatePhysicalFmVoice(virtualFmVoice, true, registerUpdateFlags);
- }
- }
- }
- }
-}
-
-void MidiDriver_Miles_AdLib::programChange(byte midiChannel, byte patchId) {
- const InstrumentEntry *instrumentPtr = NULL;
- byte patchBank = _midiChannels[midiChannel].currentPatchBank;
-
- // we check, if we actually have data for the requested instrument...
- instrumentPtr = searchInstrument(patchBank, patchId);
- if (!instrumentPtr) {
- warning("MILES-ADLIB: unknown instrument requested (%d, %d)", patchBank, patchId);
- return;
- }
-
- // and remember it in that case for the current MIDI-channel
- _midiChannels[midiChannel].currentInstrumentPtr = instrumentPtr;
-}
-
-const InstrumentEntry *MidiDriver_Miles_AdLib::searchInstrument(byte bankId, byte patchId) {
- const InstrumentEntry *instrumentPtr = _instrumentTablePtr;
-
- for (uint16 instrumentNr = 0; instrumentNr < _instrumentTableCount; instrumentNr++) {
- if ((instrumentPtr->bankId == bankId) && (instrumentPtr->patchId == patchId)) {
- return instrumentPtr;
- }
- instrumentPtr++;
- }
-
- return NULL;
-}
-
-void MidiDriver_Miles_AdLib::pitchBendChange(byte midiChannel, byte parameter1, byte parameter2) {
- // Miles Audio actually didn't shift parameter 2 1 down in here
- // which means in memory it used a 15-bit pitch bender, which also means the default was 0x4000
- if ((parameter1 & 0x80) || (parameter2 & 0x80)) {
- warning("MILES-ADLIB: invalid pitch bend change");
- return;
- }
- _midiChannels[midiChannel].currentPitchBender = parameter1 | (parameter2 << 7);
-}
-
-void MidiDriver_Miles_AdLib::setRegister(int reg, int value) {
- if (!(reg & 0x100)) {
- _opl->write(0x220, reg);
- _opl->write(0x221, value);
- //warning("OPL write %x %x (%d)", reg, value, value);
- } else {
- _opl->write(0x222, reg & 0xFF);
- _opl->write(0x223, value);
- //warning("OPL3 write %x %x (%d)", reg & 0xFF, value, value);
- }
-}
-
-uint32 MidiDriver_Miles_AdLib::property(int prop, uint32 param) {
- return 0;
-}
-
-MidiDriver *MidiDriver_Miles_AdLib_create(const Common::String instrumentDataFilename, const Common::String instrumentDataFilenameOPL3) {
- // Load adlib instrument data from file SAMPLE.AD (OPL3: SAMPLE.OPL)
- Common::File *fileStream = new Common::File();
- uint32 fileSize = 0;
- byte *fileDataPtr = NULL;
- uint32 fileDataOffset = 0;
- uint32 fileDataLeft = 0;
-
- byte curBankId = 0;
- byte curPatchId = 0;
-
- InstrumentEntry *instrumentTablePtr = NULL;
- uint16 instrumentTableCount = 0;
- InstrumentEntry *instrumentPtr = NULL;
- uint32 instrumentOffset = 0;
- uint16 instrumentDataSize = 0;
-
- if (!fileStream->open(instrumentDataFilename))
- error("MILES-ADLIB: could not open instrument file");
-
- fileSize = fileStream->size();
-
- fileDataPtr = new byte[fileSize];
-
- if (fileStream->read(fileDataPtr, fileSize) != fileSize)
- error("MILES-ADLIB: error while reading instrument file");
- fileStream->close();
- delete fileStream;
-
- // File is like this:
- // [patch:BYTE] [bank:BYTE] [patchoffset:UINT32]
- // ...
- // until patch + bank are both 0xFF, which signals end of header
-
- // First we check how many entries there are
- fileDataOffset = 0;
- fileDataLeft = fileSize;
- while (1) {
- if (fileDataLeft < 6)
- error("MILES-ADLIB: unexpected EOF in instrument file");
-
- curPatchId = fileDataPtr[fileDataOffset++];
- curBankId = fileDataPtr[fileDataOffset++];
-
- if ((curBankId == 0xFF) && (curPatchId == 0xFF))
- break;
-
- fileDataOffset += 4; // skip over offset
- instrumentTableCount++;
- }
-
- if (instrumentTableCount == 0)
- error("MILES-ADLIB: no instruments in instrument file");
-
- // Allocate space for instruments
- instrumentTablePtr = new InstrumentEntry[instrumentTableCount];
-
- // Now actually read all entries
- instrumentPtr = instrumentTablePtr;
-
- fileDataOffset = 0;
- fileDataLeft = fileSize;
- while (1) {
- curPatchId = fileDataPtr[fileDataOffset++];
- curBankId = fileDataPtr[fileDataOffset++];
-
- if ((curBankId == 0xFF) && (curPatchId == 0xFF))
- break;
-
- instrumentOffset = READ_LE_UINT32(fileDataPtr + fileDataOffset);
- fileDataOffset += 4;
-
- instrumentPtr->bankId = curBankId;
- instrumentPtr->patchId = curPatchId;
-
- instrumentDataSize = READ_LE_UINT16(fileDataPtr + instrumentOffset);
- if (instrumentDataSize != 14)
- error("MILES-ADLIB: unsupported instrument size");
-
- instrumentPtr->transposition = (signed char)fileDataPtr[instrumentOffset + 2];
- instrumentPtr->reg20op1 = fileDataPtr[instrumentOffset + 3];
- instrumentPtr->reg40op1 = fileDataPtr[instrumentOffset + 4];
- instrumentPtr->reg60op1 = fileDataPtr[instrumentOffset + 5];
- instrumentPtr->reg80op1 = fileDataPtr[instrumentOffset + 6];
- instrumentPtr->regE0op1 = fileDataPtr[instrumentOffset + 7];
- instrumentPtr->regC0 = fileDataPtr[instrumentOffset + 8];
- instrumentPtr->reg20op2 = fileDataPtr[instrumentOffset + 9];
- instrumentPtr->reg40op2 = fileDataPtr[instrumentOffset + 10];
- instrumentPtr->reg60op2 = fileDataPtr[instrumentOffset + 11];
- instrumentPtr->reg80op2 = fileDataPtr[instrumentOffset + 12];
- instrumentPtr->regE0op2 = fileDataPtr[instrumentOffset + 13];
-
- // Instrument read, next instrument please
- instrumentPtr++;
- }
-
- // Free instrument file data
- delete[] fileDataPtr;
-
- return new MidiDriver_Miles_AdLib(g_system->getMixer(), instrumentTablePtr, instrumentTableCount);
-}
-
-} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/drivers/tattoo_mididriver.h b/engines/sherlock/tattoo/drivers/tattoo_mididriver.h
deleted file mode 100644
index d140135834..0000000000
--- a/engines/sherlock/tattoo/drivers/tattoo_mididriver.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* 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.
- *
- */
-
-#ifndef SHERLOCK_TATTOO_DRIVERS_MIDIDRIVER_H
-#define SHERLOCK_TATTOO_DRIVERS_MIDIDRIVER_H
-
-#include "sherlock/sherlock.h"
-#include "audio/mididrv.h"
-#include "common/error.h"
-
-namespace Sherlock {
-
-#define MILES_MIDI_CHANNEL_COUNT 16
-
-// Miles Audio supported controllers for control change messages
-#define MILES_CONTROLLER_SELECT_PATCH_BANK 114
-#define MILES_CONTROLLER_PROTECT_VOICE 112
-#define MILES_CONTROLLER_PROTECT_TIMBRE 113
-#define MILES_CONTROLLER_MODULATION 1
-#define MILES_CONTROLLER_VOLUME 7
-#define MILES_CONTROLLER_EXPRESSION 11
-#define MILES_CONTROLLER_PANNING 10
-#define MILES_CONTROLLER_SUSTAIN 64
-#define MILES_CONTROLLER_PITCH_RANGE 6
-#define MILES_CONTROLLER_RESET_ALL 121
-#define MILES_CONTROLLER_ALL_NOTES_OFF 123
-#define MILES_CONTROLLER_PATCH_REVERB 59
-#define MILES_CONTROLLER_PATCH_BENDER 60
-#define MILES_CONTROLLER_REVERB_MODE 61
-#define MILES_CONTROLLER_REVERB_TIME 62
-#define MILES_CONTROLLER_REVERB_LEVEL 63
-#define MILES_CONTROLLER_RHYTHM_KEY_TIMBRE 58
-
-// 3 SysEx controllers, each range 14
-#define MILES_CONTROLLER_SYSEX_RANGE_BEGIN 32
-#define MILES_CONTROLLER_SYSEX_RANGE_END 64
-
-#define MILES_CONTROLLER_XMIDI_RANGE_BEGIN 110
-#define MILES_CONTROLLER_XMIDI_RANGE_END 120
-
-// Miles Audio actually used 0x4000, because they didn't shift the 2 bytes properly
-#define MILES_PITCHBENDER_DEFAULT 0x2000
-
-extern MidiDriver *MidiDriver_Miles_AdLib_create(const Common::String instrumentDataFilename, const Common::String instrumentDataFilenameOPL3);
-
-extern MidiDriver *MidiDriver_Miles_MT32_create(const Common::String instrumentDataFilename);
-
-} // End of namespace Sherlock
-
-#endif // SHERLOCK_TATTOO_DRIVERS_MIDIDRIVER_H
diff --git a/engines/sherlock/tattoo/drivers/tattoo_mt32.cpp b/engines/sherlock/tattoo/drivers/tattoo_mt32.cpp
deleted file mode 100644
index 73bc1b9dda..0000000000
--- a/engines/sherlock/tattoo/drivers/tattoo_mt32.cpp
+++ /dev/null
@@ -1,437 +0,0 @@
-/* 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 "sherlock/sherlock.h"
-#include "sherlock/tattoo/drivers/tattoo_mididriver.h"
-
-#include "common/config-manager.h"
-#include "common/file.h"
-#include "common/system.h"
-#include "common/textconsole.h"
-
-namespace Sherlock {
-
-#define MILES_MT32_PATCH_COUNT 128
-
-const byte milesMT32SysExResetParameters[] = {
- 0x01, 0xFF
-};
-
-const byte milesMT32SysExChansSetup[] = {
- 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF
-};
-
-const byte milesMT32SysExPartialReserveTable[] = {
- 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x04, 0xFF
-};
-
-const byte milesMT32SysExInitReverb[] = {
- 0x00, 0x03, 0x02, 0xFF // Reverb mode 0, reverb time 3, reverb level 2
-};
-
-class MidiDriver_Miles_MT32 : public MidiDriver {
-public:
- MidiDriver_Miles_MT32();
- virtual ~MidiDriver_Miles_MT32();
-
- // MidiDriver
- int open();
- void close();
- bool isOpen() const { return _isOpen; }
-
- void send(uint32 b);
-
- MidiChannel *allocateChannel() {
- if (_driver)
- return _driver->allocateChannel();
- return NULL;
- }
- MidiChannel *getPercussionChannel() {
- if (_driver)
- return _driver->getPercussionChannel();
- return NULL;
- }
-
- void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) {
- if (_driver)
- _driver->setTimerCallback(timer_param, timer_proc);
- }
-
- uint32 getBaseTempo() {
- if (_driver) {
- return _driver->getBaseTempo();
- }
- return 1000000 / _baseFreq;
- }
-
-protected:
- Common::Mutex _mutex;
- MidiDriver *_driver;
- bool _MT32;
- bool _nativeMT32;
-
- bool _isOpen;
- int _baseFreq;
-
-public:
-
-private:
- void resetMT32();
-
- void MT32SysEx(const uint32 targetAddress, const byte *dataPtr);
-
- void writePatchTimbre(byte patchId, byte timbreGroup, byte timbreId);
- void writePatchByte(byte patchId, byte index, byte patchValue);
- void writeToSystemArea(byte index, byte value);
-
- void controlChange(byte midiChannel, byte controllerNumber, byte controllerValue);
- void programChange(byte midiChannel, byte patchId);
-
- void setupPatch(byte patchId, byte patchBank);
-
-private:
- struct MidiChannelEntry {
- byte currentPatchBank;
- byte currentPatchId;
- bool patchIdSet;
-
- MidiChannelEntry() : currentPatchBank(0),
- currentPatchId(0),
- patchIdSet(false) { }
- };
-
- // stores information about all MIDI channels
- MidiChannelEntry _midiChannels[MILES_MIDI_CHANNEL_COUNT];
-
- byte _patchesBank[MILES_MT32_PATCH_COUNT];
-};
-
-MidiDriver_Miles_MT32::MidiDriver_Miles_MT32() {
- _driver = NULL;
- _isOpen = false;
- _MT32 = false;
- _nativeMT32 = false;
- _baseFreq = 250;
-
- memset(_patchesBank, 0, sizeof(_patchesBank));
-}
-
-MidiDriver_Miles_MT32::~MidiDriver_Miles_MT32() {
- Common::StackLock lock(_mutex);
- if (_driver) {
- _driver->setTimerCallback(0, 0);
- _driver->close();
- delete _driver;
- }
- _driver = NULL;
-}
-
-int MidiDriver_Miles_MT32::open() {
- assert(!_driver);
-
- // Setup midi driver
- MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_PREFER_MT32);
- MusicType musicType = MidiDriver::getMusicType(dev);
-
- switch (musicType) {
- case MT_MT32:
- _nativeMT32 = true;
- break;
- case MT_GM:
- if (ConfMan.getBool("native_mt32")) {
- _nativeMT32 = true;
- }
- break;
- default:
- break;
- }
-
- if (!_nativeMT32) {
- error("MILES-MT32: non-mt32 currently not supported!");
- }
-
- _driver = MidiDriver::createMidi(dev);
- if (!_driver)
- return 255;
-
- if (_nativeMT32)
- _driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
-
- int ret = _driver->open();
- if (ret)
- return ret;
-
- if (_nativeMT32) {
- _driver->sendMT32Reset();
-
- resetMT32();
- }
-
- return 0;
-}
-
-void MidiDriver_Miles_MT32::close() {
- if (_driver) {
- _driver->close();
- }
-}
-
-void MidiDriver_Miles_MT32::resetMT32() {
- // reset all internal parameters / patches
- MT32SysEx(0x7F0000, milesMT32SysExResetParameters);
-
- // init part/channel assignments
- MT32SysEx(0x10000D, milesMT32SysExChansSetup);
-
- // partial reserve table
- MT32SysEx(0x100004, milesMT32SysExPartialReserveTable);
-
- // init reverb
- MT32SysEx(0x100001, milesMT32SysExInitReverb);
-}
-
-void MidiDriver_Miles_MT32::MT32SysEx(const uint32 targetAddress, const byte *dataPtr) {
- byte sysExMessage[270];
- uint16 sysExPos = 0;
- byte sysExByte = 0;
- uint16 sysExChecksum = 0;
-
- memset(&sysExMessage, 0, sizeof(sysExMessage));
-
- sysExMessage[0] = 0x41; // Roland
- sysExMessage[1] = 0x10;
- sysExMessage[2] = 0x16; // Model MT32
- sysExMessage[3] = 0x12; // Command DT1
-
- sysExChecksum = 0;
-
- sysExMessage[4] = (targetAddress >> 16) & 0xFF;
- sysExMessage[5] = (targetAddress >> 8) & 0xFF;
- sysExMessage[6] = targetAddress & 0xFF;
-
- sysExChecksum -= sysExMessage[4];
- sysExChecksum -= sysExMessage[5];
- sysExChecksum -= sysExMessage[6];
-
- sysExPos = 7;
- while (1) {
- sysExByte = *dataPtr++;
- if (sysExByte == 0xff)
- break; // Message done
-
- assert(sysExPos < sizeof(sysExMessage));
- sysExMessage[sysExPos++] = sysExByte;
- sysExChecksum -= sysExByte;
- }
-
- // Calculate checksum
- assert(sysExPos < sizeof(sysExMessage));
- sysExMessage[sysExPos++] = sysExChecksum & 0x7f;
-
- // Send SysEx
- _driver->sysEx(sysExMessage, sysExPos);
-
- // Wait the time it takes to send the SysEx data
- uint32 delay = (sysExPos + 2) * 1000 / 3125;
-
- // Plus an additional delay for the MT-32 rev00
- if (_nativeMT32)
- delay += 40;
-
- g_system->delayMillis(delay);
-}
-
-// MIDI messages can be found at http://www.midi.org/techspecs/midimessages.php
-void MidiDriver_Miles_MT32::send(uint32 b) {
- byte command = b & 0xf0;
- byte channel = b & 0xf;
- byte op1 = (b >> 8) & 0xff;
- byte op2 = (b >> 16) & 0xff;
-
- switch (command) {
- case 0x80: // note off
- case 0x90: // note on
- case 0xe0: // pitch bend change
- _driver->send(b);
- break;
- case 0xb0: // Control change
- controlChange(channel, op1, op2);
- break;
- case 0xc0: // Program Change
- programChange(channel, op1);
- break;
- case 0xa0: // Polyphonic key pressure (aftertouch)
- case 0xd0: // Channel pressure (aftertouch)
- // Aftertouch doesn't seem to be implemented in the Sherlock Holmes adlib driver
- break;
- case 0xf0: // SysEx
- warning("MILES-MT32: SysEx: %x", b);
- break;
- default:
- warning("MILES-MT32: Unknown event %02x", command);
- }
-}
-
-void MidiDriver_Miles_MT32::controlChange(byte midiChannel, byte controllerNumber, byte controllerValue) {
- byte channelPatchId = 0;
-
- switch (controllerNumber) {
- case MILES_CONTROLLER_SELECT_PATCH_BANK:
- _midiChannels[midiChannel].currentPatchBank = controllerValue;
- return;
-
- case MILES_CONTROLLER_PATCH_REVERB:
- channelPatchId = _midiChannels[midiChannel].currentPatchId;
-
- writePatchByte(channelPatchId, 6, controllerValue);
- _driver->send(0xC0 | midiChannel | (channelPatchId << 8)); // execute program change
- return;
-
- case MILES_CONTROLLER_PATCH_BENDER:
- channelPatchId = _midiChannels[midiChannel].currentPatchId;
-
- writePatchByte(channelPatchId, 4, controllerValue);
- _driver->send(0xC0 | midiChannel | (channelPatchId << 8)); // execute program change
- return;
-
- case MILES_CONTROLLER_REVERB_MODE:
- writeToSystemArea(1, controllerValue);
- return;
-
- case MILES_CONTROLLER_REVERB_TIME:
- writeToSystemArea(2, controllerValue);
- return;
-
- case MILES_CONTROLLER_REVERB_LEVEL:
- writeToSystemArea(3, controllerValue);
- return;
-
- case MILES_CONTROLLER_RHYTHM_KEY_TIMBRE:
- // uses .MT data, cannot implement atm
- return;
-
- case MILES_CONTROLLER_PROTECT_TIMBRE:
- // timbre .MT data, cannot implement atm
- return;
-
- default:
- break;
- }
-
- if ((controllerNumber >= MILES_CONTROLLER_SYSEX_RANGE_BEGIN) && (controllerNumber <= MILES_CONTROLLER_SYSEX_RANGE_END)) {
- // send SysEx
- warning("MILES-MT32: embedded SysEx controller %2x, value %2x", controllerNumber, controllerValue);
- return;
- }
-
- if ((controllerNumber >= MILES_CONTROLLER_XMIDI_RANGE_BEGIN) && (controllerNumber <= MILES_CONTROLLER_XMIDI_RANGE_END)) {
- // XMIDI controllers? ignore those
- return;
- }
-
- _driver->send(0xB0 | midiChannel | (controllerNumber << 8) | (controllerValue << 16));
-}
-
-void MidiDriver_Miles_MT32::programChange(byte midiChannel, byte patchId) {
- byte channelPatchBank = _midiChannels[midiChannel].currentPatchBank;
- byte activePatchBank = _patchesBank[patchId];
-
- // remember patch id for the current MIDI-channel
- _midiChannels[midiChannel].currentPatchId = patchId;
-
- if (channelPatchBank != activePatchBank) {
- // associate patch with timbre
- setupPatch(patchId, channelPatchBank);
- warning("setup patch");
- }
-
- // Search timbre and remember it (only used when timbre file is available)
- // TODO
-
- // Finally send to MT32
- _driver->send(0xC0 | midiChannel | (patchId << 8));
-}
-
-void MidiDriver_Miles_MT32::setupPatch(byte patchId, byte patchBank) {
- byte timbreId = 0;
-
- _patchesBank[patchId] = patchBank;
-
- if (patchBank) {
- // non-built-in bank
- // TODO: search timbre
- }
-
- // for built-in bank (or timbres, that are not available) use default MT32 timbres
- timbreId = patchId & 0x3F;
- if (!(patchId & 0x40)) {
- writePatchTimbre(patchId, 0, timbreId); // Group A
- } else {
- writePatchTimbre(patchId, 1, timbreId); // Group B
- }
-}
-
-void MidiDriver_Miles_MT32::writePatchTimbre(byte patchId, byte timbreGroup, byte timbreId) {
- byte sysExData[3];
- uint32 targetAddress = 0;
-
- targetAddress = ((patchId << 3) << 16) | 0x000500;
-
- sysExData[0] = timbreGroup;
- sysExData[1] = timbreId;
- sysExData[2] = 0xFF; // terminator
-
- MT32SysEx(targetAddress, sysExData);
-}
-
-void MidiDriver_Miles_MT32::writePatchByte(byte patchId, byte index, byte patchValue) {
- byte sysExData[2];
- uint32 targetAddress = 0;
-
- targetAddress = (((patchId << 3) + index ) << 16) | 0x000500;
-
- sysExData[0] = patchValue;
- sysExData[1] = 0xFF; // terminator
-
- MT32SysEx(targetAddress, sysExData);
-}
-
-void MidiDriver_Miles_MT32::writeToSystemArea(byte index, byte value) {
- byte sysExData[2];
- uint32 targetAddress = 0;
-
- targetAddress = 0x100000 | index;
-
- sysExData[0] = value;
- sysExData[1] = 0xFF; // terminator
-
- MT32SysEx(targetAddress, sysExData);
-}
-
-MidiDriver *MidiDriver_Miles_MT32_create(const Common::String instrumentDataFilename) {
- // For some games there are timbre files called [something].MT
- // Sherlock Holmes 2 doesn't have one of those
- // so I can't implement them
- return new MidiDriver_Miles_MT32();
-}
-
-} // End of namespace Sherlock