aboutsummaryrefslogtreecommitdiff
path: root/engines/sherlock/scalpel/drivers/adlib.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sherlock/scalpel/drivers/adlib.cpp')
-rw-r--r--engines/sherlock/scalpel/drivers/adlib.cpp63
1 files changed, 50 insertions, 13 deletions
diff --git a/engines/sherlock/scalpel/drivers/adlib.cpp b/engines/sherlock/scalpel/drivers/adlib.cpp
index ca11012b1a..c1dbddbc04 100644
--- a/engines/sherlock/scalpel/drivers/adlib.cpp
+++ b/engines/sherlock/scalpel/drivers/adlib.cpp
@@ -221,7 +221,7 @@ uint16 adlib_FrequencyLookUpTable[SHERLOCK_ADLIB_NOTES_COUNT] = {
class MidiDriver_AdLib : public MidiDriver_Emulated {
public:
MidiDriver_AdLib(Audio::Mixer *mixer)
- : MidiDriver_Emulated(mixer), _masterVolume(15), _rhythmKeyMap(0), _opl(0) {
+ : MidiDriver_Emulated(mixer), _masterVolume(15), _opl(0) {
memset(_voiceChannelMapping, 0, sizeof(_voiceChannelMapping));
}
virtual ~MidiDriver_AdLib() { }
@@ -245,25 +245,23 @@ public:
void setVolume(byte volume);
virtual uint32 property(int prop, uint32 param);
- bool useRhythmChannel() const { return _rhythmKeyMap != NULL; }
-
void newMusicData(byte *musicData, int32 musicDataSize);
private:
struct adlib_ChannelEntry {
- bool inUse;
- const adlib_InstrumentEntry *currentInstrumentPtr;
- byte currentNote;
- byte currentA0hReg;
- byte currentB0hReg;
-
- adlib_ChannelEntry() : inUse(false), currentInstrumentPtr(NULL), currentNote(0),
+ bool inUse;
+ uint16 inUseTimer;
+ const adlib_InstrumentEntry *currentInstrumentPtr;
+ byte currentNote;
+ byte currentA0hReg;
+ byte currentB0hReg;
+
+ adlib_ChannelEntry() : inUse(false), inUseTimer(0), currentInstrumentPtr(NULL), currentNote(0),
currentA0hReg(0), currentB0hReg(0) { }
};
OPL::OPL *_opl;
int _masterVolume;
- byte *_rhythmKeyMap;
// points to a MIDI channel for each of the new voice channels
byte _voiceChannelMapping[SHERLOCK_ADLIB_VOICES_COUNT];
@@ -271,6 +269,8 @@ private:
// stores information about all FM voice channels
adlib_ChannelEntry _channels[SHERLOCK_ADLIB_VOICES_COUNT];
+ void updateChannelInUseTimers();
+
void resetAdLib();
void resetAdLib_OperatorRegisters(byte baseRegister, byte value);
void resetAdLib_FMVoiceChannelRegisters(byte baseRegister, byte value);
@@ -330,7 +330,6 @@ void MidiDriver_AdLib::close() {
_mixer->stopHandle(_mixerSoundHandle);
delete _opl;
- delete[] _rhythmKeyMap;
}
void MidiDriver_AdLib::setVolume(byte volume) {
@@ -338,6 +337,17 @@ void MidiDriver_AdLib::setVolume(byte volume) {
//renewNotes(-1, true);
}
+// this should normally get called per tick
+// but calling it per send() shouldn't be a problem
+// TODO: maybe change inUseTimer to a 32-bit integer to make sure there are no overruns?!?!
+void MidiDriver_AdLib::updateChannelInUseTimers() {
+ for (byte FMvoiceChannel = 0; FMvoiceChannel < SHERLOCK_ADLIB_VOICES_COUNT; FMvoiceChannel++) {
+ if (_channels[FMvoiceChannel].inUse) {
+ _channels[FMvoiceChannel].inUseTimer++;
+ }
+ }
+}
+
// Called when a music track got loaded into memory
void MidiDriver_AdLib::newMusicData(byte *musicData, int32 musicDataSize) {
assert(musicDataSize >= 0x7F);
@@ -401,6 +411,8 @@ void MidiDriver_AdLib::send(uint32 b) {
byte op1 = (b >> 8) & 0xff;
byte op2 = (b >> 16) & 0xff;
+ updateChannelInUseTimers();
+
switch (command) {
case 0x80:
noteOff(channel, op1);
@@ -435,6 +447,9 @@ void MidiDriver_AdLib::generateSamples(int16 *data, int len) {
}
void MidiDriver_AdLib::noteOn(byte MIDIchannel, byte note, byte velocity) {
+ int16 oldestInUseChannel = -1;
+ uint16 oldestInUseTimer = 0;
+
if (velocity == 0)
return noteOff(MIDIchannel, note);
@@ -451,7 +466,29 @@ void MidiDriver_AdLib::noteOn(byte MIDIchannel, byte note, byte velocity) {
}
}
}
+
+ // Look for oldest in-use channel
+ for (byte FMvoiceChannel = 0; FMvoiceChannel < SHERLOCK_ADLIB_VOICES_COUNT; FMvoiceChannel++) {
+ if (_voiceChannelMapping[FMvoiceChannel] == MIDIchannel) {
+ if (_channels[FMvoiceChannel].inUseTimer > oldestInUseTimer) {
+ oldestInUseTimer = _channels[FMvoiceChannel].inUseTimer;
+ oldestInUseChannel = FMvoiceChannel;
+ }
+ }
+ }
+ if (oldestInUseChannel >= 0) {
+ // channel found
+ warning("used In-Use channel");
+ voiceOnOff(oldestInUseChannel, false, 0, 0);
+
+ _channels[oldestInUseChannel].inUse = true;
+ _channels[oldestInUseChannel].inUseTimer = 0; // safety, original driver also did this
+ _channels[oldestInUseChannel].currentNote = note;
+ voiceOnOff(oldestInUseChannel, true, note, velocity);
+ return;
+ }
warning("MIDI channel not mapped/all FM voice channels busy %d", MIDIchannel);
+
} else {
// Percussion channel
warning("percussion!");
@@ -466,7 +503,6 @@ void MidiDriver_AdLib::noteOn(byte MIDIchannel, byte note, byte velocity) {
}
}
}
- // TODO: driver does some extra things in case no channel is found
warning("percussion MIDI channel not mapped/all FM voice channels busy");
}
}
@@ -476,6 +512,7 @@ void MidiDriver_AdLib::noteOff(byte MIDIchannel, byte note) {
if (_voiceChannelMapping[FMvoiceChannel] == MIDIchannel) {
if (_channels[FMvoiceChannel].currentNote == note) {
_channels[FMvoiceChannel].inUse = false;
+ _channels[FMvoiceChannel].inUseTimer = 0;
_channels[FMvoiceChannel].currentNote = 0;
if (MIDIchannel != 9) {