diff options
Diffstat (limited to 'engines/scumm/player_ad.cpp')
-rw-r--r-- | engines/scumm/player_ad.cpp | 959 |
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 |