aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm/player_ad.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/scumm/player_ad.cpp')
-rw-r--r--engines/scumm/player_ad.cpp959
1 files changed, 0 insertions, 959 deletions
diff --git a/engines/scumm/player_ad.cpp b/engines/scumm/player_ad.cpp
deleted file mode 100644
index ed368afbf6..0000000000
--- a/engines/scumm/player_ad.cpp
+++ /dev/null
@@ -1,959 +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 "scumm/player_ad.h"
-#include "scumm/imuse/imuse.h"
-#include "scumm/scumm.h"
-#include "scumm/resource.h"
-
-#include "audio/fmopl.h"
-
-#include "common/textconsole.h"
-#include "common/config-manager.h"
-
-namespace Scumm {
-
-#define AD_CALLBACK_FREQUENCY 472
-
-Player_AD::Player_AD(ScummEngine *scumm, Audio::Mixer *mixer)
- : _vm(scumm), _mixer(mixer), _rate(mixer->getOutputRate()) {
- _opl2 = OPL::Config::create();
- if (!_opl2->init(_rate)) {
- error("Could not initialize OPL2 emulator");
- }
-
- _samplesPerCallback = _rate / AD_CALLBACK_FREQUENCY;
- _samplesPerCallbackRemainder = _rate % AD_CALLBACK_FREQUENCY;
- _samplesTillCallback = 0;
- _samplesTillCallbackRemainder = 0;
-
- memset(_registerBackUpTable, 0, sizeof(_registerBackUpTable));
- writeReg(0x01, 0x00);
- writeReg(0xBD, 0x00);
- writeReg(0x08, 0x00);
- writeReg(0x01, 0x20);
-
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-
- _engineMusicTimer = 0;
- _soundPlaying = -1;
-
- _curOffset = 0;
-
- _sfxTimer = 4;
- _rndSeed = 1;
-
- memset(_channels, 0, sizeof(_channels));
- memset(_sfxResource, 0, sizeof(_sfxResource));
- memset(_sfxPriority, 0, sizeof(_sfxPriority));
-}
-
-Player_AD::~Player_AD() {
- _mixer->stopHandle(_soundHandle);
-
- stopAllSounds();
- Common::StackLock lock(_mutex);
- delete _opl2;
- _opl2 = 0;
-}
-
-void Player_AD::setMusicVolume(int vol) {
- // HACK: We ignore the parameter and set up the volume specified in the
- // config manager. This allows us to differentiate between music and sfx
- // volume changes.
- setupVolume();
-}
-
-void Player_AD::startSound(int sound) {
- Common::StackLock lock(_mutex);
-
- // Query the sound resource
- const byte *res = _vm->getResourceAddress(rtSound, sound);
-
- if (res[2] == 0x80) {
- // Stop the current sounds
- stopAllSounds();
-
- // Lock the new music resource
- _soundPlaying = sound;
- _vm->_res->lock(rtSound, _soundPlaying);
-
- // Start the new music resource
- _resource = res;
- startMusic();
- } else {
- // Only try to start a sfx when no music is playing.
- if (_soundPlaying == -1) {
- const byte priority = res[0];
- const byte channel = res[1];
-
- // Check for out of bounds access
- if (channel >= 3) {
- warning("AdLib sfx resource %d uses channel %d", sound, channel);
- return;
- }
-
- // Check whether the channel is free or the priority of the new
- // sfx resource is above the old one.
- if (_channels[channel * 3 + 0].state
- || _channels[channel * 3 + 1].state
- || _channels[channel * 3 + 2].state) {
- if (_sfxPriority[channel] > priority) {
- return;
- }
- }
-
- // Lock the new resource
- _sfxResource[channel] = sound;
- _sfxPriority[channel] = priority;
- _vm->_res->lock(rtSound, sound);
-
- // Start the actual sfx resource
- _resource = res;
- startSfx();
- }
- }
-
- // Setup the sound volume
- setupVolume();
-}
-
-void Player_AD::stopSound(int sound) {
- Common::StackLock lock(_mutex);
-
- if (sound == _soundPlaying) {
- stopAllSounds();
- } else {
- for (int i = 0; i < 3; ++i) {
- if (_sfxResource[i] == sound) {
- if (_channels[i * 3 + 0].state
- || _channels[i * 3 + 1].state
- || _channels[i * 3 + 2].state) {
- // Unlock the sound resource
- _vm->_res->unlock(rtSound, sound);
-
- // Stop the actual sfx playback
- _channels[i * 3 + 0].state = 0;
- _channels[i * 3 + 1].state = 0;
- _channels[i * 3 + 2].state = 0;
- clearChannel(i * 3 + 0);
- clearChannel(i * 3 + 1);
- clearChannel(i * 3 + 2);
- }
- }
- }
- }
-}
-
-void Player_AD::stopAllSounds() {
- Common::StackLock lock(_mutex);
-
- // Unlock the music resource if present
- if (_soundPlaying != -1) {
- _vm->_res->unlock(rtSound, _soundPlaying);
- _soundPlaying = -1;
- }
-
- // Stop the music playback
- _curOffset = 0;
-
- // Unloack all used sfx resources
- for (int i = 0; i < 3; ++i) {
- if (_channels[i * 3 + 0].state || _channels[i * 3 + 1].state || _channels[i * 3 + 2].state) {
- _vm->_res->unlock(rtSound, _sfxResource[i]);
- }
- }
-
- // Reset all the sfx channels
- for (int i = 0; i < 9; ++i) {
- _channels[i].state = 0;
- clearChannel(i);
- }
-
- writeReg(0xBD, 0x00);
-}
-
-int Player_AD::getMusicTimer() {
- return _engineMusicTimer;
-}
-
-int Player_AD::getSoundStatus(int sound) const {
- return (sound == _soundPlaying);
-}
-
-void Player_AD::saveLoadWithSerializer(Serializer *ser) {
- Common::StackLock lock(_mutex);
-
- if (ser->getVersion() < VER(95)) {
- IMuse *dummyImuse = IMuse::create(_vm->_system, NULL, NULL);
- dummyImuse->save_or_load(ser, _vm, false);
- delete dummyImuse;
- return;
- }
-
- // TODO: Be nicer than the original and save the data to continue the
- // currently played sound resources on load?
-}
-
-int Player_AD::readBuffer(int16 *buffer, const int numSamples) {
- Common::StackLock lock(_mutex);
-
- int len = numSamples;
-
- while (len > 0) {
- if (!_samplesTillCallback) {
- // Run the update callback for music or sfx depending on which is
- // active.
- if (_curOffset) {
- updateMusic();
- } else {
- updateSfx();
- }
-
- _samplesTillCallback = _samplesPerCallback;
- _samplesTillCallbackRemainder += _samplesPerCallbackRemainder;
- if (_samplesTillCallbackRemainder >= AD_CALLBACK_FREQUENCY) {
- ++_samplesTillCallback;
- _samplesTillCallbackRemainder -= AD_CALLBACK_FREQUENCY;
- }
- }
-
- const int samplesToRead = MIN(len, _samplesTillCallback);
- _opl2->readBuffer(buffer, samplesToRead);
-
- buffer += samplesToRead;
- len -= samplesToRead;
- _samplesTillCallback -= samplesToRead;
- }
-
- return numSamples;
-}
-
-void Player_AD::setupVolume() {
- // Setup the correct volume
- int soundVolumeMusic = CLIP<int>(ConfMan.getInt("music_volume"), 0, Audio::Mixer::kMaxChannelVolume);
- int soundVolumeSfx = CLIP<int>(ConfMan.getInt("sfx_volume"), 0, Audio::Mixer::kMaxChannelVolume);
- if (ConfMan.hasKey("mute")) {
- if (ConfMan.getBool("mute")) {
- soundVolumeMusic = 0;
- soundVolumeSfx = 0;
- }
- }
-
- // In case a music is being played set the music volume. Set the sfx
- // volume otherwise. This is safe because in the latter case either
- // sfx are playing or there is no sound being played at all.
- if (_soundPlaying != -1) {
- _mixer->setChannelVolume(_soundHandle, soundVolumeMusic);
- } else {
- _mixer->setChannelVolume(_soundHandle, soundVolumeSfx);
- }
-}
-
-void Player_AD::writeReg(int r, int v) {
- if (r >= 0 && r < ARRAYSIZE(_registerBackUpTable)) {
- _registerBackUpTable[r] = v;
- }
- _opl2->writeReg(r, v);
-}
-
-uint8 Player_AD::readReg(int r) const {
- if (r >= 0 && r < ARRAYSIZE(_registerBackUpTable)) {
- return _registerBackUpTable[r];
- } else {
- return 0;
- }
-}
-
-void Player_AD::setupChannel(const uint channel, const byte *instrOffset) {
- instrOffset += 2;
- writeReg(0xC0 + channel, *instrOffset++);
- setupOperator(_operatorOffsetTable[channel * 2 + 0], instrOffset);
- setupOperator(_operatorOffsetTable[channel * 2 + 1], instrOffset);
-}
-
-void Player_AD::setupOperator(const uint opr, const byte *&instrOffset) {
- writeReg(0x20 + opr, *instrOffset++);
- writeReg(0x40 + opr, *instrOffset++);
- writeReg(0x60 + opr, *instrOffset++);
- writeReg(0x80 + opr, *instrOffset++);
- writeReg(0xE0 + opr, *instrOffset++);
-}
-
-const int Player_AD::_operatorOffsetTable[18] = {
- 0, 3, 1, 4,
- 2, 5, 8, 11,
- 9, 12, 10, 13,
- 16, 19, 17, 20,
- 18, 21
-};
-
-// Music
-
-void Player_AD::startMusic() {
- memset(_instrumentOffset, 0, sizeof(_instrumentOffset));
- memset(_channelLastEvent, 0, sizeof(_channelLastEvent));
- memset(_channelFrequency, 0, sizeof(_channelFrequency));
- memset(_channelB0Reg, 0, sizeof(_channelB0Reg));
-
- _voiceChannels = 0;
- uint instruments = _resource[10];
- for (uint i = 0; i < instruments; ++i) {
- const int instrIndex = _resource[11 + i] - 1;
- if (0 <= instrIndex && instrIndex < 16) {
- _instrumentOffset[instrIndex] = i * 16 + 16 + 3;
- _voiceChannels |= _resource[_instrumentOffset[instrIndex] + 13];
- }
- }
-
- if (_voiceChannels) {
- _mdvdrState = 0x20;
- _voiceChannels = 6;
- } else {
- _mdvdrState = 0;
- _voiceChannels = 9;
- }
-
- _curOffset = 0x93;
- // TODO: is this the same for Loom?
- _nextEventTimer = 40;
- _engineMusicTimer = 0;
- _internalMusicTimer = 0;
- _musicTimer = 0;
-
- writeReg(0xBD, _mdvdrState);
-
- const bool isLoom = (_vm->_game.id == GID_LOOM);
- _timerLimit = isLoom ? 473 : 256;
- _musicTicks = _resource[3] * (isLoom ? 2 : 1);
- _loopFlag = (_resource[4] == 0);
- _musicLoopStart = READ_LE_UINT16(_resource + 5);
-}
-
-void Player_AD::updateMusic() {
- _musicTimer += _musicTicks;
- if (_musicTimer < _timerLimit) {
- return;
- }
- _musicTimer -= _timerLimit;
-
- ++_internalMusicTimer;
- if (_internalMusicTimer > 120) {
- _internalMusicTimer = 0;
- ++_engineMusicTimer;
- }
-
- --_nextEventTimer;
- if (_nextEventTimer) {
- return;
- }
-
- while (true) {
- uint command = _resource[_curOffset++];
- if (command == 0xFF) {
- // META EVENT
- // Get the command number.
- command = _resource[_curOffset++];
- if (command == 47) {
- // End of track
- if (_loopFlag) {
- // In case the track is looping jump to the start.
- _curOffset = _musicLoopStart;
- _nextEventTimer = 0;
- } else {
- // Otherwise completely stop playback.
- stopAllSounds();
- }
- return;
- } else if (command == 88) {
- // This is proposedly a debug information insertion. The CMS
- // player code handles this differently, but is still using
- // the same resources...
- _curOffset += 5;
- } else if (command == 81) {
- // Change tempo. This is used exclusively in Loom.
- const uint timing = _resource[_curOffset + 2] | (_resource[_curOffset + 1] << 8);
- _musicTicks = 0x73000 / timing;
- command = _resource[_curOffset++];
- _curOffset += command;
- } else {
- // In case an unknown meta event occurs just skip over the
- // data by using the length supplied.
- command = _resource[_curOffset++];
- _curOffset += command;
- }
- } else {
- if (command >= 0x90) {
- // NOTE ON
- // Extract the channel number and save it in command.
- command -= 0x90;
-
- const uint instrOffset = _instrumentOffset[command];
- if (instrOffset) {
- if (_resource[instrOffset + 13] != 0) {
- setupRhythm(_resource[instrOffset + 13], instrOffset);
- } else {
- int channel = findFreeChannel();
- if (channel != -1) {
- noteOff(channel);
- setupChannel(channel, instrOffset);
- _channelLastEvent[channel] = command + 0x90;
- _channelFrequency[channel] = _resource[_curOffset];
- setupFrequency(channel, _resource[_curOffset]);
- }
- }
- }
- } else {
- // NOTE OFF
- const uint note = _resource[_curOffset];
- command += 0x10;
-
- // Find the output channel which plays the note.
- uint channel = 0xFF;
- for (uint i = 0; i < _voiceChannels; ++i) {
- if (_channelFrequency[i] == note && _channelLastEvent[i] == command) {
- channel = i;
- break;
- }
- }
-
- if (channel != 0xFF) {
- // In case a output channel playing the note was found,
- // stop it.
- noteOff(channel);
- } else {
- // In case there is no such note this will disable the
- // rhythm instrument played on the channel.
- command -= 0x90;
- const uint instrOffset = _instrumentOffset[command];
- if (instrOffset && _resource[instrOffset + 13] != 0) {
- const uint rhythmInstr = _resource[instrOffset + 13];
- if (rhythmInstr < 6) {
- _mdvdrState &= _mdvdrTable[rhythmInstr] ^ 0xFF;
- writeReg(0xBD, _mdvdrState);
- }
- }
- }
- }
-
- _curOffset += 2;
- }
-
- // In case there is a delay till the next event stop handling.
- if (_resource[_curOffset] != 0) {
- break;
- }
- ++_curOffset;
- }
-
- _nextEventTimer = _resource[_curOffset++];
- if (_nextEventTimer & 0x80) {
- _nextEventTimer -= 0x80;
- _nextEventTimer <<= 7;
- _nextEventTimer |= _resource[_curOffset++];
- }
-
- _nextEventTimer >>= (_vm->_game.id == GID_LOOM) ? 2 : 1;
- if (!_nextEventTimer) {
- _nextEventTimer = 1;
- }
-}
-
-void Player_AD::noteOff(uint channel) {
- _channelLastEvent[channel] = 0;
- writeReg(0xB0 + channel, _channelB0Reg[channel] & 0xDF);
-}
-
-int Player_AD::findFreeChannel() {
- for (uint i = 0; i < _voiceChannels; ++i) {
- if (!_channelLastEvent[i]) {
- return i;
- }
- }
-
- return -1;
-}
-
-void Player_AD::setupFrequency(uint channel, int8 frequency) {
- frequency -= 31;
- if (frequency < 0) {
- frequency = 0;
- }
-
- uint octave = 0;
- while (frequency >= 12) {
- frequency -= 12;
- ++octave;
- }
-
- const uint noteFrequency = _noteFrequencies[frequency];
- octave <<= 2;
- octave |= noteFrequency >> 8;
- octave |= 0x20;
- writeReg(0xA0 + channel, noteFrequency & 0xFF);
- _channelB0Reg[channel] = octave;
- writeReg(0xB0 + channel, octave);
-}
-
-void Player_AD::setupRhythm(uint rhythmInstr, uint instrOffset) {
- if (rhythmInstr == 1) {
- setupChannel(6, instrOffset);
- writeReg(0xA6, _resource[instrOffset++]);
- writeReg(0xB6, _resource[instrOffset] & 0xDF);
- _mdvdrState |= 0x10;
- writeReg(0xBD, _mdvdrState);
- } else if (rhythmInstr < 6) {
- const byte *secondOperatorOffset = _resource + instrOffset + 8;
- setupOperator(_rhythmOperatorTable[rhythmInstr], secondOperatorOffset);
- writeReg(0xA0 + _rhythmChannelTable[rhythmInstr], _resource[instrOffset++]);
- writeReg(0xB0 + _rhythmChannelTable[rhythmInstr], _resource[instrOffset++] & 0xDF);
- writeReg(0xC0 + _rhythmChannelTable[rhythmInstr], _resource[instrOffset]);
- _mdvdrState |= _mdvdrTable[rhythmInstr];
- writeReg(0xBD, _mdvdrState);
- }
-}
-
-const uint Player_AD::_noteFrequencies[12] = {
- 0x200, 0x21E, 0x23F, 0x261,
- 0x285, 0x2AB, 0x2D4, 0x300,
- 0x32E, 0x35E, 0x390, 0x3C7
-};
-
-const uint Player_AD::_mdvdrTable[6] = {
- 0x00, 0x10, 0x08, 0x04, 0x02, 0x01
-};
-
-const uint Player_AD::_rhythmOperatorTable[6] = {
- 0x00, 0x00, 0x14, 0x12, 0x15, 0x11
-};
-
-const uint Player_AD::_rhythmChannelTable[6] = {
- 0x00, 0x00, 0x07, 0x08, 0x08, 0x07
-};
-
-// SFX
-
-void Player_AD::startSfx() {
- writeReg(0xBD, 0x00);
-
- // The second byte of the resource defines the logical channel where
- // the sound effect should be played.
- const int startChannel = _resource[1] * 3;
-
- // Clear the channel.
- _channels[startChannel + 0].state = 0;
- _channels[startChannel + 1].state = 0;
- _channels[startChannel + 2].state = 0;
-
- clearChannel(startChannel + 0);
- clearChannel(startChannel + 1);
- clearChannel(startChannel + 2);
-
- // Set up the first channel to pick up playback.
- _channels[startChannel].currentOffset = _channels[startChannel].startOffset = _resource + 2;
- _channels[startChannel].state = 1;
-
- // Scan for the start of the other channels and set them up if required.
- int curChannel = startChannel + 1;
- const byte *bufferPosition = _resource + 2;
- uint8 command = 0;
- while ((command = *bufferPosition) != 0xFF) {
- switch (command) {
- case 1:
- // INSTRUMENT DEFINITION
- bufferPosition += 15;
- break;
-
- case 2:
- // NOTE DEFINITION
- bufferPosition += 11;
- break;
-
- case 0x80:
- // LOOP
- bufferPosition += 1;
- break;
-
- default:
- // START OF CHANNEL
- bufferPosition += 1;
- _channels[curChannel].currentOffset = bufferPosition;
- _channels[curChannel].startOffset = bufferPosition;
- _channels[curChannel].state = 1;
- ++curChannel;
- break;
- }
- }
-}
-
-void Player_AD::updateSfx() {
- if (--_sfxTimer) {
- return;
- }
- _sfxTimer = 4;
-
- for (int i = 0; i <= 9; ++i) {
- if (!_channels[i].state) {
- continue;
- }
-
- updateChannel(i);
- }
-}
-
-void Player_AD::clearChannel(int channel) {
- writeReg(0xA0 + channel, 0x00);
- writeReg(0xB0 + channel, 0x00);
-}
-
-void Player_AD::updateChannel(int channel) {
- if (_channels[channel].state == 1) {
- parseSlot(channel);
- } else {
- updateSlot(channel);
- }
-}
-
-void Player_AD::parseSlot(int channel) {
- while (true) {
- const byte *curOffset = _channels[channel].currentOffset;
-
- switch (*curOffset) {
- case 1:
- // INSTRUMENT DEFINITION
- ++curOffset;
- _channels[channel].instrumentData[0] = *(curOffset + 0);
- _channels[channel].instrumentData[1] = *(curOffset + 2);
- _channels[channel].instrumentData[2] = *(curOffset + 9);
- _channels[channel].instrumentData[3] = *(curOffset + 8);
- _channels[channel].instrumentData[4] = *(curOffset + 4);
- _channels[channel].instrumentData[5] = *(curOffset + 3);
- _channels[channel].instrumentData[6] = 0;
-
- setupChannel(channel, curOffset);
-
- writeReg(0xA0 + channel, *(curOffset + 0));
- writeReg(0xB0 + channel, *(curOffset + 1) & 0xDF);
-
- _channels[channel].currentOffset += 15;
- break;
-
- case 2:
- // NOTE DEFINITION
- ++curOffset;
- _channels[channel].state = 2;
- noteOffOn(channel);
- parseNote(channel, 0, curOffset);
- parseNote(channel, 1, curOffset);
- return;
-
- case 0x80:
- // LOOP
- _channels[channel].currentOffset = _channels[channel].startOffset;
- break;
-
- default:
- // START OF CHANNEL
- // When we encounter a start of another channel while playback
- // it means that the current channel is finished. Thus, we will
- // stop it.
- clearChannel(channel);
- _channels[channel].state = 0;
-
- // If no channel of the sound effect is playing anymore, unlock
- // the resource.
- channel /= 3;
- if (!_channels[channel + 0].state
- && !_channels[channel + 1].state
- && !_channels[channel + 2].state) {
- _vm->_res->unlock(rtSound, _sfxResource[channel]);
- }
- return;
- }
- }
-}
-
-void Player_AD::updateSlot(int channel) {
- const byte *curOffset = _channels[channel].currentOffset + 1;
-
- for (int num = 0; num <= 1; ++num, curOffset += 5) {
- if (!(*curOffset & 0x80)) {
- continue;
- }
-
- const int note = channel * 2 + num;
- bool updateNote = false;
-
- if (_notes[note].state == 2) {
- if (!--_notes[note].sustainTimer) {
- updateNote = true;
- }
- } else {
- updateNote = processNoteEnvelope(note, _notes[note].instrumentValue);
-
- if (_notes[note].bias) {
- writeRegisterSpecial(note, _notes[note].bias - _notes[note].instrumentValue, *curOffset & 0x07);
- } else {
- writeRegisterSpecial(note, _notes[note].instrumentValue, *curOffset & 0x07);
- }
- }
-
- if (updateNote) {
- if (processNote(note, curOffset)) {
- if (!(*curOffset & 0x08)) {
- _channels[channel].currentOffset += 11;
- _channels[channel].state = 1;
- continue;
- } else if (*curOffset & 0x10) {
- noteOffOn(channel);
- }
-
- _notes[note].state = -1;
- processNote(note, curOffset);
- }
- }
-
- if ((*curOffset & 0x20) && !--_notes[note].playTime) {
- _channels[channel].currentOffset += 11;
- _channels[channel].state = 1;
- }
- }
-}
-
-void Player_AD::parseNote(int channel, int num, const byte *offset) {
- if (num) {
- offset += 5;
- }
-
- if (*offset & 0x80) {
- const int note = channel * 2 + num;
- _notes[note].state = -1;
- processNote(note, offset);
- _notes[note].playTime = 0;
-
- if (*offset & 0x20) {
- _notes[note].playTime = (*(offset + 4) >> 4) * 118;
- _notes[note].playTime += (*(offset + 4) & 0x0F) * 8;
- }
- }
-}
-
-bool Player_AD::processNote(int note, const byte *offset) {
- if (++_notes[note].state == 4) {
- return true;
- }
-
- const int instrumentDataOffset = *offset & 0x07;
- _notes[note].bias = _noteBiasTable[instrumentDataOffset];
-
- uint8 instrumentDataValue = 0;
- if (_notes[note].state == 0) {
- instrumentDataValue = _channels[note / 2].instrumentData[instrumentDataOffset];
- }
-
- uint8 noteInstrumentValue = readRegisterSpecial(note, instrumentDataValue, instrumentDataOffset);
- if (_notes[note].bias) {
- noteInstrumentValue = _notes[note].bias - noteInstrumentValue;
- }
- _notes[note].instrumentValue = noteInstrumentValue;
-
- if (_notes[note].state == 2) {
- _notes[note].sustainTimer = _numStepsTable[*(offset + 3) >> 4];
-
- if (*offset & 0x40) {
- _notes[note].sustainTimer = (((getRnd() << 8) * _notes[note].sustainTimer) >> 16) + 1;
- }
- } else {
- int timer1, timer2;
- if (_notes[note].state == 3) {
- timer1 = *(offset + 3) & 0x0F;
- timer2 = 0;
- } else {
- timer1 = *(offset + _notes[note].state + 1) >> 4;
- timer2 = *(offset + _notes[note].state + 1) & 0x0F;
- }
-
- int adjustValue = ((_noteAdjustTable[timer2] * _noteAdjustScaleTable[instrumentDataOffset]) >> 16) - noteInstrumentValue;
- setupNoteEnvelopeState(note, _numStepsTable[timer1], adjustValue);
- }
-
- return false;
-}
-
-void Player_AD::noteOffOn(int channel) {
- const uint8 regValue = readReg(0xB0 | channel);
- writeReg(0xB0 | channel, regValue & 0xDF);
- writeReg(0xB0 | channel, regValue | 0x20);
-}
-
-void Player_AD::writeRegisterSpecial(int note, uint8 value, int offset) {
- if (offset == 6) {
- return;
- }
-
- // Division by 2 extracts the channel number out of the note.
- note /= 2;
-
- uint8 regNum;
- if (_useOperatorTable[offset]) {
- regNum = _operatorOffsetTable[_channelOperatorOffsetTable[offset] + note * 2];
- } else {
- regNum = _channelOffsetTable[note];
- }
-
- regNum += _baseRegisterTable[offset];
-
- uint8 regValue = readReg(regNum) & (~_registerMaskTable[offset]);
- regValue |= value << _registerShiftTable[offset];
-
- writeReg(regNum, regValue);
-}
-
-uint8 Player_AD::readRegisterSpecial(int note, uint8 defaultValue, int offset) {
- if (offset == 6) {
- return 0;
- }
-
- // Division by 2 extracts the channel number out of the note.
- note /= 2;
-
- uint8 regNum;
- if (_useOperatorTable[offset]) {
- regNum = _operatorOffsetTable[_channelOperatorOffsetTable[offset] + note * 2];
- } else {
- regNum = _channelOffsetTable[note];
- }
-
- regNum += _baseRegisterTable[offset];
-
- uint8 regValue;
- if (defaultValue) {
- regValue = defaultValue;
- } else {
- regValue = readReg(regNum);
- }
-
- regValue &= _registerMaskTable[offset];
- regValue >>= _registerShiftTable[offset];
-
- return regValue;
-}
-
-void Player_AD::setupNoteEnvelopeState(int note, int steps, int adjust) {
- _notes[note].preIncrease = 0;
- if (ABS(adjust) > steps) {
- _notes[note].preIncrease = 1;
- _notes[note].adjust = adjust / steps;
- _notes[note].envelope.stepIncrease = ABS(adjust % steps);
- } else {
- _notes[note].adjust = adjust;
- _notes[note].envelope.stepIncrease = ABS(adjust);
- }
-
- _notes[note].envelope.step = steps;
- _notes[note].envelope.stepCounter = 0;
- _notes[note].envelope.timer = steps;
-}
-
-bool Player_AD::processNoteEnvelope(int note, int &instrumentValue) {
- if (_notes[note].preIncrease) {
- instrumentValue += _notes[note].adjust;
- }
-
- _notes[note].envelope.stepCounter += _notes[note].envelope.stepIncrease;
- if (_notes[note].envelope.stepCounter >= _notes[note].envelope.step) {
- _notes[note].envelope.stepCounter -= _notes[note].envelope.step;
-
- if (_notes[note].adjust < 0) {
- --instrumentValue;
- } else {
- ++instrumentValue;
- }
- }
-
- if (--_notes[note].envelope.timer) {
- return false;
- } else {
- return true;
- }
-}
-
-uint8 Player_AD::getRnd() {
- if (_rndSeed & 1) {
- _rndSeed >>= 1;
- _rndSeed ^= 0xB8;
- } else {
- _rndSeed >>= 1;
- }
-
- return _rndSeed;
-}
-
-const uint Player_AD::_noteBiasTable[7] = {
- 0x00, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x00
-};
-
-const uint Player_AD::_numStepsTable[16] = {
- 1, 4, 6, 8,
- 10, 14, 18, 24,
- 36, 64, 100, 160,
- 240, 340, 600, 1200
-};
-
-const uint Player_AD::_noteAdjustScaleTable[7] = {
- 255, 7, 63, 15, 63, 15, 63
-};
-
-const uint Player_AD::_noteAdjustTable[16] = {
- 0, 4369, 8738, 13107,
- 17476, 21845, 26214, 30583,
- 34952, 39321, 43690, 48059,
- 52428, 46797, 61166, 65535
-};
-
-const bool Player_AD::_useOperatorTable[7] = {
- false, false, true, true, true, true, false
-};
-
-const uint Player_AD::_channelOffsetTable[11] = {
- 0, 1, 2, 3,
- 4, 5, 6, 7,
- 8, 8, 7
-};
-
-const uint Player_AD::_channelOperatorOffsetTable[7] = {
- 0, 0, 1, 1, 0, 0, 0
-};
-
-const uint Player_AD::_baseRegisterTable[7] = {
- 0xA0, 0xC0, 0x40, 0x20, 0x40, 0x20, 0x00
-};
-
-const uint Player_AD::_registerMaskTable[7] = {
- 0xFF, 0x0E, 0x3F, 0x0F, 0x3F, 0x0F, 0x00
-};
-
-const uint Player_AD::_registerShiftTable[7] = {
- 0, 1, 0, 0, 0, 0, 0
-};
-
-} // End of namespace Scumm