Skip to content

Commit

Permalink
SHERLOCK: Tattoo: Miles Audio 3 AdLib driver
Browse files Browse the repository at this point in the history
- implement Miles Audio 3 AdLib driver
- also cleanup of Scalpel AdLib driver
- work in progress, sustain and for example OPL-3 missing
  • Loading branch information
Martin Kiewitz committed Jun 26, 2015
1 parent 27673db commit 57aa098
Show file tree
Hide file tree
Showing 6 changed files with 1,179 additions and 62 deletions.
1 change: 1 addition & 0 deletions engines/sherlock/module.mk
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ MODULE_OBJS = \
scalpel/scalpel_talk.o \
scalpel/scalpel_user_interface.o \
scalpel/settings.o \
tattoo/drivers/tattoo_adlib.o \
tattoo/tattoo.o \
tattoo/tattoo_journal.o \
tattoo/tattoo_map.o \
Expand Down
47 changes: 31 additions & 16 deletions engines/sherlock/music.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "sherlock/sherlock.h"
#include "sherlock/music.h"
#include "sherlock/scalpel/drivers/mididriver.h"
#include "sherlock/tattoo/drivers/tattoo_mididriver.h"
// for 3DO digital music
#include "audio/decoders/aiff.h"

Expand Down Expand Up @@ -240,7 +241,7 @@ Music::Music(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {

switch (_musicType) {
case MT_ADLIB:
_midiDriver = MidiDriver_AdLib_create();
_midiDriver = MidiDriver_SH_AdLib_create();
break;
case MT_MT32:
_midiDriver = MidiDriver_MT32_create();
Expand All @@ -266,8 +267,21 @@ Music::Music(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {

_midiParser = MidiParser::createParser_XMIDI();
dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
_musicType = MT_GM;
_midiDriver = MidiDriver::createMidi(dev);
_musicType = MidiDriver::getMusicType(dev);

switch (_musicType) {
case MT_ADLIB:
// 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");
break;
default:
// HACK
_musicType = MT_GM;
_midiDriver = MidiDriver::createMidi(dev);
break;
}
}

if (_midiDriver) {
Expand Down Expand Up @@ -437,21 +451,22 @@ bool Music::playMusic(const Common::String &name) {
}
}

switch (_musicType) {
case MT_ADLIB:
MidiDriver_AdLib_newMusicData(_midiDriver, dataPos, dataSize);
break;

case MT_MT32:
MidiDriver_MT32_newMusicData(_midiDriver, dataPos, dataSize);
break;
if (IS_SERRATED_SCALPEL) {
// Pass the music data to the driver as well
// because channel mapping and a few other things inside the header
switch (_musicType) {
case MT_ADLIB:
MidiDriver_SH_AdLib_newMusicData(_midiDriver, dataPos, dataSize);
break;

case MT_GM:
break;
case MT_MT32:
MidiDriver_MT32_newMusicData(_midiDriver, dataPos, dataSize);
break;

default:
// should never happen
break;
default:
// should never happen
break;
}
}

_midiParser->loadMusic(midiMusicData, midiMusicDataSize);
Expand Down
82 changes: 41 additions & 41 deletions engines/sherlock/scalpel/drivers/adlib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,21 @@ namespace Sherlock {
#define SHERLOCK_ADLIB_VOICES_COUNT 9
#define SHERLOCK_ADLIB_NOTES_COUNT 96

byte adlib_Operator1Register[SHERLOCK_ADLIB_VOICES_COUNT] = {
byte operator1Register[SHERLOCK_ADLIB_VOICES_COUNT] = {
0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12
};

byte adlib_Operator2Register[SHERLOCK_ADLIB_VOICES_COUNT] = {
byte operator2Register[SHERLOCK_ADLIB_VOICES_COUNT] = {
0x03, 0x04, 0x05, 0x0B, 0x0C, 0x0D, 0x13, 0x14, 0x15
};

struct adlib_percussionChannelEntry {
struct percussionChannelEntry {
byte requiredNote;
byte replacementNote;
};

// hardcoded, dumped from ADHOM.DRV
const adlib_percussionChannelEntry adlib_percussionChannelTable[SHERLOCK_ADLIB_VOICES_COUNT] = {
const percussionChannelEntry percussionChannelTable[SHERLOCK_ADLIB_VOICES_COUNT] = {
{ 0x00, 0x00 },
{ 0x00, 0x00 },
{ 0x00, 0x00 },
Expand All @@ -61,7 +61,7 @@ const adlib_percussionChannelEntry adlib_percussionChannelTable[SHERLOCK_ADLIB_V
{ 0x26, 0x1E }
};

struct adlib_InstrumentEntry {
struct InstrumentEntry {
byte reg20op1;
byte reg40op1;
byte reg60op1;
Expand All @@ -77,7 +77,7 @@ struct adlib_InstrumentEntry {
};

// hardcoded, dumped from ADHOM.DRV
const adlib_InstrumentEntry adlib_instrumentTable[] = {
const InstrumentEntry instrumentTable[] = {
{ 0x71, 0x89, 0x51, 0x11, 0x00, 0x61, 0x23, 0x42, 0x15, 0x01, 0x02, 0xF4 },
{ 0x22, 0x20, 0x97, 0x89, 0x00, 0xA2, 0x1F, 0x70, 0x07, 0x00, 0x0A, 0xF4 },
{ 0x70, 0x1A, 0x64, 0x13, 0x00, 0x20, 0x1F, 0x53, 0x46, 0x00, 0x0E, 0xF4 },
Expand Down Expand Up @@ -203,7 +203,7 @@ const adlib_InstrumentEntry adlib_instrumentTable[] = {
};

// hardcoded, dumped from ADHOM.DRV
uint16 adlib_FrequencyLookUpTable[SHERLOCK_ADLIB_NOTES_COUNT] = {
uint16 frequencyLookUpTable[SHERLOCK_ADLIB_NOTES_COUNT] = {
0x0158, 0x016C, 0x0182, 0x0199, 0x01B1, 0x01CB, 0x01E6, 0x0203, 0x0222, 0x0242,
0x0265, 0x0289, 0x0558, 0x056C, 0x0582, 0x0599, 0x05B1, 0x05CB, 0x05E6, 0x0603,
0x0622, 0x0642, 0x0665, 0x0689, 0x0958, 0x096C, 0x0982, 0x0999, 0x09B1, 0x09CB,
Expand All @@ -216,13 +216,13 @@ uint16 adlib_FrequencyLookUpTable[SHERLOCK_ADLIB_NOTES_COUNT] = {
0x1DE6, 0x1E03, 0x1E22, 0x1E42, 0x1E65, 0x1E89
};

class MidiDriver_AdLib : public MidiDriver_Emulated {
class MidiDriver_SH_AdLib : public MidiDriver_Emulated {
public:
MidiDriver_AdLib(Audio::Mixer *mixer)
MidiDriver_SH_AdLib(Audio::Mixer *mixer)
: MidiDriver_Emulated(mixer), _masterVolume(15), _opl(0) {
memset(_voiceChannelMapping, 0, sizeof(_voiceChannelMapping));
}
virtual ~MidiDriver_AdLib() { }
virtual ~MidiDriver_SH_AdLib() { }

// MidiDriver
int open();
Expand All @@ -249,7 +249,7 @@ class MidiDriver_AdLib : public MidiDriver_Emulated {
struct adlib_ChannelEntry {
bool inUse;
uint16 inUseTimer;
const adlib_InstrumentEntry *currentInstrumentPtr;
const InstrumentEntry *currentInstrumentPtr;
byte currentNote;
byte currentA0hReg;
byte currentB0hReg;
Expand Down Expand Up @@ -284,7 +284,7 @@ class MidiDriver_AdLib : public MidiDriver_Emulated {
void pitchBendChange(byte MIDIchannel, byte parameter1, byte parameter2);
};

int MidiDriver_AdLib::open() {
int MidiDriver_SH_AdLib::open() {
int rate = _mixer->getOutputRate();

debugC(kDebugLevelAdLibDriver, "AdLib: starting driver");
Expand All @@ -303,21 +303,21 @@ int MidiDriver_AdLib::open() {
return 0;
}

void MidiDriver_AdLib::close() {
void MidiDriver_SH_AdLib::close() {
_mixer->stopHandle(_mixerSoundHandle);

delete _opl;
}

void MidiDriver_AdLib::setVolume(byte volume) {
void MidiDriver_SH_AdLib::setVolume(byte volume) {
_masterVolume = volume;
//renewNotes(-1, true);
}

// this should/must get called per tick
// original driver did this before MIDI data processing on each tick
// we do it atm after MIDI data processing
void MidiDriver_AdLib::onTimer() {
void MidiDriver_SH_AdLib::onTimer() {
for (byte FMvoiceChannel = 0; FMvoiceChannel < SHERLOCK_ADLIB_VOICES_COUNT; FMvoiceChannel++) {
if (_channels[FMvoiceChannel].inUse) {
_channels[FMvoiceChannel].inUseTimer++;
Expand All @@ -326,7 +326,7 @@ void MidiDriver_AdLib::onTimer() {
}

// Called when a music track got loaded into memory
void MidiDriver_AdLib::newMusicData(byte *musicData, int32 musicDataSize) {
void MidiDriver_SH_AdLib::newMusicData(byte *musicData, int32 musicDataSize) {
assert(musicDataSize >= 0x7F);
// MIDI Channel <-> FM Voice Channel mapping at offset 0x22 of music data
memcpy(&_voiceChannelMapping, musicData + 0x22, 9);
Expand All @@ -338,7 +338,7 @@ void MidiDriver_AdLib::newMusicData(byte *musicData, int32 musicDataSize) {
memset(&_channels, 0, sizeof(_channels));
}

void MidiDriver_AdLib::resetAdLib() {
void MidiDriver_SH_AdLib::resetAdLib() {

setRegister(0x01, 0x20); // enable waveform control on both operators
setRegister(0x04, 0xE0); // Timer control
Expand All @@ -357,7 +357,7 @@ void MidiDriver_AdLib::resetAdLib() {
resetAdLib_OperatorRegisters(0x40, 0x3F);
}

void MidiDriver_AdLib::resetAdLib_OperatorRegisters(byte baseRegister, byte value) {
void MidiDriver_SH_AdLib::resetAdLib_OperatorRegisters(byte baseRegister, byte value) {
byte operatorIndex;

for (operatorIndex = 0; operatorIndex < 0x16; operatorIndex++) {
Expand All @@ -373,7 +373,7 @@ void MidiDriver_AdLib::resetAdLib_OperatorRegisters(byte baseRegister, byte valu
}
}

void MidiDriver_AdLib::resetAdLib_FMVoiceChannelRegisters(byte baseRegister, byte value) {
void MidiDriver_SH_AdLib::resetAdLib_FMVoiceChannelRegisters(byte baseRegister, byte value) {
byte FMvoiceChannel;

for (FMvoiceChannel = 0; FMvoiceChannel < SHERLOCK_ADLIB_VOICES_COUNT; FMvoiceChannel++) {
Expand All @@ -382,7 +382,7 @@ void MidiDriver_AdLib::resetAdLib_FMVoiceChannelRegisters(byte baseRegister, byt
}

// MIDI messages can be found at http://www.midi.org/techspecs/midimessages.php
void MidiDriver_AdLib::send(uint32 b) {
void MidiDriver_SH_AdLib::send(uint32 b) {
byte command = b & 0xf0;
byte channel = b & 0xf;
byte op1 = (b >> 8) & 0xff;
Expand Down Expand Up @@ -417,11 +417,11 @@ void MidiDriver_AdLib::send(uint32 b) {
}
}

void MidiDriver_AdLib::generateSamples(int16 *data, int len) {
void MidiDriver_SH_AdLib::generateSamples(int16 *data, int len) {
_opl->readBuffer(data, len);
}

void MidiDriver_AdLib::noteOn(byte MIDIchannel, byte note, byte velocity) {
void MidiDriver_SH_AdLib::noteOn(byte MIDIchannel, byte note, byte velocity) {
int16 oldestInUseChannel = -1;
uint16 oldestInUseTimer = 0;

Expand Down Expand Up @@ -470,11 +470,11 @@ void MidiDriver_AdLib::noteOn(byte MIDIchannel, byte note, byte velocity) {
// Percussion channel
for (byte FMvoiceChannel = 0; FMvoiceChannel < SHERLOCK_ADLIB_VOICES_COUNT; FMvoiceChannel++) {
if (_voiceChannelMapping[FMvoiceChannel] == MIDIchannel) {
if (note == adlib_percussionChannelTable[FMvoiceChannel].requiredNote) {
if (note == percussionChannelTable[FMvoiceChannel].requiredNote) {
_channels[FMvoiceChannel].inUse = true;
_channels[FMvoiceChannel].currentNote = note;

voiceOnOff(FMvoiceChannel, true, adlib_percussionChannelTable[FMvoiceChannel].replacementNote, velocity);
voiceOnOff(FMvoiceChannel, true, percussionChannelTable[FMvoiceChannel].replacementNote, velocity);
return;
}
}
Expand All @@ -483,7 +483,7 @@ void MidiDriver_AdLib::noteOn(byte MIDIchannel, byte note, byte velocity) {
}
}

void MidiDriver_AdLib::noteOff(byte MIDIchannel, byte note) {
void MidiDriver_SH_AdLib::noteOff(byte MIDIchannel, byte note) {
for (byte FMvoiceChannel = 0; FMvoiceChannel < SHERLOCK_ADLIB_VOICES_COUNT; FMvoiceChannel++) {
if (_voiceChannelMapping[FMvoiceChannel] == MIDIchannel) {
if (_channels[FMvoiceChannel].currentNote == note) {
Expand All @@ -495,15 +495,15 @@ void MidiDriver_AdLib::noteOff(byte MIDIchannel, byte note) {
// not-percussion
voiceOnOff(FMvoiceChannel, false, note, 0);
} else {
voiceOnOff(FMvoiceChannel, false, adlib_percussionChannelTable[FMvoiceChannel].replacementNote, 0);
voiceOnOff(FMvoiceChannel, false, percussionChannelTable[FMvoiceChannel].replacementNote, 0);
}
return;
}
}
}
}

void MidiDriver_AdLib::voiceOnOff(byte FMvoiceChannel, bool keyOn, byte note, byte velocity) {
void MidiDriver_SH_AdLib::voiceOnOff(byte FMvoiceChannel, bool keyOn, byte note, byte velocity) {
byte frequencyOffset = 0;
uint16 frequency = 0;
byte op2RegAdjust = 0;
Expand All @@ -521,15 +521,15 @@ void MidiDriver_AdLib::voiceOnOff(byte FMvoiceChannel, bool keyOn, byte note, by
warning("CRITICAL - AdLib driver: bad note!!!");
return;
}
frequency = adlib_FrequencyLookUpTable[frequencyOffset];
frequency = frequencyLookUpTable[frequencyOffset];

if (keyOn) {
// adjust register 40h
if (_channels[FMvoiceChannel].currentInstrumentPtr) {
regValue40h = _channels[FMvoiceChannel].currentInstrumentPtr->reg40op2;
}
regValue40h = regValue40h - (velocity >> 3);
op2RegAdjust = adlib_Operator2Register[FMvoiceChannel];
op2RegAdjust = operator2Register[FMvoiceChannel];
setRegister(0x40 + op2RegAdjust, regValue40h);
}

Expand All @@ -545,7 +545,7 @@ void MidiDriver_AdLib::voiceOnOff(byte FMvoiceChannel, bool keyOn, byte note, by
_channels[FMvoiceChannel].currentB0hReg = regValueB0h;
}

void MidiDriver_AdLib::pitchBendChange(byte MIDIchannel, byte parameter1, byte parameter2) {
void MidiDriver_SH_AdLib::pitchBendChange(byte MIDIchannel, byte parameter1, byte parameter2) {
uint16 channelFrequency = 0;
byte channelRegB0hWithoutFrequency = 0;
uint16 parameter = 0;
Expand Down Expand Up @@ -584,20 +584,20 @@ void MidiDriver_AdLib::pitchBendChange(byte MIDIchannel, byte parameter1, byte p
}
}

void MidiDriver_AdLib::programChange(byte MIDIchannel, byte op1) {
const adlib_InstrumentEntry *instrumentPtr;
void MidiDriver_SH_AdLib::programChange(byte MIDIchannel, byte op1) {
const InstrumentEntry *instrumentPtr;
byte op1Reg = 0;
byte op2Reg = 0;

// setup instrument
instrumentPtr = &adlib_instrumentTable[op1];
instrumentPtr = &instrumentTable[op1];
//warning("program change for MIDI channel %d, instrument id %d", MIDIchannel, op1);

for (byte FMvoiceChannel = 0; FMvoiceChannel < SHERLOCK_ADLIB_VOICES_COUNT; FMvoiceChannel++) {
if (_voiceChannelMapping[FMvoiceChannel] == MIDIchannel) {

op1Reg = adlib_Operator1Register[FMvoiceChannel];
op2Reg = adlib_Operator2Register[FMvoiceChannel];
op1Reg = operator1Register[FMvoiceChannel];
op2Reg = operator2Register[FMvoiceChannel];

setRegister(0x20 + op1Reg, instrumentPtr->reg20op1);
setRegister(0x40 + op1Reg, instrumentPtr->reg40op1);
Expand All @@ -618,21 +618,21 @@ void MidiDriver_AdLib::programChange(byte MIDIchannel, byte op1) {
}
}
}
void MidiDriver_AdLib::setRegister(int reg, int value) {
void MidiDriver_SH_AdLib::setRegister(int reg, int value) {
_opl->write(0x220, reg);
_opl->write(0x221, value);
}

uint32 MidiDriver_AdLib::property(int prop, uint32 param) {
uint32 MidiDriver_SH_AdLib::property(int prop, uint32 param) {
return 0;
}

MidiDriver *MidiDriver_AdLib_create() {
return new MidiDriver_AdLib(g_system->getMixer());
MidiDriver *MidiDriver_SH_AdLib_create() {
return new MidiDriver_SH_AdLib(g_system->getMixer());
}

void MidiDriver_AdLib_newMusicData(MidiDriver *driver, byte *musicData, int32 musicDataSize) {
static_cast<MidiDriver_AdLib *>(driver)->newMusicData(musicData, musicDataSize);
void MidiDriver_SH_AdLib_newMusicData(MidiDriver *driver, byte *musicData, int32 musicDataSize) {
static_cast<MidiDriver_SH_AdLib *>(driver)->newMusicData(musicData, musicDataSize);
}

} // End of namespace Sherlock

0 comments on commit 57aa098

Please sign in to comment.