diff options
Diffstat (limited to 'engines/scumm/player')
34 files changed, 0 insertions, 13693 deletions
diff --git a/engines/scumm/player/ad.cpp b/engines/scumm/player/ad.cpp deleted file mode 100644 index d3cd0483b6..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 diff --git a/engines/scumm/player/ad.h b/engines/scumm/player/ad.h deleted file mode 100644 index da6c7177ef..0000000000 --- a/engines/scumm/player/ad.h +++ /dev/null @@ -1,190 +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 SCUMM_PLAYER_AD_H -#define SCUMM_PLAYER_AD_H - -#include "scumm/music.h" - -#include "audio/audiostream.h" -#include "audio/mixer.h" - -#include "common/mutex.h" - -namespace OPL { -class OPL; -} - -namespace Scumm { - -class ScummEngine; - -/** - * Sound output for v3/v4 AdLib data. - */ -class Player_AD : public MusicEngine, public Audio::AudioStream { -public: - Player_AD(ScummEngine *scumm, Audio::Mixer *mixer); - virtual ~Player_AD(); - - // MusicEngine API - virtual void setMusicVolume(int vol); - virtual void startSound(int sound); - virtual void stopSound(int sound); - virtual void stopAllSounds(); - virtual int getMusicTimer(); - virtual int getSoundStatus(int sound) const; - - virtual void saveLoadWithSerializer(Serializer *ser); - - // AudioStream API - virtual int readBuffer(int16 *buffer, const int numSamples); - virtual bool isStereo() const { return false; } - virtual bool endOfData() const { return false; } - virtual int getRate() const { return _rate; } - -private: - ScummEngine *const _vm; - Common::Mutex _mutex; - Audio::Mixer *const _mixer; - const int _rate; - Audio::SoundHandle _soundHandle; - void setupVolume(); - - OPL::OPL *_opl2; - - int _samplesPerCallback; - int _samplesPerCallbackRemainder; - int _samplesTillCallback; - int _samplesTillCallbackRemainder; - - int _soundPlaying; - int _engineMusicTimer; - - // AdLib register utilities - uint8 _registerBackUpTable[256]; - void writeReg(int r, int v); - uint8 readReg(int r) const; - - // Instrument setup - void setupChannel(const uint channel, uint instrOffset) { - setupChannel(channel, _resource + instrOffset); - } - void setupChannel(const uint channel, const byte *instrOffset); - void setupOperator(const uint opr, const byte *&instrOffset); - static const int _operatorOffsetTable[18]; - - // Sound data - const byte *_resource; - - // Music handling - void startMusic(); - void updateMusic(); - void noteOff(uint channel); - int findFreeChannel(); - void setupFrequency(uint channel, int8 frequency); - void setupRhythm(uint rhythmInstr, uint instrOffset); - - uint _timerLimit; - uint _musicTicks; - uint _musicTimer; - uint _internalMusicTimer; - bool _loopFlag; - uint _musicLoopStart; - uint _instrumentOffset[16]; - uint _channelLastEvent[9]; - uint _channelFrequency[9]; - uint _channelB0Reg[9]; - - uint _mdvdrState; - uint _voiceChannels; - - uint _curOffset; - uint _nextEventTimer; - - static const uint _noteFrequencies[12]; - static const uint _mdvdrTable[6]; - static const uint _rhythmOperatorTable[6]; - static const uint _rhythmChannelTable[6]; - - // SFX handling - void startSfx(); - void updateSfx(); - void clearChannel(int channel); - void updateChannel(int channel); - void parseSlot(int channel); - void updateSlot(int channel); - void parseNote(int channel, int num, const byte *offset); - bool processNote(int note, const byte *offset); - void noteOffOn(int channel); - void writeRegisterSpecial(int note, uint8 value, int offset); - uint8 readRegisterSpecial(int note, uint8 defaultValue, int offset); - void setupNoteEnvelopeState(int note, int steps, int adjust); - bool processNoteEnvelope(int note, int &instrumentValue); - - int _sfxTimer; - - int _sfxResource[3]; - int _sfxPriority[3]; - - struct Channel { - int state; - const byte *currentOffset; - const byte *startOffset; - uint8 instrumentData[7]; - } _channels[11]; - - uint8 _rndSeed; - uint8 getRnd(); - - struct Note { - int state; - int playTime; - int sustainTimer; - int instrumentValue; - int bias; - int preIncrease; - int adjust; - - struct Envelope { - int stepIncrease; - int step; - int stepCounter; - int timer; - } envelope; - } _notes[22]; - - static const uint _noteBiasTable[7]; - static const uint _numStepsTable[16]; - static const uint _noteAdjustScaleTable[7]; - static const uint _noteAdjustTable[16]; - static const bool _useOperatorTable[7]; - static const uint _channelOffsetTable[11]; - static const uint _channelOperatorOffsetTable[7]; - static const uint _baseRegisterTable[7]; - static const uint _registerMaskTable[7]; - static const uint _registerShiftTable[7]; -}; - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/player/apple2.cpp b/engines/scumm/player/apple2.cpp deleted file mode 100644 index 671cbf9580..0000000000 --- a/engines/scumm/player/apple2.cpp +++ /dev/null @@ -1,500 +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 "engines/engine.h" -#include "scumm/player/apple2.h" -#include "scumm/scumm.h" - -namespace Scumm { - -/************************************ - * Apple-II sound-resource parsers - ************************************/ - -/* - * SoundFunction1: frequency up/down - */ -class AppleII_SoundFunction1_FreqUpDown : public AppleII_SoundFunction { -public: - virtual void init(Player_AppleII *player, const byte *params) { - _player = player; - _delta = params[0]; - _count = params[1]; - _interval = params[2]; - _limit = params[3]; - _decInterval = (params[4] >= 0x40); - } - - virtual bool update() { // D085 - if (_decInterval) { - do { - _update(_interval, _count); - _interval -= _delta; - } while (_interval >= _limit); - } else { - do { - _update(_interval, _count); - _interval += _delta; - } while (_interval < _limit); - } - return true; - } - -private: - void _update(int interval /*a*/, int count /*y*/) { // D076 - assert(interval > 0); // 0 == 256? - assert(count > 0); // 0 == 256? - - for (; count >= 0; --count) { - _player->speakerToggle(); - _player->generateSamples(17 + 5 * interval); - } - } - -protected: - int _delta; - int _count; - byte _interval; // must be unsigned byte ("interval < delta" possible) - int _limit; - bool _decInterval; -}; - -/* - * SoundFunction2: symmetric wave (~) - */ -class AppleII_SoundFunction2_SymmetricWave : public AppleII_SoundFunction { -public: - virtual void init(Player_AppleII *player, const byte *params) { - _player = player; - _params = params; - _pos = 1; - } - - virtual bool update() { // D0D6 - // while (pos = 1; pos < 256; ++pos) - if (_pos < 256) { - byte interval = _params[_pos]; - if (interval == 0xFF) - return true; - _update(interval, _params[0] /*, LD12F=interval*/); - - ++_pos; - return false; - } - return true; - } - -private: - void _update(int interval /*a*/, int count) { // D0EF - if (interval == 0xFE) { - _player->wait(interval, 10); - } else { - assert(count > 0); // 0 == 256? - assert(interval > 0); // 0 == 256? - - int a = (interval >> 3) + count; - for (int y = a; y > 0; --y) { - _player->generateSamples(1292 - 5*interval); - _player->speakerToggle(); - - _player->generateSamples(1287 - 5*interval); - _player->speakerToggle(); - } - } - } - -protected: - const byte *_params; - int _pos; -}; - -/* - * SoundFunction3: asymmetric wave (__-) - */ -class AppleII_SoundFunction3_AsymmetricWave : public AppleII_SoundFunction { -public: - virtual void init(Player_AppleII *player, const byte *params) { - _player = player; - _params = params; - _pos = 1; - } - - virtual bool update() { // D132 - // while (pos = 1; pos < 256; ++pos) - if (_pos < 256) { - byte interval = _params[_pos]; - if (interval == 0xFF) - return true; - _update(interval, _params[0]); - - ++_pos; - return false; - } - return true; - } - -private: - void _update(int interval /*a*/, int count /*LD12D*/) { // D14B - if (interval == 0xFE) { - _player->wait(interval, 70); - } else { - assert(interval > 0); // 0 == 256? - assert(count > 0); // 0 == 256? - - for (int y = count; y > 0; --y) { - _player->generateSamples(1289 - 5*interval); - _player->speakerToggle(); - } - } - } - -protected: - const byte *_params; - int _pos; -}; - -/* - * SoundFunction4: polyphone (2 voices) - */ -class AppleII_SoundFunction4_Polyphone : public AppleII_SoundFunction { -public: - virtual void init(Player_AppleII *player, const byte *params) { - _player = player; - _params = params; - _updateRemain1 = 80; - _updateRemain2 = 10; - _count = 0; - } - - virtual bool update() { // D170 - // while (_params[0] != 0x01) - if (_params[0] != 0x01) { - if (_count == 0) // prepare next loop - nextLoop(_params[0], _params[1], _params[2]); - if (loopIteration()) // loop finished -> fetch next parameter set - _params += 3; - return false; - } - return true; - } - -private: - /* - * prepare for next parameter set loop - */ - void nextLoop(byte param0, byte param1, byte param2) { // LD182 - _count = (-param2 << 8) | 0x3; - - _bitmask1 = 0x3; - _bitmask2 = 0x3; - - _updateInterval2 = param0; - if (_updateInterval2 == 0) - _bitmask2 = 0x0; - - _updateInterval1 = param1; - if (_updateInterval1 == 0) { - _bitmask1 = 0x0; - if (_bitmask2 != 0) { - _bitmask1 = _bitmask2; - _bitmask2 = 0; - _updateInterval1 = _updateInterval2; - } - } - - _speakerShiftReg = 0; - } - - /* - * perform one loop iteration - * Returns true if loop finished - */ - bool loopIteration() { // D1A2 - --_updateRemain1; - --_updateRemain2; - - if (_updateRemain2 == 0) { - _updateRemain2 = _updateInterval2; - // use only first voice's data (bitmask1) if both voices are triggered - if (_updateRemain1 != 0) { - _speakerShiftReg ^= _bitmask2; - } - } - - if (_updateRemain1 == 0) { - _updateRemain1 = _updateInterval1; - _speakerShiftReg ^= _bitmask1; - } - - if (_speakerShiftReg & 0x1) - _player->speakerToggle(); - _speakerShiftReg >>= 1; - _player->generateSamples(42); /* actually 42.5 */ - - ++_count; - return (_count == 0); - } - -protected: - const byte *_params; - - byte _updateRemain1; - byte _updateRemain2; - - uint16 _count; - byte _bitmask1; - byte _bitmask2; - byte _updateInterval1; - byte _updateInterval2; - byte _speakerShiftReg; -}; - -/* - * SoundFunction5: periodic noise - */ -class AppleII_SoundFunction5_Noise : public AppleII_SoundFunction { -public: - virtual void init(Player_AppleII *player, const byte *params) { - _player = player; - _index = 0; - _param0 = params[0]; - assert(_param0 > 0); - } - - virtual bool update() { // D222 - const byte noiseMask[] = { - 0x3F, 0x3F, 0x7F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F - }; - - // while (i = 0; i < 10; ++i) - if (_index < 10) { - int count = _param0; - do { - _update(noise() & noiseMask[_index], 1); - --count; - } while (count > 0); - - ++_index; - return false; - } - - return true; - } - -private: - void _update(int interval /*a*/, int count) { // D270 - assert(count > 0); // 0 == 256? - if (interval == 0) - interval = 256; - - for (int i = count; i > 0; --i) { - _player->generateSamples(10 + 5*interval); - _player->speakerToggle(); - - _player->generateSamples(5 + 5*interval); - _player->speakerToggle(); - } - } - - byte /*a*/ noise() { // D261 - static int pos = 0; // initial value? - byte result = _noiseTable[pos]; - pos = (pos + 1) % 256; - return result; - } - -protected: - int _index; - int _param0; - -private: - static const byte _noiseTable[256]; -}; - -// LD000[loc] ^ LD00A[loc] -const byte AppleII_SoundFunction5_Noise::_noiseTable[256] = { - 0x65, 0x1b, 0xda, 0x11, 0x61, 0xe5, 0x77, 0x57, 0x92, 0xc8, 0x51, 0x1c, 0xd4, 0x91, 0x62, 0x63, - 0x00, 0x38, 0x57, 0xd5, 0x18, 0xd8, 0xdc, 0x40, 0x03, 0x86, 0xd3, 0x2f, 0x10, 0x11, 0xd8, 0x3c, - 0xbe, 0x00, 0x19, 0xc5, 0xd2, 0xc3, 0xca, 0x34, 0x00, 0x28, 0xbf, 0xb9, 0x18, 0x20, 0x01, 0xcc, - 0xda, 0x08, 0xbc, 0x75, 0x7c, 0xb0, 0x8d, 0xe0, 0x09, 0x18, 0xbf, 0x5d, 0xe9, 0x8c, 0x75, 0x64, - 0xe5, 0xb5, 0x5d, 0xe0, 0xb7, 0x7d, 0xe9, 0x8c, 0x55, 0x65, 0xc5, 0xb5, 0x5d, 0xd8, 0x09, 0x0d, - 0x64, 0xf0, 0xf0, 0x08, 0x63, 0x03, 0x00, 0x55, 0x35, 0xc0, 0x00, 0x20, 0x74, 0xa5, 0x1e, 0xe3, - 0x00, 0x06, 0x3c, 0x52, 0xd1, 0x70, 0xd0, 0x57, 0x02, 0xf0, 0x00, 0xb6, 0xfc, 0x02, 0x11, 0x9a, - 0x3b, 0xc8, 0x38, 0xdf, 0x1a, 0xb0, 0xd1, 0xb8, 0xd0, 0x18, 0x8a, 0x4a, 0xea, 0x1b, 0x12, 0x5d, - 0x29, 0x58, 0xd8, 0x43, 0xb8, 0x2d, 0xd2, 0x61, 0x10, 0x3c, 0x0c, 0x5d, 0x1b, 0x61, 0x10, 0x3c, - 0x0a, 0x5d, 0x1d, 0x61, 0x10, 0x3c, 0x0b, 0x19, 0x88, 0x21, 0xc0, 0x21, 0x07, 0x00, 0x65, 0x62, - 0x08, 0xe9, 0x36, 0x40, 0x20, 0x41, 0x06, 0x00, 0x20, 0x00, 0x00, 0xed, 0xa3, 0x00, 0x88, 0x06, - 0x98, 0x01, 0x5d, 0x7f, 0x02, 0x1d, 0x78, 0x03, 0x60, 0xcb, 0x3a, 0x01, 0xbd, 0x78, 0x02, 0x5d, - 0x7e, 0x03, 0x1d, 0xf5, 0xa6, 0x40, 0x81, 0xb4, 0xd0, 0x8d, 0xd3, 0xd0, 0x6d, 0xd5, 0x61, 0x48, - 0x61, 0x4d, 0xd1, 0xc8, 0xb1, 0xd8, 0x69, 0xff, 0x61, 0xd9, 0xed, 0xa0, 0xfe, 0x19, 0x91, 0x37, - 0x19, 0x37, 0x00, 0xf1, 0x00, 0x01, 0x1f, 0x00, 0xad, 0xc1, 0x01, 0x01, 0x2e, 0x00, 0x40, 0xc6, - 0x7a, 0x9b, 0x95, 0x43, 0xfc, 0x18, 0xd2, 0x9e, 0x2a, 0x5a, 0x4b, 0x2a, 0xb6, 0x87, 0x30, 0x6c -}; - -/************************************ - * Apple-II player - ************************************/ - -Player_AppleII::Player_AppleII(ScummEngine *scumm, Audio::Mixer *mixer) - : _mixer(mixer), _vm(scumm), _soundFunc(0) { - resetState(); - setSampleRate(_mixer->getOutputRate()); - _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); -} - -Player_AppleII::~Player_AppleII() { - _mixer->stopHandle(_soundHandle); - delete _soundFunc; -} - -void Player_AppleII::resetState() { - _soundNr = 0; - _type = 0; - _loop = 0; - _params = NULL; - _speakerState = 0; - delete _soundFunc; - _soundFunc = 0; - _sampleConverter.reset(); -} - -void Player_AppleII::startSound(int nr) { - Common::StackLock lock(_mutex); - - byte *data = _vm->getResourceAddress(rtSound, nr); - assert(data); - byte *ptr1 = data + 4; - - resetState(); - _soundNr = nr; - _type = ptr1[0]; - _loop = ptr1[1]; - _params = &ptr1[2]; - - switch (_type) { - case 0: // empty (nothing to play) - resetState(); - return; - case 1: - _soundFunc = new AppleII_SoundFunction1_FreqUpDown(); - break; - case 2: - _soundFunc = new AppleII_SoundFunction2_SymmetricWave(); - break; - case 3: - _soundFunc = new AppleII_SoundFunction3_AsymmetricWave(); - break; - case 4: - _soundFunc = new AppleII_SoundFunction4_Polyphone(); - break; - case 5: - _soundFunc = new AppleII_SoundFunction5_Noise(); - break; - } - _soundFunc->init(this, _params); - - assert(_loop > 0); - - debug(4, "startSound %d: type %d, loop %d", - nr, _type, _loop); -} - -bool Player_AppleII::updateSound() { - if (!_soundFunc) - return false; - - if (_soundFunc->update()) { - --_loop; - if (_loop <= 0) { - delete _soundFunc; - _soundFunc = 0; - } else { - // reset function state on each loop - _soundFunc->init(this, _params); - } - } - - return true; -} - -void Player_AppleII::stopAllSounds() { - Common::StackLock lock(_mutex); - resetState(); -} - -void Player_AppleII::stopSound(int nr) { - Common::StackLock lock(_mutex); - if (_soundNr == nr) { - resetState(); - } -} - -int Player_AppleII::getSoundStatus(int nr) const { - Common::StackLock lock(_mutex); - return (_soundNr == nr); -} - -int Player_AppleII::getMusicTimer() { - /* Apple-II sounds are synchronous -> no music timer */ - return 0; -} - -int Player_AppleII::readBuffer(int16 *buffer, const int numSamples) { - Common::StackLock lock(_mutex); - - if (!_soundNr) - return 0; - - int samplesLeft = numSamples; - do { - int nSamplesRead = _sampleConverter.readSamples(buffer, samplesLeft); - samplesLeft -= nSamplesRead; - buffer += nSamplesRead; - } while ((samplesLeft > 0) && updateSound()); - - // reset state if sound is played completely - if (!_soundFunc && (_sampleConverter.availableSize() == 0)) - resetState(); - - return numSamples - samplesLeft; -} - -/************************************ - * Apple-II sound-resource helpers - ************************************/ - -// toggle speaker on/off -void Player_AppleII::speakerToggle() { - _speakerState ^= 0x1; -} - -void Player_AppleII::generateSamples(int cycles) { - _sampleConverter.addCycles(_speakerState, cycles); -} - -void Player_AppleII::wait(int interval, int count /*y*/) { - assert(count > 0); // 0 == 256? - assert(interval > 0); // 0 == 256? - generateSamples(11 + count*(8 + 5 * interval)); -} - -} // End of namespace Scumm diff --git a/engines/scumm/player/apple2.h b/engines/scumm/player/apple2.h deleted file mode 100644 index e1ec9d8946..0000000000 --- a/engines/scumm/player/apple2.h +++ /dev/null @@ -1,297 +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 SCUMM_PLAYER_APPLEII_H -#define SCUMM_PLAYER_APPLEII_H - -#include "common/mutex.h" -#include "common/scummsys.h" -#include "common/memstream.h" -#include "scumm/music.h" -#include "audio/audiostream.h" -#include "audio/mixer.h" -#include "audio/softsynth/sid.h" - -namespace Scumm { - -class ScummEngine; - -/* - * Optimized for use with periodical read/write phases when the buffer - * is filled in a write phase and completely read in a read phase. - * The growing strategy is optimized for repeated small (e.g. 2 bytes) - * single writes resulting in large buffers - * (avg.: 4KB, max: 18KB @ 16bit/22.050kHz (MM sound21)). - */ -class SampleBuffer { -public: - SampleBuffer() : _data(0) { - clear(); - } - - ~SampleBuffer() { - free(_data); - } - - void clear() { - free(_data); - _data = 0; - _capacity = 0; - _writePos = 0; - _readPos = 0; - } - - void ensureFree(uint32 needed) { - // if data was read completely, reset read/write pos to front - if ((_writePos != 0) && (_writePos == _readPos)) { - _writePos = 0; - _readPos = 0; - } - - // check for enough space at end of buffer - uint32 freeEndCnt = _capacity - _writePos; - if (needed <= freeEndCnt) - return; - - uint32 avail = availableSize(); - - // check for enough space at beginning and end of buffer - if (needed <= _readPos + freeEndCnt) { - // move unread data to front of buffer - memmove(_data, _data + _readPos, avail); - _writePos = avail; - _readPos = 0; - } else { // needs a grow - byte *old_data = _data; - uint32 new_len = avail + needed; - - _capacity = new_len + 2048; - _data = (byte *)malloc(_capacity); - - if (old_data) { - // copy old unread data to front of new buffer - memcpy(_data, old_data + _readPos, avail); - free(old_data); - _writePos = avail; - _readPos = 0; - } - } - } - - uint32 availableSize() const { - if (_readPos >= _writePos) - return 0; - return _writePos - _readPos; - } - - uint32 write(const void *dataPtr, uint32 dataSize) { - ensureFree(dataSize); - memcpy(_data + _writePos, dataPtr, dataSize); - _writePos += dataSize; - return dataSize; - } - - uint32 read(byte *dataPtr, uint32 dataSize) { - uint32 avail = availableSize(); - if (avail == 0) - return 0; - if (dataSize > avail) - dataSize = avail; - memcpy(dataPtr, _data + _readPos, dataSize); - _readPos += dataSize; - return dataSize; - } - -private: - uint32 _writePos; - uint32 _readPos; - uint32 _capacity; - byte *_data; -}; - -// CPU_CLOCK according to AppleWin -static const double APPLEII_CPU_CLOCK = 1020484.5; // ~ 1.02 MHz - -/* - * Converts the 1-bit speaker state values into audio samples. - * This is done by aggregation of the speaker states at each - * CPU cycle in a sampling period into an audio sample. - */ -class SampleConverter { -private: - void addSampleToBuffer(int sample) { - int16 value = sample * _volume / _maxVolume; - _buffer.write(&value, sizeof(value)); - } - -public: - SampleConverter() : - _cyclesPerSampleFP(0), - _missingCyclesFP(0), - _sampleCyclesSumFP(0), - _volume(_maxVolume) - {} - - ~SampleConverter() {} - - void reset() { - _missingCyclesFP = 0; - _sampleCyclesSumFP = 0; - _buffer.clear(); - } - - uint32 availableSize() const { - return _buffer.availableSize(); - } - - void setMusicVolume(int vol) { - assert(vol >= 0 && vol <= _maxVolume); - _volume = vol; - } - - void setSampleRate(int rate) { - /* ~46 CPU cycles per sample @ 22.05kHz */ - _cyclesPerSampleFP = int(APPLEII_CPU_CLOCK * (1 << PREC_SHIFT) / rate); - reset(); - } - - void addCycles(byte level, const int cycles) { - /* convert to fixed precision floats */ - int cyclesFP = cycles << PREC_SHIFT; - - // step 1: if cycles are left from the last call, process them first - if (_missingCyclesFP > 0) { - int n = (_missingCyclesFP < cyclesFP) ? _missingCyclesFP : cyclesFP; - if (level) - _sampleCyclesSumFP += n; - cyclesFP -= n; - _missingCyclesFP -= n; - if (_missingCyclesFP == 0) { - addSampleToBuffer(2*32767 * _sampleCyclesSumFP / _cyclesPerSampleFP - 32767); - } else { - return; - } - } - - _sampleCyclesSumFP = 0; - - // step 2: process blocks of cycles fitting into a whole sample - while (cyclesFP >= _cyclesPerSampleFP) { - addSampleToBuffer(level ? 32767 : -32767); - cyclesFP -= _cyclesPerSampleFP; - } - - // step 3: remember cycles left for next call - if (cyclesFP > 0) { - _missingCyclesFP = _cyclesPerSampleFP - cyclesFP; - if (level) - _sampleCyclesSumFP = cyclesFP; - } - } - - uint32 readSamples(void *buffer, int numSamples) { - return _buffer.read((byte *)buffer, numSamples * 2) / 2; - } - -private: - static const int PREC_SHIFT = 7; - -private: - int _cyclesPerSampleFP; /* (fixed precision) */ - int _missingCyclesFP; /* (fixed precision) */ - int _sampleCyclesSumFP; /* (fixed precision) */ - int _volume; /* 0 - 256 */ - static const int _maxVolume = 256; - SampleBuffer _buffer; -}; - -class Player_AppleII; - -class AppleII_SoundFunction { -public: - AppleII_SoundFunction() {} - virtual ~AppleII_SoundFunction() {} - virtual void init(Player_AppleII *player, const byte *params) = 0; - /* returns true if finished */ - virtual bool update() = 0; -protected: - Player_AppleII *_player; -}; - -class Player_AppleII : public Audio::AudioStream, public MusicEngine { -public: - Player_AppleII(ScummEngine *scumm, Audio::Mixer *mixer); - virtual ~Player_AppleII(); - - virtual void setMusicVolume(int vol) { _sampleConverter.setMusicVolume(vol); } - void setSampleRate(int rate) { - _sampleRate = rate; - _sampleConverter.setSampleRate(rate); - } - virtual void startSound(int sound); - virtual void stopSound(int sound); - virtual void stopAllSounds(); - virtual int getSoundStatus(int sound) const; - virtual int getMusicTimer(); - - // AudioStream API - int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { return false; } - bool endOfData() const { return false; } - int getRate() const { return _sampleRate; } - -public: - void speakerToggle(); - void generateSamples(int cycles); - void wait(int interval, int count); - -private: - // sound number - int _soundNr; - // type of sound - int _type; - // number of loops left - int _loop; - // global sound param list - const byte *_params; - // speaker toggle state (0 / 1) - byte _speakerState; - // sound function - AppleII_SoundFunction *_soundFunc; - // cycle to sample converter - SampleConverter _sampleConverter; - -private: - ScummEngine *_vm; - Audio::Mixer *_mixer; - Audio::SoundHandle _soundHandle; - int _sampleRate; - Common::Mutex _mutex; - -private: - void resetState(); - bool updateSound(); -}; - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/player/mac.cpp b/engines/scumm/player/mac.cpp deleted file mode 100644 index 1fba266311..0000000000 --- a/engines/scumm/player/mac.cpp +++ /dev/null @@ -1,419 +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 "common/macresman.h" -#include "common/translation.h" -#include "engines/engine.h" -#include "gui/message.h" -#include "scumm/player/mac.h" -#include "scumm/resource.h" -#include "scumm/scumm.h" -#include "scumm/imuse/imuse.h" - -namespace Scumm { - -Player_Mac::Player_Mac(ScummEngine *scumm, Audio::Mixer *mixer, int numberOfChannels, int channelMask, bool fadeNoteEnds) - : _vm(scumm), - _mixer(mixer), - _sampleRate(_mixer->getOutputRate()), - _soundPlaying(-1), - _numberOfChannels(numberOfChannels), - _channelMask(channelMask), - _fadeNoteEnds(fadeNoteEnds) { - assert(scumm); - assert(mixer); -} - -void Player_Mac::init() { - _channel = new Player_Mac::Channel[_numberOfChannels]; - - int i; - - for (i = 0; i < _numberOfChannels; i++) { - _channel[i]._looped = false; - _channel[i]._length = 0; - _channel[i]._data = NULL; - _channel[i]._pos = 0; - _channel[i]._pitchModifier = 0; - _channel[i]._velocity = 0; - _channel[i]._remaining = 0; - _channel[i]._notesLeft = false; - _channel[i]._instrument._data = NULL; - _channel[i]._instrument._size = 0; - _channel[i]._instrument._rate = 0; - _channel[i]._instrument._loopStart = 0; - _channel[i]._instrument._loopEnd = 0; - _channel[i]._instrument._baseFreq = 0; - _channel[i]._instrument._pos = 0; - _channel[i]._instrument._subPos = 0; - } - - _pitchTable[116] = 1664510; - _pitchTable[117] = 1763487; - _pitchTable[118] = 1868350; - _pitchTable[119] = 1979447; - _pitchTable[120] = 2097152; - _pitchTable[121] = 2221855; - _pitchTable[122] = 2353973; - _pitchTable[123] = 2493948; - _pitchTable[124] = 2642246; - _pitchTable[125] = 2799362; - _pitchTable[126] = 2965820; - _pitchTable[127] = 3142177; - for (i = 115; i >= 0; --i) { - _pitchTable[i] = _pitchTable[i + 12] / 2; - } - - setMusicVolume(255); - - if (!checkMusicAvailable()) { - return; - } - - _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); -} - -Player_Mac::~Player_Mac() { - Common::StackLock lock(_mutex); - _mixer->stopHandle(_soundHandle); - stopAllSounds_Internal(); - delete[] _channel; -} - -void Player_Mac::saveLoadWithSerializer(Serializer *ser) { - Common::StackLock lock(_mutex); - if (ser->getVersion() < VER(94)) { - if (_vm->_game.id == GID_MONKEY && ser->isLoading()) { - IMuse *dummyImuse = IMuse::create(_vm->_system, NULL, NULL); - dummyImuse->save_or_load(ser, _vm, false); - delete dummyImuse; - } - } else { - static const SaveLoadEntry musicEntries[] = { - MKLINE(Player_Mac, _sampleRate, sleUint32, VER(94)), - MKLINE(Player_Mac, _soundPlaying, sleInt16, VER(94)), - MKEND() - }; - - static const SaveLoadEntry channelEntries[] = { - MKLINE(Channel, _pos, sleUint16, VER(94)), - MKLINE(Channel, _pitchModifier, sleInt32, VER(94)), - MKLINE(Channel, _velocity, sleUint8, VER(94)), - MKLINE(Channel, _remaining, sleUint32, VER(94)), - MKLINE(Channel, _notesLeft, sleUint8, VER(94)), - MKEND() - }; - - static const SaveLoadEntry instrumentEntries[] = { - MKLINE(Instrument, _pos, sleUint32, VER(94)), - MKLINE(Instrument, _subPos, sleUint32, VER(94)), - MKEND() - }; - - uint32 mixerSampleRate = _sampleRate; - int i; - - ser->saveLoadEntries(this, musicEntries); - - if (ser->isLoading() && _soundPlaying != -1) { - const byte *ptr = _vm->getResourceAddress(rtSound, _soundPlaying); - assert(ptr); - loadMusic(ptr); - } - - ser->saveLoadArrayOf(_channel, _numberOfChannels, sizeof(Channel), channelEntries); - for (i = 0; i < _numberOfChannels; i++) { - ser->saveLoadEntries(&_channel[i], instrumentEntries); - } - - if (ser->isLoading()) { - // If necessary, adjust the channel data to fit the - // current sample rate. - if (_soundPlaying != -1 && _sampleRate != mixerSampleRate) { - double mult = (double)_sampleRate / (double)mixerSampleRate; - for (i = 0; i < _numberOfChannels; i++) { - _channel[i]._pitchModifier = (int)((double)_channel[i]._pitchModifier * mult); - _channel[i]._remaining = (int)((double)_channel[i]._remaining / mult); - } - } - _sampleRate = mixerSampleRate; - } - } -} - -void Player_Mac::setMusicVolume(int vol) { - debug(5, "Player_Mac::setMusicVolume(%d)", vol); -} - -void Player_Mac::stopAllSounds_Internal() { - if (_soundPlaying != -1) { - _vm->_res->unlock(rtSound, _soundPlaying); - } - _soundPlaying = -1; - for (int i = 0; i < _numberOfChannels; i++) { - // The channel data is managed by the resource manager, so - // don't delete that. - delete[] _channel[i]._instrument._data; - _channel[i]._instrument._data = NULL; - - _channel[i]._remaining = 0; - _channel[i]._notesLeft = false; - } -} - -void Player_Mac::stopAllSounds() { - Common::StackLock lock(_mutex); - debug(5, "Player_Mac::stopAllSounds()"); - stopAllSounds_Internal(); -} - -void Player_Mac::stopSound(int nr) { - Common::StackLock lock(_mutex); - debug(5, "Player_Mac::stopSound(%d)", nr); - - if (nr == _soundPlaying) { - stopAllSounds(); - } -} - -void Player_Mac::startSound(int nr) { - Common::StackLock lock(_mutex); - debug(5, "Player_Mac::startSound(%d)", nr); - - stopAllSounds_Internal(); - - const byte *ptr = _vm->getResourceAddress(rtSound, nr); - assert(ptr); - - if (!loadMusic(ptr)) { - return; - } - - _vm->_res->lock(rtSound, nr); - _soundPlaying = nr; -} - -bool Player_Mac::Channel::loadInstrument(Common::SeekableReadStream *stream) { - uint16 soundType = stream->readUint16BE(); - if (soundType != 1) { - warning("Player_Mac::loadInstrument: Unsupported sound type %d", soundType); - return false; - } - uint16 typeCount = stream->readUint16BE(); - if (typeCount != 1) { - warning("Player_Mac::loadInstrument: Unsupported data type count %d", typeCount); - return false; - } - uint16 dataType = stream->readUint16BE(); - if (dataType != 5) { - warning("Player_Mac::loadInstrument: Unsupported data type %d", dataType); - return false; - } - - stream->readUint32BE(); // initialization option - - uint16 cmdCount = stream->readUint16BE(); - if (cmdCount != 1) { - warning("Player_Mac::loadInstrument: Unsupported command count %d", cmdCount); - return false; - } - uint16 command = stream->readUint16BE(); - if (command != 0x8050 && command != 0x8051) { - warning("Player_Mac::loadInstrument: Unsupported command 0x%04X", command); - return false; - } - - stream->readUint16BE(); // 0 - uint32 soundHeaderOffset = stream->readUint32BE(); - - stream->seek(soundHeaderOffset); - - uint32 soundDataOffset = stream->readUint32BE(); - uint32 size = stream->readUint32BE(); - uint32 rate = stream->readUint32BE() >> 16; - uint32 loopStart = stream->readUint32BE(); - uint32 loopEnd = stream->readUint32BE(); - byte encoding = stream->readByte(); - byte baseFreq = stream->readByte(); - - if (encoding != 0) { - warning("Player_Mac::loadInstrument: Unsupported encoding %d", encoding); - return false; - } - - stream->skip(soundDataOffset); - - byte *data = new byte[size]; - stream->read(data, size); - - _instrument._data = data; - _instrument._size = size; - _instrument._rate = rate; - _instrument._loopStart = loopStart; - _instrument._loopEnd = loopEnd; - _instrument._baseFreq = baseFreq; - - return true; -} - -int Player_Mac::getMusicTimer() { - return 0; -} - -int Player_Mac::getSoundStatus(int nr) const { - return _soundPlaying == nr; -} - -uint32 Player_Mac::durationToSamples(uint16 duration) { - // The correct formula should be: - // - // (duration * 473 * _sampleRate) / (4 * 480 * 480) - // - // But that's likely to cause integer overflow, so we do it in two - // steps using bitwise operations to perform - // ((duration * 473 * _sampleRate) / 4096) without overflowing, - // then divide this by 225 - // (note that 4 * 480 * 480 == 225 * 4096 == 225 << 12) - // - // The original code is a bit unclear on if it should be 473 or 437, - // but since the comments indicated 473 I'm assuming 437 was a typo. - uint32 samples = (duration * _sampleRate); - samples = (samples >> 12) * 473 + (((samples & 4095) * 473) >> 12); - samples = samples / 225; - return samples; -} - -int Player_Mac::noteToPitchModifier(byte note, Instrument *instrument) { - if (note > 0) { - const int pitchIdx = note + 60 - instrument->_baseFreq; - // I don't want to use floating-point arithmetics here, but I - // ran into overflow problems with the church music in Monkey - // Island. It's only once per note, so it should be ok. - double mult = (double)instrument->_rate / (double)_sampleRate; - return (int)(mult * _pitchTable[pitchIdx]); - } else { - return 0; - } -} - -int Player_Mac::readBuffer(int16 *data, const int numSamples) { - Common::StackLock lock(_mutex); - - memset(data, 0, numSamples * 2); - if (_soundPlaying == -1) { - return numSamples; - } - - bool notesLeft = false; - - for (int i = 0; i < _numberOfChannels; i++) { - if (!(_channelMask & (1 << i))) { - continue; - } - - uint samplesLeft = numSamples; - int16 *ptr = data; - - while (samplesLeft > 0) { - int generated; - if (_channel[i]._remaining == 0) { - uint32 samples; - int pitchModifier; - byte velocity; - if (getNextNote(i, samples, pitchModifier, velocity)) { - _channel[i]._remaining = samples; - _channel[i]._pitchModifier = pitchModifier; - _channel[i]._velocity = velocity; - - } else { - _channel[i]._pitchModifier = 0; - _channel[i]._velocity = 0; - _channel[i]._remaining = samplesLeft; - } - } - generated = MIN<uint32>(_channel[i]._remaining, samplesLeft); - if (_channel[i]._velocity != 0) { - _channel[i]._instrument.generateSamples(ptr, _channel[i]._pitchModifier, _channel[i]._velocity, generated, _channel[i]._remaining, _fadeNoteEnds); - } - ptr += generated; - samplesLeft -= generated; - _channel[i]._remaining -= generated; - } - - if (_channel[i]._notesLeft) { - notesLeft = true; - } - } - - if (!notesLeft) { - stopAllSounds_Internal(); - } - - return numSamples; -} - -void Player_Mac::Instrument::generateSamples(int16 *data, int pitchModifier, int volume, int numSamples, int remainingSamplesOnNote, bool fadeNoteEnds) { - int samplesLeft = numSamples; - while (samplesLeft) { - _subPos += pitchModifier; - while (_subPos >= 0x10000) { - _subPos -= 0x10000; - _pos++; - if (_pos >= _loopEnd) { - _pos = _loopStart; - } - } - - int newSample = (((int16)((_data[_pos] << 8) ^ 0x8000)) * volume) / 255; - - if (fadeNoteEnds) { - // Fade out the last 100 samples on each note. Even at - // low output sample rates this is just a fraction of a - // second, but it gets rid of distracting "pops" at the - // end when the sample would otherwise go abruptly from - // something to nothing. This was particularly - // noticeable on the distaff notes in Loom. - // - // The reason it's conditional is that Monkey Island - // appears to have a "hold current note" command, and - // if we fade out the current note in that case we - // will actually introduce new "pops". - - remainingSamplesOnNote--; - if (remainingSamplesOnNote < 100) { - newSample = (newSample * remainingSamplesOnNote) / 100; - } - } - - int sample = *data + newSample; - if (sample > 32767) { - sample = 32767; - } else if (sample < -32768) { - sample = -32768; - } - - *data++ = sample; - samplesLeft--; - } -} - -} // End of namespace Scumm diff --git a/engines/scumm/player/mac.h b/engines/scumm/player/mac.h deleted file mode 100644 index 09307b4e57..0000000000 --- a/engines/scumm/player/mac.h +++ /dev/null @@ -1,133 +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 SCUMM_PLAYER_MAC_H -#define SCUMM_PLAYER_MAC_H - -#include "common/scummsys.h" -#include "common/util.h" -#include "common/mutex.h" -#include "scumm/music.h" -#include "scumm/saveload.h" -#include "audio/audiostream.h" -#include "audio/mixer.h" - -#define RES_SND MKTAG('s', 'n', 'd', ' ') - -class Mixer; - -namespace Scumm { - -class ScummEngine; - -/** - * Scumm Macintosh music driver, base class. - */ -class Player_Mac : public Audio::AudioStream, public MusicEngine { -public: - Player_Mac(ScummEngine *scumm, Audio::Mixer *mixer, int numberOfChannels, int channelMask, bool fadeNoteEnds); - virtual ~Player_Mac(); - - void init(); - - // MusicEngine API - virtual void setMusicVolume(int vol); - virtual void startSound(int sound); - virtual void stopSound(int sound); - virtual void stopAllSounds(); - virtual int getMusicTimer(); - virtual int getSoundStatus(int sound) const; - - // AudioStream API - virtual int readBuffer(int16 *buffer, const int numSamples); - virtual bool isStereo() const { return false; } - virtual bool endOfData() const { return false; } - virtual int getRate() const { return _sampleRate; } - - virtual void saveLoadWithSerializer(Serializer *ser); - -private: - Common::Mutex _mutex; - Audio::Mixer *const _mixer; - Audio::SoundHandle _soundHandle; - uint32 _sampleRate; - int _soundPlaying; - - void stopAllSounds_Internal(); - - struct Instrument { - byte *_data; - uint32 _size; - uint32 _rate; - uint32 _loopStart; - uint32 _loopEnd; - byte _baseFreq; - - uint _pos; - uint _subPos; - - void newNote() { - _pos = 0; - _subPos = 0; - } - - void generateSamples(int16 *data, int pitchModifier, int volume, int numSamples, int remainingSamplesOnNote, bool fadeNoteEnds); - }; - - int _pitchTable[128]; - int _numberOfChannels; - int _channelMask; - bool _fadeNoteEnds; - - virtual bool checkMusicAvailable() { return false; } - virtual bool loadMusic(const byte *ptr) { return false; } - virtual bool getNextNote(int ch, uint32 &samples, int &pitchModifier, byte &velocity) { return false; } - -protected: - struct Channel { - virtual ~Channel() {} - - Instrument _instrument; - bool _looped; - uint32 _length; - const byte *_data; - - uint _pos; - int _pitchModifier; - byte _velocity; - uint32 _remaining; - - bool _notesLeft; - - bool loadInstrument(Common::SeekableReadStream *stream); - }; - - ScummEngine *const _vm; - Channel *_channel; - - uint32 durationToSamples(uint16 duration); - int noteToPitchModifier(byte note, Instrument *instrument); -}; - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/player/mod.cpp b/engines/scumm/player/mod.cpp deleted file mode 100644 index afa8967343..0000000000 --- a/engines/scumm/player/mod.cpp +++ /dev/null @@ -1,223 +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/mod.h" -#include "audio/mixer.h" -#include "audio/rate.h" -#include "audio/decoders/raw.h" - -namespace Scumm { - -Player_MOD::Player_MOD(Audio::Mixer *mixer) - : _mixer(mixer), _sampleRate(mixer->getOutputRate()) { - int i; - _mixamt = 0; - _mixpos = 0; - - for (i = 0; i < MOD_MAXCHANS; i++) { - _channels[i].id = 0; - _channels[i].vol = 0; - _channels[i].freq = 0; - _channels[i].input = NULL; - _channels[i].ctr = 0; - _channels[i].pos = 0; - } - - _playproc = NULL; - _playparam = NULL; - - _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); -} - -Player_MOD::~Player_MOD() { - _mixer->stopHandle(_soundHandle); - for (int i = 0; i < MOD_MAXCHANS; i++) { - if (!_channels[i].id) - continue; - delete _channels[i].input; - } -} - -void Player_MOD::setMusicVolume(int vol) { - _maxvol = vol; -} - -void Player_MOD::setUpdateProc(ModUpdateProc *proc, void *param, int freq) { - _playproc = proc; - _playparam = param; - _mixamt = _sampleRate / freq; -} -void Player_MOD::clearUpdateProc() { - _playproc = NULL; - _playparam = NULL; - _mixamt = 0; -} - -void Player_MOD::startChannel(int id, void *data, int size, int rate, uint8 vol, int loopStart, int loopEnd, int8 pan) { - int i; - if (id == 0) - error("player_mod - attempted to start channel id 0"); - - for (i = 0; i < MOD_MAXCHANS; i++) { - if (!_channels[i].id) - break; - } - if (i == MOD_MAXCHANS) { - warning("player_mod - too many music channels playing (%i max)",MOD_MAXCHANS); - return; - } - _channels[i].id = id; - _channels[i].vol = vol; - _channels[i].pan = pan; - _channels[i].freq = rate; - _channels[i].ctr = 0; - - Audio::SeekableAudioStream *stream = Audio::makeRawStream((const byte *)data, size, rate, 0); - if (loopStart != loopEnd) { - _channels[i].input = new Audio::SubLoopingAudioStream(stream, 0, Audio::Timestamp(0, loopStart, rate), Audio::Timestamp(0, loopEnd, rate)); - } else { - _channels[i].input = stream; - } - - // read the first sample - _channels[i].input->readBuffer(&_channels[i].pos, 1); -} - -void Player_MOD::stopChannel(int id) { - if (id == 0) - error("player_mod - attempted to stop channel id 0"); - for (int i = 0; i < MOD_MAXCHANS; i++) { - if (_channels[i].id == id) { - delete _channels[i].input; - _channels[i].input = NULL; - _channels[i].id = 0; - _channels[i].vol = 0; - _channels[i].freq = 0; - _channels[i].ctr = 0; - _channels[i].pos = 0; - } - } -} -void Player_MOD::setChannelVol(int id, uint8 vol) { - if (id == 0) - error("player_mod - attempted to set volume for channel id 0"); - for (int i = 0; i < MOD_MAXCHANS; i++) { - if (_channels[i].id == id) { - _channels[i].vol = vol; - break; - } - } -} - -void Player_MOD::setChannelPan(int id, int8 pan) { - if (id == 0) - error("player_mod - attempted to set pan for channel id 0"); - for (int i = 0; i < MOD_MAXCHANS; i++) { - if (_channels[i].id == id) { - _channels[i].pan = pan; - break; - } - } -} - -void Player_MOD::setChannelFreq(int id, int freq) { - if (id == 0) - error("player_mod - attempted to set frequency for channel id 0"); - for (int i = 0; i < MOD_MAXCHANS; i++) { - if (_channels[i].id == id) { - if (freq > 31400) // this is about as high as WinUAE goes - freq = 31400; // can't easily verify on my own Amiga - _channels[i].freq = freq; - break; - } - } -} - -void Player_MOD::do_mix(int16 *data, uint len) { - int i; - int dpos = 0; - uint dlen = 0; - memset(data, 0, 2 * len * sizeof(int16)); - while (len) { - if (_playproc) { - dlen = _mixamt - _mixpos; - if (!_mixpos) - _playproc(_playparam); - if (dlen <= len) { - _mixpos = 0; - len -= dlen; - } else { - _mixpos = len; - dlen = len; - len = 0; - } - } else { - dlen = len; - len = 0; - } - for (i = 0; i < MOD_MAXCHANS; i++) { - if (_channels[i].id) { - Audio::st_volume_t vol_l = (127 - _channels[i].pan) * _channels[i].vol / 127; - Audio::st_volume_t vol_r = (127 + _channels[i].pan) * _channels[i].vol / 127; - for (uint j = 0; j < dlen; j++) { - // simple linear resample, unbuffered - int delta = (uint32)(_channels[i].freq * 0x10000) / _sampleRate; - uint16 cfrac = ~_channels[i].ctr & 0xFFFF; - if (_channels[i].ctr + delta < 0x10000) - cfrac = delta; - _channels[i].ctr += delta; - int32 cpos = _channels[i].pos * cfrac / 0x10000; - while (_channels[i].ctr >= 0x10000) { - if (_channels[i].input->readBuffer(&_channels[i].pos, 1) != 1) { // out of data - stopChannel(_channels[i].id); - goto skipchan; // exit 2 loops at once - } - _channels[i].ctr -= 0x10000; - if (_channels[i].ctr > 0x10000) - cpos += _channels[i].pos; - else - cpos += (int32)(_channels[i].pos * (_channels[i].ctr & 0xFFFF)) / 0x10000; - } - int16 pos = 0; - // if too many samples play in a row, the calculation below will overflow and clip - // so try and split it up into pieces it can manage comfortably - while (cpos < -0x8000) { - pos -= 0x80000000 / delta; - cpos += 0x8000; - } - while (cpos > 0x7FFF) { - pos += 0x7FFF0000 / delta; - cpos -= 0x7FFF; - } - pos += cpos * 0x10000 / delta; - Audio::clampedAdd(data[(dpos + j) * 2 + 0], pos * vol_l / Audio::Mixer::kMaxMixerVolume); - Audio::clampedAdd(data[(dpos + j) * 2 + 1], pos * vol_r / Audio::Mixer::kMaxMixerVolume); - } - } -skipchan: ; // channel ran out of data - } - dpos += dlen; - } -} - -} // End of namespace Scumm diff --git a/engines/scumm/player/mod.h b/engines/scumm/player/mod.h deleted file mode 100644 index 619d83541d..0000000000 --- a/engines/scumm/player/mod.h +++ /dev/null @@ -1,100 +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 SCUMM_PLAYER_MOD_H -#define SCUMM_PLAYER_MOD_H - -#include "scumm/scumm.h" -#include "audio/audiostream.h" -#include "audio/mixer.h" - -namespace Audio { -class RateConverter; -} - -namespace Scumm { - -/** - * Generic Amiga MOD mixer - provides a 60Hz 'update' routine. - */ -class Player_MOD : public Audio::AudioStream { -public: - Player_MOD(Audio::Mixer *mixer); - virtual ~Player_MOD(); - virtual void setMusicVolume(int vol); - - virtual void startChannel(int id, void *data, int size, int rate, uint8 vol, int loopStart = 0, int loopEnd = 0, int8 pan = 0); - virtual void stopChannel(int id); - virtual void setChannelVol(int id, uint8 vol); - virtual void setChannelPan(int id, int8 pan); - virtual void setChannelFreq(int id, int freq); - - typedef void ModUpdateProc(void *param); - - virtual void setUpdateProc(ModUpdateProc *proc, void *param, int freq); - virtual void clearUpdateProc(); - - // AudioStream API - int readBuffer(int16 *buffer, const int numSamples) { - do_mix(buffer, numSamples / 2); - return numSamples; - } - bool isStereo() const { return true; } - bool endOfData() const { return false; } - int getRate() const { return _sampleRate; } - -private: - enum { - MOD_MAXCHANS = 24 - }; - - struct soundChan { - int id; - uint8 vol; - int8 pan; - uint16 freq; - - uint32 ctr; - int16 pos; - Audio::AudioStream *input; - }; - - Audio::Mixer *_mixer; - Audio::SoundHandle _soundHandle; - - uint32 _mixamt; - uint32 _mixpos; - const int _sampleRate; - - soundChan _channels[MOD_MAXCHANS]; - - uint8 _maxvol; - - virtual void do_mix(int16 *buf, uint len); - - ModUpdateProc *_playproc; - void *_playparam; -}; - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/player/nes.cpp b/engines/scumm/player/nes.cpp deleted file mode 100644 index 072f46dd5a..0000000000 --- a/engines/scumm/player/nes.cpp +++ /dev/null @@ -1,1067 +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 - * aint32 with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#ifndef DISABLE_NES_APU - -#include "engines/engine.h" -#include "scumm/player/nes.h" -#include "scumm/scumm.h" -#include "audio/mixer.h" - -namespace Scumm { - -static const byte channelMask[4] = {1, 2, 4, 8}; - -static const uint16 freqTable[64] = { - 0x07F0, 0x077E, 0x0712, 0x06AE, 0x064E, 0x05F3, 0x059E, 0x054D, - 0x0501, 0x04B9, 0x0475, 0x0435, 0x03F8, 0x03BF, 0x0389, 0x0357, - 0x0327, 0x02F9, 0x02CF, 0x02A6, 0x0280, 0x025C, 0x023A, 0x021A, - 0x01FC, 0x01DF, 0x01C4, 0x01AB, 0x0193, 0x017C, 0x0167, 0x0152, - 0x013F, 0x012D, 0x011C, 0x010C, 0x00FD, 0x00EE, 0x00E1, 0x00D4, - 0x00C8, 0x00BD, 0x00B2, 0x00A8, 0x009F, 0x0096, 0x008D, 0x0085, - 0x007E, 0x0076, 0x0070, 0x0069, 0x0063, 0x005E, 0x0058, 0x0053, - 0x004F, 0x004A, 0x0046, 0x0042, 0x003E, 0x003A, 0x0037, 0x0034 -}; - -static const byte instChannel[16] = { - 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 1, 3, 3, 3 -}; -static const byte startCmd[16] = { - 0x05, 0x03, 0x06, 0x08, 0x0B, 0x01, 0x01, 0x1A, - 0x16, 0x06, 0x04, 0x17, 0x02, 0x10, 0x0E, 0x0D -}; -static const byte releaseCmd[16] = { - 0x0F, 0x00, 0x00, 0x09, 0x00, 0x14, 0x15, 0x00, - 0x00, 0x00, 0x1B, 0x1B, 0x0F, 0x0F, 0x0F, 0x0F -}; -static const byte nextCmd[28] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0x17, 0xFF, 0x07, 0xFF, - 0xFF, 0x0A, 0x09, 0x0C, 0x00, 0x00, 0x00, 0x00, - 0x11, 0x12, 0x11, 0x03, 0xFF, 0xFF, 0x18, 0x00, - 0x19, 0x00, 0x00, 0x00 -}; -static const byte nextDelay[28] = { - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, - 0x00, 0x05, 0x08, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, - 0x03, 0x00, 0x00, 0x00 -}; - -namespace APUe { - -static const byte LengthCounts[32] = { - 0x0A,0xFE, - 0x14,0x02, - 0x28,0x04, - 0x50,0x06, - 0xA0,0x08, - 0x3C,0x0A, - 0x0E,0x0C, - 0x1A,0x0E, - - 0x0C,0x10, - 0x18,0x12, - 0x30,0x14, - 0x60,0x16, - 0xC0,0x18, - 0x48,0x1A, - 0x10,0x1C, - 0x20,0x1E -}; - -class SoundGen { -protected: - byte wavehold; - uint32 freq; // short - uint32 CurD; - -public: - byte Timer; - int32 Pos; - uint32 Cycles; // short - - inline byte GetTimer() const { return Timer; } -}; - -class Square : public SoundGen { -protected: - byte volume, envelope, duty, swpspeed, swpdir, swpstep, swpenab; - byte Vol; - byte EnvCtr, Envelope, BendCtr; - bool Enabled, ValidFreq, Active; - bool EnvClk, SwpClk; - - void CheckActive(); - -public: - void Reset(); - void Write(int Reg, byte Val); - void Run(); - void QuarterFrame(); - void HalfFrame(); -}; - -static const int8 Duties[4][8] = { - {-4,+4,-4,-4,-4,-4,-4,-4}, - {-4,+4,+4,-4,-4,-4,-4,-4}, - {-4,+4,+4,+4,+4,-4,-4,-4}, - {+4,-4,-4,+4,+4,+4,+4,+4} -}; - -void Square::Reset() { - memset(this, 0, sizeof(*this)); - Cycles = 1; - EnvCtr = 1; - BendCtr = 1; -} - -void Square::CheckActive() { - ValidFreq = (freq >= 0x8) && ((swpdir) || !((freq + (freq >> swpstep)) & 0x800)); - Active = Timer && ValidFreq; - Pos = Active ? (Duties[duty][CurD] * Vol) : 0; -} - -void Square::Write(int Reg, byte Val) { - switch (Reg) { - case 0: - volume = Val & 0xF; - envelope = Val & 0x10; - wavehold = Val & 0x20; - duty = (Val >> 6) & 0x3; - Vol = envelope ? volume : Envelope; - break; - - case 1: - swpstep = Val & 0x07; - swpdir = Val & 0x08; - swpspeed = (Val >> 4) & 0x7; - swpenab = Val & 0x80; - SwpClk = true; - break; - - case 2: - freq &= 0x700; - freq |= Val; - break; - - case 3: - freq &= 0xFF; - freq |= (Val & 0x7) << 8; - - if (Enabled) - Timer = LengthCounts[(Val >> 3) & 0x1F]; - - CurD = 0; - EnvClk = true; - break; - - case 4: - Enabled = (Val != 0); - if (!Enabled) - Timer = 0; - break; - } - CheckActive(); -} - -void Square::Run() { - Cycles = (freq + 1) << 1; - CurD = (CurD + 1) & 0x7; - - if (Active) - Pos = Duties[duty][CurD] * Vol; -} - -void Square::QuarterFrame() { - if (EnvClk) { - EnvClk = false; - Envelope = 0xF; - EnvCtr = volume + 1; - } else if (!--EnvCtr) { - EnvCtr = volume + 1; - - if (Envelope) - Envelope--; - else - Envelope = wavehold ? 0xF : 0x0; - } - - Vol = envelope ? volume : Envelope; - CheckActive(); -} - -void Square::HalfFrame() { - if (!--BendCtr) { - BendCtr = swpspeed + 1; - - if (swpenab && swpstep && ValidFreq) { - int sweep = freq >> swpstep; - // FIXME: Is -sweep or ~sweep correct??? - freq += swpdir ? -sweep : sweep; - } - } - - if (SwpClk) { - SwpClk = false; - BendCtr = swpspeed + 1; - } - - if (Timer && !wavehold) - Timer--; - - CheckActive(); -} - - -class Triangle : public SoundGen { -protected: - byte linear; - byte LinCtr; - bool Enabled, Active; - bool LinClk; - - void CheckActive(); - -public: - void Reset(); - void Write(int Reg, byte Val); - void Run(); - void QuarterFrame(); - void HalfFrame(); -}; - -static const int8 TriDuty[32] = { - -8,-7,-6,-5,-4,-3,-2,-1, - +0,+1,+2,+3,+4,+5,+6,+7, - +7,+6,+5,+4,+3,+2,+1,+0, - -1,-2,-3,-4,-5,-6,-7,-8 -}; - -void Triangle::Reset() { - memset(this, 0, sizeof(*this)); - Cycles = 1; -} - -void Triangle::CheckActive() { - Active = Timer && LinCtr; - - if (freq < 4) - Pos = 0; // beyond hearing range - else - Pos = TriDuty[CurD] * 8; -} - -void Triangle::Write(int Reg, byte Val) { - switch (Reg) { - case 0: - linear = Val & 0x7F; - wavehold = (Val >> 7) & 0x1; - break; - - case 2: - freq &= 0x700; - freq |= Val; - break; - - case 3: - freq &= 0xFF; - freq |= (Val & 0x7) << 8; - - if (Enabled) - Timer = LengthCounts[(Val >> 3) & 0x1F]; - - LinClk = true; - break; - - case 4: - Enabled = (Val != 0); - if (!Enabled) - Timer = 0; - break; - } - CheckActive(); -} - -void Triangle::Run() { - Cycles = freq + 1; - - if (Active) { - CurD++; - CurD &= 0x1F; - - if (freq < 4) - Pos = 0; // beyond hearing range - else - Pos = TriDuty[CurD] * 8; - } -} - -void Triangle::QuarterFrame() { - if (LinClk) - LinCtr = linear; - else if (LinCtr) - LinCtr--; - - if (!wavehold) - LinClk = false; - - CheckActive(); -} - -void Triangle::HalfFrame() { - if (Timer && !wavehold) - Timer--; - - CheckActive(); -} - -class Noise : public SoundGen { -protected: - byte volume, envelope, datatype; - byte Vol; - byte EnvCtr, Envelope; - bool Enabled; - bool EnvClk; - - void CheckActive(); - -public: - void Reset(); - void Write(int Reg, byte Val); - void Run(); - void QuarterFrame(); - void HalfFrame(); -}; - -static const uint32 NoiseFreq[16] = { - 0x004,0x008,0x010,0x020,0x040,0x060,0x080,0x0A0, - 0x0CA,0x0FE,0x17C,0x1FC,0x2FA,0x3F8,0x7F2,0xFE4 -}; - -void Noise::Reset() { - memset(this, 0, sizeof(*this)); - CurD = 1; - Cycles = 1; - EnvCtr = 1; - -} - -void Noise::Write(int Reg, byte Val) { - switch (Reg) { - case 0: - volume = Val & 0x0F; - envelope = Val & 0x10; - wavehold = Val & 0x20; - Vol = envelope ? volume : Envelope; - - if (Timer) - Pos = ((CurD & 0x4000) ? -2 : 2) * Vol; - break; - - case 2: - freq = Val & 0xF; - datatype = Val & 0x80; - break; - - case 3: - if (Enabled) - Timer = LengthCounts[(Val >> 3) & 0x1F]; - - EnvClk = true; - break; - - case 4: - Enabled = (Val != 0); - if (!Enabled) - Timer = 0; - break; - } -} - -void Noise::Run() { - Cycles = NoiseFreq[freq]; /* no + 1 here */ - - if (datatype) - CurD = (CurD << 1) | (((CurD >> 14) ^ (CurD >> 8)) & 0x1); - else - CurD = (CurD << 1) | (((CurD >> 14) ^ (CurD >> 13)) & 0x1); - - if (Timer) - Pos = ((CurD & 0x4000) ? -2 : 2) * Vol; -} - -void Noise::QuarterFrame() { - if (EnvClk) { - EnvClk = false; - Envelope = 0xF; - EnvCtr = volume + 1; - } else if (!--EnvCtr) { - EnvCtr = volume + 1; - - if (Envelope) - Envelope--; - else - Envelope = wavehold ? 0xF : 0x0; - } - - Vol = envelope ? volume : Envelope; - - if (Timer) - Pos = ((CurD & 0x4000) ? -2 : 2) * Vol; -} - -void Noise::HalfFrame() { - if (Timer && !wavehold) - Timer--; -} - -class APU { -protected: - int BufPos; - int SampleRate; - - Square _square0; - Square _square1; - Triangle _triangle; - Noise _noise; - - struct { - uint32 Cycles; - int Num; - } Frame; - -public: - APU(int rate) : SampleRate(rate) { - Reset(); - } - - void WriteReg(int Addr, byte Val); - byte Read4015(); - void Reset (); - int16 GetSample(); -}; - -void APU::WriteReg(int Addr, byte Val) { - switch (Addr) { - case 0x000: _square0.Write(0,Val); break; - case 0x001: _square0.Write(1,Val); break; - case 0x002: _square0.Write(2,Val); break; - case 0x003: _square0.Write(3,Val); break; - case 0x004: _square1.Write(0,Val); break; - case 0x005: _square1.Write(1,Val); break; - case 0x006: _square1.Write(2,Val); break; - case 0x007: _square1.Write(3,Val); break; - case 0x008: _triangle.Write(0,Val); break; - case 0x009: _triangle.Write(1,Val); break; - case 0x00A: _triangle.Write(2,Val); break; - case 0x00B: _triangle.Write(3,Val); break; - case 0x00C: _noise.Write(0,Val); break; - case 0x00D: _noise.Write(1,Val); break; - case 0x00E: _noise.Write(2,Val); break; - case 0x00F: _noise.Write(3,Val); break; - case 0x015: _square0.Write(4,Val & 0x1); - _square1.Write(4,Val & 0x2); - _triangle.Write(4,Val & 0x4); - _noise.Write(4,Val & 0x8); - break; - } -} - -byte APU::Read4015() { - byte result = - (( _square0.GetTimer()) ? 0x01 : 0) | - (( _square1.GetTimer()) ? 0x02 : 0) | - ((_triangle.GetTimer()) ? 0x04 : 0) | - (( _noise.GetTimer()) ? 0x08 : 0); - return result; -} - -void APU::Reset () { - BufPos = 0; - - _square0.Reset(); - _square1.Reset(); - _triangle.Reset(); - _noise.Reset(); - - Frame.Num = 0; - Frame.Cycles = 1; -} - -template<class T> -int step(T &obj, int sampcycles, uint frame_Cycles, int frame_Num) { - int samppos = 0; - while (sampcycles) { - // Compute the maximal amount we can step ahead before triggering - // an action (i.e. compute the minimum of sampcycles, frame_Cycles - // and obj.Cycles). - uint max_step = sampcycles; - if (max_step > frame_Cycles) - max_step = frame_Cycles; - if (max_step > obj.Cycles) - max_step = obj.Cycles; - - // During all but the last of these steps, we just add the value of obj.Pos - // to samppos -- so we can to that all at once with a simple multiplication: - samppos += obj.Pos * (max_step - 1); - - // Now step ahead... - sampcycles -= max_step; - frame_Cycles -= max_step; - obj.Cycles -= max_step; - - if (!frame_Cycles) { - frame_Cycles = 7457; - - if (frame_Num < 4) { - obj.QuarterFrame(); - - if (frame_Num & 1) - frame_Cycles++; - else - obj.HalfFrame(); - - frame_Num++; - } else - frame_Num = 0; - } - - if (!obj.Cycles) - obj.Run(); - - samppos += obj.Pos; - } - - return samppos; -} - -int16 APU::GetSample() { - int samppos = 0; - - const int sampcycles = 1+(1789773-BufPos-1)/SampleRate; - BufPos = BufPos + sampcycles * SampleRate - 1789773; - - samppos += step( _square0, sampcycles, Frame.Cycles, Frame.Num); - samppos += step( _square1, sampcycles, Frame.Cycles, Frame.Num); - samppos += step(_triangle, sampcycles, Frame.Cycles, Frame.Num); - samppos += step( _noise, sampcycles, Frame.Cycles, Frame.Num); - - uint tmp = sampcycles; - while (tmp >= Frame.Cycles) { - tmp -= Frame.Cycles; - Frame.Cycles = 7457; - - if (Frame.Num < 4) { - if (Frame.Num & 1) - Frame.Cycles++; - Frame.Num++; - } else - Frame.Num = 0; - } - - Frame.Cycles -= tmp; - - return (samppos << 6) / sampcycles; -} - -} // End of namespace APUe - -Player_NES::Player_NES(ScummEngine *scumm, Audio::Mixer *mixer) { - int i; - _vm = scumm; - _mixer = mixer; - _sampleRate = _mixer->getOutputRate(); - _apu = new APUe::APU(_sampleRate); - - _samples_per_frame = _sampleRate / 60; - _current_sample = 0; - - for (i = 0; i < NUMSLOTS; i++) { - _slot[i].id = -1; - _slot[i].framesleft = 0; - _slot[i].type = 0; - _slot[i].offset = 0; - _slot[i].data = NULL; - } - - for (i = 0; i < NUMCHANS; i++) { - _mchan[i].command = 0; - _mchan[i].framedelay = 0; - _mchan[i].pitch = 0; - _mchan[i].volume = 0; - _mchan[i].voldelta = 0; - _mchan[i].envflags = 0; - _mchan[i].cmdlock = 0; - } - isSFXplaying = wasSFXplaying = false; - - auxData1 = auxData2 = NULL; - numNotes = 0; - - APU_writeControl(0); - - _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); -} - -Player_NES::~Player_NES() { - _mixer->stopHandle(_soundHandle); - delete _apu; -} - -void Player_NES::setMusicVolume (int vol) { - _maxvol = vol; -} - -int Player_NES::readBuffer(int16 *buffer, const int numSamples) { - for (int n = 0; n < numSamples; n++) { - buffer[n] = _apu->GetSample() * _maxvol / 255; - _current_sample++; - - if (_current_sample == _samples_per_frame) { - _current_sample = 0; - sound_play(); - } - } - return numSamples; -} -void Player_NES::stopAllSounds() { - for (int i = 0; i < NUMSLOTS; i++) { - _slot[i].framesleft = 0; - _slot[i].type = 0; - _slot[i].id = -1; - } - - isSFXplaying = 0; - checkSilenceChannels(0); -} - -void Player_NES::stopSound(int nr) { - if (nr == -1) - return; - - for (int i = 0; i < NUMSLOTS; i++) { - if (_slot[i].id != nr) - continue; - - isSFXplaying = 0; - _slot[i].framesleft = 0; - _slot[i].type = 0; - _slot[i].id = -1; - checkSilenceChannels(i); - } -} - -void Player_NES::startSound(int nr) { - byte *data = _vm->getResourceAddress(rtSound, nr) + 2; - assert(data); - - int soundType = data[1]; - int chan = data[0]; - - if (chan == 4) { - if (_slot[2].framesleft) - return; - chan = 0; - } - - if (soundType < _slot[chan].type) - return; - - _slot[chan].type = soundType; - _slot[chan].id = nr; - _slot[chan].data = data; - _slot[chan].offset = 2; - _slot[chan].framesleft = 1; - checkSilenceChannels(chan); - if (chan == 2) { - numNotes = _slot[chan].data[2]; - auxData1 = _slot[chan].data + 3; - auxData2 = auxData1 + numNotes; - _slot[chan].data = auxData2 + numNotes; - _slot[chan].offset = 0; - - for (int i = 0; i < NUMCHANS; i++) - _mchan[i].cmdlock = 0; - } -} - -void Player_NES::checkSilenceChannels(int chan) { - for (chan--; chan >= 0; chan--) { - if (_slot[chan].framesleft) - return; - } - APU_writeControl(0); -} - -void Player_NES::sound_play() { - if (_slot[0].framesleft) - playSFX(0); - else if (_slot[1].framesleft) - playSFX(1); - - playMusic(); -} - -void Player_NES::playSFX (int nr) { - if (--_slot[nr].framesleft) - return; - - while (1) { - int a = _slot[nr].data[_slot[nr].offset++]; - if (a < 16) { - a >>= 2; - APU_writeControl(APU_readStatus() | channelMask[a]); - isSFXplaying = true; - APU_writeChannel(a, 0, _slot[nr].data[_slot[nr].offset++]); - APU_writeChannel(a, 1, _slot[nr].data[_slot[nr].offset++]); - APU_writeChannel(a, 2, _slot[nr].data[_slot[nr].offset++]); - APU_writeChannel(a, 3, _slot[nr].data[_slot[nr].offset++]); - } else if (a == 0xFE) { - _slot[nr].offset = 2; - } else if (a == 0xFF) { - _slot[nr].id = -1; - _slot[nr].type = 0; - isSFXplaying = false; - APU_writeControl(0); - - if (!nr && _slot[1].framesleft) { - _slot[1].framesleft = 1; - isSFXplaying = true; - } - return; - } else { - _slot[nr].framesleft = _slot[nr].data[_slot[nr].offset++]; - return; - } - } -} - -void Player_NES::playMusic() { - if (!_slot[2].framesleft) - return; - - if (wasSFXplaying && !isSFXplaying) - for (int x = 1; x >= 0; x--) - if (_mchan[x].cmdlock) { - _mchan[x].command = _mchan[x].cmdlock; - _mchan[x].framedelay = 1; - } - - wasSFXplaying = isSFXplaying; - if (!--_slot[2].framesleft) { -top: - int b = _slot[2].data[_slot[2].offset++]; - if (b == 0xFF) { - _slot[2].id = -1; - _slot[2].type = 0; - b = 0; - } else if (b == 0xFE) { - _slot[2].offset = 0; - goto top; - } else { - if (b < numNotes) { - int inst = auxData1[b]; - int ch = instChannel[inst]; - _mchan[ch].pitch = auxData2[b]; - _mchan[ch].cmdlock = startCmd[inst]; - _mchan[ch].command = startCmd[inst]; - _mchan[ch].framedelay = 1; - goto top; - } - b -= numNotes; - if (b < 16) { - int inst = b; - int ch = instChannel[inst]; - _mchan[ch].cmdlock = 0; - _mchan[ch].command = releaseCmd[inst]; - _mchan[ch].framedelay = 1; - goto top; - } - b -= 16; - } - _slot[2].framesleft = b; - } - - for (int x = NUMCHANS - 1; x >= 0; x--) { - if (_slot[0].framesleft || _slot[1].framesleft) { - _mchan[x].volume = 0; - _mchan[x].framedelay = 0; - continue; - } - - if (_mchan[x].framedelay && !--_mchan[x].framedelay) { - switch (_mchan[x].command) { - case 0x00: - case 0x13: - _mchan[x].voldelta = -10; - break; - - case 0x01: - case 0x03: - case 0x08: - case 0x16: - _mchan[x].envflags = 0x30; - _mchan[x].volume = 0x6F; - _mchan[x].voldelta = 0; - - APU_writeChannel(x, 0, 0x00); - APU_writeChannel(x, 1, 0x7F); - APU_writeControl(APU_readStatus() | channelMask[x]); - APU_writeChannel(x, 2, freqTable[_mchan[x].pitch] & 0xFF); - APU_writeChannel(x, 3, freqTable[_mchan[x].pitch] >> 8); - - chainCommand(x); - break; - - case 0x02: - _mchan[x].envflags = 0xB0; - _mchan[x].volume = 0x6F; - _mchan[x].voldelta = 0; - - APU_writeChannel(x, 0, 0x00); - APU_writeChannel(x, 1, 0x84); - APU_writeControl(APU_readStatus() | channelMask[x]); - APU_writeChannel(x, 2, freqTable[_mchan[x].pitch] & 0xFF); - APU_writeChannel(x, 3, freqTable[_mchan[x].pitch] >> 8); - - chainCommand(x); - break; - - case 0x04: - _mchan[x].envflags = 0x80; - _mchan[x].volume = 0x6F; - _mchan[x].voldelta = 0; - - APU_writeChannel(x, 0, 0x00); - APU_writeChannel(x, 1, 0x7F); - APU_writeControl(APU_readStatus() | channelMask[x]); - APU_writeChannel(x, 2, freqTable[_mchan[x].pitch] & 0xFF); - APU_writeChannel(x, 3, freqTable[_mchan[x].pitch] >> 8); - - chainCommand(x); - break; - - case 0x05: - _mchan[x].envflags = 0xF0; - _mchan[x].volume = 0x6F; - _mchan[x].voldelta = -15; - - APU_writeChannel(x, 1, 0x7F); - APU_writeControl(APU_readStatus() | channelMask[x]); - APU_writeChannel(x, 2, freqTable[_mchan[x].pitch] & 0xFF); - APU_writeChannel(x, 3, freqTable[_mchan[x].pitch] >> 8); - - chainCommand(x); - break; - - case 0x06: - _mchan[x].pitch += 0x18; - _mchan[x].envflags = 0x80; - _mchan[x].volume = 0x6F; - _mchan[x].voldelta = 0; - - APU_writeChannel(x, 0, 0x00); - APU_writeChannel(x, 1, 0x7F); - APU_writeControl(APU_readStatus() | channelMask[x]); - APU_writeChannel(x, 2, freqTable[_mchan[x].pitch] & 0xFF); - APU_writeChannel(x, 3, freqTable[_mchan[x].pitch] >> 8); - - chainCommand(x); - break; - - case 0x07: - APU_writeChannel(x, 2, freqTable[_mchan[x].pitch - 0x0C] & 0xFF); - APU_writeChannel(x, 3, freqTable[_mchan[x].pitch - 0x0C] >> 8); - - chainCommand(x); - break; - - case 0x09: - _mchan[x].voldelta = -2; - - APU_writeChannel(x, 1, 0x7F); - APU_writeChannel(x, 2, freqTable[_mchan[x].pitch] & 0xFF); - APU_writeChannel(x, 3, freqTable[_mchan[x].pitch] >> 8); - - chainCommand(x); - break; - - case 0x0A: - APU_writeChannel(x, 1, 0x86); - APU_writeChannel(x, 2, freqTable[_mchan[x].pitch] & 0xFF); - APU_writeChannel(x, 3, freqTable[_mchan[x].pitch] >> 8); - - chainCommand(x); - break; - - case 0x0B: case 0x1A: - _mchan[x].envflags = 0x70; - _mchan[x].volume = 0x6F; - _mchan[x].voldelta = 0; - - APU_writeChannel(x, 0, 0x00); - APU_writeChannel(x, 1, 0x7F); - APU_writeControl(APU_readStatus() | channelMask[x]); - APU_writeChannel(x, 2, freqTable[_mchan[x].pitch] & 0xFF); - APU_writeChannel(x, 3, freqTable[_mchan[x].pitch] >> 8); - - chainCommand(x); - break; - - case 0x0C: - _mchan[x].envflags = 0xB0; - - chainCommand(x); - break; - - case 0x0D: - _mchan[x].envflags = 0x30; - _mchan[x].volume = 0x5F; - _mchan[x].voldelta = -22; - - APU_writeChannel(x, 0, 0x00); - APU_writeControl(APU_readStatus() | channelMask[x]); - APU_writeChannel(x, 2, _mchan[x].pitch & 0xF); - APU_writeChannel(x, 3, 0xFF); - - chainCommand(x); - break; - - case 0x0E: - case 0x10: - _mchan[x].envflags = 0x30; - _mchan[x].volume = 0x5F; - _mchan[x].voldelta = -6; - - APU_writeChannel(x, 0, 0x00); - APU_writeControl(APU_readStatus() | channelMask[x]); - APU_writeChannel(x, 2, _mchan[x].pitch & 0xF); - APU_writeChannel(x, 3, 0xFF); - - chainCommand(x); - break; - - case 0x0F: - chainCommand(x); - break; - - case 0x11: - APU_writeChannel(x, 2, _mchan[x].pitch & 0xF); - APU_writeChannel(x, 3, 0xFF); - - chainCommand(x); - break; - - case 0x12: - APU_writeChannel(x, 2, (_mchan[x].pitch + 3) & 0xF); - APU_writeChannel(x, 3, 0xFF); - - chainCommand(x); - break; - - case 0x14: - _mchan[x].voldelta = -12; - - APU_writeChannel(x, 1, 0x8C); - - chainCommand(x); - break; - - case 0x15: - _mchan[x].voldelta = -12; - - APU_writeChannel(x, 1, 0x84); - - chainCommand(x); - break; - - case 0x17: - _mchan[x].pitch += 0x0C; - _mchan[x].envflags = 0x80; - _mchan[x].volume = 0x6F; - _mchan[x].voldelta = 0; - - APU_writeChannel(x, 0, 0x00); - APU_writeChannel(x, 1, 0x7F); - APU_writeControl(APU_readStatus() | channelMask[x]); - APU_writeChannel(x, 2, freqTable[_mchan[x].pitch] & 0xFF); - APU_writeChannel(x, 3, freqTable[_mchan[x].pitch] >> 8); - - chainCommand(x); - break; - - case 0x18: - _mchan[x].envflags = 0x70; - - chainCommand(x); - break; - - case 0x19: - _mchan[x].envflags = 0xB0; - - chainCommand(x); - break; - - case 0x1B: - _mchan[x].envflags = 0x00; - _mchan[x].voldelta = -10; - break; - } - } - - _mchan[x].volume += _mchan[x].voldelta; - - if (_mchan[x].volume < 0) - _mchan[x].volume = 0; - if (_mchan[x].volume > MAXVOLUME) - _mchan[x].volume = MAXVOLUME; - - APU_writeChannel(x, 0, (_mchan[x].volume >> 3) | _mchan[x].envflags); - } -} - -void Player_NES::chainCommand(int c) { - int i = _mchan[c].command; - _mchan[c].command = nextCmd[i]; - _mchan[c].framedelay = nextDelay[i]; -} - -int Player_NES::getSoundStatus(int nr) const { - for (int i = 0; i < NUMSLOTS; i++) - if (_slot[i].id == nr) - return 1; - return 0; -} - -void Player_NES::APU_writeChannel(int chan, int offset, byte value) { - _apu->WriteReg(0x000 + 4 * chan + offset, value); -} -void Player_NES::APU_writeControl(byte value) { - _apu->WriteReg(0x015, value); -} -byte Player_NES::APU_readStatus() { - return _apu->Read4015(); -} - -} // End of namespace Scumm - -#endif // DISABLE_NES_APU diff --git a/engines/scumm/player/nes.h b/engines/scumm/player/nes.h deleted file mode 100644 index be1617e0f6..0000000000 --- a/engines/scumm/player/nes.h +++ /dev/null @@ -1,114 +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 SCUMM_PLAYER_NES_H -#define SCUMM_PLAYER_NES_H - -#include "common/scummsys.h" -#include "scumm/music.h" -#include "audio/audiostream.h" -#include "audio/mixer.h" - -namespace Scumm { - -class ScummEngine; -namespace APUe { -class APU; -} - -static const int MAXVOLUME = 0x7F; -static const int NUMSLOTS = 3; -static const int NUMCHANS = 4; - -/** - * Scumm NES sound/music driver. - */ -class Player_NES : public Audio::AudioStream, public MusicEngine { -public: - Player_NES(ScummEngine *scumm, Audio::Mixer *mixer); - virtual ~Player_NES(); - - virtual void setMusicVolume(int vol); - virtual void startSound(int sound); - virtual void stopSound(int sound); - virtual void stopAllSounds(); - virtual int getSoundStatus(int sound) const; - - // AudioStream API - int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { return false; } - bool endOfData() const { return false; } - int getRate() const { return _sampleRate; } - -private: - - void sound_play(); - void playSFX(int nr); - void playMusic(); - byte fetchSoundByte(int nr); - void chainCommand(int chan); - void checkSilenceChannels(int chan); - - void APU_writeChannel(int chan, int offset, byte value); - void APU_writeControl(byte value); - byte APU_readStatus(); - - ScummEngine *_vm; - Audio::Mixer *_mixer; - Audio::SoundHandle _soundHandle; - APUe::APU *_apu; - int _sampleRate; - int _samples_per_frame; - int _current_sample; - int _maxvol; - - struct slot { - int framesleft; - int id; - int type; - byte *data; - int offset; - } _slot[NUMSLOTS]; - - struct mchan { - int command; - int framedelay; - int pitch; - int volume; - int voldelta; - int envflags; - int cmdlock; - } _mchan[NUMCHANS]; - - bool isSFXplaying, wasSFXplaying; - - byte *dataStart; - int numNotes; - byte *auxData1; - byte *auxData2; - - byte *soundptr; -}; - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/player/pce.cpp b/engines/scumm/player/pce.cpp deleted file mode 100644 index 0a9cbaa315..0000000000 --- a/engines/scumm/player/pce.cpp +++ /dev/null @@ -1,756 +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. - * - */ - -/* - * The PSG_HuC6280 class is based on the HuC6280 sound chip emulator - * by Charles MacDonald (E-mail: cgfm2@hotmail.com, WWW: http://cgfm2.emuviews.com) - * The implementation used here was taken from MESS (http://www.mess.org/) - * the Multiple Emulator Super System (sound/c6280.c). - * LFO and noise channel support have been removed (not used by Loom PCE). - */ - -#include <math.h> -#include "scumm/player/pce.h" -#include "common/endian.h" - -// PCE sound engine is only used by Loom, which requires 16bit color support -#ifdef USE_RGB_COLOR - -namespace Scumm { - -// CPU and PSG use the same base clock but with a different divider -const double MASTER_CLOCK = 21477270.0; // ~21.48 MHz -const double CPU_CLOCK = MASTER_CLOCK / 3; // ~7.16 MHz -const double PSG_CLOCK = MASTER_CLOCK / 6; // ~3.58 MHz -const double TIMER_CLOCK = CPU_CLOCK / 1024; // ~6.9 kHz - -// The PSG update routine is originally triggered by the timer IRQ (not by VSYNC) -// approx. 120 times per second (TIML=0x39). But as just every second call is used -// to update the PSG we will call the update routine approx. 60 times per second. -const double UPDATE_FREQ = TIMER_CLOCK / (57 + 1) / 2; // ~60 Hz - -// $AFA5 -static const byte wave_table[7][32] = { - { // sine - 0x10, 0x19, 0x1C, 0x1D, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1D, 0x1C, 0x19, - 0x10, 0x05, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x05, - }, { // mw-shaped - 0x10, 0x1C, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F, 0x1E, 0x1C, 0x1E, 0x1F, 0x1F, 0x1E, 0x1E, 0x1D, 0x1C, - 0x10, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, - }, { // square - 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - }, { // triangle - 0x10, 0x0C, 0x08, 0x04, 0x01, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 0x1F, 0x1C, 0x18, 0x14, - 0x10, 0x0C, 0x08, 0x04, 0x01, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 0x1F, 0x1C, 0x18, 0x14, - }, { // saw-tooth - 0x00, 0x01, 0x02, 0x03, 0x04, 0x06, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, - }, { // sigmoid - 0x07, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x1F, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, - 0x08, 0x06, 0x05, 0x03, 0x02, 0x01, 0x00, 0x00, 0x0F, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x16, - }, { // MW-shaped - 0x1F, 0x1E, 0x1D, 0x1D, 0x1C, 0x1A, 0x17, 0x0F, 0x0F, 0x17, 0x1A, 0x1C, 0x1D, 0x1D, 0x1E, 0x1F, - 0x00, 0x01, 0x02, 0x02, 0x03, 0x05, 0x08, 0x0F, 0x0F, 0x08, 0x05, 0x03, 0x02, 0x02, 0x01, 0x00 - } -}; - -// AEBC -static const int control_offsets[14] = { - 0, 7, 20, 33, 46, 56, 75, 88, 116, 126, 136, 152, 165, 181 -}; - -// AED8 -static const byte control_data[205] = { - /* 0*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0xFF, - /* 7*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x01, 0x00, 0xF0, 0x3A, 0x00, 0xFD, 0xFF, - /* 20*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x01, 0x00, 0xF0, 0x1D, 0x00, 0xF8, 0xFF, - /* 33*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x02, 0x00, 0xF0, 0x1E, 0x00, 0xFC, 0xFF, - /* 46*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x07, 0x00, 0xE0, 0xFF, - /* 56*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x01, 0x00, 0xD8, 0xF0, 0x00, 0xD8, 0x01, 0x00, 0x00, 0x04, 0x00, 0xF0, 0xFF, - /* 75*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x03, 0x00, 0xF8, 0x6E, 0x00, 0xFF, 0xFF, - /* 88*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x08, 0x00, 0xF0, 0xF0, 0x00, 0xD0, 0x01, 0x00, 0x00, 0x05, 0x00, 0xF0, 0xF0, 0x00, 0xB8, 0xE6, 0x80, 0xFF, 0xE6, 0x80, 0xFF, 0xFF, - /*116*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x05, 0x00, 0xD0, 0xFF, - /*126*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x04, 0x00, 0xF8, 0xFF, - /*136*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x03, 0x00, 0xF4, 0xE6, 0xC0, 0xFF, 0xE6, 0xC0, 0xFF, 0xFF, - /*152*/ 0xF0, 0x00, 0xD0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x10, 0x0E, 0x00, 0xFE, 0xFF, - /*165*/ 0xF0, 0x00, 0xA8, 0x01, 0x00, 0x00, 0x18, 0x00, 0x02, 0xE6, 0x80, 0xFE, 0xE6, 0xC0, 0xFF, 0xFF, - /*181*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x02, 0x00, 0xF8, 0x02, 0x00, 0x00, 0x02, 0x00, 0xF0, 0x01, 0x00, 0xF8, 0x02, 0x00, 0x08, 0xF1, 0x99, 0xAF -}; - -static const uint16 lookup_table[87] = { - 0x0D40, 0x0C80, 0x0BC0, 0x0B20, 0x0A80, 0x09E0, 0x0940, 0x08C0, - 0x0840, 0x07E0, 0x0760, 0x0700, 0x06A0, 0x0640, 0x05E0, 0x0590, - 0x0540, 0x04F0, 0x04A0, 0x0460, 0x0420, 0x03F0, 0x03B0, 0x0380, - 0x0350, 0x0320, 0x02F0, 0x02C8, 0x02A0, 0x0278, 0x0250, 0x0230, - 0x0210, 0x01F8, 0x01D8, 0x01C0, 0x01A8, 0x0190, 0x0178, 0x0164, - 0x0150, 0x013C, 0x0128, 0x0118, 0x0108, 0x00FC, 0x00EC, 0x00E0, - 0x00D4, 0x00C8, 0x00BC, 0x00B2, 0x00A8, 0x009E, 0x0094, 0x008C, - 0x0084, 0x007E, 0x0076, 0x0070, 0x006A, 0x0064, 0x005E, 0x0059, - 0x0054, 0x004F, 0x004A, 0x0046, 0x0042, 0x003F, 0x003B, 0x0038, - 0x0035, 0x0032, 0x0030, 0x002D, 0x002A, 0x0028, 0x0026, 0x0024, - 0x0022, 0x0020, 0x001E, 0x001C, 0x001B, 0x8E82, 0xB500 -}; - -// B27B -static const uint16 freq_offset[3] = { - 0, 2, 9 -}; - -static const uint16 freq_table[] = { - 0x0000, 0x0800, - 0xFFB0, 0xFFD1, 0xFFE8, 0xFFF1, 0x0005, 0x0000, 0x0800, - 0xFF9C, 0xFFD8, 0x0000, 0x000F, 0x0005, 0x0000, 0x0800 -}; - -static const int sound_table[13] = { - 0, 2, 3, 4, 5, 6, 7, 8, 9, 11, 1, 10, 11 -}; - -// 0xAE12 -// Note: -// - offsets relative to data_table -// - byte one of each sound was always 0x3F (= use all channels) -> removed from table -static const uint16 sounds[13][6] = { - { 481, 481, 481, 481, 481, 481 }, - { 395, 408, 467, 480, 480, 480 }, - { 85, 96, 109, 109, 109, 109 }, - { 110, 121, 134, 134, 134, 134 }, - { 135, 146, 159, 159, 159, 159 }, - { 160, 171, 184, 184, 184, 184 }, - { 185, 196, 209, 209, 209, 209 }, - { 210, 221, 234, 234, 234, 234 }, - { 235, 246, 259, 259, 259, 259 }, - { 260, 271, 284, 284, 284, 284 }, - { 285, 298, 311, 324, 335, 348 }, - { 349, 360, 361, 362, 373, 384 }, - { 0, 84, 84, 84, 84, 84 } // unused -}; - -// 0xB2A1 -static const byte data_table[482] = { - /* 0*/ 0xE2, 0x0A, 0xE1, 0x0D, 0xE6, 0xED, 0xE0, 0x0F, 0xE2, 0x00, 0xE1, 0x00, - 0xF2, 0xF2, 0xB2, 0xE1, 0x01, 0xF2, 0xF2, 0xB2, 0xE1, 0x02, 0xF2, 0xF2, - 0xB2, 0xE1, 0x03, 0xF2, 0xF2, 0xB2, 0xE1, 0x04, 0xF2, 0xF2, 0xB2, 0xE1, - 0x05, 0xF2, 0xF2, 0xB2, 0xE1, 0x06, 0xF2, 0xF2, 0xB2, 0xE1, 0x07, 0xF2, - 0xF2, 0xB2, 0xE1, 0x08, 0xF2, 0xF2, 0xB2, 0xE1, 0x09, 0xF2, 0xF2, 0xB2, - 0xE1, 0x0A, 0xF2, 0xF2, 0xB2, 0xE1, 0x0B, 0xF2, 0xF2, 0xB2, 0xE1, 0x0C, - 0xF2, 0xF2, 0xB2, 0xE1, 0x0D, 0xF2, 0xF2, 0xB2, 0xFF, 0xD1, 0x03, 0xF3, - /* 84*/ 0xFF, - - /* 85*/ 0xE2, 0x0C, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD3, 0x07, 0xFF, - /* 96*/ 0xE2, 0x06, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD4, 0xF0, 0x0C, 0x07, 0xFF, - /*109*/ 0xFF, - - /*110*/ 0xE2, 0x0C, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD3, 0x27, 0xFF, - /*121*/ 0xE2, 0x06, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD4, 0xF0, 0x0C, 0x27, 0xFF, - /*134*/ 0xFF, - - /*135*/ 0xE2, 0x0C, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD3, 0x47, 0xFF, - /*146*/ 0xE2, 0x06, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD4, 0xF0, 0x0C, 0x47, 0xFF, - /*159*/ 0xFF, - - /*160*/ 0xE2, 0x0C, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD3, 0x57, 0xFF, - /*171*/ 0xE2, 0x06, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD4, 0xF0, 0x0C, 0x57, 0xFF, - /*184*/ 0xFF, - - /*185*/ 0xE2, 0x0C, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD3, 0x77, 0xFF, - /*196*/ 0xE2, 0x06, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD4, 0xF0, 0x0C, 0x77, 0xFF, - /*209*/ 0xFF, - - /*210*/ 0xE2, 0x0C, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD3, 0x97, 0xFF, - /*221*/ 0xE2, 0x06, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD4, 0xF0, 0x0C, 0x97, 0xFF, - /*234*/ 0xFF, - - /*235*/ 0xE2, 0x0C, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD3, 0xB7, 0xFF, - /*246*/ 0xE2, 0x06, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD4, 0xF0, 0x0C, 0xB7, 0xFF, - /*259*/ 0xFF, - - /*260*/ 0xE2, 0x0C, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD4, 0x07, 0xFF, - /*271*/ 0xE2, 0x06, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD5, 0xF0, 0x0C, 0x07, 0xFF, - /*284*/ 0xFF, - - /*285*/ 0xE2, 0x0B, 0xE1, 0x04, 0xE6, 0xED, 0xE0, 0x0A, 0xD0, 0xDB, 0x14, 0x0E, 0xFF, - /*298*/ 0xE2, 0x0B, 0xE1, 0x04, 0xE6, 0xED, 0xE0, 0x0A, 0xD0, 0xDB, 0x32, 0x1E, 0xFF, - /*311*/ 0xE2, 0x0B, 0xE1, 0x0B, 0xE6, 0xED, 0xE0, 0x0A, 0xD0, 0xDB, 0x50, 0x1E, 0xFF, - /*324*/ 0xE2, 0x0B, 0xE1, 0x0B, 0xE6, 0xED, 0xE0, 0x0A, 0xD0, 0x0E, 0xFF, - /*335*/ 0xE2, 0x0B, 0xE1, 0x02, 0xE6, 0xED, 0xE0, 0x0A, 0xD0, 0xDB, 0x0A, 0x0E, 0xFF, - /*348*/ 0xFF, - - /*349*/ 0xE2, 0x03, 0xE1, 0x01, 0xE6, 0xED, 0xE0, 0x06, 0xD6, 0x17, 0xFF, - /*360*/ 0xFF, - /*361*/ 0xFF, - /*362*/ 0xE2, 0x04, 0xE1, 0x04, 0xE6, 0xED, 0xE0, 0x06, 0xD5, 0xA7, 0xFF, - /*373*/ 0xE2, 0x03, 0xE1, 0x06, 0xE6, 0xED, 0xE0, 0x06, 0xD6, 0x37, 0xFF, - /*384*/ 0xE2, 0x04, 0xE1, 0x06, 0xE6, 0xED, 0xE0, 0x06, 0xD3, 0x87, 0xFF, - - /*395*/ 0xE2, 0x0C, 0xE1, 0x00, 0xE0, 0x04, 0xE6, 0xED, 0xD4, 0x0B, 0xE8, 0x0B, 0xFF, - /*408*/ 0xE2, 0x0C, 0xE1, 0x03, 0xE0, 0x04, 0xE6, 0xED, 0xD4, 0xF0, 0x0C, 0x00, - 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, - 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, - 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, - 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xFF, - /*467*/ 0xE2, 0x0C, 0xE1, 0x00, 0xE0, 0x04, 0xE6, 0xED, 0xD4, 0x1B, 0xE8, 0x1B, 0xFF, - /*480*/ 0xFF, - - /*481*/ 0xFF -}; - - -/* - * PSG_HuC6280 - */ - -class PSG_HuC6280 { -private: - typedef struct { - uint16 frequency; - uint8 control; - uint8 balance; - uint8 waveform[32]; - uint8 index; - int16 dda; - uint32 counter; - } channel_t; - - double _clock; - double _rate; - uint8 _select; - uint8 _balance; - channel_t _channel[8]; - int16 _volumeTable[32]; - uint32 _noiseFreqTable[32]; - uint32 _waveFreqTable[4096]; - -public: - void init(); - void reset(); - void write(int offset, byte data); - void update(int16* samples, int sampleCnt); - - PSG_HuC6280(double clock, double samplerate); -}; - -PSG_HuC6280::PSG_HuC6280(double clock, double samplerate) { - _clock = clock; - _rate = samplerate; - - // Initialize PSG_HuC6280 emulator - init(); -} - -void PSG_HuC6280::init() { - int i; - double step; - - // Loudest volume level for table - double level = 65535.0 / 6.0 / 32.0; - - // Clear context - reset(); - - // Make waveform frequency table - for (i = 0; i < 4096; i++) { - step = ((_clock / _rate) * 4096) / (i+1); - _waveFreqTable[(1 + i) & 0xFFF] = (uint32)step; - } - - // Make noise frequency table - for (i = 0; i < 32; i++) { - step = ((_clock / _rate) * 32) / (i+1); - _noiseFreqTable[i] = (uint32)step; - } - - // Make volume table - // PSG_HuC6280 has 48dB volume range spread over 32 steps - step = 48.0 / 32.0; - for (i = 0; i < 31; i++) { - _volumeTable[i] = (uint16)level; - level /= pow(10.0, step / 20.0); - } - _volumeTable[31] = 0; -} - -void PSG_HuC6280::reset() { - _select = 0; - _balance = 0xFF; - memset(_channel, 0, sizeof(_channel)); - memset(_volumeTable, 0, sizeof(_volumeTable)); - memset(_noiseFreqTable, 0, sizeof(_noiseFreqTable)); - memset(_waveFreqTable, 0, sizeof(_waveFreqTable)); -} - -void PSG_HuC6280::write(int offset, byte data) { - channel_t *chan = &_channel[_select]; - - switch(offset & 0x0F) { - case 0x00: // Channel select - _select = data & 0x07; - break; - - case 0x01: // Global balance - _balance = data; - break; - - case 0x02: // Channel frequency (LSB) - chan->frequency = (chan->frequency & 0x0F00) | data; - chan->frequency &= 0x0FFF; - break; - - case 0x03: // Channel frequency (MSB) - chan->frequency = (chan->frequency & 0x00FF) | (data << 8); - chan->frequency &= 0x0FFF; - break; - - case 0x04: // Channel control (key-on, DDA mode, volume) - // 1-to-0 transition of DDA bit resets waveform index - if ((chan->control & 0x40) && ((data & 0x40) == 0)) { - chan->index = 0; - } - chan->control = data; - break; - - case 0x05: // Channel balance - chan->balance = data; - break; - - case 0x06: // Channel waveform data - switch(chan->control & 0xC0) { - case 0x00: - chan->waveform[chan->index & 0x1F] = data & 0x1F; - chan->index = (chan->index + 1) & 0x1F; - break; - - case 0x40: - break; - - case 0x80: - chan->waveform[chan->index & 0x1F] = data & 0x1F; - chan->index = (chan->index + 1) & 0x1F; - break; - - case 0xC0: - chan->dda = data & 0x1F; - break; - } - - break; - - case 0x07: // Noise control (enable, frequency) - case 0x08: // LFO frequency - case 0x09: // LFO control (enable, mode) - break; - - default: - break; - } -} - -void PSG_HuC6280::update(int16* samples, int sampleCnt) { - static const int scale_tab[] = { - 0x00, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, - 0x10, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F - }; - int ch; - int i; - - int lmal = (_balance >> 4) & 0x0F; - int rmal = (_balance >> 0) & 0x0F; - int vll, vlr; - - lmal = scale_tab[lmal]; - rmal = scale_tab[rmal]; - - // Clear buffer - memset(samples, 0, 2 * sampleCnt * sizeof(int16)); - - for (ch = 0; ch < 6; ch++) { - // Only look at enabled channels - if (_channel[ch].control & 0x80) { - int lal = (_channel[ch].balance >> 4) & 0x0F; - int ral = (_channel[ch].balance >> 0) & 0x0F; - int al = _channel[ch].control & 0x1F; - - lal = scale_tab[lal]; - ral = scale_tab[ral]; - - // Calculate volume just as the patent says - vll = (0x1F - lal) + (0x1F - al) + (0x1F - lmal); - if (vll > 0x1F) vll = 0x1F; - - vlr = (0x1F - ral) + (0x1F - al) + (0x1F - rmal); - if (vlr > 0x1F) vlr = 0x1F; - - vll = _volumeTable[vll]; - vlr = _volumeTable[vlr]; - - // Check channel mode - if (_channel[ch].control & 0x40) { - /* DDA mode */ - for (i = 0; i < sampleCnt; i++) { - samples[2*i] += (int16)(vll * (_channel[ch].dda - 16)); - samples[2*i + 1] += (int16)(vlr * (_channel[ch].dda - 16)); - } - } else { - /* Waveform mode */ - uint32 step = _waveFreqTable[_channel[ch].frequency]; - for (i = 0; i < sampleCnt; i += 1) { - int offset; - int16 data; - offset = (_channel[ch].counter >> 12) & 0x1F; - _channel[ch].counter += step; - _channel[ch].counter &= 0x1FFFF; - data = _channel[ch].waveform[offset]; - samples[2*i] += (int16)(vll * (data - 16)); - samples[2*i + 1] += (int16)(vlr * (data - 16)); - } - } - } - } -} - - -/* - * Player_PCE - */ - -void Player_PCE::PSG_Write(int reg, byte data) { - _psg->write(reg, data); -} - -void Player_PCE::setupWaveform(byte bank) { - const byte *ptr = wave_table[bank]; - PSG_Write(4, 0x40); - PSG_Write(4, 0x00); - for (int i = 0; i < 32; ++i) { - PSG_Write(6, ptr[i]); - } -} - -// A541 -void Player_PCE::procA541(channel_t *channel) { - channel->soundDataPtr = NULL; - channel->controlVecShort10 = 0; - - channel->controlVecShort03 = 0; - channel->controlVecShort06 = 0; - channel->controlVec8 = 0; - channel->controlVec9 = 0; - channel->controlVec10 = 0; - channel->soundUpdateCounter = 0; - channel->controlVec18 = 0; - channel->controlVec19 = 0; - channel->controlVec23 = false; - channel->controlVec24 = false; - channel->controlVec21 = 0; - - channel->waveformCtrl = 0x80; -} - -// A592 -void Player_PCE::startSound(int sound) { - channel_t *channel; - const uint16 *ptr = sounds[sound_table[sound]]; - - for (int i = 0; i < 6; ++i) { - channel = &channels[i]; - procA541(channel); - - channel->controlVec24 = true; - channel->waveformCtrl = 0; - channel->controlVec0 = 0; - channel->controlVec19 = 0; - channel->controlVec18 = 0; - channel->soundDataPtr = &data_table[*ptr++]; - } -} - -// A64B -void Player_PCE::updateSound() { - for (int i = 0; i < 12; i++) { - channel_t *channel = &channels[i]; - bool cond = true; - if (i < 6) { - channel->controlVec21 ^= 0xFF; - if (!channel->controlVec21) - cond = false; - } - if (cond) { - processSoundData(channel); - procAB7F(channel); - procAC24(channel); - channel->controlVec11 = (channel->controlVecShort10 >> 11) | 0x80; - channel->balance = channel->balance2; - } - } - - for (int i = 0; i < 6; ++i) { - procA731(&channels[i]); - } -} - -int Player_PCE::readBuffer(int16 *buffer, const int numSamples) { - int sampleCopyCnt; - int samplesLeft = numSamples; - - Common::StackLock lock(_mutex); - - while (true) { - // copy samples to output buffer - sampleCopyCnt = (samplesLeft < _sampleBufferCnt) ? samplesLeft : _sampleBufferCnt; - if (sampleCopyCnt > 0) { - memcpy(buffer, _sampleBuffer, sampleCopyCnt * sizeof(int16)); - buffer += sampleCopyCnt; - samplesLeft -= sampleCopyCnt; - _sampleBufferCnt -= sampleCopyCnt; - } - - if (samplesLeft == 0) - break; - - // retrieve samples for one timer period - updateSound(); - _psg->update(_sampleBuffer, _samplesPerPeriod / 2); - _sampleBufferCnt = _samplesPerPeriod; - } - - // copy remaining samples to the front of the buffer - if (_sampleBufferCnt > 0) { - memmove(&_sampleBuffer[0], - &_sampleBuffer[_samplesPerPeriod - _sampleBufferCnt], - _sampleBufferCnt * sizeof(int16)); - } - - return numSamples; -} - -void Player_PCE::procA731(channel_t *channel) { - PSG_Write(0, channel->id); - PSG_Write(2, channel->freq & 0xFF); - PSG_Write(3, (channel->freq >> 8) & 0xFF); - - int tmp = channel->controlVec11; - if ((channel->controlVec11 & 0xC0) == 0x80) { - tmp = channel->controlVec11 & 0x1F; - if (tmp != 0) { - tmp -= channel->controlVec0; - if (tmp >= 0) { - tmp |= 0x80; - } else { - tmp = 0; - } - } - } - - PSG_Write(5, channel->balance); - if ((channel->waveformCtrl & 0x80) == 0) { - channel->waveformCtrl |= 0x80; - PSG_Write(0, channel->id); - setupWaveform(channel->waveformCtrl & 0x7F); - } - - PSG_Write(4, tmp); -} - -// A793 -void Player_PCE::processSoundData(channel_t *channel) { - channel->soundUpdateCounter--; - if (channel->soundUpdateCounter > 0) { - return; - } - - while (true) { - const byte *ptr = channel->soundDataPtr; - byte value = (ptr ? *ptr++ : 0xFF); - if (value < 0xD0) { - int mult = (value & 0x0F) + 1; - channel->soundUpdateCounter = mult * channel->controlVec1; - value >>= 4; - procAA62(channel, value); - channel->soundDataPtr = ptr; - return; - } - - // jump_table (A7F7) - switch (value - 0xD0) { - case 0: /*A85A*/ - case 1: /*A85D*/ - case 2: /*A861*/ - case 3: /*A865*/ - case 4: /*A869*/ - case 5: /*A86D*/ - case 6: /*A871*/ - channel->controlVec2 = (value - 0xD0) * 12; - break; - case 11: /*A8A8*/ - channel->controlVecShort06 = (int8)*ptr++; - break; - case 16: /*A8C2*/ - channel->controlVec1 = *ptr++; - break; - case 17: /*A8CA*/ - channel->waveformCtrl = *ptr++; - break; - case 18: /*A8D2*/ - channel->controlVec10 = *ptr++; - break; - case 22: /*A8F2*/ - value = *ptr; - channel->balance = value; - channel->balance2 = value; - ptr++; - break; - case 24: /*A905*/ - channel->controlVec23 = true; - break; - case 32: /*A921*/ - ptr++; - break; - case 47: - channel->controlVec24 = false; - channel->controlVec10 &= 0x7F; - channel->controlVecShort10 &= 0x00FF; - return; - default: - // unused -> ignore - break; - } - - channel->soundDataPtr = ptr; - } -} - -void Player_PCE::procAA62(channel_t *channel, int a) { - procACEA(channel, a); - if (channel->controlVec23) { - channel->controlVec23 = false; - return; - } - - channel->controlVec18 = 0; - - channel->controlVec10 |= 0x80; - int y = channel->controlVec10 & 0x7F; - channel->controlBufferPos = &control_data[control_offsets[y]]; - channel->controlVec5 = 0; -} - -void Player_PCE::procAB7F(channel_t *channel) { - uint16 freqValue = channel->controlVecShort02; - channel->controlVecShort02 += channel->controlVecShort03; - - int pos = freq_offset[channel->controlVec19] + channel->controlVec18; - freqValue += freq_table[pos]; - if (freq_table[pos + 1] != 0x0800) { - channel->controlVec18++; - } - freqValue += channel->controlVecShort06; - - channel->freq = freqValue; -} - -void Player_PCE::procAC24(channel_t *channel) { - if ((channel->controlVec10 & 0x80) == 0) - return; - - if (channel->controlVec5 == 0) { - const byte *ctrlPtr = channel->controlBufferPos; - byte value = *ctrlPtr++; - while (value >= 0xF0) { - if (value == 0xF0) { - channel->controlVecShort10 = READ_LE_UINT16(ctrlPtr); - ctrlPtr += 2; - } else if (value == 0xFF) { - channel->controlVec10 &= 0x7F; - return; - } else { - // unused - } - value = *ctrlPtr++; - } - channel->controlVec5 = value; - channel->controlVecShort09 = READ_LE_UINT16(ctrlPtr); - ctrlPtr += 2; - channel->controlBufferPos = ctrlPtr; - } - - channel->controlVecShort10 += channel->controlVecShort09; - channel->controlVec5--; -} - -void Player_PCE::procACEA(channel_t *channel, int a) { - int x = a + - channel->controlVec2 + - channel->controlVec8 + - channel->controlVec9; - channel->controlVecShort02 = lookup_table[x]; -} - -Player_PCE::Player_PCE(ScummEngine *scumm, Audio::Mixer *mixer) { - for (int i = 0; i < 12; ++i) { - memset(&channels[i], 0, sizeof(channel_t)); - channels[i].id = i; - } - - _mixer = mixer; - _sampleRate = _mixer->getOutputRate(); - _vm = scumm; - - _samplesPerPeriod = 2 * (int)(_sampleRate / UPDATE_FREQ); - _sampleBuffer = new int16[_samplesPerPeriod]; - _sampleBufferCnt = 0; - - _psg = new PSG_HuC6280(PSG_CLOCK, _sampleRate); - - _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); -} - -Player_PCE::~Player_PCE() { - _mixer->stopHandle(_soundHandle); - delete[] _sampleBuffer; - delete _psg; -} - -void Player_PCE::stopSound(int nr) { - // TODO: implement -} - -void Player_PCE::stopAllSounds() { - // TODO: implement -} - -int Player_PCE::getSoundStatus(int nr) const { - // TODO: status for each sound - for (int i = 0; i < 6; ++i) { - if (channels[i].controlVec24) - return 1; - } - return 0; -} - -int Player_PCE::getMusicTimer() { - return 0; -} - -} // End of namespace Scumm - -#endif // USE_RGB_COLOR diff --git a/engines/scumm/player/pce.h b/engines/scumm/player/pce.h deleted file mode 100644 index 427fb1ace6..0000000000 --- a/engines/scumm/player/pce.h +++ /dev/null @@ -1,133 +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 SCUMM_PLAYER_PCE_H -#define SCUMM_PLAYER_PCE_H - -#include "common/scummsys.h" -#include "common/mutex.h" -#include "scumm/music.h" -#include "audio/audiostream.h" -#include "audio/mixer.h" - -// PCE sound engine is only used by Loom, which requires 16bit color support -#ifdef USE_RGB_COLOR - -namespace Scumm { - -class ScummEngine; -class PSG_HuC6280; - -class Player_PCE : public Audio::AudioStream, public MusicEngine { -private: - struct channel_t { - int id; - - byte controlVec0; - byte controlVec1; - byte controlVec2; - byte controlVec5; - byte balance; - byte balance2; - byte controlVec8; - byte controlVec9; - byte controlVec10; - byte controlVec11; - int16 soundUpdateCounter; - byte controlVec18; - byte controlVec19; - byte waveformCtrl; - byte controlVec21; - bool controlVec23; - bool controlVec24; - - uint16 controlVecShort02; - uint16 controlVecShort03; - int16 controlVecShort06; - uint16 freq; - uint16 controlVecShort09; - uint16 controlVecShort10; - - const byte* soundDataPtr; - const byte* controlBufferPos; - }; - -public: - Player_PCE(ScummEngine *scumm, Audio::Mixer *mixer); - virtual ~Player_PCE(); - - virtual void setMusicVolume(int vol) { _maxvol = vol; } - virtual void startSound(int sound); - virtual void stopSound(int sound); - virtual void stopAllSounds(); - virtual int getSoundStatus(int sound) const; - virtual int getMusicTimer(); - - // AudioStream API - int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { return true; } - bool endOfData() const { return false; } - int getRate() const { return _sampleRate; } - -private: - ScummEngine *_vm; - Audio::Mixer *_mixer; - Audio::SoundHandle _soundHandle; - int _sampleRate; - int _maxvol; - -private: - PSG_HuC6280 *_psg; - channel_t channels[12]; - Common::Mutex _mutex; - - // number of samples per timer period - int _samplesPerPeriod; - int16* _sampleBuffer; - int _sampleBufferCnt; - - void init(); - bool isPlaying(); - - void PSG_Write(int reg, byte data); - - void setupWaveform(byte bank); - void procA541(channel_t *channel); - void updateSound(); - void procA731(channel_t *channel); - void processSoundData(channel_t *channel); - void procA9F3(int x); - void procAA62(channel_t *channel, int a); - uint16 procAAF6(int x); - void procAB7F(channel_t *channel); - void procAC24(channel_t *channel); - void procACEA(channel_t *channel, int a); - void procAD21(int a, int x); - void procAD29(int value); - void procAD3D(int a, int x); -}; - -} // End of namespace Scumm - -#endif // USE_RGB_COLOR - -#endif diff --git a/engines/scumm/player/sid.cpp b/engines/scumm/player/sid.cpp deleted file mode 100644 index ae5346f18f..0000000000 --- a/engines/scumm/player/sid.cpp +++ /dev/null @@ -1,1384 +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 DISABLE_SID - -#include "engines/engine.h" -#include "scumm/player/sid.h" -#include "scumm/scumm.h" -#include "audio/mixer.h" - -namespace Scumm { - -/* - * The player's update() routine is called once per (NTSC/PAL) frame as it is - * called by the VIC Rasterline interrupt handler which is in turn called - * approx. 50 (PAL) or 60 (NTSC) times per second. - * The SCUMM V0/V1 music playback routines or sound data have not been adjusted - * to PAL systems. As a consequence, music is played audibly (-16%) slower - * on PAL systems. - * In addition, the SID oscillator frequency depends on the video clock too. - * As SCUMM games use an NTSC frequency table for both NTSC and PAL versions - * all tone frequencies on PAL systems are slightly (-4%) lower than on NTSC ones. - * - * For more info on the SID chip see: - * - http://www.dopeconnection.net/C64_SID.htm (German) - * For more info on the VIC chip see: - * - http://www.htu.tugraz.at/~herwig/c64/man-vic.php (German) - * - http://www.c64-wiki.de/index.php/VIC (German) - */ - -struct TimingProps { - double clockFreq; - int cyclesPerFrame; -}; - -static const TimingProps timingProps[2] = { - { 17734472.0 / 18, 312 * 63 }, // PAL: 312*63 cycles/frame @ 985248 Hz (~50Hz) - { 14318180.0 / 14, 263 * 65 } // NTSC: 263*65 cycles/frame @ 1022727 Hz (~60Hz) -}; - -static const uint8 BITMASK[7] = { - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40 -}; -static const uint8 BITMASK_INV[7] = { - 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF -}; - -static const int SID_REG_OFFSET[7] = { - 0, 7, 14, 21, 2, 9, 16 -}; - -// NTSC frequency table (also used for PAL versions). -// FREQ_TBL[i] = tone_freq[i] * 2^24 / clockFreq -static const uint16 FREQ_TBL[97] = { - 0x0000, 0x010C, 0x011C, 0x012D, 0x013E, 0x0151, 0x0166, 0x017B, - 0x0191, 0x01A9, 0x01C3, 0x01DD, 0x01FA, 0x0218, 0x0238, 0x025A, - 0x027D, 0x02A3, 0x02CC, 0x02F6, 0x0323, 0x0353, 0x0386, 0x03BB, - 0x03F4, 0x0430, 0x0470, 0x04B4, 0x04FB, 0x0547, 0x0598, 0x05ED, - 0x0647, 0x06A7, 0x070C, 0x0777, 0x07E9, 0x0861, 0x08E1, 0x0968, - 0x09F7, 0x0A8F, 0x0B30, 0x0BDA, 0x0C8F, 0x0D4E, 0x0E18, 0x0EEF, - 0x0FD2, 0x10C3, 0x11C3, 0x12D1, 0x13EF, 0x151F, 0x1660, 0x17B5, - 0x191E, 0x1A9C, 0x1C31, 0x1DDF, 0x1FA5, 0x2187, 0x2386, 0x25A2, - 0x27DF, 0x2A3E, 0x2CC1, 0x2F6B, 0x323C, 0x3539, 0x3863, 0x3BBE, - 0x3F4B, 0x430F, 0x470C, 0x4B45, 0x4FBF, 0x547D, 0x5983, 0x5ED6, - 0x6479, 0x6A73, 0x70C7, 0x777C, 0x7E97, 0x861E, 0x8E18, 0x968B, - 0x9F7E, 0xA8FA, 0xB306, 0xBDAC, 0xC8F3, 0xD4E6, 0xE18F, 0xEEF8, - 0xFD2E -}; - -static const int SONG_CHANNEL_OFFSET[3] = { 6, 8, 10 }; -static const int RES_ID_CHANNEL[3] = { 3, 4, 5 }; - -#define LOBYTE_(a) ((a) & 0xFF) -#define HIBYTE_(a) (((a) >> 8) & 0xFF) - -#define GETBIT(var, pos) ((var) & (1<<(pos))) - -void Player_SID::handleMusicBuffer() { // $33cd - int channel = 2; - while (channel >= 0) { - if ((statusBits1A & BITMASK[channel]) == 0 || - (busyChannelBits & BITMASK[channel]) != 0) { - --channel; - continue; - } - - if (setupSongFileData() == 1) - return; - - uint8* l_chanFileDataPtr = chanFileData[channel]; - - uint16 l_freq = 0; - bool l_keepFreq = false; - - int y = 0; - uint8 curByte = l_chanFileDataPtr[y++]; - - // freq or 0/0xFF - if (curByte == 0) { - func_3674(channel); - if (!isMusicPlaying) - return; - continue; - } else if (curByte == 0xFF) { - l_keepFreq = true; - } else { - l_freq = FREQ_TBL[curByte]; - } - - uint8 local1 = 0; - curByte = l_chanFileDataPtr[y++]; - bool isLastCmdByte = (curByte & 0x80) != 0; - uint16 curStepSum = stepTbl[curByte & 0x7f]; - - for (int i = 0; !isLastCmdByte && (i < 2); ++i) { - curByte = l_chanFileDataPtr[y++]; - isLastCmdByte = (curByte & 0x80) != 0; - if (curByte & 0x40) { - // note: bit used in zak theme (95) only (not used/handled in MM) - _music_timer = curByte & 0x3f; - } else { - local1 = curByte & 0x3f; - } - } - - chanFileData[channel] += y; - chanDataOffset[channel] += y; - - uint8 *l_chanBuf = getResource(RES_ID_CHANNEL[channel]); - - if (local1 != 0) { - // TODO: signed or unsigned? - uint16 offset = READ_LE_UINT16(&actSongFileData[local1*2 + 12]); - l_chanFileDataPtr = actSongFileData + offset; - - // next five bytes: freqDelta, attack, sustain and phase bit - for (int i = 0; i < 5; ++i) { - l_chanBuf[15 + i] = l_chanFileDataPtr[i]; - } - phaseBit[channel] = l_chanFileDataPtr[4]; - - for (int i = 0; i < 17; ++i) { - l_chanBuf[25 + i] = l_chanFileDataPtr[5 + i]; - } - } - - if (l_keepFreq) { - if (!releasePhase[channel]) { - l_chanBuf[10] &= 0xfe; // release phase - } - releasePhase[channel] = true; - } else { - if (releasePhase[channel]) { - l_chanBuf[19] = phaseBit[channel]; - l_chanBuf[10] |= 0x01; // attack phase - } - l_chanBuf[11] = LOBYTE_(l_freq); - l_chanBuf[12] = HIBYTE_(l_freq); - releasePhase[channel] = false; - } - - // set counter value for frequency update (freqDeltaCounter) - l_chanBuf[13] = LOBYTE_(curStepSum); - l_chanBuf[14] = HIBYTE_(curStepSum); - - _soundQueue[channel] = RES_ID_CHANNEL[channel]; - processSongData(channel); - _soundQueue[channel+4] = RES_ID_CHANNEL[channel]; - processSongData(channel+4); - --channel; - } -} - -int Player_SID::setupSongFileData() { // $36cb - // no song playing - // TODO: remove (never NULL) - if (_music == NULL) { - for (int i = 2; i >= 0; --i) { - if (songChannelBits & BITMASK[i]) { - func_3674(i); - } - } - return 1; - } - - // no new song - songFileOrChanBufData = _music; - if (_music == actSongFileData) { - return 0; - } - - // new song selected - actSongFileData = _music; - for (int i = 0; i < 3; ++i) { - chanFileData[i] = _music + chanDataOffset[i]; - } - - return -1; -} - -//x:0..2 -void Player_SID::func_3674(int channel) { // $3674 - statusBits1B &= BITMASK_INV[channel]; - if (statusBits1B == 0) { - isMusicPlaying = false; - unlockCodeLocation(); - safeUnlockResource(resID_song); - for (int i = 0; i < 3; ++i) { - safeUnlockResource(RES_ID_CHANNEL[i]); - } - } - - chanPrio[channel] = 2; - - statusBits1A &= BITMASK_INV[channel]; - phaseBit[channel] = 0; - - func_4F45(channel); -} - -void Player_SID::resetPlayerState() { // $48f7 - for (int i = 6; i >= 0; --i) - releaseChannel(i); - - isMusicPlaying = false; - unlockCodeLocation(); // does nothing - statusBits1B = 0; - statusBits1A = 0; - freeChannelCount = 3; - swapPrepared = false; - filterSwapped = false; - pulseWidthSwapped = false; - //var5163 = 0; -} - -void Player_SID::resetSID() { // $48D8 - SIDReg24 = 0x0f; - - SID_Write( 4, 0); - SID_Write(11, 0); - SID_Write(18, 0); - SID_Write(23, 0); - SID_Write(21, 0); - SID_Write(22, 0); - SID_Write(24, SIDReg24); - - resetPlayerState(); -} - -void Player_SID::update() { // $481B - if (initializing) - return; - - if (_soundInQueue) { - for (int i = 6; i >= 0; --i) { - if (_soundQueue[i] != -1) - processSongData(i); - } - _soundInQueue = false; - } - - // no sound - if (busyChannelBits == 0) - return; - - for (int i = 6; i >= 0; --i) { - if (busyChannelBits & BITMASK[i]) { - updateFreq(i); - } - } - - // seems to be used for background (prio=1?) sounds. - // If a bg sound cannot be played because all SID - // voices are used by higher priority sounds, the - // bg sound's state is updated here so it will be at - // the correct state when a voice is available again. - if (swapPrepared) { - swapVars(0, 0); - swapVarLoaded = true; - updateFreq(0); - swapVars(0, 0); - if (pulseWidthSwapped) { - swapVars(4, 1); - updateFreq(4); - swapVars(4, 1); - } - swapVarLoaded = false; - } - - for (int i = 6; i >= 0; --i) { - if (busyChannelBits & BITMASK[i]) - setSIDWaveCtrlReg(i); - }; - - if (isMusicPlaying) { - handleMusicBuffer(); - } - - return; -} - -// channel: 0..6 -void Player_SID::processSongData(int channel) { // $4939 - // always: _soundQueue[channel] != -1 - // -> channelMap[channel] != -1 - channelMap[channel] = _soundQueue[channel]; - _soundQueue[channel] = -1; - songPosUpdateCounter[channel] = 0; - - isVoiceChannel = (channel < 3); - - songFileOrChanBufOffset[channel] = vec6[channel]; - - setupSongPtr(channel); - - //vec5[channel] = songFileOrChanBufData; // not used - - if (songFileOrChanBufData == NULL) { // chanBuf (4C1C) - /* - // TODO: do we need this? - LOBYTE_(vec20[channel]) = 0; - LOBYTE_(songPosPtr[channel]) = LOBYTE_(songFileOrChanBufOffset[channel]); - */ - releaseResourceUnk(channel); - return; - } - - vec20[channel] = songFileOrChanBufData; // chanBuf (4C1C) - songPosPtr[channel] = songFileOrChanBufData + songFileOrChanBufOffset[channel]; // chanBuf (4C1C) - uint8* ptr1 = songPosPtr[channel]; - - int y = -1; - if (channel < 4) { - ++y; - if (channel == 3) { - readSetSIDFilterAndProps(&y, ptr1); - } else if (statusBits1A & BITMASK[channel]) { - ++y; - } else { // channel = 0/1/2 - waveCtrlReg[channel] = ptr1[y]; - - ++y; - if (ptr1[y] & 0x0f) { - // filter on for voice channel - SIDReg23 |= BITMASK[channel]; - } else { - // filter off for voice channel - SIDReg23 &= BITMASK_INV[channel]; - } - SID_Write(23, SIDReg23); - } - } - - saveSongPos(y, channel); - busyChannelBits |= BITMASK[channel]; - readSongChunk(channel); -} - -void Player_SID::readSetSIDFilterAndProps(int *offset, uint8* dataPtr) { // $49e7 - SIDReg23 |= dataPtr[*offset]; - SID_Write(23, SIDReg23); - ++*offset; - SIDReg24 = dataPtr[*offset]; - SID_Write(24, SIDReg24); -} - -void Player_SID::saveSongPos(int y, int channel) { - ++y; - songPosPtr[channel] += y; - songFileOrChanBufOffset[channel] += y; -} - -// channel: 0..6 -void Player_SID::updateFreq(int channel) { - isVoiceChannel = (channel < 3); - - --freqDeltaCounter[channel]; - if (freqDeltaCounter[channel] < 0) { - readSongChunk(channel); - } else { - freqReg[channel] += freqDelta[channel]; - } - setSIDFreqAS(channel); -} - -void Player_SID::resetFreqDelta(int channel) { - freqDeltaCounter[channel] = 0; - freqDelta[channel] = 0; -} - -void Player_SID::readSongChunk(int channel) { // $4a6b - while (true) { - if (setupSongPtr(channel) == 1) { - // do something with code resource - releaseResourceUnk(1); - return; - } - - uint8* ptr1 = songPosPtr[channel]; - - //curChannelActive = true; - - uint8 l_cmdByte = ptr1[0]; - if (l_cmdByte == 0) { - //curChannelActive = false; - songPosUpdateCounter[channel] = 0; - - var481A = -1; - releaseChannel(channel); - return; - } - - //vec19[channel] = l_cmdByte; - - // attack (1) / release (0) phase - if (isVoiceChannel) { - if (GETBIT(l_cmdByte, 0)) - waveCtrlReg[channel] |= 0x01; // start attack phase - else - waveCtrlReg[channel] &= 0xfe; // start release phase - } - - // channel finished bit - if (GETBIT(l_cmdByte, 1)) { - var481A = -1; - releaseChannel(channel); - return; - } - - int y = 0; - - // frequency - if (GETBIT(l_cmdByte, 2)) { - y += 2; - freqReg[channel] = READ_LE_UINT16(&ptr1[y-1]); - if (!GETBIT(l_cmdByte, 6)) { - y += 2; - freqDeltaCounter[channel] = READ_LE_UINT16(&ptr1[y-1]); - y += 2; - freqDelta[channel] = READ_LE_UINT16(&ptr1[y-1]); - } else { - resetFreqDelta(channel); - } - } else { - resetFreqDelta(channel); - } - - // attack / release - if (isVoiceChannel && GETBIT(l_cmdByte, 3)) { - // start release phase - waveCtrlReg[channel] &= 0xfe; - setSIDWaveCtrlReg(channel); - - ++y; - attackReg[channel] = ptr1[y]; - ++y; - sustainReg[channel] = ptr1[y]; - - // set attack (1) or release (0) phase - waveCtrlReg[channel] |= (l_cmdByte & 0x01); - } - - if (GETBIT(l_cmdByte, 4)) { - ++y; - uint8 curByte = ptr1[y]; - - // pulse width - if (isVoiceChannel && GETBIT(curByte, 0)) { - int reg = SID_REG_OFFSET[channel+4]; - - y += 2; - SID_Write(reg, ptr1[y-1]); - SID_Write(reg+1, ptr1[y]); - } - - if (GETBIT(curByte, 1)) { - ++y; - readSetSIDFilterAndProps(&y, ptr1); - - y += 2; - SID_Write(21, ptr1[y-1]); - SID_Write(22, ptr1[y]); - } - - if (GETBIT(curByte, 2)) { - resetFreqDelta(channel); - - y += 2; - freqDeltaCounter[channel] = READ_LE_UINT16(&ptr1[y-1]); - } - } - - // set waveform (?) - if (GETBIT(l_cmdByte, 5)) { - ++y; - waveCtrlReg[channel] = (waveCtrlReg[channel] & 0x0f) | ptr1[y]; - } - - // song position - if (GETBIT(l_cmdByte, 7)) { - if (songPosUpdateCounter[channel] == 1) { - y += 2; - --songPosUpdateCounter[channel]; - saveSongPos(y, channel); - } else { - // looping / skipping / ... - ++y; - songPosPtr[channel] -= ptr1[y]; - songFileOrChanBufOffset[channel] -= ptr1[y]; - - ++y; - if (songPosUpdateCounter[channel] == 0) { - songPosUpdateCounter[channel] = ptr1[y]; - } else { - --songPosUpdateCounter[channel]; - } - } - } else { - saveSongPos(y, channel); - return; - } - } -} - -/** - * Sets frequency, attack and sustain register - */ -void Player_SID::setSIDFreqAS(int channel) { // $4be6 - if (swapVarLoaded) - return; - int reg = SID_REG_OFFSET[channel]; - SID_Write(reg, LOBYTE_(freqReg[channel])); // freq/pulseWidth voice 1/2/3 - SID_Write(reg+1, HIBYTE_(freqReg[channel])); - if (channel < 3) { - SID_Write(reg+5, attackReg[channel]); // attack - SID_Write(reg+6, sustainReg[channel]); // sustain - } -} - -void Player_SID::setSIDWaveCtrlReg(int channel) { // $4C0D - if (channel < 3) { - int reg = SID_REG_OFFSET[channel]; - SID_Write(reg+4, waveCtrlReg[channel]); - } -} - -// channel: 0..6 -int Player_SID::setupSongPtr(int channel) { // $4C1C - //resID:5,4,3,songid - int resID = channelMap[channel]; - - // TODO: when does this happen, only if resID == 0? - if (getResource(resID) == NULL) { - releaseResourceUnk(resID); - if (resID == bgSoundResID) { - bgSoundResID = 0; - bgSoundActive = false; - swapPrepared = false; - pulseWidthSwapped = false; - } - return 1; - } - - songFileOrChanBufData = getResource(resID); // chanBuf (4C1C) - if (songFileOrChanBufData == vec20[channel]) { - return 0; - } else { - vec20[channel] = songFileOrChanBufData; - songPosPtr[channel] = songFileOrChanBufData + songFileOrChanBufOffset[channel]; - return -1; - } -} - -// ignore: no effect -// chanResIndex: 3,4,5 or 58 -void Player_SID::unlockResource(int chanResIndex) { // $4CDA - if ((resStatus[chanResIndex] & 0x7F) != 0) - --resStatus[chanResIndex]; -} - -void Player_SID::countFreeChannels() { // $4f26 - freeChannelCount = 0; - for (int i = 0; i < 3; ++i) { - if (GETBIT(usedChannelBits, i) == 0) - ++freeChannelCount; - } -} - -void Player_SID::func_4F45(int channel) { // $4F45 - if (swapVarLoaded) { - if (channel == 0) { - swapPrepared = false; - resetSwapVars(); - } - pulseWidthSwapped = false; - } else { - if (channel == 3) { - filterUsed = false; - } - - if (chanPrio[channel] == 1) { - if (var481A == 1) - prepareSwapVars(channel); - else if (channel < 3) - clearSIDWaveform(channel); - } else if (channel < 3 && bgSoundActive && swapPrepared && - !(filterSwapped && filterUsed)) - { - busyChannelBits |= BITMASK[channel]; - useSwapVars(channel); - waveCtrlReg[channel] |= 0x01; - setSIDWaveCtrlReg(channel); - - safeUnlockResource(channelMap[channel]); - return; - } - - chanPrio[channel] = 0; - usedChannelBits &= BITMASK_INV[channel]; - countFreeChannels(); - } - - int resIndex = channelMap[channel]; - channelMap[channel] = 0; - safeUnlockResource(resIndex); -} - -// chanResIndex: 3,4,5 or 58 -void Player_SID::safeUnlockResource(int resIndex) { // $4FEA - if (!isMusicPlaying) { - unlockResource(resIndex); - } -} - -void Player_SID::releaseResource(int resIndex) { // $5031 - releaseResChannels(resIndex); - if (resIndex == bgSoundResID && var481A == -1) { - safeUnlockResource(resIndex); - - bgSoundResID = 0; - bgSoundActive = false; - swapPrepared = false; - pulseWidthSwapped = false; - - resetSwapVars(); - } -} - -void Player_SID::releaseResChannels(int resIndex) { // $5070 - for (int i = 3; i >= 0; --i) { - if (resIndex == channelMap[i]) { - releaseChannel(i); - } - } -} - -void Player_SID::stopSound_intern(int soundResID) { // $5093 - for (int i = 0; i < 7; ++i) { - if (soundResID == _soundQueue[i]) { - _soundQueue[i] = -1; - } - } - var481A = -1; - releaseResource(soundResID); -} - -void Player_SID::stopMusic_intern() { // $4CAA - statusBits1B = 0; - isMusicPlaying = false; - - if (resID_song != 0) { - unlockResource(resID_song); - } - - chanPrio[0] = 2; - chanPrio[1] = 2; - chanPrio[2] = 2; - - statusBits1A = 0; - phaseBit[0] = 0; - phaseBit[1] = 0; - phaseBit[2] = 0; -} - -void Player_SID::releaseResourceUnk(int resIndex) { // $50A4 - var481A = -1; - releaseResource(resIndex); -} - -// a: 0..6 -void Player_SID::releaseChannel(int channel) { - stopChannel(channel); - if (channel >= 4) { - return; - } - if (channel < 3) { - SIDReg23Stuff = SIDReg23; - clearSIDWaveform(channel); - } - func_4F45(channel); - if (channel >= 3) { - return; - } - if ((SIDReg23 != SIDReg23Stuff) && - (SIDReg23 & 0x07) == 0) - { - if (filterUsed) { - func_4F45(3); - stopChannel(3); - } - } - - stopChannel(channel + 4); -} - -void Player_SID::clearSIDWaveform(int channel) { - if (!isMusicPlaying && var481A == -1) { - waveCtrlReg[channel] &= 0x0e; - setSIDWaveCtrlReg(channel); - } -} - -void Player_SID::stopChannel(int channel) { - songPosUpdateCounter[channel] = 0; - // clear "channel" bit - busyChannelBits &= BITMASK_INV[channel]; - if (channel >= 4) { - // pulsewidth = 0 - channelMap[channel] = 0; - } -} - -// channel: 0..6, swapIndex: 0..2 -void Player_SID::swapVars(int channel, int swapIndex) { // $51a5 - if (channel < 3) { - SWAP(attackReg[channel], swapAttack[swapIndex]); - SWAP(sustainReg[channel], swapSustain[swapIndex]); - } - //SWAP(vec5[channel], swapVec5[swapIndex]); // not used - //SWAP(vec19[channel], swapVec19[swapIndex]); // not used - - SWAP(chanPrio[channel], swapSongPrio[swapIndex]); - SWAP(channelMap[channel], swapVec479C[swapIndex]); - SWAP(songPosUpdateCounter[channel], swapSongPosUpdateCounter[swapIndex]); - SWAP(waveCtrlReg[channel], swapWaveCtrlReg[swapIndex]); - SWAP(songPosPtr[channel], swapSongPosPtr[swapIndex]); - SWAP(freqReg[channel], swapFreqReg[swapIndex]); - SWAP(freqDeltaCounter[channel], swapVec11[swapIndex]); - SWAP(freqDelta[channel], swapVec10[swapIndex]); - SWAP(vec20[channel], swapVec20[swapIndex]); - SWAP(songFileOrChanBufOffset[channel], swapVec8[swapIndex]); -} - -void Player_SID::resetSwapVars() { // $52d0 - for (int i = 0; i < 2; ++i) { - swapAttack[i] = 0; - swapSustain[i] = 0; - } - for (int i = 0; i < 3; ++i) { - swapVec5[i] = 0; - swapSongPrio[i] = 0; - swapVec479C[i] = 0; - swapVec19[i] = 0; - swapSongPosUpdateCounter[i] = 0; - swapWaveCtrlReg[i] = 0; - swapSongPosPtr[i] = 0; - swapFreqReg[i] = 0; - swapVec11[i] = 0; - swapVec10[i] = 0; - swapVec20[i] = 0; - swapVec8[i] = 0; - } -} - -void Player_SID::prepareSwapVars(int channel) { // $52E5 - if (channel >= 4) - return; - - if (channel < 3) { - if (!keepSwapVars) { - resetSwapVars(); - } - swapVars(channel, 0); - if (busyChannelBits & BITMASK[channel+4]) { - swapVars(channel+4, 1); - pulseWidthSwapped = true; - } - } else if (channel == 3) { - SIDReg24_HiNibble = SIDReg24 & 0x70; - resetSwapVars(); - keepSwapVars = true; - swapVars(3, 2); - filterSwapped = true; - } - swapPrepared = true; -} - -void Player_SID::useSwapVars(int channel) { // $5342 - if (channel >= 3) - return; - - swapVars(channel, 0); - setSIDFreqAS(channel); - if (pulseWidthSwapped) { - swapVars(channel+4, 1); - setSIDFreqAS(channel+4); - } - if (filterSwapped) { - swapVars(3, 2); - - // resonating filter freq. or voice-to-filter mapping? - SIDReg23 = (SIDReg23Stuff & 0xf0) | BITMASK[channel]; - SID_Write(23, SIDReg23); - - // filter props - SIDReg24 = (SIDReg24 & 0x0f) | SIDReg24_HiNibble; - SID_Write(24, SIDReg24); - - // filter freq. - SID_Write(21, LOBYTE_(freqReg[3])); - SID_Write(22, HIBYTE_(freqReg[3])); - } else { - SIDReg23 = SIDReg23Stuff & BITMASK_INV[channel]; - SID_Write(23, SIDReg23); - } - - swapPrepared = false; - pulseWidthSwapped = false; - keepSwapVars = false; - SIDReg24_HiNibble = 0; - filterSwapped = false; -} - -// ignore: no effect -// resIndex: 3,4,5 or 58 -void Player_SID::lockResource(int resIndex) { // $4ff4 - if (!isMusicPlaying) - ++resStatus[resIndex]; -} - -void Player_SID::reserveChannel(int channel, uint8 prioValue, int chanResIndex) { // $4ffe - if (channel == 3) { - filterUsed = true; - } else if (channel < 3) { - usedChannelBits |= BITMASK[channel]; - countFreeChannels(); - } - - chanPrio[channel] = prioValue; - lockResource(chanResIndex); -} - -// ignore: no effect -void Player_SID::unlockCodeLocation() { // $513e - resStatus[1] &= 0x80; - resStatus[2] &= 0x80; -} - -// ignore: no effect -void Player_SID::lockCodeLocation() { // $514f - resStatus[1] |= 0x01; - resStatus[2] |= 0x01; -} - -void Player_SID::initMusic(int songResIndex) { // $7de6 - unlockResource(resID_song); - - resID_song = songResIndex; - _music = getResource(resID_song); - if (_music == NULL) { - return; - } - - // song base address - uint8* songFileDataPtr = _music; - actSongFileData = _music; - - initializing = true; - _soundInQueue = false; - isMusicPlaying = false; - - unlockCodeLocation(); - resetPlayerState(); - - lockResource(resID_song); - buildStepTbl(songFileDataPtr[5]); - - // fetch sound - songChannelBits = songFileDataPtr[4]; - for (int i = 2; i >= 0; --i) { - if ((songChannelBits & BITMASK[i]) != 0) { - func_7eae(i, songFileDataPtr); - } - } - - isMusicPlaying = true; - lockCodeLocation(); - - SIDReg23 &= 0xf0; - SID_Write(23, SIDReg23); - - handleMusicBuffer(); - - initializing = false; - _soundInQueue = true; -} - -// params: -// channel: channel 0..2 -void Player_SID::func_7eae(int channel, uint8* songFileDataPtr) { - int pos = SONG_CHANNEL_OFFSET[channel]; - chanDataOffset[channel] = READ_LE_UINT16(&songFileDataPtr[pos]); - chanFileData[channel] = songFileDataPtr + chanDataOffset[channel]; - - //vec5[channel+4] = vec5[channel] = CHANNEL_BUFFER_ADDR[RES_ID_CHANNEL[channel]]; // not used - vec6[channel+4] = 0x0019; - vec6[channel] = 0x0008; - - func_819b(channel); - - waveCtrlReg[channel] = 0; -} - -void Player_SID::func_819b(int channel) { - reserveChannel(channel, 127, RES_ID_CHANNEL[channel]); - - statusBits1B |= BITMASK[channel]; - statusBits1A |= BITMASK[channel]; -} - -void Player_SID::buildStepTbl(int step) { // $82B4 - stepTbl[0] = 0; - stepTbl[1] = step - 2; - for (int i = 2; i < 33; ++i) { - stepTbl[i] = stepTbl[i-1] + step; - } -} - -int Player_SID::reserveSoundFilter(uint8 value, uint8 chanResIndex) { // $4ED0 - int channel = 3; - reserveChannel(channel, value, chanResIndex); - return channel; -} - -int Player_SID::reserveSoundVoice(uint8 value, uint8 chanResIndex) { // $4EB8 - for (int i = 2; i >= 0; --i) { - if ((usedChannelBits & BITMASK[i]) == 0) { - reserveChannel(i, value, chanResIndex); - return i; - } - } - return 0; -} - -void Player_SID::findLessPrioChannels(uint8 soundPrio) { // $4ED8 - minChanPrio = 127; - - chansWithLowerPrioCount = 0; - for (int i = 2; i >= 0; --i) { - if (usedChannelBits & BITMASK[i]) { - if (chanPrio[i] < soundPrio) - ++chansWithLowerPrioCount; - if (chanPrio[i] < minChanPrio) { - minChanPrio = chanPrio[i]; - minChanPrioIndex = i; - } - } - } - - if (chansWithLowerPrioCount == 0) - return; - - if (soundPrio >= chanPrio[3]) { - actFilterHasLowerPrio = true; - } else { - /* TODO: is this really a no-op? - if (minChanPrioIndex < chanPrio[3]) - minChanPrioIndex = minChanPrioIndex; - */ - - actFilterHasLowerPrio = false; - } -} - -void Player_SID::releaseResourceBySound(int resID) { // $5088 - var481A = 1; - releaseResource(resID); -} - -void Player_SID::readVec6Data(int x, int *offset, uint8 *songFilePtr, int chanResID) { // $4E99 - //vec5[x] = songFilePtr; - vec6[x] = songFilePtr[*offset]; - *offset += 2; - _soundQueue[x] = chanResID; -} - -int Player_SID::initSound(int soundResID) { // $4D0A - initializing = true; - - if (isMusicPlaying && (statusBits1A & 0x07) == 0x07) { - initializing = false; - return -2; - } - - uint8 *songFilePtr = getResource(soundResID); - if (songFilePtr == NULL) { - initializing = false; - return 1; - } - - uint8 soundPrio = songFilePtr[4]; - // for (mostly but not always looped) background sounds - if (soundPrio == 1) { - bgSoundResID = soundResID; - bgSoundActive = true; - } - - uint8 requestedChannels = 0; - if ((songFilePtr[5] & 0x40) == 0) { - ++requestedChannels; - if (songFilePtr[5] & 0x02) - ++requestedChannels; - if (songFilePtr[5] & 0x08) - ++requestedChannels; - } - - bool filterNeeded = (songFilePtr[5] & 0x20) != 0; - bool filterBlocked = (filterUsed && filterNeeded); - if (filterBlocked || (freeChannelCount < requestedChannels)) { - findLessPrioChannels(soundPrio); - - if ((freeChannelCount + chansWithLowerPrioCount < requestedChannels) || - (filterBlocked && !actFilterHasLowerPrio)) { - initializing = false; - return -1; - } - - if (filterBlocked) { - if (soundPrio < chanPrio[3]) { - initializing = false; - return -1; - } - - uint8 l_resID = channelMap[3]; - releaseResourceBySound(l_resID); - } - - while ((freeChannelCount < requestedChannels) || (filterNeeded && filterUsed)) { - findLessPrioChannels(soundPrio); - if (minChanPrio >= soundPrio) { - initializing = false; - return -1; - } - - uint8 l_resID = channelMap[minChanPrioIndex]; - releaseResourceBySound(l_resID); - } - } - - int x; - uint8 soundByte5 = songFilePtr[5]; - if (soundByte5 & 0x40) - x = reserveSoundFilter(soundPrio, soundResID); - else - x = reserveSoundVoice(soundPrio, soundResID); - - uint8 var4CF3 = x; - int y = 6; - if (soundByte5 & 0x01) { - x += 4; - readVec6Data(x, &y, songFilePtr, soundResID); - } - if (soundByte5 & 0x02) { - x = reserveSoundVoice(soundPrio, soundResID); - readVec6Data(x, &y, songFilePtr, soundResID); - } - if (soundByte5 & 0x04) { - x += 4; - readVec6Data(x, &y, songFilePtr, soundResID); - } - if (soundByte5 & 0x08) { - x = reserveSoundVoice(soundPrio, soundResID); - readVec6Data(x, &y, songFilePtr, soundResID); - } - if (soundByte5 & 0x10) { - x += 4; - readVec6Data(x, &y, songFilePtr, soundResID); - } - if (soundByte5 & 0x20) { - x = reserveSoundFilter(soundPrio, soundResID); - readVec6Data(x, &y, songFilePtr, soundResID); - } - - //vec5[var4CF3] = songFilePtr; - vec6[var4CF3] = y; - _soundQueue[var4CF3] = soundResID; - - initializing = false; - _soundInQueue = true; - - return soundResID; -} - -void Player_SID::unused1() { // $50AF - var481A = -1; - if (bgSoundResID != 0) { - releaseResourceUnk(bgSoundResID); - } -} - -/////////////////////////// -/////////////////////////// - -#define ZEROMEM(a) memset(a, 0, sizeof(a)) - -Player_SID::Player_SID(ScummEngine *scumm, Audio::Mixer *mixer) { - /* - * clear memory - */ - - resID_song = 0; - statusBits1A = 0; - statusBits1B = 0; - busyChannelBits = 0; - SIDReg23 = 0; - SIDReg23Stuff = 0; - SIDReg24 = 0; - bgSoundResID = 0; - freeChannelCount = 0; - usedChannelBits = 0; - var481A = 0; - songChannelBits = 0; - //var5163 = 0; - SIDReg24_HiNibble = 0; - chansWithLowerPrioCount = 0; - minChanPrio = 0; - minChanPrioIndex = 0; - - _music = NULL; - songFileOrChanBufData = NULL; - actSongFileData = NULL; - - initializing = false; - _soundInQueue = false; - isVoiceChannel = false; - isMusicPlaying = false; - swapVarLoaded = false; - bgSoundActive = false; - filterUsed = false; - pulseWidthSwapped = false; - swapPrepared = false; - filterSwapped = false; - keepSwapVars = false; - actFilterHasLowerPrio = false; - - ZEROMEM(chanFileData); - ZEROMEM(chanDataOffset); - ZEROMEM(songPosPtr); - ZEROMEM(freqReg); - ZEROMEM(vec6); - ZEROMEM(songFileOrChanBufOffset); - ZEROMEM(freqDelta); - ZEROMEM(freqDeltaCounter); - ZEROMEM(swapSongPosPtr); - ZEROMEM(swapVec5); - ZEROMEM(swapVec8); - ZEROMEM(swapVec10); - ZEROMEM(swapFreqReg); - ZEROMEM(swapVec11); - ZEROMEM(vec20); - ZEROMEM(swapVec20); - ZEROMEM(resStatus); - ZEROMEM(attackReg); - ZEROMEM(sustainReg); - ZEROMEM(phaseBit); - ZEROMEM(releasePhase); - ZEROMEM(_soundQueue); - ZEROMEM(channelMap); - ZEROMEM(songPosUpdateCounter); - ZEROMEM(chanPrio); - ZEROMEM(waveCtrlReg); - ZEROMEM(swapAttack); - ZEROMEM(swapSustain); - ZEROMEM(swapSongPrio); - ZEROMEM(swapVec479C); - ZEROMEM(swapVec19); - ZEROMEM(swapSongPosUpdateCounter); - ZEROMEM(swapWaveCtrlReg); - ZEROMEM(stepTbl); - - /* - * initialize data - */ - - const uint8 chanBuffer_const[3][45] = { - { - 0x00,0x00,0x00,0x00,0x7f,0x01,0x19,0x00, - 0x00,0x00,0x2d,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0xf0,0x40,0x10,0x04,0x00,0x00, - 0x00,0x04,0x27,0x03,0xff,0xff,0x01,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00 - }, - { - 0x00,0x00,0x00,0x00,0x7f,0x01,0x19,0x00, - 0x00,0x00,0x2d,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0xf0,0x20,0x10,0x04,0x00,0x00, - 0x00,0x04,0x27,0x03,0xff,0xff,0x02,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00 - }, - { - 0x00,0x00,0x00,0x00,0x7f,0x01,0x19,0x00, - 0x00,0x00,0x2d,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0xf0,0x20,0x10,0x04,0x00,0x00, - 0x00,0x04,0x27,0x03,0xff,0xff,0x02,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00 - } - }; - memcpy(chanBuffer, chanBuffer_const, sizeof(chanBuffer_const)); - - for (int i = 0; i < 7; ++i) { - _soundQueue[i] = -1; - }; - - _music_timer = 0; - - _mixer = mixer; - _sampleRate = _mixer->getOutputRate(); - _vm = scumm; - - // sound speed is slightly different on NTSC and PAL machines - // as the SID clock depends on the frame rate. - // ScummVM does not distinguish between NTSC and PAL targets - // so we use the NTSC timing here as the music was composed for - // NTSC systems (music on PAL systems is slower). - _videoSystem = NTSC; - _cpuCyclesLeft = 0; - - initSID(); - resetSID(); - - _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); -} - -Player_SID::~Player_SID() { - _mixer->stopHandle(_soundHandle); - delete _sid; -} - -uint8 *Player_SID::getResource(int resID) { - switch (resID) { - case 0: - return NULL; - case 3: - case 4: - case 5: - return chanBuffer[resID-3]; - default: - return _vm->getResourceAddress(rtSound, resID); - } -} - -int Player_SID::readBuffer(int16 *buffer, const int numSamples) { - int samplesLeft = numSamples; - - Common::StackLock lock(_mutex); - - while (samplesLeft > 0) { - // update SID status after each frame - if (_cpuCyclesLeft <= 0) { - update(); - _cpuCyclesLeft = timingProps[_videoSystem].cyclesPerFrame; - } - // fetch samples - int sampleCount = _sid->updateClock(_cpuCyclesLeft, (short *)buffer, samplesLeft); - samplesLeft -= sampleCount; - buffer += sampleCount; - } - - return numSamples; -} - -void Player_SID::SID_Write(int reg, uint8 data) { - _sid->write(reg, data); -} - -void Player_SID::initSID() { - _sid = new Resid::SID(); - _sid->set_sampling_parameters( - timingProps[_videoSystem].clockFreq, - _sampleRate); - _sid->enable_filter(true); - - _sid->reset(); - // Synchronize the waveform generators (must occur after reset) - _sid->write( 4, 0x08); - _sid->write(11, 0x08); - _sid->write(18, 0x08); - _sid->write( 4, 0x00); - _sid->write(11, 0x00); - _sid->write(18, 0x00); -} - -void Player_SID::startSound(int nr) { - byte *data = _vm->getResourceAddress(rtSound, nr); - assert(data); - - // WORKAROUND: - // sound[4] contains either a song prio or a music channel usage byte. - // As music channel usage is always 0x07 for all music files and - // prio 7 is never used in any sound file use this byte for auto-detection. - bool isMusic = (data[4] == 0x07); - - Common::StackLock lock(_mutex); - - if (isMusic) { - initMusic(nr); - } else { - stopSound_intern(nr); - initSound(nr); - } -} - -void Player_SID::stopSound(int nr) { - if (nr == -1) - return; - - Common::StackLock lock(_mutex); - stopSound_intern(nr); -} - -void Player_SID::stopAllSounds() { - Common::StackLock lock(_mutex); - resetPlayerState(); -} - -int Player_SID::getSoundStatus(int nr) const { - int result = 0; - - //Common::StackLock lock(_mutex); - - if (resID_song == nr && isMusicPlaying) { - result = 1; - } - - for (int i = 0; (i < 4) && (result == 0); ++i) { - if (nr == _soundQueue[i] || nr == channelMap[i]) { - result = 1; - } - } - - return result; -} - -int Player_SID::getMusicTimer() { - int result = _music_timer; - _music_timer = 0; - return result; -} - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/player/sid.h b/engines/scumm/player/sid.h deleted file mode 100644 index 12e3573575..0000000000 --- a/engines/scumm/player/sid.h +++ /dev/null @@ -1,276 +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 SCUMM_PLAYER_SID_H -#define SCUMM_PLAYER_SID_H - -#include "common/mutex.h" -#include "common/scummsys.h" -#include "scumm/music.h" -#include "audio/audiostream.h" -#include "audio/mixer.h" -#include "audio/softsynth/sid.h" - -namespace Scumm { - -// the "channel" parameters seem to be in fact SID register -// offsets. Should be replaced. -enum sid_reg_t { - FREQ_VOICE1, - FREQ_VOICE2, - FREQ_VOICE3, - FREQ_FILTER, - PULSE_VOICE1, - PULSE_VOICE2, - PULSE_VOICE3 -}; - -enum VideoStandard { - PAL, - NTSC -}; - -class ScummEngine; - -class Player_SID : public Audio::AudioStream, public MusicEngine { -public: - Player_SID(ScummEngine *scumm, Audio::Mixer *mixer); - virtual ~Player_SID(); - - virtual void setMusicVolume(int vol) { _maxvol = vol; } - virtual void startSound(int sound); - virtual void stopSound(int sound); - virtual void stopAllSounds(); - virtual int getSoundStatus(int sound) const; - virtual int getMusicTimer(); - - // AudioStream API - int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { return false; } - bool endOfData() const { return false; } - int getRate() const { return _sampleRate; } - -private: - Resid::SID *_sid; - void SID_Write(int reg, uint8 data); - void initSID(); - uint8 *getResource(int resID); - - // number of cpu cycles until next frame update - Resid::cycle_count _cpuCyclesLeft; - - ScummEngine *_vm; - Audio::Mixer *_mixer; - Audio::SoundHandle _soundHandle; - int _sampleRate; - int _maxvol; - Common::Mutex _mutex; - - VideoStandard _videoSystem; - - int _music_timer; - uint8* _music; - -private: - void initMusic(int songResIndex); // $7de6 - int initSound(int soundResID); // $4D0A - void stopSound_intern(int soundResID); // $5093 - void stopMusic_intern(); // $4CAA - - void resetSID(); // $48D8 - void update(); // $481B - void handleMusicBuffer(); - int setupSongFileData(); // $36cb - void func_3674(int channel); // $3674 - void resetPlayerState(); // $48f7 - void processSongData(int channel); // $4939 - void readSetSIDFilterAndProps(int *offset, uint8* dataPtr); // $49e7 - void saveSongPos(int y, int channel); - void updateFreq(int channel); - void resetFreqDelta(int channel); - void readSongChunk(int channel); // $4a6b - void setSIDFreqAS(int channel); // $4be6 - void setSIDWaveCtrlReg(int channel); // $4C0D - int setupSongPtr(int channel); // $4C1C - void unlockResource(int chanResIndex); // $4CDA - void countFreeChannels(); // $4f26 - void func_4F45(int channel); // $4F45 - void safeUnlockResource(int resIndex); // $4FEA - void releaseResource(int resIndex); // $5031 - void releaseResChannels(int resIndex); // $5070 - void releaseResourceUnk(int resIndex); // $50A4 - void releaseChannel(int channel); - void clearSIDWaveform(int channel); - void stopChannel(int channel); - void swapVars(int channel, int swapIndex); // $51a5 - void resetSwapVars(); // $52d0 - void prepareSwapVars(int channel); // $52E5 - void useSwapVars(int channel); // $5342 - void lockResource(int resIndex); // $4ff4 - void reserveChannel(int channel, uint8 prioValue, int chanResIndex); // $4ffe - void unlockCodeLocation(); // $513e - void lockCodeLocation(); // $514f - void func_7eae(int channel, uint8* songFileDataPtr); // $7eae - void func_819b(int channel); // $819b - void buildStepTbl(int step); // $82B4 - int reserveSoundFilter(uint8 value, uint8 chanResIndex); // $4ED0 - int reserveSoundVoice(uint8 value, uint8 chanResIndex); // $4EB8 - void findLessPrioChannels(uint8 soundPrio); // $4ED8 - void releaseResourceBySound(int resID); // $5088 - void readVec6Data(int x, int *offset, uint8 *songFilePtr, int chanResID); // $4E99 - - void unused1(); // $50AF - - uint8 chanBuffer[3][45]; - - int resID_song; - - // statusBits1A/1B are always equal - uint8 statusBits1A; - uint8 statusBits1B; - - uint8 busyChannelBits; - - uint8 SIDReg23; - uint8 SIDReg23Stuff; - uint8 SIDReg24; - - uint8* chanFileData[3]; - uint16 chanDataOffset[3]; - uint8* songPosPtr[7]; - - // 0..2: freq value voice1/2/3 - // 3: filter freq - // 4..6: pulse width - uint16 freqReg[7]; - - // start offset[i] for songFileOrChanBufData to obtain songPosPtr[i] - // vec6[0..2] = 0x0008; - // vec6[4..6] = 0x0019; - uint16 vec6[7]; - - // current offset[i] for songFileOrChanBufData to obtain songPosPtr[i] (starts with vec6[i], increased later) - uint16 songFileOrChanBufOffset[7]; - - uint16 freqDelta[7]; - int freqDeltaCounter[7]; - uint8* swapSongPosPtr[3]; - uint8* swapVec5[3]; - uint16 swapVec8[3]; - uint16 swapVec10[3]; - uint16 swapFreqReg[3]; - int swapVec11[3]; - - // never read - //uint8* vec5[7]; - // never read - //uint8 vec19[7]; - // never read (needed by scumm engine?) - //bool curChannelActive; - - uint8* vec20[7]; - - uint8* swapVec20[3]; - - // resource status (never read) - // bit7: some flag - // bit6..0: counter (use-count?), maybe just bit0 as flag (used/unused?) - uint8 resStatus[70]; - - uint8* songFileOrChanBufData; - uint8* actSongFileData; - - uint16 stepTbl[33]; - - bool initializing; - bool _soundInQueue; - bool isVoiceChannel; - - bool isMusicPlaying; - bool swapVarLoaded; - bool bgSoundActive; - bool filterUsed; - - uint8 bgSoundResID; - uint8 freeChannelCount; - - // seems to be used for managing the three voices - // bit[0..2]: 0 -> unused, 1 -> already in use - uint8 usedChannelBits; - uint8 attackReg[3]; - uint8 sustainReg[3]; - - // -1/0/1 - int var481A; - - // bit-array: 00000cba - // a/b/c: channel1/2/3 - uint8 songChannelBits; - - bool pulseWidthSwapped; - bool swapPrepared; - - // never read - //uint8 var5163; - - bool filterSwapped; - uint8 SIDReg24_HiNibble; - bool keepSwapVars; - - uint8 phaseBit[3]; - bool releasePhase[3]; - - // values: a resID or -1 - // resIDs: 3, 4, 5 or song-number - int _soundQueue[7]; - - // values: a resID or 0 - // resIDs: 3, 4, 5 or song-number - int channelMap[7]; - - uint8 songPosUpdateCounter[7]; - - // priortity of channel contents - // MM: 1: lowest .. 120: highest (1,2,A,64,6E,73,78) - // Zak: -???: lowest .. 120: highest (5,32,64,65,66,6E,78, A5,A6,AF,D7) - uint8 chanPrio[7]; - - // only [0..2] used? - uint8 waveCtrlReg[7]; - - uint8 swapAttack[2]; - uint8 swapSustain[2]; - uint8 swapSongPrio[3]; - int swapVec479C[3]; - uint8 swapVec19[3]; - uint8 swapSongPosUpdateCounter[3]; - uint8 swapWaveCtrlReg[3]; - - bool actFilterHasLowerPrio; - uint8 chansWithLowerPrioCount; - uint8 minChanPrio; - uint8 minChanPrioIndex; -}; - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/player/towns.cpp b/engines/scumm/player/towns.cpp deleted file mode 100644 index 4adb11b5a3..0000000000 --- a/engines/scumm/player/towns.cpp +++ /dev/null @@ -1,753 +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/sound.h" -#include "scumm/player/towns.h" - -namespace Scumm { - -Player_Towns::Player_Towns(ScummEngine *vm, bool isVersion2) : _vm(vm), _v2(isVersion2), _intf(0), _numSoundMax(isVersion2 ? 256 : 200), _unkFlags(0x33) { - memset(_pcmCurrentSound, 0, sizeof(_pcmCurrentSound)); -} - -void Player_Towns::setSfxVolume(int vol) { - if (!_intf) - return; - _intf->setSoundEffectVolume(vol); -} - -int Player_Towns::getSoundStatus(int sound) const { - if (!_intf) - return 0; - for (int i = 1; i < 9; i++) { - if (_pcmCurrentSound[i].index == sound) - return _intf->callback(40, 0x3f + i) ? 1 : 0; - } - return 0; -} - -void Player_Towns::saveLoadWithSerializer(Serializer *ser) { - static const SaveLoadEntry pcmEntries[] = { - MKLINE(PcmCurrentSound, index, sleInt16, VER(81)), - MKLINE(PcmCurrentSound, chan, sleInt16, VER(81)), - MKLINE(PcmCurrentSound, note, sleUint8, VER(81)), - MKLINE(PcmCurrentSound, velo, sleUint8, VER(81)), - MKLINE(PcmCurrentSound, pan, sleUint8, VER(81)), - MKLINE(PcmCurrentSound, paused, sleUint8, VER(81)), - MKLINE(PcmCurrentSound, looping, sleUint8, VER(81)), - MKLINE(PcmCurrentSound, priority, sleUint32, VER(81)), - MKEND() - }; - - for (int i = 1; i < 9; i++) { - if (!_pcmCurrentSound[i].index) - continue; - - if (_intf->callback(40, i + 0x3f)) - continue; - - _intf->callback(39, i + 0x3f); - - _pcmCurrentSound[i].index = 0; - } - - ser->saveLoadArrayOf(_pcmCurrentSound, 9, sizeof(PcmCurrentSound), pcmEntries); -} - -void Player_Towns::restoreAfterLoad() { - Common::Array<uint16> restoredSounds; - - for (int i = 1; i < 9; i++) { - if (!_pcmCurrentSound[i].index || _pcmCurrentSound[i].index == 0xffff) - continue; - - // Don't restart multichannel sounds more than once - if (Common::find(restoredSounds.begin(), restoredSounds.end(), _pcmCurrentSound[i].index) != restoredSounds.end()) - continue; - - if (!_v2) - restoredSounds.push_back(_pcmCurrentSound[i].index); - - uint8 *ptr = _vm->getResourceAddress(rtSound, _pcmCurrentSound[i].index); - if (!ptr) - continue; - - if (_vm->_game.version != 3) - ptr += 2; - - if (ptr[13]) - continue; - - playPcmTrack(_pcmCurrentSound[i].index, ptr + 6, _pcmCurrentSound[i].velo, _pcmCurrentSound[i].pan, _pcmCurrentSound[i].note, _pcmCurrentSound[i].priority); - } -} - -void Player_Towns::playPcmTrack(int sound, const uint8 *data, int velo, int pan, int note, int priority) { - if (!_intf) - return; - - const uint8 *sfxData = data + 16; - - int numChan = _v2 ? 1 : data[14]; - for (int i = 0; i < numChan; i++) { - int chan = allocatePcmChannel(sound, i, priority); - if (!chan) - return; - - _intf->callback(70, _unkFlags); - _intf->callback(3, chan + 0x3f, pan); - _intf->callback(37, chan + 0x3f, note, velo, sfxData); - - _pcmCurrentSound[chan].note = note; - _pcmCurrentSound[chan].velo = velo; - _pcmCurrentSound[chan].pan = pan; - _pcmCurrentSound[chan].paused = 0; - _pcmCurrentSound[chan].looping = READ_LE_UINT32(&sfxData[20]) ? 1 : 0; - - sfxData += (READ_LE_UINT32(&sfxData[12]) + 32); - } -} - -void Player_Towns::stopPcmTrack(int sound) { - if (!_intf) - return; - - for (int i = 1; i < 9; i++) { - if (sound == _pcmCurrentSound[i].index || !sound) { - _intf->callback(39, i + 0x3f); - _pcmCurrentSound[i].index = 0; - } - } -} - -int Player_Towns::allocatePcmChannel(int sound, int sfxChanRelIndex, uint32 priority) { - if (!_intf) - return 0; - - int chan = 0; - - if (_v2 && priority > 255) { - chan = 8; - if (_intf->callback(40, 0x47)) - _intf->callback(39, 0x47); - } else { - for (int i = 8; i; i--) { - if (!_pcmCurrentSound[i].index) { - chan = i; - continue; - } - - if (_intf->callback(40, i + 0x3f)) - continue; - - chan = i; - if (_pcmCurrentSound[chan].index == 0xffff) - _intf->callback(39, chan + 0x3f); - else - _vm->_sound->stopSound(_pcmCurrentSound[chan].index); - } - - if (!chan) { - for (int i = 1; i < 9; i++) { - if (priority >= _pcmCurrentSound[i].priority) - chan = i; - } - if (_pcmCurrentSound[chan].index == 0xffff) - _intf->callback(39, chan + 0x3f); - else - _vm->_sound->stopSound(_pcmCurrentSound[chan].index); - } - } - - if (chan) { - _pcmCurrentSound[chan].index = sound; - _pcmCurrentSound[chan].chan = sfxChanRelIndex; - _pcmCurrentSound[chan].priority = priority; - } - - return chan; -} - -Player_Towns_v1::Player_Towns_v1(ScummEngine *vm, Audio::Mixer *mixer) : Player_Towns(vm, false) { - _soundOverride = 0; - _cdaCurrentSound = _eupCurrentSound = _cdaNumLoops = 0; - _cdaForceRestart = 0; - _cdaVolLeft = _cdaVolRight = 0; - - _eupVolLeft = _eupVolRight = 0; - _eupLooping = false; - - if (_vm->_game.version == 3) { - _soundOverride = new SoundOvrParameters[_numSoundMax]; - memset(_soundOverride, 0, _numSoundMax * sizeof(SoundOvrParameters)); - } - - _driver = new TownsEuphonyDriver(mixer); -} - -Player_Towns_v1::~Player_Towns_v1() { - delete _driver; - delete[] _soundOverride; -} - -bool Player_Towns_v1::init() { - if (!_driver) - return false; - - if (!_driver->init()) - return false; - - _driver->reserveSoundEffectChannels(8); - _intf = _driver->intf(); - - // Treat all 6 fm channels and all 8 pcm channels as sound effect channels - // since music seems to exist as CD audio only in the games which use this - // MusicEngine implementation. - _intf->setSoundEffectChanMask(-1); - - setVolumeCD(255, 255); - - return true; -} - -void Player_Towns_v1::setMusicVolume(int vol) { - _driver->setMusicVolume(vol); -} - -void Player_Towns_v1::startSound(int sound) { - uint8 *ptr = _vm->getResourceAddress(rtSound, sound); - if (_vm->_game.version != 3) - ptr += 2; - - int type = ptr[13]; - - if (type == 0) { - uint8 velocity = 0; - uint8 note = 0; - - if (_vm->_game.version == 3) { - velocity = (_soundOverride[sound].vLeft + _soundOverride[sound].vRight); - note = _soundOverride[sound].note; - } - - velocity = velocity ? velocity >> 2 : ptr[14] >> 1; - uint16 len = READ_LE_UINT16(ptr) + 2; - playPcmTrack(sound, ptr + 6, velocity, 64, note ? note : (len > 50 ? ptr[50] : 60), READ_LE_UINT16(ptr + 10)); - - } else if (type == 1) { - playEuphonyTrack(sound, ptr + 6); - - } else if (type == 2) { - playCdaTrack(sound, ptr + 6); - } - - if (_vm->_game.version == 3) - _soundOverride[sound].vLeft = _soundOverride[sound].vRight = _soundOverride[sound].note = 0; -} - -void Player_Towns_v1::stopSound(int sound) { - if (sound == 0 || sound == _cdaCurrentSound) { - _cdaCurrentSound = 0; - _vm->_sound->stopCD(); - _vm->_sound->stopCDTimer(); - } - - if (sound != 0 && sound == _eupCurrentSound) { - _eupCurrentSound = 0; - _eupLooping = false; - _driver->stopParser(); - } - - stopPcmTrack(sound); -} - -void Player_Towns_v1::stopAllSounds() { - _cdaCurrentSound = 0; - _vm->_sound->stopCD(); - _vm->_sound->stopCDTimer(); - - _eupCurrentSound = 0; - _eupLooping = false; - _driver->stopParser(); - - stopPcmTrack(0); -} - -int Player_Towns_v1::getSoundStatus(int sound) const { - if (sound == _cdaCurrentSound) - return _vm->_sound->pollCD(); - if (sound == _eupCurrentSound) - return _driver->parserIsPlaying() ? 1 : 0; - return Player_Towns::getSoundStatus(sound); -} - -int32 Player_Towns_v1::doCommand(int numargs, int args[]) { - int32 res = 0; - - switch (args[0]) { - case 2: - _driver->intf()->callback(73, 0); - break; - - case 3: - restartLoopingSounds(); - break; - - case 8: - startSound(args[1]); - break; - - case 9: - _vm->_sound->stopSound(args[1]); - break; - - case 11: - stopPcmTrack(0); - break; - - case 14: - startSoundEx(args[1], args[2], args[3], args[4]); - break; - - case 15: - stopSoundSuspendLooping(args[1]); - break; - - default: - warning("Player_Towns_v1::doCommand: Unknown command %d", args[0]); - break; - } - - return res; -} - -void Player_Towns_v1::setVolumeCD(int left, int right) { - _cdaVolLeft = left & 0xff; - _cdaVolRight = right & 0xff; - _driver->setOutputVolume(1, left >> 1, right >> 1); -} - -void Player_Towns_v1::setSoundVolume(int sound, int left, int right) { - if (_soundOverride && sound > 0 && sound < _numSoundMax) { - _soundOverride[sound].vLeft = left; - _soundOverride[sound].vRight = right; - } -} - -void Player_Towns_v1::setSoundNote(int sound, int note) { - if (_soundOverride && sound > 0 && sound < _numSoundMax) - _soundOverride[sound].note = note; -} - -void Player_Towns_v1::saveLoadWithSerializer(Serializer *ser) { - _cdaCurrentSoundTemp = (_vm->_sound->pollCD() && _cdaNumLoops > 1) ? _cdaCurrentSound & 0xff : 0; - _cdaNumLoopsTemp = _cdaNumLoops & 0xff; - - static const SaveLoadEntry cdEntries[] = { - MKLINE(Player_Towns_v1, _cdaCurrentSoundTemp, sleUint8, VER(81)), - MKLINE(Player_Towns_v1, _cdaNumLoopsTemp, sleUint8, VER(81)), - MKLINE(Player_Towns_v1, _cdaVolLeft, sleUint8, VER(81)), - MKLINE(Player_Towns_v1, _cdaVolRight, sleUint8, VER(81)), - MKEND() - }; - - ser->saveLoadEntries(this, cdEntries); - - if (!_eupLooping && !_driver->parserIsPlaying()) - _eupCurrentSound = 0; - - static const SaveLoadEntry eupEntries[] = { - MKLINE(Player_Towns_v1, _eupCurrentSound, sleUint8, VER(81)), - MKLINE(Player_Towns_v1, _eupLooping, sleUint8, VER(81)), - MKLINE(Player_Towns_v1, _eupVolLeft, sleUint8, VER(81)), - MKLINE(Player_Towns_v1, _eupVolRight, sleUint8, VER(81)), - MKEND() - }; - - ser->saveLoadEntries(this, eupEntries); - - Player_Towns::saveLoadWithSerializer(ser); -} - -void Player_Towns_v1::restoreAfterLoad() { - setVolumeCD(_cdaVolLeft, _cdaVolRight); - - if (_cdaCurrentSoundTemp) { - uint8 *ptr = _vm->getResourceAddress(rtSound, _cdaCurrentSoundTemp) + 6; - if (_vm->_game.version != 3) - ptr += 2; - - if (ptr[7] == 2) { - playCdaTrack(_cdaCurrentSoundTemp, ptr, true); - _cdaCurrentSound = _cdaCurrentSoundTemp; - _cdaNumLoops = _cdaNumLoopsTemp; - } - } - - if (_eupCurrentSound) { - uint8 *ptr = _vm->getResourceAddress(rtSound, _eupCurrentSound) + 6; - if (_vm->_game.version != 3) - ptr += 2; - - if (ptr[7] == 1) { - setSoundVolume(_eupCurrentSound, _eupVolLeft, _eupVolRight); - playEuphonyTrack(_eupCurrentSound, ptr); - } - } - - Player_Towns::restoreAfterLoad(); -} - -void Player_Towns_v1::restartLoopingSounds() { - if (_cdaNumLoops && !_cdaForceRestart) - _cdaForceRestart = 1; - - for (int i = 1; i < 9; i++) { - if (!_pcmCurrentSound[i].paused) - continue; - - _pcmCurrentSound[i].paused = 0; - - uint8 *ptr = _vm->getResourceAddress(rtSound, _pcmCurrentSound[i].index); - if (!ptr) - continue; - ptr += 24; - - int c = 1; - while (_pcmCurrentSound[i].chan != c) { - ptr = ptr + READ_LE_UINT32(&ptr[12]) + 32; - c++; - } - - _driver->playSoundEffect(i + 0x3f, _pcmCurrentSound[i].note, _pcmCurrentSound[i].velo, ptr); - } - - _driver->intf()->callback(73, 1); -} - -void Player_Towns_v1::startSoundEx(int sound, int velo, int pan, int note) { - uint8 *ptr = _vm->getResourceAddress(rtSound, sound) + 2; - - if (pan > 99) - pan = 99; - - velo = velo ? (velo * ptr[14] + 50) / 100 : ptr[14]; - velo = CLIP(velo, 1, 255); - uint16 pri = READ_LE_UINT16(ptr + 10); - - if (ptr[13] == 0) { - velo >>= 1; - - if (!velo) - velo = 1; - - pan = pan ? (((pan << 7) - pan) + 50) / 100 : 64; - - playPcmTrack(sound, ptr + 6, velo ? velo : ptr[14] >> 1, pan, note ? note : ptr[50], pri); - - } else if (ptr[13] == 2) { - int volLeft = velo; - int volRight = velo; - - if (pan < 50) - volRight = ((pan * 2 + 1) * velo + 50) / 100; - else if (pan > 50) - volLeft = (((99 - pan) * 2 + 1) * velo + 50) / 100; - - setVolumeCD(volLeft, volRight); - - if (!_cdaForceRestart && sound == _cdaCurrentSound) - return; - - playCdaTrack(sound, ptr + 6, true); - } -} - -void Player_Towns_v1::stopSoundSuspendLooping(int sound) { - if (!sound) { - return; - } else if (sound == _cdaCurrentSound) { - if (_cdaNumLoops && _cdaForceRestart) - _cdaForceRestart = 1; - } else { - for (int i = 1; i < 9; i++) { - if (sound == _pcmCurrentSound[i].index) { - if (!_driver->soundEffectIsPlaying(i + 0x3f)) - continue; - _driver->stopSoundEffect(i + 0x3f); - if (_pcmCurrentSound[i].looping) - _pcmCurrentSound[i].paused = 1; - else - _pcmCurrentSound[i].index = 0; - } - } - } -} - -void Player_Towns_v1::playEuphonyTrack(int sound, const uint8 *data) { - const uint8 *pos = data + 16; - const uint8 *src = pos + data[14] * 48; - const uint8 *trackData = src + 150; - - for (int i = 0; i < 32; i++) - _driver->configChan_enable(i, *src++); - for (int i = 0; i < 32; i++) - _driver->configChan_setMode(i, 0xff); - for (int i = 0; i < 32; i++) - _driver->configChan_remap(i, *src++); - for (int i = 0; i < 32; i++) - _driver->configChan_adjustVolume(i, *src++); - for (int i = 0; i < 32; i++) - _driver->configChan_setTranspose(i, *src++); - - src += 8; - for (int i = 0; i < 6; i++) - _driver->assignChannel(i, *src++); - - for (int i = 0; i < data[14]; i++) { - _driver->loadInstrument(i, i, pos + i * 48); - _driver->intf()->callback(4, i, i); - } - - _eupVolLeft = _soundOverride[sound].vLeft; - _eupVolRight = _soundOverride[sound].vRight; - int lvl = _soundOverride[sound].vLeft + _soundOverride[sound].vRight; - if (!lvl) - lvl = data[8] + data[9]; - lvl >>= 2; - - for (int i = 0; i < 6; i++) - _driver->chanVolume(i, lvl); - - uint32 trackSize = READ_LE_UINT32(src); - src += 4; - uint8 startTick = *src++; - - _driver->setMusicTempo(*src++); - _driver->startMusicTrack(trackData, trackSize, startTick); - - _eupLooping = (*src != 1) ? 1 : 0; - _driver->setMusicLoop(_eupLooping != 0); - _driver->continueParsing(); - _eupCurrentSound = sound; -} - -void Player_Towns_v1::playCdaTrack(int sound, const uint8 *data, bool skipTrackVelo) { - const uint8 *ptr = data; - - if (!sound) - return; - - if (!skipTrackVelo) { - if (_vm->_game.version == 3) { - if (_soundOverride[sound].vLeft + _soundOverride[sound].vRight) - setVolumeCD(_soundOverride[sound].vLeft, _soundOverride[sound].vRight); - else - setVolumeCD(ptr[8], ptr[9]); - } else { - setVolumeCD(ptr[8], ptr[9]); - } - } - - if (sound == _cdaCurrentSound && _vm->_sound->pollCD() == 1) - return; - - ptr += 16; - - int track = ptr[0]; - _cdaNumLoops = ptr[1]; - int start = (ptr[2] * 60 + ptr[3]) * 75 + ptr[4]; - int end = (ptr[5] * 60 + ptr[6]) * 75 + ptr[7]; - - _vm->_sound->playCDTrack(track, _cdaNumLoops == 0xff ? -1 : _cdaNumLoops, start, end <= start ? 0 : end - start); - _cdaForceRestart = 0; - _cdaCurrentSound = sound; -} - -Player_Towns_v2::Player_Towns_v2(ScummEngine *vm, Audio::Mixer *mixer, IMuse *imuse, bool disposeIMuse) : Player_Towns(vm, true), _imuse(imuse), _imuseDispose(disposeIMuse), _sblData(0) { - _soundOverride = new SoundOvrParameters[_numSoundMax]; - memset(_soundOverride, 0, _numSoundMax * sizeof(SoundOvrParameters)); - _intf = new TownsAudioInterface(mixer, 0); -} - -Player_Towns_v2::~Player_Towns_v2() { - delete _intf; - _intf = 0; - - if (_imuseDispose) - delete _imuse; - - delete[] _sblData; - delete[] _soundOverride; -} - -bool Player_Towns_v2::init() { - if (!_intf) - return false; - - if (!_intf->init()) - return false; - - _intf->callback(33, 8); - _intf->setSoundEffectChanMask(~0x3f); - - return true; -} - -void Player_Towns_v2::setMusicVolume(int vol) { - _imuse->setMusicVolume(vol); -} - -int Player_Towns_v2::getSoundStatus(int sound) const { - if (_soundOverride[sound].type == 7) - return Player_Towns::getSoundStatus(sound); - return _imuse->getSoundStatus(sound); -} - -void Player_Towns_v2::startSound(int sound) { - uint8 *ptr = _vm->getResourceAddress(rtSound, sound); - - if (READ_BE_UINT32(ptr) == MKTAG('T','O','W','S')) { - _soundOverride[sound].type = 7; - uint8 velo = _soundOverride[sound].velo ? _soundOverride[sound].velo - 1: (ptr[10] + ptr[11] + 1) >> 1; - uint8 pan = _soundOverride[sound].pan ? _soundOverride[sound].pan - 1 : 64; - uint8 pri = ptr[9]; - _soundOverride[sound].velo = _soundOverride[sound].pan = 0; - playPcmTrack(sound, ptr + 8, velo, pan, ptr[52], pri); - - } else if (READ_BE_UINT32(ptr) == MKTAG('S','B','L',' ')) { - _soundOverride[sound].type = 5; - playVocTrack(ptr + 27); - - } else { - _soundOverride[sound].type = 3; - _imuse->startSound(sound); - } -} - -void Player_Towns_v2::stopSound(int sound) { - if (_soundOverride[sound].type == 7) { - stopPcmTrack(sound); - } else { - _imuse->stopSound(sound); - } -} - -void Player_Towns_v2::stopAllSounds() { - stopPcmTrack(0); - _imuse->stopAllSounds(); -} - -int32 Player_Towns_v2::doCommand(int numargs, int args[]) { - int32 res = -1; - uint8 *ptr = 0; - - switch (args[0]) { - case 8: - startSound(args[1]); - res = 0; - break; - - case 9: - case 15: - stopSound(args[1]); - res = 0; - break; - - case 11: - stopPcmTrack(0); - break; - - case 13: - res = getSoundStatus(args[1]); - break; - - case 258: - if (_soundOverride[args[1]].type == 0) { - ptr = _vm->getResourceAddress(rtSound, args[1]); - if (READ_BE_UINT32(ptr) == MKTAG('T','O','W','S')) - _soundOverride[args[1]].type = 7; - } - if (_soundOverride[args[1]].type == 7) { - _soundOverride[args[1]].velo = args[2] + 1; - res = 0; - } - break; - - case 259: - if (_soundOverride[args[1]].type == 0) { - ptr = _vm->getResourceAddress(rtSound, args[1]); - if (READ_BE_UINT32(ptr) == MKTAG('T','O','W','S')) - _soundOverride[args[1]].type = 7; - } - if (_soundOverride[args[1]].type == 7) { - _soundOverride[args[1]].pan = 64 - CLIP<int>(args[2], -63, 63); - res = 0; - } - break; - - default: - break; - } - - if (res == -1) - return _imuse->doCommand(numargs, args); - - return res; -} - -void Player_Towns_v2::saveLoadWithSerializer(Serializer *ser) { - if (ser->getVersion() >= 83) - Player_Towns::saveLoadWithSerializer(ser); -} - -void Player_Towns_v2::playVocTrack(const uint8 *data) { - static const uint8 header[] = { - 0x54, 0x61, 0x6C, 0x6B, 0x69, 0x65, 0x20, 0x20, - 0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x36, 0x04, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00 - }; - - uint32 len = (READ_LE_UINT32(data) >> 8) - 2; - - int chan = allocatePcmChannel(0xffff, 0, 0x1000); - if (!chan) - return; - - delete[] _sblData; - _sblData = new uint8[len + 32]; - - memcpy(_sblData, header, 32); - WRITE_LE_UINT32(_sblData + 12, len); - - const uint8 *src = data + 6; - uint8 *dst = _sblData + 32; - for (uint32 i = 0; i < len; i++) - *dst++ = *src & 0x80 ? (*src++ & 0x7f) : -*src++; - - _intf->callback(37, 0x3f + chan, 60, 127, _sblData); - _pcmCurrentSound[chan].paused = 0; -} - -} // End of namespace Scumm diff --git a/engines/scumm/player/towns.h b/engines/scumm/player/towns.h deleted file mode 100644 index 5c76d7c6c7..0000000000 --- a/engines/scumm/player/towns.h +++ /dev/null @@ -1,180 +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 SCUMM_PLAYER_TOWNS_H -#define SCUMM_PLAYER_TOWNS_H - -#include "scumm/scumm.h" -#include "scumm/imuse/imuse.h" -#include "audio/softsynth/fmtowns_pc98/towns_euphony.h" -#include "audio/softsynth/fmtowns_pc98/towns_midi.h" - -namespace Scumm { - -class Player_Towns : public MusicEngine { -public: - Player_Towns(ScummEngine *vm, bool isVersion2); - virtual ~Player_Towns() {} - - virtual bool init() = 0; - - void setSfxVolume(int vol); - - int getSoundStatus(int sound) const; - - virtual int32 doCommand(int numargs, int args[]) = 0; - - virtual void saveLoadWithSerializer(Serializer *ser); - virtual void restoreAfterLoad(); - - // version 1 specific - virtual int getCurrentCdaSound() { return 0; } - virtual int getCurrentCdaVolume() { return 0; } - virtual void setVolumeCD(int left, int right) {} - virtual void setSoundVolume(int sound, int left, int right) {} - virtual void setSoundNote(int sound, int note) {} - -protected: - void playPcmTrack(int sound, const uint8 *data, int velo = 0, int pan = 64, int note = 0, int priority = 0); - void stopPcmTrack(int sound); - - int allocatePcmChannel(int sound, int sfxChanRelIndex, uint32 priority); - - struct PcmCurrentSound { - uint16 index; - uint16 chan; - uint8 note; - uint8 velo; - uint8 pan; - uint8 paused; - uint8 looping; - uint32 priority; - } _pcmCurrentSound[9]; - - uint8 _unkFlags; - - TownsAudioInterface *_intf; - ScummEngine *_vm; - - const int _numSoundMax; - const bool _v2; -}; - -class Player_Towns_v1 : public Player_Towns { -public: - Player_Towns_v1(ScummEngine *vm, Audio::Mixer *mixer); - ~Player_Towns_v1(); - - bool init(); - - void setMusicVolume(int vol); - void startSound(int sound); - void stopSound(int sound); - void stopAllSounds(); - - int getSoundStatus(int sound) const; - int getCurrentCdaSound() { return _cdaCurrentSound; } - int getCurrentCdaVolume() { return (_cdaVolLeft + _cdaVolRight + 1) >> 1; } - - int32 doCommand(int numargs, int args[]); - - void setVolumeCD(int left, int right); - void setSoundVolume(int sound, int left, int right); - void setSoundNote(int sound, int note); - - void saveLoadWithSerializer(Serializer *ser); - void restoreAfterLoad(); - - TownsEuphonyDriver *driver() { return _driver; } - -private: - void restartLoopingSounds(); - void startSoundEx(int sound, int velo, int pan, int note); - void stopSoundSuspendLooping(int sound); - - void playEuphonyTrack(int sound, const uint8 *data); - void playCdaTrack(int sound, const uint8 *data, bool skipTrackVelo = false); - - struct SoundOvrParameters { - uint8 vLeft; - uint8 vRight; - uint8 note; - }; - - SoundOvrParameters *_soundOverride; - - uint8 _cdaVolLeft; - uint8 _cdaVolRight; - - uint8 _eupCurrentSound; - uint8 _eupLooping; - uint8 _eupVolLeft; - uint8 _eupVolRight; - - uint8 _cdaCurrentSound; - uint8 _cdaNumLoops; - uint8 _cdaForceRestart; - - uint8 _cdaCurrentSoundTemp; - uint8 _cdaNumLoopsTemp; - - TownsEuphonyDriver *_driver; -}; - -class Player_Towns_v2 : public Player_Towns { -public: - Player_Towns_v2(ScummEngine *vm, Audio::Mixer *mixer, IMuse *imuse, bool disposeIMuse); - ~Player_Towns_v2(); - - bool init(); - - void setMusicVolume(int vol); - - int getSoundStatus(int sound) const; - void startSound(int sound); - void stopSound(int sound); - void stopAllSounds(); - - int32 doCommand(int numargs, int args[]); - - void saveLoadWithSerializer(Serializer *ser); - -private: - void playVocTrack(const uint8 *data); - - struct SoundOvrParameters { - uint8 velo; - uint8 pan; - uint8 type; - }; - - SoundOvrParameters *_soundOverride; - - uint8 *_sblData; - - IMuse *_imuse; - const bool _imuseDispose; -}; - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/player/v1.cpp b/engines/scumm/player/v1.cpp deleted file mode 100644 index 25f42f143c..0000000000 --- a/engines/scumm/player/v1.cpp +++ /dev/null @@ -1,607 +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 "engines/engine.h" -#include "scumm/player/v1.h" -#include "scumm/scumm.h" - -namespace Scumm { - -#define FB_WNOISE 0x12000 /* feedback for white noise */ -#define FB_PNOISE 0x08000 /* feedback for periodic noise */ - -#define TIMER_BASE_FREQ 1193000 -#define FIXP_SHIFT 16 - -Player_V1::Player_V1(ScummEngine *scumm, Audio::Mixer *mixer, bool pcjr) - : Player_V2(scumm, mixer, pcjr) { - // Initialize channel code - for (int i = 0; i < 4; ++i) - clear_channel(i); - - _mplex_step = (_sampleRate << FIXP_SHIFT) / 1193000; - _next_chunk = _repeat_chunk = 0; - _forced_level = 0; - _random_lsr = 0; -} - -Player_V1::~Player_V1() { -} - -void Player_V1::chainSound(int nr, byte *data) { - uint i; - for (i = 0; i < 4; ++i) - clear_channel(i); - - _current_nr = nr; - _current_data = data; - _repeat_chunk = _next_chunk = data + (_pcjr ? 2 : 4); - - debug(4, "Chaining new sound %d", nr); - if (_pcjr) - parsePCjrChunk(); - else - parseSpeakerChunk(); -} - -void Player_V1::startSound(int nr) { - Common::StackLock lock(_mutex); - - byte *data = _vm->getResourceAddress(rtSound, nr); - assert(data); - - int offset = _pcjr ? READ_LE_UINT16(data+4) : 6; - int cprio = _current_data ? *(_current_data) & 0x7f : 0; - int prio = *(data + offset) & 0x7f; - int restartable = *(data + offset) & 0x80; - - debug(4, "startSound %d: prio %d%s, cprio %d", - nr, prio, restartable ? " restartable" : "", cprio); - - if (!_current_nr || cprio <= prio) { - if (_current_data && (*(_current_data) & 0x80)) { - _next_nr = _current_nr; - _next_data = _current_data; - } - - chainSound(nr, data + offset); - } -} - -void Player_V1::stopAllSounds() { - Common::StackLock lock(_mutex); - - for (int i = 0; i < 4; i++) - clear_channel(i); - _repeat_chunk = _next_chunk = 0; - _next_nr = _current_nr = 0; - _next_data = _current_data = 0; -} - -void Player_V1::stopSound(int nr) { - Common::StackLock lock(_mutex); - - if (_next_nr == nr) { - _next_nr = 0; - _next_data = 0; - } - if (_current_nr == nr) { - for (int i = 0; i < 4; i++) { - clear_channel(i); - } - _repeat_chunk = _next_chunk = 0; - _current_nr = 0; - _current_data = 0; - chainNextSound(); - } -} - -void Player_V1::clear_channel(int i) { - _channels[i].freq = 0; - _channels[i].volume = 15; -} - -int Player_V1::getMusicTimer() { - /* Do V1 games have a music timer? */ - return 0; -} - -void Player_V1::parseSpeakerChunk() { - set_mplex(3000); - _forced_level = 0; - - parse_again: - _chunk_type = READ_LE_UINT16(_next_chunk); - debug(6, "parseSpeakerChunk: sound %d, offset %lx, chunk %x", - _current_nr, (long)(_next_chunk - _current_data), _chunk_type); - - _next_chunk += 2; - switch (_chunk_type) { - case 0xffff: - _current_nr = 0; - _current_data = 0; - _channels[0].freq = 0; - _next_chunk = 0; - chainNextSound(); - break; - case 0xfffe: - _repeat_chunk = _next_chunk; - goto parse_again; - - case 0xfffd: - _next_chunk = _repeat_chunk; - goto parse_again; - - case 0xfffc: - /* handle reset. We don't need this do we? */ - goto parse_again; - - case 0: - _time_left = 1; - set_mplex(READ_LE_UINT16(_next_chunk)); - _next_chunk += 2; - break; - case 1: - set_mplex(READ_LE_UINT16(_next_chunk)); - _start = READ_LE_UINT16(_next_chunk + 2); - _end = READ_LE_UINT16(_next_chunk + 4); - _delta = (int16) READ_LE_UINT16(_next_chunk + 6); - _repeat_ctr = READ_LE_UINT16(_next_chunk + 8); - _channels[0].freq = _start; - _next_chunk += 10; - debug(6, "chunk 1: mplex %d, freq %d -> %d step %d x %d", - _mplex, _start, _end, _delta, _repeat_ctr); - break; - case 2: - _start = READ_LE_UINT16(_next_chunk); - _end = READ_LE_UINT16(_next_chunk + 2); - _delta = (int16) READ_LE_UINT16(_next_chunk + 4); - _channels[0].freq = 0; - _next_chunk += 6; - _forced_level = -1; - debug(6, "chunk 2: %d -> %d step %d", - _start, _end, _delta); - break; - case 3: - _start = READ_LE_UINT16(_next_chunk); - _end = READ_LE_UINT16(_next_chunk + 2); - _delta = (int16) READ_LE_UINT16(_next_chunk + 4); - _channels[0].freq = 0; - _next_chunk += 6; - _forced_level = -1; - debug(6, "chunk 3: %d -> %d step %d", - _start, _end, _delta); - break; - } -} - -void Player_V1::nextSpeakerCmd() { - uint16 lsr; - switch (_chunk_type) { - case 0: - if (--_time_left) - return; - _time_left = READ_LE_UINT16(_next_chunk); - _next_chunk += 2; - if (_time_left == 0xfffb) { - /* handle 0xfffb?? */ - _time_left = READ_LE_UINT16(_next_chunk); - _next_chunk += 2; - } - debug(7, "nextSpeakerCmd: chunk %d, offset %4lx: notelen %d", - _chunk_type, (long)(_next_chunk - 2 - _current_data), _time_left); - if (_time_left == 0) { - parseSpeakerChunk(); - } else { - _channels[0].freq = READ_LE_UINT16(_next_chunk); - _next_chunk += 2; - debug(7, "freq_current: %d", _channels[0].freq); - } - break; - - case 1: - _channels[0].freq = (_channels[0].freq + _delta) & 0xffff; - if (_channels[0].freq == _end) { - if (!--_repeat_ctr) { - parseSpeakerChunk(); - return; - } - _channels[0].freq = _start; - } - break; - - case 2: - _start = (_start + _delta) & 0xffff; - if (_start == _end) { - parseSpeakerChunk(); - return; - } - set_mplex(_start); - _forced_level = -_forced_level; - break; - case 3: - _start = (_start + _delta) & 0xffff; - if (_start == _end) { - parseSpeakerChunk(); - return; - } - lsr = _random_lsr + 0x9248; - lsr = (lsr >> 3) | (lsr << 13); - _random_lsr = lsr; - set_mplex((_start & lsr) | 0x180); - _forced_level = -_forced_level; - break; - } -} - -void Player_V1::parsePCjrChunk() { - uint tmp; - uint i; - - set_mplex(3000); - _forced_level = 0; - -parse_again: - - _chunk_type = READ_LE_UINT16(_next_chunk); - debug(6, "parsePCjrChunk: sound %d, offset %4lx, chunk %x", - _current_nr, (long)(_next_chunk - _current_data), _chunk_type); - - _next_chunk += 2; - switch (_chunk_type) { - case 0xffff: - for (i = 0; i < 4; ++i) - clear_channel(i); - _current_nr = 0; - _current_data = 0; - _repeat_chunk = _next_chunk = 0; - chainNextSound(); - break; - - case 0xfffe: - _repeat_chunk = _next_chunk; - goto parse_again; - - case 0xfffd: - _next_chunk = _repeat_chunk; - goto parse_again; - - case 0xfffc: - /* handle reset. We don't need this do we? */ - goto parse_again; - - case 0: - set_mplex(READ_LE_UINT16(_next_chunk)); - _next_chunk += 2; - for (i = 0; i < 4; i++) { - tmp = READ_LE_UINT16(_next_chunk); - _next_chunk += 2; - if (tmp == 0xffff) { - _channels[i].cmd_ptr = 0; - continue; - } - _channels[i].attack = READ_LE_UINT16(_current_data + tmp); - _channels[i].decay = READ_LE_UINT16(_current_data + tmp + 2); - _channels[i].level = READ_LE_UINT16(_current_data + tmp + 4); - _channels[i].sustain_1 = READ_LE_UINT16(_current_data + tmp + 6); - _channels[i].sustain_2 = READ_LE_UINT16(_current_data + tmp + 8); - _channels[i].notelen = 1; - _channels[i].volume = 15; - _channels[i].cmd_ptr = _current_data + tmp + 10; - } - break; - - case 1: - set_mplex(READ_LE_UINT16(_next_chunk)); - tmp = READ_LE_UINT16(_next_chunk + 2); - _channels[0].cmd_ptr = tmp != 0xffff ? _current_data + tmp : NULL; - tmp = READ_LE_UINT16(_next_chunk + 4); - _start = READ_LE_UINT16(_next_chunk + 6); - _delta = (int16) READ_LE_UINT16(_next_chunk + 8); - _time_left = READ_LE_UINT16(_next_chunk + 10); - _next_chunk += 12; - if (tmp >= 0xe0) { - _channels[3].freq = tmp & 0xf; - _value_ptr = &_channels[3].volume; - } else { - assert(!(tmp & 0x10)); - tmp = (tmp & 0x60) >> 5; - _value_ptr = &_channels[tmp].freq; - _channels[tmp].volume = 0; - } - *_value_ptr = _start; - if (_channels[0].cmd_ptr) { - tmp = READ_LE_UINT16(_channels[0].cmd_ptr); - _start_2 = READ_LE_UINT16(_channels[0].cmd_ptr + 2); - _delta_2 = (int16) READ_LE_UINT16(_channels[0].cmd_ptr + 4); - _time_left_2 = READ_LE_UINT16(_channels[0].cmd_ptr + 6); - _channels[0].cmd_ptr += 8; - if (_value_ptr == &_channels[3].volume) { - tmp = (tmp & 0x70) >> 4; - if (tmp & 1) - _value_ptr_2 = &_channels[tmp >> 1].volume; - else - _value_ptr_2 = &_channels[tmp >> 1].freq; - } else { - assert(!(tmp & 0x10)); - tmp = (tmp & 0x60) >> 5; - _value_ptr_2 = &_channels[tmp].freq; - _channels[tmp].volume = 0; - } - *_value_ptr_2 = _start_2; - } - debug(6, "chunk 1: %lu: %d step %d for %d, %lu: %d step %d for %d", - (long)(_value_ptr - (uint *)_channels), _start, _delta, _time_left, - (long)(_value_ptr_2 - (uint *)_channels), _start_2, _delta_2, _time_left_2); - break; - - case 2: - _start = READ_LE_UINT16(_next_chunk); - _end = READ_LE_UINT16(_next_chunk + 2); - _delta = (int16) READ_LE_UINT16(_next_chunk + 4); - _channels[0].freq = 0; - _next_chunk += 6; - _forced_level = -1; - debug(6, "chunk 2: %d -> %d step %d", - _start, _end, _delta); - break; - case 3: - set_mplex(READ_LE_UINT16(_next_chunk)); - tmp = READ_LE_UINT16(_next_chunk + 2); - assert((tmp & 0xf0) == 0xe0); - _channels[3].freq = tmp & 0xf; - if ((tmp & 3) == 3) { - _next_chunk += 2; - _channels[2].freq = READ_LE_UINT16(_next_chunk + 2); - } - _channels[3].volume = READ_LE_UINT16(_next_chunk + 4); - _repeat_ctr = READ_LE_UINT16(_next_chunk + 6); - _delta = (int16) READ_LE_UINT16(_next_chunk + 8); - _next_chunk += 10; - break; - } -} - -void Player_V1::nextPCjrCmd() { - uint i; - int dummy; - switch (_chunk_type) { - case 0: - for (i = 0; i < 4; i++) { - if (!_channels[i].cmd_ptr) - continue; - if (!--_channels[i].notelen) { - dummy = READ_LE_UINT16(_channels[i].cmd_ptr); - if (dummy >= 0xfffe) { - if (dummy == 0xfffe) - _next_chunk = _current_data + 2; - parsePCjrChunk(); - return; - } - _channels[i].notelen = 4 * dummy; - dummy = READ_LE_UINT16(_channels[i].cmd_ptr + 2); - if (dummy == 0) { - _channels[i].hull_counter = 4; - _channels[i].sustctr = _channels[i].sustain_2; - } else { - _channels[i].hull_counter = 1; - _channels[i].freq = dummy; - } - debug(7, "chunk 0: channel %d play %d for %d", - i, dummy, _channels[i].notelen); - _channels[i].cmd_ptr += 4; - } - - - switch (_channels[i].hull_counter) { - case 1: - _channels[i].volume -= _channels[i].attack; - if ((int) _channels[i].volume <= 0) { - _channels[i].volume = 0; - _channels[i].hull_counter++; - } - break; - case 2: - _channels[i].volume += _channels[i].decay; - if (_channels[i].volume >= _channels[i].level) { - _channels[i].volume = _channels[i].level; - _channels[i].hull_counter++; - } - break; - case 4: - if (--_channels[i].sustctr < 0) { - _channels[i].sustctr = _channels[i].sustain_2; - _channels[i].volume += _channels[i].sustain_1; - if ((int) _channels[i].volume >= 15) { - _channels[i].volume = 15; - _channels[i].hull_counter++; - } - } - break; - } - } - break; - - case 1: - _start += _delta; - *_value_ptr = _start; - if (!--_time_left) { - _start = READ_LE_UINT16(_next_chunk); - _next_chunk += 2; - if (_start == 0xffff) { - parsePCjrChunk(); - return; - } - _delta = (int16) READ_LE_UINT16(_next_chunk); - _time_left = READ_LE_UINT16(_next_chunk + 2); - _next_chunk += 4; - *_value_ptr = _start; - } - - if (_channels[0].cmd_ptr) { - _start_2 += _delta_2; - *_value_ptr_2 = _start_2; - if (!--_time_left_2) { - _start_2 = READ_LE_UINT16(_channels[0].cmd_ptr); - if (_start_2 == 0xffff) { - _next_chunk = _channels[0].cmd_ptr + 2; - parsePCjrChunk(); - return; - } - _delta_2 = (int16) READ_LE_UINT16(_channels[0].cmd_ptr + 2); - _time_left_2 = READ_LE_UINT16(_channels[0].cmd_ptr + 4); - _channels[0].cmd_ptr += 6; - } - } - break; - - case 2: - _start += _delta; - if (_start == _end) { - parsePCjrChunk(); - return; - } - set_mplex(_start); - debug(7, "chunk 2: mplex %d curve %d", _start, _forced_level); - _forced_level = -_forced_level; - break; - case 3: - dummy = _channels[3].volume + _delta; - if (dummy >= 15) { - _channels[3].volume = 15; - } else if (dummy <= 0) { - _channels[3].volume = 0; - } else { - _channels[3].volume = dummy; - break; - } - - if (!--_repeat_ctr) { - parsePCjrChunk(); - return; - } - _delta = READ_LE_UINT16(_next_chunk); - _next_chunk += 2; - break; - } -} - -void Player_V1::set_mplex(uint mplex) { - if (mplex == 0) - mplex = 65536; - _mplex = mplex; - _tick_len = _mplex_step * mplex; -} - -void Player_V1::nextTick() { - if (_next_chunk) { - if (_pcjr) - nextPCjrCmd(); - else - nextSpeakerCmd(); - } -} - -void Player_V1::generateSpkSamples(int16 *data, uint len) { - uint i; - - memset(data, 0, 2 * sizeof(int16) * len); - if (_channels[0].freq == 0) { - if (_forced_level) { - int sample = _forced_level * _volumetable[0]; - for (i = 0; i < len; i++) - data[2*i] = data[2*i+1] = sample; - debug(9, "speaker: %8x: forced one", _tick_len); - } else if (!_level) { - return; - } - } else { - squareGenerator(0, _channels[0].freq, 0, 0, data, len); - debug(9, "speaker: %8x: freq %d %.1f", _tick_len, - _channels[0].freq, 1193000.0 / _channels[0].freq); - } - lowPassFilter(data, len); -} - -void Player_V1::generatePCjrSamples(int16 *data, uint len) { - uint i, j; - uint freq, vol; - bool hasdata = false; - - memset(data, 0, 2 * sizeof(int16) * len); - - if (_forced_level) { - int sample = _forced_level * _volumetable[0]; - for (i = 0; i < len; i++) - data[2*i] = data[2*i+1] = sample; - hasdata = true; - debug(9, "channel[4]: %8x: forced one", _tick_len); - } - - for (i = 1; i < 3; i++) { - freq = _channels[i].freq; - if (freq) { - for (j = 0; j < i; j++) { - if (freq == _channels[j].freq) { - /* HACK: this channel is playing at - * the same frequency as another. - * Synchronize it to the same phase to - * prevent interference. - */ - _timer_count[i] = _timer_count[j]; - _timer_output ^= (1 << i) & - (_timer_output ^ _timer_output << (i - j)); - } - } - } - } - - for (i = 0; i < 4; i++) { - freq = _channels[i].freq; - vol = _channels[i].volume; - if (!_volumetable[_channels[i].volume]) { - _timer_count[i] -= len << FIXP_SHIFT; - if (_timer_count[i] < 0) - _timer_count[i] = 0; - } else if (i < 3) { - hasdata = true; - squareGenerator(i, freq, vol, 0, data, len); - debug(9, "channel[%d]: %8x: freq %d %.1f ; volume %d", - i, _tick_len, freq, 111860.0 / freq, vol); - } else { - int noiseFB = (freq & 4) ? FB_WNOISE : FB_PNOISE; - int n = (freq & 3); - - freq = (n == 3) ? 2 * (_channels[2].freq) : 1 << (5 + n); - hasdata = true; - squareGenerator(i, freq, vol, noiseFB, data, len); - debug(9, "channel[%d]: %x: noise freq %d %.1f ; volume %d", - i, _tick_len, freq, 111860.0 / freq, vol); - } - } - - if (_level || hasdata) - lowPassFilter(data, len); -} - -} // End of namespace Scumm diff --git a/engines/scumm/player/v1.h b/engines/scumm/player/v1.h deleted file mode 100644 index d6e08bd7ab..0000000000 --- a/engines/scumm/player/v1.h +++ /dev/null @@ -1,98 +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 SCUMM_PLAYER_V1_H -#define SCUMM_PLAYER_V1_H - -#include "scumm/player/v2.h" - -namespace Scumm { - -/** - * Scumm V1 PC-Speaker player. - */ -class Player_V1 : public Player_V2 { -public: - Player_V1(ScummEngine *scumm, Audio::Mixer *mixer, bool pcjr); - ~Player_V1(); - - virtual void startSound(int sound); - virtual void stopSound(int sound); - virtual void stopAllSounds(); - virtual int getMusicTimer(); - -protected: - virtual void nextTick(); - virtual void clear_channel(int i); - virtual void chainSound(int nr, byte *data); - - virtual void generateSpkSamples(int16 *data, uint len); - virtual void generatePCjrSamples(int16 *data, uint len); - - void restartSound(); - - void set_mplex(uint mplex); - void parseSpeakerChunk(); - void nextSpeakerCmd(); - void parsePCjrChunk(); - void nextPCjrCmd(); - -private: - struct channel_data_v1 { - uint freq; - uint volume; - byte *cmd_ptr; - uint notelen; - uint hull_counter; - uint attack; - uint decay; - uint level; - uint sustain_1; - uint sustain_2; - int sustctr; - }; - - channel_data_v1 _channels[4]; - - byte *_next_chunk; - byte *_repeat_chunk; - uint _chunk_type; - uint _mplex_step; - uint _mplex; - uint _repeat_ctr; - uint _freq_current; - int _forced_level; - uint16 _random_lsr; - uint *_value_ptr; - uint _time_left; - uint _start; - uint _end; - int _delta; - uint *_value_ptr_2; - uint _time_left_2; - uint _start_2; - int _delta_2; -}; - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/player/v2.cpp b/engines/scumm/player/v2.cpp deleted file mode 100644 index e3b3c978dd..0000000000 --- a/engines/scumm/player/v2.cpp +++ /dev/null @@ -1,327 +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/v2.h" -#include "scumm/scumm.h" - -namespace Scumm { - -#define SPK_DECAY 0xa000 /* Depends on sample rate */ -#define PCJR_DECAY 0xa000 /* Depends on sample rate */ - -#define NG_PRESET 0x0f35 /* noise generator preset */ -#define FB_WNOISE 0x12000 /* feedback for white noise */ -#define FB_PNOISE 0x08000 /* feedback for periodic noise */ - - -Player_V2::Player_V2(ScummEngine *scumm, Audio::Mixer *mixer, bool pcjr) - : Player_V2Base(scumm, mixer, pcjr) { - - int i; - - // Initialize square generator - _level = 0; - - _RNG = NG_PRESET; - - _pcjr = pcjr; - - if (_pcjr) { - _decay = PCJR_DECAY; - _update_step = (_sampleRate << FIXP_SHIFT) / (111860 * 2); - } else { - _decay = SPK_DECAY; - _update_step = (_sampleRate << FIXP_SHIFT) / (1193000 * 2); - } - - // Adapt _decay to sample rate. It must be squared when - // sample rate doubles. - for (i = 0; (_sampleRate << i) < 30000; i++) - _decay = _decay * _decay / 65536; - - _timer_output = 0; - for (i = 0; i < 4; i++) - _timer_count[i] = 0; - - setMusicVolume(255); - - _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); -} - -Player_V2::~Player_V2() { - Common::StackLock lock(_mutex); - _mixer->stopHandle(_soundHandle); -} - -void Player_V2::setMusicVolume (int vol) { - if (vol > 255) - vol = 255; - - /* scale to int16, FIXME: find best value */ - double out = vol * 128 / 3; - - /* build volume table (2dB per step) */ - for (int i = 0; i < 15; i++) { - /* limit volume to avoid clipping */ - if (out > 0xffff) - _volumetable[i] = 0xffff; - else - _volumetable[i] = (int) out; - - out /= 1.258925412; /* = 10 ^ (2/20) = 2dB */ - } - _volumetable[15] = 0; -} - -void Player_V2::stopAllSounds() { - Common::StackLock lock(_mutex); - - for (int i = 0; i < 4; i++) { - clear_channel(i); - } - _next_nr = _current_nr = 0; - _next_data = _current_data = 0; -} - -void Player_V2::stopSound(int nr) { - Common::StackLock lock(_mutex); - - if (_next_nr == nr) { - _next_nr = 0; - _next_data = 0; - } - if (_current_nr == nr) { - for (int i = 0; i < 4; i++) { - clear_channel(i); - } - _current_nr = 0; - _current_data = 0; - chainNextSound(); - } -} - -void Player_V2::startSound(int nr) { - Common::StackLock lock(_mutex); - - byte *data = _vm->getResourceAddress(rtSound, nr); - assert(data); - - int cprio = _current_data ? *(_current_data + _header_len) : 0; - int prio = *(data + _header_len); - int nprio = _next_data ? *(_next_data + _header_len) : 0; - - int restartable = *(data + _header_len + 1); - - if (!_current_nr || cprio <= prio) { - int tnr = _current_nr; - int tprio = cprio; - byte *tdata = _current_data; - - chainSound(nr, data); - nr = tnr; - prio = tprio; - data = tdata; - restartable = data ? *(data + _header_len + 1) : 0; - } - - if (!_current_nr) { - nr = 0; - _next_nr = 0; - _next_data = 0; - } - - if (nr != _current_nr - && restartable - && (!_next_nr - || nprio <= prio)) { - - _next_nr = nr; - _next_data = data; - } -} - -int Player_V2::getSoundStatus(int nr) const { - return _current_nr == nr || _next_nr == nr; -} - -int Player_V2::readBuffer(int16 *data, const int numSamples) { - Common::StackLock lock(_mutex); - - uint step; - uint len = numSamples / 2; - - do { - if (!(_next_tick >> FIXP_SHIFT)) { - _next_tick += _tick_len; - nextTick(); - } - - step = len; - if (step > (_next_tick >> FIXP_SHIFT)) - step = (_next_tick >> FIXP_SHIFT); - if (_pcjr) - generatePCjrSamples(data, step); - else - generateSpkSamples(data, step); - data += 2 * step; - _next_tick -= step << FIXP_SHIFT; - } while (len -= step); - - return numSamples; -} - -void Player_V2::lowPassFilter(int16 *sample, uint len) { - for (uint i = 0; i < len; i++) { - _level = (int) (_level * _decay - + sample[0] * (0x10000 - _decay)) >> 16; - sample[0] = sample[1] = _level; - sample += 2; - } -} - -void Player_V2::squareGenerator(int channel, int freq, int vol, - int noiseFeedback, int16 *sample, uint len) { - int32 period = _update_step * freq; - int32 nsample; - if (period == 0) - period = _update_step; - - for (uint i = 0; i < len; i++) { - uint32 duration = 0; - - if (_timer_output & (1 << channel)) - duration += _timer_count[channel]; - - _timer_count[channel] -= (1 << FIXP_SHIFT); - while (_timer_count[channel] <= 0) { - - if (noiseFeedback) { - if (_RNG & 1) { - _RNG ^= noiseFeedback; - _timer_output ^= (1 << channel); - } - _RNG >>= 1; - } else { - _timer_output ^= (1 << channel); - } - - if (_timer_output & (1 << channel)) - duration += period; - - _timer_count[channel] += period; - } - - if (_timer_output & (1 << channel)) - duration -= _timer_count[channel]; - - nsample = *sample + - (((int32) (duration - (1 << (FIXP_SHIFT - 1))) - * (int32) _volumetable[vol]) >> FIXP_SHIFT); - /* overflow: clip value */ - if (nsample > 0x7fff) - nsample = 0x7fff; - if (nsample < -0x8000) - nsample = -0x8000; - *sample = nsample; - // The following write isn't necessary, because the lowPassFilter does it for us - //sample[1] = sample[0]; - sample += 2; - } -} - -void Player_V2::generateSpkSamples(int16 *data, uint len) { - int winning_channel = -1; - for (int i = 0; i < 4; i++) { - if (winning_channel == -1 - && _channels[i].d.volume - && _channels[i].d.time_left) { - winning_channel = i; - } - } - - memset(data, 0, 2 * sizeof(int16) * len); - if (winning_channel != -1) { - squareGenerator(0, _channels[winning_channel].d.freq, 0, - 0, data, len); - } else if (_level == 0) - /* shortcut: no sound is being played. */ - return; - - lowPassFilter(data, len); -} - -void Player_V2::generatePCjrSamples(int16 *data, uint len) { - int i, j; - int freq, vol; - - memset(data, 0, 2 * sizeof(int16) * len); - bool hasdata = false; - - for (i = 1; i < 3; i++) { - freq = _channels[i].d.freq >> 6; - if (_channels[i].d.volume && _channels[i].d.time_left) { - for (j = 0; j < i; j++) { - if (_channels[j].d.volume - && _channels[j].d.time_left - && freq == (_channels[j].d.freq >> 6)) { - /* HACK: this channel is playing at - * the same frequency as another. - * Synchronize it to the same phase to - * prevent interference. - */ - _timer_count[i] = _timer_count[j]; - _timer_output ^= (1 << i) & - (_timer_output ^ _timer_output << (i - j)); - } - } - } - } - - for (i = 0; i < 4; i++) { - freq = _channels[i].d.freq >> 6; - vol = (65535 - _channels[i].d.volume) >> 12; - if (!_channels[i].d.volume || !_channels[i].d.time_left) { - _timer_count[i] -= len << FIXP_SHIFT; - if (_timer_count[i] < 0) - _timer_count[i] = 0; - } else if (i < 3) { - hasdata = true; - squareGenerator(i, freq, vol, 0, data, len); - } else { - int noiseFB = (freq & 4) ? FB_WNOISE : FB_PNOISE; - int n = (freq & 3); - - freq = (n == 3) ? 2 * (_channels[2].d.freq>>6) : 1 << (5 + n); - hasdata = true; - squareGenerator(i, freq, vol, noiseFB, data, len); - } -#if 0 - debug(9, "channel[%d]: freq %d %.1f ; volume %d", - i, freq, 111860.0 / freq, vol); -#endif - } - - if (_level || hasdata) - lowPassFilter(data, len); -} - -} // End of namespace Scumm diff --git a/engines/scumm/player/v2.h b/engines/scumm/player/v2.h deleted file mode 100644 index e23f74cb31..0000000000 --- a/engines/scumm/player/v2.h +++ /dev/null @@ -1,72 +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 SCUMM_PLAYER_V2_H -#define SCUMM_PLAYER_V2_H - -#include "scumm/player/v2base.h" - -namespace Scumm { - -/** - * Scumm V2 PC-Speaker MIDI driver. - * This simulates the pc speaker sound, which is driven by the 8253 (square - * wave generator) and a low-band filter. - */ -class Player_V2 : public Player_V2Base { -public: - Player_V2(ScummEngine *scumm, Audio::Mixer *mixer, bool pcjr); - virtual ~Player_V2(); - - // MusicEngine API - virtual void setMusicVolume(int vol); - virtual void startSound(int sound); - virtual void stopSound(int sound); - virtual void stopAllSounds(); -// virtual int getMusicTimer(); - virtual int getSoundStatus(int sound) const; - - // AudioStream API - virtual int readBuffer(int16 *buffer, const int numSamples); - -protected: - unsigned int _update_step; - unsigned int _decay; - int _level; - unsigned int _RNG; - unsigned int _volumetable[16]; - - int _timer_count[4]; - int _timer_output; - -protected: - virtual void generateSpkSamples(int16 *data, uint len); - virtual void generatePCjrSamples(int16 *data, uint len); - - void lowPassFilter(int16 *data, uint len); - void squareGenerator(int channel, int freq, int vol, - int noiseFeedback, int16 *sample, uint len); -}; - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/player/v2a.cpp b/engines/scumm/player/v2a.cpp deleted file mode 100644 index 2350d7e048..0000000000 --- a/engines/scumm/player/v2a.cpp +++ /dev/null @@ -1,1954 +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 "engines/engine.h" -#include "scumm/player/v2a.h" -#include "scumm/scumm.h" - -namespace Scumm { - -#define BASE_FREQUENCY 3579545 - -static uint32 CRCtable[256]; - - -static void InitCRC() { - const uint32 poly = 0xEDB88320; - int i, j; - uint32 n; - - for (i = 0; i < 256; i++) { - n = i; - for (j = 0; j < 8; j++) - n = (n & 1) ? ((n >> 1) ^ poly) : (n >> 1); - CRCtable[i] = n; - } -} - -static uint32 GetCRC(byte *data, int len) { - uint32 CRC = 0xFFFFFFFF; - int i; - for (i = 0; i < len; i++) - CRC = (CRC >> 8) ^ CRCtable[(CRC ^ data[i]) & 0xFF]; - return CRC ^ 0xFFFFFFFF; -} - -class V2A_Sound { -public: - V2A_Sound() : _id(0), _mod(NULL) { } - virtual ~V2A_Sound() {} - virtual void start(Player_MOD *mod, int id, const byte *data) = 0; - virtual bool update() = 0; - virtual void stop() = 0; -protected: - int _id; - Player_MOD *_mod; -}; - -// unsupported sound effect, print warning message to console -class V2A_Sound_Unsupported : public V2A_Sound { -public: - V2A_Sound_Unsupported() { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - warning("player_v2a - sound %i not supported", id); - } - virtual bool update() { return false; } - virtual void stop() { } -}; - -// template, automatically stops all channels when a sound is silenced -template<int numChan> -class V2A_Sound_Base : public V2A_Sound { -public: - V2A_Sound_Base() : _offset(0), _size(0), _data(0) { } - V2A_Sound_Base(uint16 offset, uint16 size) : _offset(offset), _size(size), _data(0) { } - virtual void stop() { - assert(_id); - for (int i = 0; i < numChan; i++) - _mod->stopChannel(_id | (i << 8)); - _id = 0; - free(_data); - _data = 0; - } -protected: - const uint16 _offset; - const uint16 _size; - - char *_data; -}; - -// plays a music track -class V2A_Sound_Music : public V2A_Sound { -public: - V2A_Sound_Music(uint16 instoff, uint16 voloff, uint16 chan1off, uint16 chan2off, uint16 chan3off, uint16 chan4off, uint16 sampoff, bool looped) : - _instoff(instoff), _voloff(voloff), _chan1off(chan1off), _chan2off(chan2off), _chan3off(chan3off), _chan4off(chan4off), _sampoff(sampoff), _looped(looped) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - - _data = (char *)malloc(READ_LE_UINT16(data)); - memcpy(_data, data, READ_LE_UINT16(data)); - - _chan[0].dataptr_i = _chan1off; - _chan[1].dataptr_i = _chan2off; - _chan[2].dataptr_i = _chan3off; - _chan[3].dataptr_i = _chan4off; - for (int i = 0; i < 4; i++) { - _chan[i].dataptr = _chan[i].dataptr_i; - _chan[i].volbase = 0; - _chan[i].volptr = 0; - _chan[i].chan = 0; - _chan[i].dur = 0; - _chan[i].ticks = 0; - } - update(); - } - virtual bool update() { - assert(_id); - int i, j = 0; - for (i = 0; i < 4; i++) { - if (_chan[i].dur) { - if (!--_chan[i].dur) { - _mod->stopChannel(_id | (_chan[i].chan << 8)); - } else { - _mod->setChannelVol(_id | (_chan[i].chan << 8), - READ_BE_UINT16(_data + _chan[i].volbase + (_chan[i].volptr++ << 1))); - if (_chan[i].volptr == 0) { - _mod->stopChannel(_id | (_chan[i].chan << 8)); - _chan[i].dur = 0; - } - } - } - if (!_chan[i].dataptr) { - j++; - continue; - } - if (READ_BE_UINT16(_data + _chan[i].dataptr) <= _chan[i].ticks) { - if (READ_BE_UINT16(_data + _chan[i].dataptr + 2) == 0xFFFF) { - if (_looped) { - _chan[i].dataptr = _chan[i].dataptr_i; - _chan[i].ticks = 0; - if (READ_BE_UINT16(_data + _chan[i].dataptr) > 0) { - _chan[i].ticks++; - continue; - } - } else { - _chan[i].dataptr = 0; - j++; - continue; - } - } - int freq = BASE_FREQUENCY / READ_BE_UINT16(_data + _chan[i].dataptr + 2); - int inst = READ_BE_UINT16(_data + _chan[i].dataptr + 8); - _chan[i].volbase = _voloff + (READ_BE_UINT16(_data + _instoff + (inst << 5)) << 9); - _chan[i].volptr = 0; - _chan[i].chan = READ_BE_UINT16(_data + _chan[i].dataptr + 6) & 0x3; - - if (_chan[i].dur) // if there's something playing, stop it - _mod->stopChannel(_id | (_chan[i].chan << 8)); - - _chan[i].dur = READ_BE_UINT16(_data + _chan[i].dataptr + 4); - - int vol = READ_BE_UINT16(_data + _chan[i].volbase + (_chan[i].volptr++ << 1)); - - int pan; - if ((_chan[i].chan == 0) || (_chan[i].chan == 3)) - pan = -127; - else - pan = 127; - int offset = READ_BE_UINT16(_data + _instoff + (inst << 5) + 0x14); - int len = READ_BE_UINT16(_data + _instoff + (inst << 5) + 0x18); - int loopoffset = READ_BE_UINT16(_data + _instoff + (inst << 5) + 0x16); - int looplen = READ_BE_UINT16(_data + _instoff + (inst << 5) + 0x10); - - int size = len + looplen; - char *data = (char *)malloc(size); - memcpy(data, _data + _sampoff + offset, len); - memcpy(data + len, _data + _sampoff + loopoffset, looplen); - - _mod->startChannel(_id | (_chan[i].chan << 8), data, size, freq, vol, len, looplen + len, pan); - _chan[i].dataptr += 16; - } - _chan[i].ticks++; - } - if (j == 4) - return false; - return true; - } - virtual void stop() { - assert(_id); - for (int i = 0; i < 4; i++) { - if (_chan[i].dur) - _mod->stopChannel(_id | (_chan[i].chan << 8)); - } - free(_data); - _id = 0; - } -private: - const uint16 _instoff; - const uint16 _voloff; - const uint16 _chan1off; - const uint16 _chan2off; - const uint16 _chan3off; - const uint16 _chan4off; - const uint16 _sampoff; - const bool _looped; - - char *_data; - struct tchan { - uint16 dataptr_i; - uint16 dataptr; - uint16 volbase; - uint8 volptr; - uint16 chan; - uint16 dur; - uint16 ticks; - } _chan[4]; -}; - -// plays a single waveform -class V2A_Sound_Single : public V2A_Sound_Base<1> { -public: - V2A_Sound_Single(uint16 offset, uint16 size, uint16 freq, uint8 vol) : - V2A_Sound_Base<1>(offset, size), _freq(freq), _vol(vol) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - char *tmp_data = (char *)malloc(_size); - memcpy(tmp_data, data + _offset, _size); - int vol = (_vol << 2) | (_vol >> 4); - _mod->startChannel(_id, tmp_data, _size, BASE_FREQUENCY / _freq, vol, 0, 0); - _ticks = 1 + (60 * _size * _freq) / BASE_FREQUENCY; - } - virtual bool update() { - assert(_id); - _ticks--; - if (!_ticks) { - return false; - } - return true; - } -private: - const uint16 _freq; - const uint8 _vol; - - int _ticks; -}; - -// plays a single looped waveform -class V2A_Sound_SingleLooped : public V2A_Sound_Base<1> { -public: - V2A_Sound_SingleLooped(uint16 offset, uint16 size, uint16 freq, uint8 vol, uint16 loopoffset, uint16 loopsize) : - V2A_Sound_Base<1>(offset, size), _loopoffset(loopoffset), _loopsize(loopsize), _freq(freq), _vol(vol) { } - V2A_Sound_SingleLooped(uint16 offset, uint16 size, uint16 freq, uint8 vol) : - V2A_Sound_Base<1>(offset, size), _loopoffset(0), _loopsize(size), _freq(freq), _vol(vol) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - char *tmp_data = (char *)malloc(_size); - memcpy(tmp_data, data + _offset, _size); - int vol = (_vol << 2) | (_vol >> 4); - _mod->startChannel(_id, tmp_data, _size, BASE_FREQUENCY / _freq, vol, _loopoffset, _loopoffset + _loopsize); - } - virtual bool update() { - assert(_id); - return true; - } -private: - const uint16 _loopoffset; - const uint16 _loopsize; - const uint16 _freq; - const uint8 _vol; -}; - -// plays two looped waveforms -class V2A_Sound_MultiLooped : public V2A_Sound_Base<2> { -public: - V2A_Sound_MultiLooped(uint16 offset, uint16 size, uint16 freq1, uint8 vol1, uint16 freq2, uint8 vol2) : - V2A_Sound_Base<2>(offset, size), _freq1(freq1), _vol1(vol1), _freq2(freq2), _vol2(vol2) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - char *tmp_data1 = (char *)malloc(_size); - char *tmp_data2 = (char *)malloc(_size); - memcpy(tmp_data1, data + _offset, _size); - memcpy(tmp_data2, data + _offset, _size); - int vol1 = (_vol1 << 1) | (_vol1 >> 5); - int vol2 = (_vol2 << 1) | (_vol2 >> 5); - _mod->startChannel(_id | 0x000, tmp_data1, _size, BASE_FREQUENCY / _freq1, vol1, 0, _size, -127); - _mod->startChannel(_id | 0x100, tmp_data2, _size, BASE_FREQUENCY / _freq2, vol2, 0, _size, 127); - } - virtual bool update() { - assert(_id); - return true; - } -private: - const uint16 _freq1; - const uint8 _vol1; - const uint16 _freq2; - const uint8 _vol2; -}; - -// plays two looped waveforms for a fixed number of frames -class V2A_Sound_MultiLoopedDuration : public V2A_Sound_MultiLooped { -public: - V2A_Sound_MultiLoopedDuration(uint16 offset, uint16 size, uint16 freq1, uint8 vol1, uint16 freq2, uint8 vol2, uint16 numframes) : - V2A_Sound_MultiLooped(offset, size, freq1, vol1, freq2, vol2), _duration(numframes) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - V2A_Sound_MultiLooped::start(mod, id, data); - _ticks = 0; - } - virtual bool update() { - assert(_id); - _ticks++; - if (_ticks >= _duration) - return false; - return true; - } -private: - const uint16 _duration; - - int _ticks; -}; - -// plays a single looped waveform which starts at one frequency and bends to another frequency, where it remains until stopped -class V2A_Sound_SingleLoopedPitchbend : public V2A_Sound_Base<1> { -public: - V2A_Sound_SingleLoopedPitchbend(uint16 offset, uint16 size, uint16 freq1, uint16 freq2, uint8 vol, uint8 step) : - V2A_Sound_Base<1>(offset, size), _freq1(freq1), _freq2(freq2), _vol(vol), _step(step) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - char *tmp_data = (char *)malloc(_size); - memcpy(tmp_data, data + _offset, _size); - int vol = (_vol << 2) | (_vol >> 4); - _curfreq = _freq1; - _mod->startChannel(_id, tmp_data, _size, BASE_FREQUENCY / _curfreq, vol, 0, _size); - } - virtual bool update() { - assert(_id); - if (_freq1 < _freq2) { - _curfreq += _step; - if (_curfreq > _freq2) - _curfreq = _freq2; - else - _mod->setChannelFreq(_id, BASE_FREQUENCY / _curfreq); - } else { - _curfreq -= _step; - if (_curfreq < _freq2) - _curfreq = _freq2; - else - _mod->setChannelFreq(_id, BASE_FREQUENCY / _curfreq); - } - return true; - } -private: - const uint16 _freq1; - const uint16 _freq2; - const uint8 _vol; - const uint16 _step; - - uint16 _curfreq; -}; - -// plays a single looped waveform starting at a specific frequency/volume, dropping in frequency and fading volume to zero -// used when Maniac Mansion explodes -class V2A_Sound_Special_Maniac69 : public V2A_Sound_Base<1> { -public: - V2A_Sound_Special_Maniac69(uint16 offset, uint16 size, uint16 freq, uint8 vol) : - V2A_Sound_Base<1>(offset, size), _freq(freq), _vol(vol) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - char *tmp_data = (char *)malloc(_size); - memcpy(tmp_data, data + _offset, _size); - _curvol = (_vol << 3) | (_vol >> 3); - _curfreq = _freq; - _mod->startChannel(_id, tmp_data, _size, BASE_FREQUENCY / _curfreq, _curvol >> 1, 0, _size); - } - virtual bool update() { - assert(_id); - _curfreq += 2; - _mod->setChannelFreq(_id, BASE_FREQUENCY / _curfreq); - _curvol--; - if (_curvol == 0) - return false; - _mod->setChannelVol(_id, _curvol >> 1); - return true; - } -private: - const uint16 _freq; - const uint8 _vol; - - uint16 _curfreq; - uint16 _curvol; -}; - -// plays a single looped waveform, fading the volume from zero to maximum at one rate, then back to zero at another rate -// used when a microwave oven goes 'Ding' -class V2A_Sound_Special_ManiacDing : public V2A_Sound_Base<1> { -public: - V2A_Sound_Special_ManiacDing(uint16 offset, uint16 size, uint16 freq, uint8 fadeinrate, uint8 fadeoutrate) : - V2A_Sound_Base<1>(offset, size), _freq(freq), _fade1(fadeinrate), _fade2(fadeoutrate) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - char *tmp_data = (char *)malloc(_size); - memcpy(tmp_data, data + _offset, _size); - _curvol = 1; - _dir = 0; - _mod->startChannel(_id, tmp_data, _size, BASE_FREQUENCY / _freq, _curvol, 0, _size); - } - virtual bool update() { - assert(_id); - if (_dir == 0) { - _curvol += _fade1; - if (_curvol > 0x3F) { - _curvol = 0x3F; - _dir = 1; - } - } else { - _curvol -= _fade2; - if (_curvol < 1) - return false; - } - _mod->setChannelVol(_id, (_curvol << 2) | (_curvol >> 4)); - return true; - } -private: - const uint16 _freq; - const uint16 _fade1; - const uint16 _fade2; - - int _curvol; - int _dir; -}; - -// plays two looped waveforms, fading the volume from zero to maximum at one rate, then back to zero at another rate -// used in Zak McKracken for several stereo 'Ding' sounds -class V2A_Sound_Special_ZakStereoDing : public V2A_Sound_Base<2> { -public: - V2A_Sound_Special_ZakStereoDing(uint16 offset, uint16 size, uint16 freq1, uint16 freq2, uint8 fadeinrate, uint8 fadeoutrate) : - V2A_Sound_Base<2>(offset, size), _freq1(freq1), _freq2(freq2), _fade1(fadeinrate), _fade2(fadeoutrate) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - char *tmp_data1 = (char *)malloc(_size); - char *tmp_data2 = (char *)malloc(_size); - memcpy(tmp_data1, data + _offset, _size); - memcpy(tmp_data2, data + _offset, _size); - _curvol = 1; - _dir = 0; - _mod->startChannel(_id | 0x000, tmp_data1, _size, BASE_FREQUENCY / _freq1, 1, 0, _size, -127); - _mod->startChannel(_id | 0x100, tmp_data2, _size, BASE_FREQUENCY / _freq2, 1, 0, _size, 127); - } - virtual bool update() { - assert(_id); - if (_dir == 0) { - _curvol += _fade1; - if (_curvol > 0x3F) { - _curvol = 0x3F; - _dir = 1; - } - } else { - _curvol -= _fade2; - if (_curvol < 1) - return false; - } - _mod->setChannelVol(_id | 0x000, (_curvol << 1) | (_curvol >> 5)); - _mod->setChannelVol(_id | 0x100, (_curvol << 1) | (_curvol >> 5)); - return true; - } -private: - const uint16 _freq1; - const uint16 _freq2; - const uint16 _fade1; - const uint16 _fade2; - - int _curvol; - int _dir; -}; - -// plays a single looped waveform, starting at one frequency and at full volume, bending down to another frequency, and then fading volume to zero -// used in Maniac Mansion for the tentacle sounds -class V2A_Sound_Special_ManiacTentacle : public V2A_Sound_Base<1> { -public: - V2A_Sound_Special_ManiacTentacle(uint16 offset, uint16 size, uint16 freq1, uint16 freq2, uint16 step) : - V2A_Sound_Base<1>(offset, size), _freq1(freq1), _freq2(freq2), _step(step) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - char *tmp_data = (char *)malloc(_size); - memcpy(tmp_data, data + _offset, _size); - _curfreq = _freq1; - _curvol = 0x3F; - _mod->startChannel(_id, tmp_data, _size, BASE_FREQUENCY / _curfreq, (_curvol << 2) | (_curvol >> 4), 0, _size); - } - virtual bool update() { - assert(_id); - if (_curfreq > _freq2) - _curvol = 0x3F + _freq2 - _curfreq; - if (_curvol < 1) - return false; - _curfreq += _step; - _mod->setChannelFreq(_id, BASE_FREQUENCY / _curfreq); - _mod->setChannelVol(_id, (_curvol << 2) | (_curvol >> 4)); - return true; - } -private: - const uint16 _freq1; - const uint16 _freq2; - const uint16 _step; - - uint16 _curfreq; - int _curvol; -}; - -// plays a single looped waveform, starting at one frequency, bending down to another frequency, and then back up to the original frequency -// used for electronic noises -class V2A_Sound_Special_Maniac59 : public V2A_Sound_Base<1> { -public: - V2A_Sound_Special_Maniac59(uint16 offset, uint16 size, uint16 freq1, uint16 freq2, uint16 step, uint8 vol) : - V2A_Sound_Base<1>(offset, size), _freq1(freq1), _freq2(freq2), _step(step), _vol(vol) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - char *tmp_data = (char *)malloc(_size); - memcpy(tmp_data, data + _offset, _size); - int vol = (_vol << 2) | (_vol >> 4); - _curfreq = _freq1; - _dir = 2; - _mod->startChannel(_id, tmp_data, _size, BASE_FREQUENCY / _curfreq, vol, 0, _size); - } - virtual bool update() { - assert(_id); - if (_dir == 2) { - _curfreq += _step; - if (_curfreq > _freq2) { - _curfreq = _freq2; - _dir = 1; - } - _mod->setChannelFreq(_id, BASE_FREQUENCY / _curfreq); - } else if (_dir == 1) { - _curfreq -= _step; - if (_curfreq < _freq1) { - _curfreq = _freq1; - _dir = 0; - } - _mod->setChannelFreq(_id, BASE_FREQUENCY / _curfreq); - } - return true; - } -private: - const uint16 _freq1; - const uint16 _freq2; - const uint16 _step; - const uint8 _vol; - - uint16 _curfreq; - int _dir; -}; - -// plays a single looped waveform, simultaneously bending the frequency downward and slowly fading volume to zero -// don't remember where this one is used -class V2A_Sound_Special_Maniac61 : public V2A_Sound_Base<1> { -public: - V2A_Sound_Special_Maniac61(uint16 offset, uint16 size, uint16 freq1, uint16 freq2) : - V2A_Sound_Base<1>(offset, size), _freq1(freq1), _freq2(freq2) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - char *tmp_data = (char *)malloc(_size); - memcpy(tmp_data, data + _offset, _size); - _curfreq = _freq1; - _curvol = 0x3F; - _mod->startChannel(_id, tmp_data, _size, BASE_FREQUENCY / _curfreq, (_curvol << 2) | (_curvol >> 4), 0, _size); - } - virtual bool update() { - assert(_id); - _curfreq++; - if (!(_curfreq & 3)) - _curvol--; - if ((_curfreq == _freq2) || (_curvol == 0)) - return false; - _mod->setChannelFreq(_id, BASE_FREQUENCY / _curfreq); - _mod->setChannelVol(_id, (_curvol << 2) | (_curvol >> 4)); - return true; - } -private: - const uint16 _freq1; - const uint16 _freq2; - - uint16 _curfreq; - uint8 _curvol; -}; - -// intermittently plays two looped waveforms for a specific duration -// used for ringing telephones -class V2A_Sound_Special_ManiacPhone : public V2A_Sound_Base<2> { -public: - V2A_Sound_Special_ManiacPhone(uint16 offset, uint16 size, uint16 freq1, uint8 vol1, uint16 freq2, uint8 vol2, uint16 numframes, uint8 playwidth, uint8 loopwidth) : - V2A_Sound_Base<2>(offset, size), _freq1(freq1), _vol1(vol1), _freq2(freq2), _vol2(vol2), _duration(numframes), _playwidth(playwidth), _loopwidth(loopwidth) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - _data = (char *)malloc(READ_LE_UINT16(data)); - memcpy(_data, data, READ_LE_UINT16(data)); - soundon(); - _ticks = 0; - _loop = 0; - } - virtual bool update() { - assert(_id); - if (_loop == _playwidth) { - _mod->stopChannel(_id | 0x000); - _mod->stopChannel(_id | 0x100); - } - if (_loop == _loopwidth) { - _loop = 0; - soundon(); - } - _loop++; - _ticks++; - if (_ticks >= _duration) - return false; - return true; - } -private: - const uint16 _freq1; - const uint8 _vol1; - const uint16 _freq2; - const uint8 _vol2; - const uint16 _duration; - const uint8 _playwidth; - const uint8 _loopwidth; - - int _ticks; - int _loop; - - void soundon() { - char *tmp_data1 = (char *)malloc(_size); - char *tmp_data2 = (char *)malloc(_size); - memcpy(tmp_data1, _data + _offset, _size); - memcpy(tmp_data2, _data + _offset, _size); - int vol1 = (_vol1 << 1) | (_vol1 >> 5); - int vol2 = (_vol2 << 1) | (_vol2 >> 5); - _mod->startChannel(_id | 0x000, tmp_data1, _size, BASE_FREQUENCY / _freq1, vol1, 0, _size, -127); - _mod->startChannel(_id | 0x100, tmp_data2, _size, BASE_FREQUENCY / _freq2, vol2, 0, _size, 127); - } -}; - -// intermittently plays a single waveform for a specified duration -// used when applying a wrench to a pipe -class V2A_Sound_Special_Maniac46 : public V2A_Sound_Base<1> { -public: - V2A_Sound_Special_Maniac46(uint16 offset, uint16 size, uint16 freq, uint8 vol, uint8 loopwidth, uint8 numloops) : - V2A_Sound_Base<1>(offset, size), _freq(freq), _vol(vol), _loopwidth(loopwidth), _numloops(numloops) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - _data = (char *)malloc(READ_LE_UINT16(data)); - memcpy(_data, data, READ_LE_UINT16(data)); - soundon(); - _loop = 0; - _loopctr = 0; - } - virtual bool update() { - assert(_id); - _loop++; - if (_loop == _loopwidth) { - _loop = 0; - _loopctr++; - if (_loopctr == _numloops) - return false; - _mod->stopChannel(_id); - soundon(); - } - return true; - } -private: - const uint16 _freq; - const uint8 _vol; - const uint8 _loopwidth; - const uint8 _numloops; - - int _loop; - int _loopctr; - - void soundon() { - char *tmp_data = (char *)malloc(_size); - memcpy(tmp_data, _data + _offset, _size); - _mod->startChannel(_id, tmp_data, _size, BASE_FREQUENCY / _freq, (_vol << 2) | (_vol >> 4), 0, 0); - } -}; - -// plays a single waveform at irregular intervals for a specified number of frames, possibly looped -// used for typewriter noises, as well as tapping on the bus in Zak McKracken -class V2A_Sound_Special_ManiacTypewriter : public V2A_Sound_Base<1> { -public: - V2A_Sound_Special_ManiacTypewriter(uint16 offset, uint16 size, uint16 freq, uint8 vol, uint8 numdurs, const uint8 *durations, bool looped) : - V2A_Sound_Base<1>(offset, size), _freq(freq), _vol(vol), _numdurs(numdurs), _durations(durations), _looped(looped) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - _data = (char *)malloc(READ_LE_UINT16(data)); - memcpy(_data, data, READ_LE_UINT16(data)); - soundon(); - _curdur = 0; - _ticks = _durations[_curdur++]; - } - virtual bool update() { - assert(_id); - _ticks--; - if (!_ticks) { - if (_curdur == _numdurs) { - if (_looped) - _curdur = 0; - else - return false; - } - _mod->stopChannel(_id); - soundon(); - _ticks = _durations[_curdur++]; - } - return true; - } -private: - const uint16 _freq; - const uint8 _vol; - const uint8 _numdurs; - const uint8 *_durations; - const bool _looped; - - int _ticks; - int _curdur; - - void soundon() { - char *tmp_data = (char *)malloc(_size); - memcpy(tmp_data, _data + _offset, _size); - _mod->startChannel(_id, tmp_data, _size, BASE_FREQUENCY / _freq, (_vol << 2) | (_vol >> 4), 0, 0); - } -}; - -// plays two looped waveforms pitch bending up at various predefined rates -// used for some sort of siren-like noise in Maniac Mansion -class V2A_Sound_Special_Maniac44 : public V2A_Sound_Base<2> { -public: - V2A_Sound_Special_Maniac44(uint16 offset1, uint16 size1, uint16 offset2, uint16 size2, uint16 freq1, uint16 freq2, uint8 vol) : - _offset1(offset1), _size1(size1), _offset2(offset2), _size2(size2), _freq1(freq1), _freq2(freq2), _vol(vol) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - _data = (char *)malloc(READ_LE_UINT16(data)); - memcpy(_data, data, READ_LE_UINT16(data)); - - _loopnum = 1; - _step = 2; - _curfreq = _freq1; - - soundon(_data + _offset1, _size1); - } - virtual bool update() { - assert(_id); - _mod->setChannelFreq(_id | 0x000, BASE_FREQUENCY / _curfreq); - _mod->setChannelFreq(_id | 0x100, BASE_FREQUENCY / (_curfreq + 3)); - _curfreq -= _step; - if (_loopnum == 7) { - if ((BASE_FREQUENCY / _curfreq) >= 65536) - return false; - else - return true; - } - if (_curfreq >= _freq2) - return true; - const char steps[8] = {0, 2, 2, 3, 4, 8, 15, 2}; - _curfreq = _freq1; - _step = steps[++_loopnum]; - if (_loopnum == 7) { - _mod->stopChannel(_id | 0x000); - _mod->stopChannel(_id | 0x100); - soundon(_data + _offset2, _size2); - } - return true; - } -private: - const uint16 _offset1; - const uint16 _size1; - const uint16 _offset2; - const uint16 _size2; - const uint16 _freq1; - const uint16 _freq2; - const uint8 _vol; - - int _curfreq; - uint16 _loopnum; - uint16 _step; - - void soundon(const char *data, int size) { - char *tmp_data1 = (char *)malloc(size); - char *tmp_data2 = (char *)malloc(size); - memcpy(tmp_data1, data, size); - memcpy(tmp_data2, data, size); - int vol = (_vol << 1) | (_vol >> 5); - _mod->startChannel(_id | 0x000, tmp_data1, size, BASE_FREQUENCY / _curfreq, vol, 0, size, -127); - _mod->startChannel(_id | 0x100, tmp_data2, size, BASE_FREQUENCY / (_curfreq + 3), vol, 0, size, 127); - } -}; - -// plays 4 looped waveforms, each at modulating frequencies -// used for the siren noise in Maniac Mansion -class V2A_Sound_Special_Maniac32 : public V2A_Sound_Base<4> { -public: - V2A_Sound_Special_Maniac32(uint16 offset1, uint16 size1, uint16 offset2, uint16 size2, uint8 vol) : - _offset1(offset1), _size1(size1), _offset2(offset2), _size2(size2), _vol(vol) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - - _freq1 = 0x02D0; - _step1 = -0x000A; - _freq2 = 0x0122; - _step2 = 0x000A; - _freq3 = 0x02BC; - _step3 = -0x0005; - _freq4 = 0x010E; - _step4 = 0x0007; - - char *tmp_data1 = (char *)malloc(_size1); - char *tmp_data2 = (char *)malloc(_size2); - char *tmp_data3 = (char *)malloc(_size1); - char *tmp_data4 = (char *)malloc(_size2); - memcpy(tmp_data1, data + _offset1, _size1); - memcpy(tmp_data2, data + _offset2, _size2); - memcpy(tmp_data3, data + _offset1, _size1); - memcpy(tmp_data4, data + _offset2, _size2); - _mod->startChannel(_id | 0x000, tmp_data1, _size1, BASE_FREQUENCY / _freq1, _vol, 0, _size1, -127); - _mod->startChannel(_id | 0x100, tmp_data2, _size2, BASE_FREQUENCY / _freq2, _vol, 0, _size2, 127); - _mod->startChannel(_id | 0x200, tmp_data3, _size1, BASE_FREQUENCY / _freq3, _vol, 0, _size1, 127); - _mod->startChannel(_id | 0x300, tmp_data4, _size2, BASE_FREQUENCY / _freq4, _vol, 0, _size2, -127); - } - virtual bool update() { - assert(_id); - updatefreq(_freq1, _step1, 0x00AA, 0x00FA); - updatefreq(_freq2, _step2, 0x019A, 0x03B6); - updatefreq(_freq3, _step3, 0x00AA, 0x00FA); - updatefreq(_freq4, _step4, 0x019A, 0x03B6); - _mod->setChannelFreq(_id | 0x000, BASE_FREQUENCY / _freq1); - _mod->setChannelFreq(_id | 0x100, BASE_FREQUENCY / _freq2); - _mod->setChannelFreq(_id | 0x200, BASE_FREQUENCY / _freq3); - _mod->setChannelFreq(_id | 0x300, BASE_FREQUENCY / _freq4); - return true; - } -private: - const uint16 _offset1; - const uint16 _size1; - const uint16 _offset2; - const uint16 _size2; - const uint8 _vol; - - uint16 _freq1; - int16 _step1; - uint16 _freq2; - int16 _step2; - uint16 _freq3; - int16 _step3; - uint16 _freq4; - int16 _step4; - - void updatefreq(uint16 &freq, int16 &step, uint16 min, uint16 max) { - freq += step; - if (freq <= min) { - freq = min; - step = -step; - } - if (freq >= max) { - freq = max; - step = -step; - } - } -}; - -// plays 4 looped waveforms -// used in the white crystal chamber -class V2A_Sound_Special_Zak70 : public V2A_Sound_Base<4> { -public: - V2A_Sound_Special_Zak70(uint16 offset, uint16 size, uint16 freq1, uint16 freq2, uint16 freq3, uint16 freq4, uint8 vol) : - V2A_Sound_Base<4>(offset, size), _freq1(freq1), _freq2(freq2), _freq3(freq3), _freq4(freq4), _vol(vol) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - - char *tmp_data1 = (char *)malloc(_size); - char *tmp_data2 = (char *)malloc(_size); - char *tmp_data3 = (char *)malloc(_size); - char *tmp_data4 = (char *)malloc(_size); - memcpy(tmp_data1, data + _offset, _size); - memcpy(tmp_data2, data + _offset, _size); - memcpy(tmp_data3, data + _offset, _size); - memcpy(tmp_data4, data + _offset, _size); - _mod->startChannel(_id | 0x000, tmp_data1, _size, BASE_FREQUENCY / _freq1, _vol, 0, _size, -127); - _mod->startChannel(_id | 0x100, tmp_data2, _size, BASE_FREQUENCY / _freq2, _vol, 0, _size, 127); - _mod->startChannel(_id | 0x200, tmp_data3, _size, BASE_FREQUENCY / _freq3, _vol, 0, _size, 127); - _mod->startChannel(_id | 0x300, tmp_data4, _size, BASE_FREQUENCY / _freq4, _vol, 0, _size, -127); - } - virtual bool update() { - assert(_id); - return true; - } -protected: - const uint16 _freq1; - const uint16 _freq2; - const uint16 _freq3; - const uint16 _freq4; - const uint8 _vol; -}; - -// plays 4 looped waveforms and fades volume to zero after a specific delay -// used when the Mindbender disappears -class V2A_Sound_Special_Zak101 : public V2A_Sound_Special_Zak70 { -public: - V2A_Sound_Special_Zak101(uint16 offset, uint16 size, uint16 freq1, uint16 freq2, uint16 freq3, uint16 freq4, uint8 vol, uint16 dur) : - V2A_Sound_Special_Zak70(offset, size, freq1, freq2, freq3, freq4, vol), _dur(dur) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - V2A_Sound_Special_Zak70::start(mod, id, data); - _ticks = _dur; - } - virtual bool update() { - assert(_id); - if (!--_ticks) - return false; - if (_ticks < _vol) { - _mod->setChannelVol(_id | 0x000, _ticks); - _mod->setChannelVol(_id | 0x100, _ticks); - _mod->setChannelVol(_id | 0x200, _ticks); - _mod->setChannelVol(_id | 0x300, _ticks); - } - return true; - } -private: - const uint16 _dur; - - int _ticks; -}; - -// plays a single looped waveform and slowly fades volume to zero -// used when refilling oxygen -class V2A_Sound_Special_Zak37 : public V2A_Sound_Base<1> { -public: - V2A_Sound_Special_Zak37(uint16 offset, uint16 size, uint16 freq, uint8 vol) : - V2A_Sound_Base<1>(offset, size), _freq(freq), _vol(vol) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - char *tmp_data = (char *)malloc(_size); - memcpy(tmp_data, data + _offset, _size); - _curvol = _vol << 2; - _mod->startChannel(_id, tmp_data, _size, BASE_FREQUENCY / _freq, _curvol, 0, _size); - } - virtual bool update() { - assert(_id); - if (!--_curvol) - return false; - _mod->setChannelVol(_id, _curvol); - return true; - } -private: - const uint16 _freq; - const uint8 _vol; - - int _curvol; -}; - -// plays a single looped waveform, slowly bending from one frequency to another and then slowly fading volume from max to zero -// used in Zak for airplane taking off and landing -class V2A_Sound_Special_ZakAirplane : public V2A_Sound_Base<1> { -public: - V2A_Sound_Special_ZakAirplane(uint16 offset, uint16 size, uint16 freq1, uint16 freq2) : - V2A_Sound_Base<1>(offset, size), _freq1(freq1), _freq2(freq2) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - char *tmp_data = (char *)malloc(_size); - memcpy(tmp_data, data + _offset, _size); - _curfreq = _freq1; - _curvol = 0x3F; - _mod->startChannel(_id, tmp_data, _size, BASE_FREQUENCY / _curfreq, (_curvol << 2) | (_curvol >> 4), 0, _size); - _ticks = 0; - } - virtual bool update() { - assert(_id); - _ticks++; - if (_ticks < 4) - return true; - _ticks = 0; - if (_curfreq == _freq2) { - _curvol--; - if (_curvol == 0) - return false; - _mod->setChannelVol(_id, (_curvol << 2) | (_curvol >> 4)); - } else { - if (_freq1 < _freq2) - _curfreq++; - else - _curfreq--; - _mod->setChannelFreq(_id, BASE_FREQUENCY / _curfreq); - } - return true; - } -private: - const uint16 _freq1; - const uint16 _freq2; - - uint16 _curfreq; - int _curvol; - int _ticks; -}; - -// plays 4 looped waveforms, starting at specific frequencies and bending at different rates while fading volume to zero -// used when the white crystal machine turns off -class V2A_Sound_Special_Zak71 : public V2A_Sound_Base<4> { -public: - V2A_Sound_Special_Zak71(uint16 offset, uint16 size) : - _offset(offset), _size(size) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - - _freq1 = 0x00C8; - _freq2 = 0x0190; - _freq3 = 0x0320; - _freq4 = 0x0640; - _vol = 0x78; - - char *tmp_data1 = (char *)malloc(_size); - char *tmp_data2 = (char *)malloc(_size); - char *tmp_data3 = (char *)malloc(_size); - char *tmp_data4 = (char *)malloc(_size); - memcpy(tmp_data1, data + _offset, _size); - memcpy(tmp_data2, data + _offset, _size); - memcpy(tmp_data3, data + _offset, _size); - memcpy(tmp_data4, data + _offset, _size); - _mod->startChannel(_id | 0x000, tmp_data1, _size, BASE_FREQUENCY / _freq1, MIN((_vol >> 1) + 3, 0x32), 0, _size, -127); - _mod->startChannel(_id | 0x100, tmp_data2, _size, BASE_FREQUENCY / _freq2, MIN((_vol >> 1) + 3, 0x32), 0, _size, 127); - _mod->startChannel(_id | 0x200, tmp_data3, _size, BASE_FREQUENCY / _freq3, MIN((_vol >> 1) + 3, 0x32), 0, _size, 127); - _mod->startChannel(_id | 0x300, tmp_data4, _size, BASE_FREQUENCY / _freq4, MIN((_vol >> 1) + 3, 0x32), 0, _size, -127); - } - virtual bool update() { - assert(_id); - _freq1 += 0x14; - _freq2 += 0x1E; - _freq3 += 0x32; - _freq4 += 0x50; - _mod->setChannelFreq(_id | 0x000, BASE_FREQUENCY / _freq1); - _mod->setChannelFreq(_id | 0x100, BASE_FREQUENCY / _freq2); - _mod->setChannelFreq(_id | 0x200, BASE_FREQUENCY / _freq3); - _mod->setChannelFreq(_id | 0x300, BASE_FREQUENCY / _freq4); - _vol--; - if (_vol == 0) - return false; - _mod->setChannelVol(_id | 0x000, MIN((_vol >> 1) + 3, 0x32)); - _mod->setChannelVol(_id | 0x100, MIN((_vol >> 1) + 3, 0x32)); - _mod->setChannelVol(_id | 0x200, MIN((_vol >> 1) + 3, 0x32)); - _mod->setChannelVol(_id | 0x300, MIN((_vol >> 1) + 3, 0x32)); - return true; - } -private: - const uint16 _offset; - const uint16 _size; - - uint16 _freq1; - uint16 _freq2; - uint16 _freq3; - uint16 _freq4; - uint8 _vol; -}; - -// plays a single looped waveform, bending the frequency upward at a varying rate -// used when the Skolarian device activates -class V2A_Sound_Special_Zak99 : public V2A_Sound_Base<1> { -public: - V2A_Sound_Special_Zak99(uint16 offset, uint16 size, uint16 freq1, uint16 freq2, uint8 vol) : - V2A_Sound_Base<1>(offset, size), _freq1(freq1), _freq2(freq2), _vol(vol) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - char *tmp_data = (char *)malloc(_size); - memcpy(tmp_data, data + _offset, _size); - _curfreq = _freq1; - _mod->startChannel(_id, tmp_data, _size, BASE_FREQUENCY / _curfreq, (_vol << 2) | (_vol >> 4), 0, _size); - _bendrate = 8; - _bendctr = 100; - _holdctr = 30; - } - virtual bool update() { - assert(_id); - if (_curfreq >= _freq2) { - _mod->setChannelFreq(_id, BASE_FREQUENCY / _curfreq); - _curfreq -= _bendrate; - if (--_bendctr) - return true; - _bendrate--; - if (_bendrate < 2) - _bendrate = 2; - } else { - if (!--_holdctr) - return false; - } - return true; - } -private: - const uint16 _freq1; - const uint16 _freq2; - const uint16 _vol; - - uint16 _curfreq; - uint16 _bendrate; - uint16 _bendctr; - uint16 _holdctr; -}; - -// plays one waveform, then switches to a different looped waveform and slowly fades volume to zero -// used when depressurizing the hostel -class V2A_Sound_Special_Zak54 : public V2A_Sound_Base<1> { -public: - V2A_Sound_Special_Zak54(uint16 offset1, uint16 size1, uint16 offset2, uint16 size2, uint16 freq) : - _offset1(offset1), _size1(size1), _offset2(offset2), _size2(size2), _freq(freq) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - _data = (char *)malloc(READ_LE_UINT16(data)); - memcpy(_data, data, READ_LE_UINT16(data)); - char *tmp_data = (char *)malloc(_size1); - memcpy(tmp_data, data + _offset1, _size1); - _vol = 0xFC; - _mod->startChannel(_id, tmp_data, _size1, BASE_FREQUENCY / _freq, _vol, 0, _size1); - _loop = _size1 * _freq * 60 / BASE_FREQUENCY; - } - virtual bool update() { - assert(_id); - if (!_loop) { - _vol--; - if (_vol) - _mod->setChannelVol(_id, _vol); - else - return false; - } else if (!--_loop) { - _mod->stopChannel(_id); - char *tmp_data = (char *)malloc(_size2); - memcpy(tmp_data, _data + _offset2, _size2); - _mod->startChannel(_id, tmp_data, _size2, BASE_FREQUENCY / _freq, _vol, 0, _size2); - } - return true; - } - -private: - const uint16 _offset1; - const uint16 _offset2; - const uint16 _size1; - const uint16 _size2; - const uint16 _freq; - - int _vol; - int _loop; -}; - -// plays 2 looped waveforms at different frequencies, pulsing at different frequencies and ramping the volume up and down once -// used when abducted at the Bermuda Triangle -class V2A_Sound_Special_Zak110 : public V2A_Sound_Base<2> { -public: - V2A_Sound_Special_Zak110(uint16 offset1, uint16 size1, uint16 offset2, uint16 size2, uint16 freq1, uint16 freq2) : - _offset1(offset1), _size1(size1), _offset2(offset2), _size2(size2), _freq1(freq1), _freq2(freq2) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - _data = (char *)malloc(READ_LE_UINT16(data)); - memcpy(_data, data, READ_LE_UINT16(data)); - - _loopnum = 0; - _vol = 0x1500; - _beepcount = 0; - } - virtual bool update() { - char *tmp_data; - assert(_id); - - int vol = (((_vol >> 7) & 0x7E) | ((_vol >> 15) & 0x01)); - _beepcount++; - - switch (_beepcount & 0x3) { - case 0: - _mod->stopChannel(_id | 0x000); - break; - case 1: - tmp_data = (char *)malloc(_size1); - memcpy(tmp_data, _data + _offset1, _size1); - _mod->startChannel(_id | 0x000, tmp_data, _size1, BASE_FREQUENCY / _freq1, vol, 0, _size1, -127); - break; - default: - _mod->setChannelVol(_id | 0x000, vol); - break; - } - - switch (_beepcount & 0x7) { - case 0: - _mod->stopChannel(_id | 0x100); - break; - case 1: - tmp_data = (char *)malloc(_size2); - memcpy(tmp_data, _data + _offset2, _size2); - _mod->startChannel(_id | 0x100, tmp_data, _size2, BASE_FREQUENCY / _freq2, vol, 0, _size2, 127); - break; - default: - _mod->setChannelVol(_id | 0x100, vol); - break; - } - - if (_loopnum == 0) { - _vol += 0x80; - if (_vol == 0x4000) { - _vol = 0x3F00; - _loopnum = 1; - } - } else if (_loopnum == 1) { - _vol -= 0x20; - if (_vol == 0x2000) - _loopnum = 2; - } - return true; - } -private: - const uint16 _offset1; - const uint16 _size1; - const uint16 _offset2; - const uint16 _size2; - const uint16 _freq1; - const uint16 _freq2; - - uint16 _loopnum; - uint16 _vol; - uint16 _beepcount; -}; - -// plays a stereo siren, sweeping up and down quickly several times before sweeping up slowly, stopping, and then going silent -// door orb sound in the Mars Face -class V2A_Sound_Special_Zak32 : public V2A_Sound_Base<2> { -public: - V2A_Sound_Special_Zak32(uint16 offset1, uint16 offset2, uint16 size1, uint16 size2) : - _offset1(offset1), _offset2(offset2), _size1(size1), _size2(size2) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - _data = (char *)malloc(READ_LE_UINT16(data)); - memcpy(_data, data, READ_LE_UINT16(data)); - - _loopnum = 1; - _freqmod = -4; - _freq = 0x00C8; - - char *tmp_data1 = (char *)malloc(_size1); - char *tmp_data2 = (char *)malloc(_size1); - memcpy(tmp_data1, _data + _offset1, _size1); - memcpy(tmp_data2, _data + _offset1, _size1); - _mod->startChannel(_id | 0x000, tmp_data1, _size1, BASE_FREQUENCY / _freq, 0x7F, 0, _size1, -127); - _mod->startChannel(_id | 0x100, tmp_data2, _size1, BASE_FREQUENCY / (_freq + 3), 0x7F, 0, _size1, 127); - } - virtual bool update() { - assert(_id); - - if (_loopnum < 7) { - _mod->setChannelFreq(_id | 0x000, BASE_FREQUENCY / _freq); - _mod->setChannelFreq(_id | 0x100, BASE_FREQUENCY / (_freq + 3)); - _freq += _freqmod; - if (_freq <= 0x80) - _freqmod = -_freqmod; - else if (_freq >= 0xC8) { - _freqmod = -_freqmod; - _loopnum++; - if (_loopnum == 7) { - _freq = 0x00C8; - _freqmod = 2; - } - } - return true; - } else { - if (_loopnum == 7) { - _mod->stopChannel(_id | 0x000); - _mod->stopChannel(_id | 0x100); - - char *tmp_data1 = (char *)malloc(_size2); - char *tmp_data2 = (char *)malloc(_size2); - memcpy(tmp_data1, _data + _offset2, _size2); - memcpy(tmp_data2, _data + _offset2, _size2); - _mod->startChannel(_id | 0x000, tmp_data1, _size2, BASE_FREQUENCY / (_freq), 0x7F, 0, _size2, -127); - _mod->startChannel(_id | 0x100, tmp_data2, _size2, BASE_FREQUENCY / (_freq + 3), 0x7F, 0, _size2, 127); - _loopnum++; - } else { - _mod->setChannelFreq(_id | 0x000, BASE_FREQUENCY / _freq); - _mod->setChannelFreq(_id | 0x100, BASE_FREQUENCY / (_freq + 3)); - } - _freq -= _freqmod; - if (_freq > 0) - return true; - else - return false; - } - } -private: - const uint16 _offset1; - const uint16 _offset2; - const uint16 _size1; - const uint16 _size2; - - uint16 _loopnum; - int16 _freqmod; - uint16 _freq; -}; - -// plays a looped waveform, increasing frequency and reducing volume once the frequency reaches a certain point -// probably used for some sort of vehicle sound -class V2A_Sound_Special_Zak52 : public V2A_Sound_Base<1> { -public: - V2A_Sound_Special_Zak52(uint16 offset, uint16 size) : - _offset(offset), _size(size) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - _data = (char *)malloc(READ_LE_UINT16(data)); - memcpy(_data, data, READ_LE_UINT16(data)); - - _curfreq = 0x0312; - - char *tmp_data = (char *)malloc(_size); - memcpy(tmp_data, _data + _offset, _size); - _mod->startChannel(_id | 0x000, tmp_data, _size, BASE_FREQUENCY / _curfreq, 0xFF, 0, _size, -127); - } - virtual bool update() { - assert(_id); - int vol = (_curfreq - 0xC8) >> 3; - if (vol > 0x3F) - vol = 0x3F; - vol = (vol << 2) | (vol >> 4); - _mod->setChannelFreq(_id | 0x000, BASE_FREQUENCY / _curfreq); - _mod->setChannelVol(_id | 0x000, vol); - _curfreq--; - if (_curfreq >= 0x107) - return true; - else - return false; - } -private: - const uint16 _offset; - const uint16 _size; - - uint16 _curfreq; -}; - -// plays a looped waveform, sweeping the frequency up while modulating it (alternating which channel updates) and fading volume out -// used when teleporting out with the yellow crystal -class V2A_Sound_Special_Zak61 : public V2A_Sound_Base<2> { -public: - V2A_Sound_Special_Zak61(uint16 offset, uint16 size) : - _offset(offset), _size(size) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - _data = (char *)malloc(READ_LE_UINT16(data)); - memcpy(_data, data, READ_LE_UINT16(data)); - - _loop = 1; - _curfreq = 0x01F4; - - char *tmp_data1 = (char *)malloc(_size); - char *tmp_data2 = (char *)malloc(_size); - memcpy(tmp_data1, _data + _offset, _size); - memcpy(tmp_data2, _data + _offset, _size); - _mod->startChannel(_id | 0x000, tmp_data1, _size, BASE_FREQUENCY / _curfreq, 0x7F, 0, _size, -127); - // start 2nd channel silent - _mod->startChannel(_id | 0x100, tmp_data2, _size, BASE_FREQUENCY / _curfreq, 0, 0, _size, 127); - } - virtual bool update() { - assert(_id); - int freq = (_loop << 4) + _curfreq; - int vol = freq - 0x76; - if (vol > 0x3F) - vol = 0x3F; - vol = (vol << 1) | (vol >> 5); - switch (_loop) { - case 0: - _mod->setChannelFreq(_id | 0x000, BASE_FREQUENCY / freq); - _mod->setChannelVol(_id | 0x000, vol); - break; - case 1: - _mod->setChannelFreq(_id | 0x100, BASE_FREQUENCY / freq); - _mod->setChannelVol(_id | 0x100, vol); - break; - } - _loop = (_loop + 1) & 3; - if (!_loop) { - _curfreq -= 4; - if (_curfreq <= 0x80) - return false; - } - return true; - } -private: - const uint16 _offset; - const uint16 _size; - - uint16 _loop; - uint16 _curfreq; -}; - -// just like Zak61, but sweeps frequency in the other direction -// used when teleporting in with the yellow crystal -class V2A_Sound_Special_Zak62 : public V2A_Sound_Base<2> { -public: - V2A_Sound_Special_Zak62(uint16 offset, uint16 size) : - _offset(offset), _size(size) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - _data = (char *)malloc(READ_LE_UINT16(data)); - memcpy(_data, data, READ_LE_UINT16(data)); - - _loop = 1; - _curfreq = 0x0080; - - char *tmp_data1 = (char *)malloc(_size); - char *tmp_data2 = (char *)malloc(_size); - memcpy(tmp_data1, _data + _offset, _size); - memcpy(tmp_data2, _data + _offset, _size); - _mod->startChannel(_id | 0x000, tmp_data1, _size, BASE_FREQUENCY / _curfreq, 0x7F, 0, _size, -127); - // start 2nd channel silent - _mod->startChannel(_id | 0x100, tmp_data2, _size, BASE_FREQUENCY / _curfreq, 0, 0, _size, 127); - } - virtual bool update() { - assert(_id); - int freq = (_loop << 4) + _curfreq; - int vol = 0x0200 - freq; - if (vol > 0x3F) - vol = 0x3F; - vol = (vol << 1) | (vol >> 5); - switch (_loop) { - case 0: - _mod->setChannelFreq(_id | 0x000, BASE_FREQUENCY / freq); - _mod->setChannelVol(_id | 0x000, vol); - break; - case 1: - _mod->setChannelFreq(_id | 0x100, BASE_FREQUENCY / freq); - _mod->setChannelVol(_id | 0x100, vol); - break; - } - _loop = (_loop + 1) & 3; - if (!_loop) { - _curfreq += 4; - if (_curfreq >= 0x01F4) - return false; - } - return true; - } -private: - const uint16 _offset; - const uint16 _size; - - uint16 _loop; - uint16 _curfreq; -}; - -// plays a series of double-looped sounds at varying frequencies and delays, very specialized -// Guardian of the Sphinx, perhaps? -class V2A_Sound_Special_Zak82 : public V2A_Sound_Base<4> { -public: - V2A_Sound_Special_Zak82(uint16 offset, uint16 size) : - _offset(offset), _size(size) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - _data = (char *)malloc(READ_LE_UINT16(data)); - memcpy(_data, data, READ_LE_UINT16(data)); - - // Wait values were to insure playing an integral number of loops on each sample - // and have been adjusted to reflect the actual duration spent playing - _loop = 0; - _playctr = 240; - _wait1 = 76; // was 39, extended to loop twice - _wait2 = 10000; - _wait3 = 10000; - _wait4 = 10000; - - int size = 2000; - int offset = _offset; - assert(offset + size <= _offset + _size); - char *tmp_data = (char *)malloc(size); - memcpy(tmp_data, _data + offset, size); - _mod->startChannel(_id | 0x000, tmp_data, size, BASE_FREQUENCY / 0x0479, 0xFF, 0, size); - } - virtual bool update() { - assert(_id); - char *tmp_data1, *tmp_data2; - int size, offset = _offset; - - if (!--_wait1) { - _wait1 = 10000; - _mod->stopChannel(_id | 0x000); - } else if (!--_wait2) { - _wait2 = 10000; - _mod->stopChannel(_id | 0x000); - } else if (!--_wait3) { - _wait3 = 10000; - _mod->stopChannel(_id | 0x200); - } else if (!--_wait4) { - _wait4 = 10000; - _mod->stopChannel(_id | 0x100); - _mod->stopChannel(_id | 0x300); - } - if (--_playctr) - return true; - - switch (++_loop) { - case 1: - size = 6300; - offset += 0x07D0; - assert(offset + size <= _offset + _size); - tmp_data1 = (char *)malloc(size); - memcpy(tmp_data1, _data + offset, size); - _mod->startChannel(_id | 0x000, tmp_data1, size, BASE_FREQUENCY / 0x0479, 0x7F, 0, size, -127); - _wait2 = 241; // was 120, extended to loop twice - _playctr = 10; - break; - case 2: - size = 6292; - offset += 0x206C; - assert(offset + size <= _offset + _size); - tmp_data1 = (char *)malloc(size); - memcpy(tmp_data1, _data + offset, size); - _mod->startChannel(_id | 0x200, tmp_data1, size, BASE_FREQUENCY / 0x0384, 0x7F, 0, size, 127); - _wait3 = 189; // was 94, extended to loop twice - _playctr = 20; - break; - case 3: - size = 6300; - offset += 0x07D0; - assert(offset + size <= _offset + _size); - tmp_data1 = (char *)malloc(size); - tmp_data2 = (char *)malloc(size); - memcpy(tmp_data1, _data + offset, size); - memcpy(tmp_data2, _data + offset, size); - _mod->startChannel(_id | 0x100, tmp_data1, size, BASE_FREQUENCY / 0x01E0, 0x7F, 0, size, 127); - _mod->startChannel(_id | 0x300, tmp_data2, size, BASE_FREQUENCY / 0x01E0, 0x7F, 0, size, -127); - _wait4 = 101; // was 50, extended to loop twice - _playctr = 120; - break; - default: - return false; - } - return true; - } -private: - const uint16 _offset; - const uint16 _size; - - uint16 _loop; - uint16 _playctr; - uint16 _wait1; - uint16 _wait2; - uint16 _wait3; - uint16 _wait4; -}; - -// plays a "ding" (volume 0-max-0) followed by a sound sample, a pause, then loops again -// Mars Tram about to depart -class V2A_Sound_Special_Zak86 : public V2A_Sound_Base<1> { -public: - V2A_Sound_Special_Zak86(uint16 offset, uint16 size) : - _offset(offset), _size(size) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - _data = (char *)malloc(READ_LE_UINT16(data)); - memcpy(_data, data, READ_LE_UINT16(data)); - - _mode = 0; - _vol = 0; - _volmod = 16; - - int size = 32; - int offset = _offset + 0x2B8E; - assert(offset + size <= _offset + _size); - char *tmp_data = (char *)malloc(size); - memcpy(tmp_data, _data + offset, size); - _mod->startChannel(_id | 0x000, tmp_data, size, BASE_FREQUENCY / 0x0096, 0, 0, size, 0); - } - virtual bool update() { - assert(_id); - int size, offset; - char *tmp_data; - - switch (_mode) { - case 0: - _mod->setChannelVol(_id | 0x000, (_vol << 2) | (_vol >> 4)); - if (_vol + _volmod > 0) { - _vol += _volmod; - if (_vol > 0x3F) { - _vol = 0x3F; - _volmod = -4; - } - return true; - } - _mod->stopChannel(_id | 0x000); - _mode = 1; - - size = 0x2B8E; - offset = _offset; - assert(offset + size <= _offset + _size); - tmp_data = (char *)malloc(size); - memcpy(tmp_data, _data + offset, size); - _mod->startChannel(_id | 0x000, tmp_data, size, BASE_FREQUENCY / 0x0152, 0x3F); - _volmod = 100; - break; - case 1: - if (!--_volmod) { - size = 32; - offset = _offset + 0x2B8E; - assert(offset + size <= _offset + _size); - tmp_data = (char *)malloc(size); - memcpy(tmp_data, _data + offset, size); - _mod->startChannel(_id | 0x000, tmp_data, size, BASE_FREQUENCY / 0x0096, 0, 0, size, 0); - _mode = 0; - _vol = 0; - _volmod = 16; - } - break; - } - return true; - } -private: - const uint16 _offset; - const uint16 _size; - - uint16 _mode; - uint16 _vol; - int16 _volmod; -}; - -// modulates volume on 4 samples, frequency on only 2 of them -// Skolarian device pedestal activated without any parts -class V2A_Sound_Special_Zak98 : public V2A_Sound_Base<4> { -public: - V2A_Sound_Special_Zak98(uint16 offset, uint16 size) : - _offset(offset), _size(size) { } - virtual void start(Player_MOD *mod, int id, const byte *data) { - _mod = mod; - _id = id; - _data = (char *)malloc(READ_LE_UINT16(data)); - memcpy(_data, data, READ_LE_UINT16(data)); - - _freq[0] = 0x1E0; - _freq[1] = 0x3E8; - _freq[2] = 0x200; - _freq[3] = 0x408; - _vol[0] = 0x3F; - _vol[1] = 0x3F; - _vol[2] = 0x3F; - _vol[3] = 0x3F; - _freqmod = 4; - _volmod[0] = -2; - _volmod[1] = -1; - - char *tmp_data1 = (char *)malloc(_size); - char *tmp_data2 = (char *)malloc(_size); - char *tmp_data3 = (char *)malloc(_size); - char *tmp_data4 = (char *)malloc(_size); - memcpy(tmp_data1, _data + _offset, _size); - memcpy(tmp_data2, _data + _offset, _size); - memcpy(tmp_data3, _data + _offset, _size); - memcpy(tmp_data4, _data + _offset, _size); - _mod->startChannel(_id | 0x000, tmp_data1, _size, BASE_FREQUENCY / _freq[0], _vol[0], 0, _size, -127); - _mod->startChannel(_id | 0x100, tmp_data2, _size, BASE_FREQUENCY / _freq[1], _vol[1], 0, _size, 127); - _mod->startChannel(_id | 0x200, tmp_data3, _size, BASE_FREQUENCY / _freq[2], _vol[2], 0, _size, 127); - _mod->startChannel(_id | 0x300, tmp_data4, _size, BASE_FREQUENCY / _freq[3], _vol[3], 0, _size, -127); - } - virtual bool update() { - assert(_id); - const uint16 _minvol[2] = {0x2E, 0x32}; - int i; - for (i = 0; i < 4; i++) { - _mod->setChannelFreq(_id | (i << 8), BASE_FREQUENCY / _freq[i]); - _mod->setChannelVol(_id | (i << 8), _vol[i]); - } - for (i = 0; i < 2; i++) { - _vol[i] += _volmod[i]; - if (_vol[i] > 0x3F) { - _vol[i] = 0x3F; - _volmod[i] = -_volmod[i]; - } else if (_vol[i] < _minvol[i]) { - _vol[i] = _minvol[i]; - _volmod[i] = -_volmod[i]; - } - _vol[i + 2] = _vol[i]; - } - _freq[0] += _freqmod; - if (_freq[0] > 0x2BC) { - _freq[0] = 0x2BC; - _freqmod = -_freqmod; - } else if (_freq[0] < 0x1E0) { - _freq[0] = 0x1E0; - _freqmod = -_freqmod; - } - _freq[2] = _freq[0] + 0x20; - return true; - } -private: - const uint16 _offset; - const uint16 _size; - - uint16 _freq[4]; - uint16 _vol[4]; - int16 _freqmod; - int16 _volmod[2]; -}; - -#define CRCToSound(CRC, SOUND) \ - if (crc == CRC) \ - return new SOUND - -static V2A_Sound *findSound(unsigned long crc) { - CRCToSound(0x8FAB08C4, V2A_Sound_SingleLooped(0x006C, 0x2B58, 0x016E, 0x3F)); // Maniac 17 - CRCToSound(0xB673160A, V2A_Sound_SingleLooped(0x006C, 0x1E78, 0x01C2, 0x1E)); // Maniac 38 - CRCToSound(0x4DB1D0B2, V2A_Sound_MultiLooped(0x0072, 0x1BC8, 0x023D, 0x3F, 0x0224, 0x3F)); // Maniac 20 - CRCToSound(0x754D75EF, V2A_Sound_Single(0x0076, 0x0738, 0x01FC, 0x3F)); // Maniac 10 - CRCToSound(0x6E3454AF, V2A_Sound_Single(0x0076, 0x050A, 0x017C, 0x3F)); // Maniac 12 - CRCToSound(0x92F0BBB6, V2A_Sound_Single(0x0076, 0x3288, 0x012E, 0x3F)); // Maniac 41 - CRCToSound(0xE1B13982, V2A_Sound_MultiLoopedDuration(0x0078, 0x0040, 0x007C, 0x3F, 0x007B, 0x3F, 0x001E)); // Maniac 21 - CRCToSound(0x288B16CF, V2A_Sound_MultiLoopedDuration(0x007A, 0x0040, 0x007C, 0x3F, 0x007B, 0x3F, 0x000A)); // Maniac 11 - CRCToSound(0xA7565268, V2A_Sound_MultiLoopedDuration(0x007A, 0x0040, 0x00F8, 0x3F, 0x00F7, 0x3F, 0x000A)); // Maniac 19 - CRCToSound(0x7D419BFC, V2A_Sound_MultiLoopedDuration(0x007E, 0x0040, 0x012C, 0x3F, 0x0149, 0x3F, 0x001E)); // Maniac 22 - CRCToSound(0x1B52280C, V2A_Sound_Single(0x0098, 0x0A58, 0x007F, 0x32)); // Maniac 6 - CRCToSound(0x38D4A810, V2A_Sound_Single(0x0098, 0x2F3C, 0x0258, 0x32)); // Maniac 7 - CRCToSound(0x09F98FC2, V2A_Sound_Single(0x0098, 0x0A56, 0x012C, 0x32)); // Maniac 16 - CRCToSound(0x90440A65, V2A_Sound_Single(0x0098, 0x0208, 0x0078, 0x28)); // Maniac 28 - CRCToSound(0x985C76EF, V2A_Sound_Single(0x0098, 0x0D6E, 0x00C8, 0x32)); // Maniac 30 - CRCToSound(0x76156137, V2A_Sound_Single(0x0098, 0x2610, 0x017C, 0x39)); // Maniac 39 - CRCToSound(0x5D95F88C, V2A_Sound_Single(0x0098, 0x0A58, 0x007F, 0x1E)); // Maniac 65 - CRCToSound(0x92D704EA, V2A_Sound_SingleLooped(0x009C, 0x29BC, 0x012C, 0x3F, 0x1BD4, 0x0DE8)); // Maniac 15 - CRCToSound(0x92F5513C, V2A_Sound_Single(0x009E, 0x0DD4, 0x01F4, 0x3F)); // Maniac 13 - CRCToSound(0xCC2F3B5A, V2A_Sound_Single(0x009E, 0x00DE, 0x01AC, 0x3F)); // Maniac 43 - CRCToSound(0x153207D3, V2A_Sound_Single(0x009E, 0x0E06, 0x02A8, 0x3F)); // Maniac 67 - CRCToSound(0xC4F370CE, V2A_Sound_Single(0x00AE, 0x0330, 0x01AC, 0x3F)); // Maniac 8 - CRCToSound(0x928C4BAC, V2A_Sound_Single(0x00AE, 0x08D6, 0x01AC, 0x3F)); // Maniac 9 - CRCToSound(0x62D5B11F, V2A_Sound_Single(0x00AE, 0x165C, 0x01CB, 0x3F)); // Maniac 27 - CRCToSound(0x3AB22CB5, V2A_Sound_Single(0x00AE, 0x294E, 0x012A, 0x3F)); // Maniac 62 - CRCToSound(0x2D70BBE9, V2A_Sound_SingleLoopedPitchbend(0x00B4, 0x1702, 0x03E8, 0x0190, 0x3F, 5)); // Maniac 64 - CRCToSound(0xFA4C1B1C, V2A_Sound_Special_Maniac69(0x00B2, 0x1702, 0x0190, 0x3F)); // Maniac 69 - CRCToSound(0x19D50D67, V2A_Sound_Special_ManiacDing(0x00B6, 0x0020, 0x00C8, 16, 2)); // Maniac 14 - CRCToSound(0x3E6FBE15, V2A_Sound_Special_ManiacTentacle(0x00B2, 0x0010, 0x007C, 0x016D, 1)); // Maniac 25 - CRCToSound(0x5305753C, V2A_Sound_Special_ManiacTentacle(0x00B2, 0x0010, 0x007C, 0x016D, 7)); // Maniac 36 - CRCToSound(0x28895106, V2A_Sound_Special_Maniac59(0x00C0, 0x00FE, 0x00E9, 0x0111, 4, 0x0A)); // Maniac 59 - CRCToSound(0xB641ACF6, V2A_Sound_Special_Maniac61(0x00C8, 0x0100, 0x00C8, 0x01C2)); // Maniac 61 - CRCToSound(0xE1A91583, V2A_Sound_Special_ManiacPhone(0x00D0, 0x0040, 0x007C, 0x3F, 0x007B, 0x3F, 0x3C, 5, 6)); // Maniac 23 - CRCToSound(0x64816ED5, V2A_Sound_Special_ManiacPhone(0x00D0, 0x0040, 0x00BE, 0x37, 0x00BD, 0x37, 0x3C, 5, 6)); // Maniac 24 - CRCToSound(0x639D72C2, V2A_Sound_Special_Maniac46(0x00D0, 0x10A4, 0x0080, 0x3F, 0x28, 3)); // Maniac 46 - CRCToSound(0xE8826D92, V2A_Sound_Special_ManiacTypewriter(0x00EC, 0x025A, 0x023C, 0x3F, 8, (const uint8 *)"\x20\x41\x04\x21\x08\x10\x13\x07", true)); // Maniac 45 - CRCToSound(0xEDFF3D41, V2A_Sound_Single(0x00F8, 0x2ADE, 0x01F8, 0x3F)); // Maniac 42 (this should echo, but it's barely noticeable and I don't feel like doing it) - CRCToSound(0x15606D06, V2A_Sound_Special_Maniac32(0x0148, 0x0020, 0x0168, 0x0020, 0x3F)); // Maniac 32 - CRCToSound(0x753EAFE3, V2A_Sound_Special_Maniac44(0x017C, 0x0010, 0x018C, 0x0020, 0x00C8, 0x0080, 0x3F)); // Maniac 44 - CRCToSound(0xB1AB065C, V2A_Sound_Music(0x0032, 0x00B2, 0x08B2, 0x1222, 0x1A52, 0x23C2, 0x3074, false)); // Maniac 50 - CRCToSound(0x091F5D9C, V2A_Sound_Music(0x0032, 0x0132, 0x0932, 0x1802, 0x23D2, 0x3EA2, 0x4F04, false)); // Maniac 58 - - CRCToSound(0x8E2C8AB3, V2A_Sound_SingleLooped(0x005C, 0x0F26, 0x0168, 0x3C)); // Zak 41 - CRCToSound(0x3792071F, V2A_Sound_SingleLooped(0x0060, 0x1A18, 0x06A4, 0x3F)); // Zak 88 - CRCToSound(0xF192EDE9, V2A_Sound_SingleLooped(0x0062, 0x0054, 0x01FC, 0x1E)); // Zak 68 - CRCToSound(0xC43B0245, V2A_Sound_Special_Zak70(0x006C, 0x166E, 0x00C8, 0x0190, 0x0320, 0x0640, 0x32)); // Zak 70 - CRCToSound(0xCEB51670, V2A_Sound_SingleLooped(0x00AC, 0x26DC, 0x012C, 0x3F)); // Zak 42 - CRCToSound(0x10347B51, V2A_Sound_SingleLooped(0x006C, 0x00E0, 0x0594, 0x3F)); // Zak 18 - CRCToSound(0x9D2FADC0, V2A_Sound_MultiLooped(0x0072, 0x1FC8, 0x016A, 0x3F, 0x01CE, 0x3F)); // Zak 80 - CRCToSound(0xFAD2C676, V2A_Sound_MultiLooped(0x0076, 0x0010, 0x0080, 0x3F, 0x0090, 0x3B)); // Zak 40 - CRCToSound(0x01508B48, V2A_Sound_Single(0x0076, 0x0D8C, 0x017C, 0x3F)); // Zak 90 - CRCToSound(0x9C18DC46, V2A_Sound_Single(0x0076, 0x0D8C, 0x015E, 0x3F)); // Zak 91 - CRCToSound(0xF98F7EAC, V2A_Sound_Single(0x0076, 0x0D8C, 0x0140, 0x3F)); // Zak 92 - CRCToSound(0xC925FBEF, V2A_Sound_MultiLoopedDuration(0x0080, 0x0010, 0x0080, 0x3F, 0x0090, 0x3B, 0x0168)); // Zak 53 - CRCToSound(0xCAB35257, V2A_Sound_Special_Zak101(0x00DA, 0x425C, 0x023C, 0x08F0, 0x0640, 0x0478, 0x3F, 0x012C)); // Zak 101 - CRCToSound(0xA31FE4FD, V2A_Sound_Single(0x0094, 0x036A, 0x00E1, 0x3F)); // Zak 97 - CRCToSound(0x0A1AE0F5, V2A_Sound_Single(0x009E, 0x0876, 0x0168, 0x3F)); // Zak 5 - CRCToSound(0xD01A66CB, V2A_Sound_Single(0x009E, 0x04A8, 0x0168, 0x3F)); // Zak 47 - CRCToSound(0x5497B912, V2A_Sound_Single(0x009E, 0x0198, 0x01F4, 0x3F)); // Zak 39 - CRCToSound(0x2B50362F, V2A_Sound_Single(0x009E, 0x09B6, 0x023D, 0x3F)); // Zak 67 - CRCToSound(0x7BFB6E72, V2A_Sound_Single(0x009E, 0x0D14, 0x0078, 0x3F)); // Zak 69 - CRCToSound(0xB803A792, V2A_Sound_Single(0x009E, 0x2302, 0x02BC, 0x3F)); // Zak 78 - CRCToSound(0x7AB82E39, V2A_Sound_SingleLooped(0x00A0, 0x2A3C, 0x016E, 0x3F, 0x1018, 0x1A24)); // Zak 100 - CRCToSound(0x28057CEC, V2A_Sound_Single(0x0098, 0x0FEC, 0x0140, 0x32)); // Zak 63 - CRCToSound(0x1180A2FC, V2A_Sound_Single(0x0098, 0x0F06, 0x0190, 0x32)); // Zak 64 - CRCToSound(0x12616755, V2A_Sound_Single(0x0098, 0x14C8, 0x023C, 0x14)); // Zak 9 - CRCToSound(0x642723AA, V2A_Sound_Special_Zak37(0x00A2, 0x1702, 0x01F4, 0x3F)); // Zak 37 - CRCToSound(0xDEE56848, V2A_Sound_Single(0x009A, 0x0F86, 0x0100, 0x3F)); // Zak 93 - CRCToSound(0xF9BE27B8, V2A_Sound_Special_Zak37(0x011C, 0x1704, 0x0228, 0x3F)); // Zak 113 - CRCToSound(0xC73487B2, V2A_Sound_Single(0x00B0, 0x18BA, 0x0478, 0x3F)); // Zak 81 - CRCToSound(0x32D8F925, V2A_Sound_Single(0x00B0, 0x2E46, 0x00F0, 0x3F)); // Zak 94 - CRCToSound(0x988C83A5, V2A_Sound_Single(0x00B0, 0x0DE0, 0x025B, 0x3F)); // Zak 106 - CRCToSound(0x8F1E3B3D, V2A_Sound_Single(0x00B0, 0x05FE, 0x04E2, 0x3F)); // Zak 107 - CRCToSound(0x0A2A7646, V2A_Sound_Single(0x00B0, 0x36FE, 0x016E, 0x3F)); // Zak 43 - CRCToSound(0x6F1FC435, V2A_Sound_Single(0x00B0, 0x2808, 0x044C, 0x3F)); // Zak 108 - CRCToSound(0x870EFC29, V2A_Sound_SingleLoopedPitchbend(0x00BA, 0x0100, 0x03E8, 0x00C8, 0x3F, 3)); // Zak 55 - CRCToSound(0xED773699, V2A_Sound_Special_ManiacDing(0x00B4, 0x0020, 0x012C, 8, 4)); // Zak 3 - CRCToSound(0x0BF59774, V2A_Sound_Special_ZakStereoDing(0x00BE, 0x0020, 0x00F8, 0x00F7, 8, 1)); // Zak 72 - CRCToSound(0x656FFEDE, V2A_Sound_Special_ZakStereoDing(0x00BE, 0x0020, 0x00C4, 0x00C3, 8, 1)); // Zak 73 - CRCToSound(0xFC4D41E5, V2A_Sound_Special_ZakStereoDing(0x00BE, 0x0020, 0x00A5, 0x00A4, 8, 1)); // Zak 74 - CRCToSound(0xC0DD2089, V2A_Sound_Special_ZakStereoDing(0x00BE, 0x0020, 0x009C, 0x009B, 8, 1)); // Zak 75 - CRCToSound(0x627DFD92, V2A_Sound_Special_ZakStereoDing(0x00BE, 0x0020, 0x008B, 0x008A, 8, 1)); // Zak 76 - CRCToSound(0x703E05C1, V2A_Sound_Special_ZakStereoDing(0x00BE, 0x0020, 0x007C, 0x007B, 8, 1)); // Zak 77 - CRCToSound(0xB0F77006, V2A_Sound_Special_Zak52(0x00B0, 0x01BC)); // Zak 52 - CRCToSound(0x5AE9D6A7, V2A_Sound_Special_ZakAirplane(0x00CA, 0x22A4, 0x0113, 0x0227)); // Zak 109 - CRCToSound(0xABE0D3B0, V2A_Sound_Special_ZakAirplane(0x00CE, 0x22A4, 0x0227, 0x0113)); // Zak 105 - CRCToSound(0x788CC749, V2A_Sound_Special_Zak71(0x00C8, 0x0B37)); // Zak 71 - CRCToSound(0x2E2AB1FA, V2A_Sound_Special_Zak99(0x00D4, 0x04F0, 0x0FE3, 0x0080, 0x3F)); // Zak 99 - CRCToSound(0x1304CF20, V2A_Sound_Special_ManiacTypewriter(0x00DC, 0x0624, 0x023C, 0x3C, 2, (const uint8 *)"\x14\x11", false)); // Zak 79 - CRCToSound(0xAE68ED91, V2A_Sound_Special_Zak54(0x00D4, 0x1A25, 0x1E1E, 0x0B80, 0x01F4)); // Zak 54 - CRCToSound(0xA4F40F97, V2A_Sound_Special_Zak61(0x00E4, 0x0020)); // Zak 61 - CRCToSound(0x348F85CE, V2A_Sound_Special_Zak62(0x00E4, 0x0020)); // Zak 62 - CRCToSound(0xD473AB86, V2A_Sound_Special_ManiacTypewriter(0x0122, 0x03E8, 0x00BE, 0x3F, 7, (const uint8 *)"\x0F\x0B\x04\x0F\x1E\x0F\x66", false)); // Zak 46 - CRCToSound(0x84A0BA90, V2A_Sound_Special_Zak110(0x0126, 0x0040, 0x0136, 0x0080, 0x007C, 0x0087)); // Zak 110 - CRCToSound(0x92680D9F, V2A_Sound_Special_Zak32(0x0140, 0x0150, 0x0010, 0x0010)); // Zak 32 - CRCToSound(0xABFFDB02, V2A_Sound_Special_Zak86(0x01A2, 0x2BAE)); // Zak 86 - CRCToSound(0x41045447, V2A_Sound_Special_Zak98(0x017A, 0x0020)); // Zak 98 - CRCToSound(0xC8EEBD34, V2A_Sound_Special_Zak82(0x01A6, 0x3900)); // Zak 82 - CRCToSound(0x42F9469F, V2A_Sound_Music(0x05F6, 0x0636, 0x0456, 0x0516, 0x05D6, 0x05E6, 0x0A36, true)); // Zak 96 - CRCToSound(0x038BBD78, V2A_Sound_Music(0x054E, 0x05CE, 0x044E, 0x04BE, 0x052E, 0x053E, 0x0BCE, true)); // Zak 85 - CRCToSound(0x06FFADC5, V2A_Sound_Music(0x0626, 0x0686, 0x0446, 0x04F6, 0x0606, 0x0616, 0x0C86, true)); // Zak 87 - CRCToSound(0xCE20ECF0, V2A_Sound_Music(0x0636, 0x0696, 0x0446, 0x0576, 0x0616, 0x0626, 0x0E96, true)); // Zak 114 - CRCToSound(0xBDA01BB6, V2A_Sound_Music(0x0678, 0x06B8, 0x0458, 0x0648, 0x0658, 0x0668, 0x0EB8, false)); // Zak 33 - CRCToSound(0x59976529, V2A_Sound_Music(0x088E, 0x092E, 0x048E, 0x05EE, 0x074E, 0x07EE, 0x112E, true)); // Zak 49 - CRCToSound(0xED1EED02, V2A_Sound_Music(0x08D0, 0x0950, 0x0440, 0x07E0, 0x08B0, 0x08C0, 0x1350, false)); // Zak 112 - CRCToSound(0x5A16C037, V2A_Sound_Music(0x634A, 0x64CA, 0x049A, 0x18FA, 0x398A, 0x511A, 0x6CCA, false)); // Zak 95 - return NULL; -} - -Player_V2A::Player_V2A(ScummEngine *scumm, Audio::Mixer *mixer) { - int i; - _vm = scumm; - - InitCRC(); - - for (i = 0; i < V2A_MAXSLOTS; i++) { - _slot[i].id = 0; - _slot[i].sound = NULL; - } - - _mod = new Player_MOD(mixer); - _mod->setUpdateProc(update_proc, this, 60); -} - -Player_V2A::~Player_V2A() { - delete _mod; -} - -void Player_V2A::setMusicVolume(int vol) { - _mod->setMusicVolume(vol); -} - -int Player_V2A::getSoundSlot(int id) const { - int i; - for (i = 0; i < V2A_MAXSLOTS; i++) { - if (_slot[i].id == id) - break; - } - if (i == V2A_MAXSLOTS) { - if (id == 0) - warning("player_v2a - out of sound slots"); - return -1; - } - return i; -} - -void Player_V2A::stopAllSounds() { - for (int i = 0; i < V2A_MAXSLOTS; i++) { - if (!_slot[i].id) - continue; - _slot[i].sound->stop(); - delete _slot[i].sound; - _slot[i].sound = NULL; - _slot[i].id = 0; - } -} - -void Player_V2A::stopSound(int nr) { - int i; - if (nr == 0) - return; - i = getSoundSlot(nr); - if (i == -1) - return; - _slot[i].sound->stop(); - delete _slot[i].sound; - _slot[i].sound = NULL; - _slot[i].id = 0; -} - -void Player_V2A::startSound(int nr) { - assert(_vm); - byte *data = _vm->getResourceAddress(rtSound, nr); - assert(data); - uint32 crc = GetCRC(data + 0x0A, READ_BE_UINT16(data + 0x08)); - V2A_Sound *snd = findSound(crc); - if (snd == NULL) { - warning("player_v2a - sound %i not recognized yet (crc %08X)", nr, crc); - return; - } - stopSound(nr); - int i = getSoundSlot(); - if (i == -1) { - delete snd; - return; - } - _slot[i].id = nr; - _slot[i].sound = snd; - _slot[i].sound->start(_mod, nr, data); -} - -void Player_V2A::update_proc(void *param) { - ((Player_V2A *)param)->updateSound(); -} - -void Player_V2A::updateSound() { - int i; - for (i = 0; i < V2A_MAXSLOTS; i++) { - if ((_slot[i].id) && (!_slot[i].sound->update())) { - _slot[i].sound->stop(); - delete _slot[i].sound; - _slot[i].sound = NULL; - _slot[i].id = 0; - } - } -} - -int Player_V2A::getMusicTimer() { - return 0; // FIXME - need to keep track of playing music resources -} - -int Player_V2A::getSoundStatus(int nr) const { - for (int i = 0; i < V2A_MAXSLOTS; i++) { - if (_slot[i].id == nr) - return 1; - } - return 0; -} - -} // End of namespace Scumm diff --git a/engines/scumm/player/v2a.h b/engines/scumm/player/v2a.h deleted file mode 100644 index cc2f4a7362..0000000000 --- a/engines/scumm/player/v2a.h +++ /dev/null @@ -1,73 +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 SCUMM_PLAYER_V2A_H -#define SCUMM_PLAYER_V2A_H - -#include "common/scummsys.h" -#include "scumm/music.h" -#include "scumm/player/mod.h" - -class Mixer; - -namespace Scumm { - -class ScummEngine; -class V2A_Sound; - -/** - * Scumm V2 Amiga sound/music driver. - */ -class Player_V2A : public MusicEngine { -public: - Player_V2A(ScummEngine *scumm, Audio::Mixer *mixer); - virtual ~Player_V2A(); - - virtual void setMusicVolume(int vol); - virtual void startSound(int sound); - virtual void stopSound(int sound); - virtual void stopAllSounds(); - virtual int getMusicTimer(); - virtual int getSoundStatus(int sound) const; - -private: - enum { - V2A_MAXSLOTS = 8 - }; - - struct soundSlot { - int id; - V2A_Sound *sound; - }; - - ScummEngine *_vm; - Player_MOD *_mod; - soundSlot _slot[V2A_MAXSLOTS]; - - int getSoundSlot(int id = 0) const; - static void update_proc(void *param); - void updateSound(); -}; - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/player/v2base.cpp b/engines/scumm/player/v2base.cpp deleted file mode 100644 index 4b20cfc910..0000000000 --- a/engines/scumm/player/v2base.cpp +++ /dev/null @@ -1,654 +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/v2base.h" -#include "scumm/scumm.h" - -#define FREQ_HZ 236 // Don't change! - -#define MAX_OUTPUT 0x7fff - -namespace Scumm { - -const uint8 note_lengths[] = { - 0, - 0, 0, 2, - 0, 3, 4, - 5, 6, 8, - 9, 12, 16, - 18, 24, 32, - 36, 48, 64, - 72, 96 -}; - -static const uint16 hull_offsets[] = { - 0, 12, 24, 36, 48, 60, - 72, 88, 104, 120, 136, 256, - 152, 164, 180 -}; - -static const int16 hulls[] = { - // hull 0 - 3, -1, 0, 0, 0, 0, 0, 0, - 0, -1, 0, 0, - // hull 1 (staccato) - 3, -1, 0, 32, 0, -1, 0, 0, - 0, -1, 0, 0, - // hull 2 (legato) - 3, -1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, - // hull 3 (staccatissimo) - 3, -1, 0, 2, 0, -1, 0, 0, - 0, -1, 0, 0, - // hull 4 - 3, -1, 0, 6, 0, -1, 0, 0, - 0, -1, 0, 0, - // hull 5 - 3, -1, 0, 16, 0, -1, 0, 0, - 0, -1, 0, 0, - // hull 6 - (int16) 60000, -1, -1000, 20, 0, 0, 0, 0, - (int16) 40000, -1, -5000, 5, 0, -1, 0, 0, - // hull 7 - (int16) 50000, -1, 0, 8, 30000, -1, 0, 0, - 28000, -1, -5000, 5, 0, -1, 0, 0, - // hull 8 - (int16) 60000, -1, -2000, 16, 0, 0, 0, 0, - 28000, -1, -6000, 5, 0, -1, 0, 0, - // hull 9 - (int16) 55000, -1, 0, 8, (int16) 35000, -1, 0, 0, - (int16) 40000, -1, -2000, 10, 0, -1, 0, 0, - // hull 10 - (int16) 60000, -1, 0, 4, -2000, 8, 0, 0, - (int16) 40000, -1, -6000, 5, 0, -1, 0, 0, - // hull 12 - 0, -1, 150, 340, -150, 340, 0, -1, - 0, -1, 0, 0, - // hull 13 == 164 - 20000, -1, 4000, 7, 1000, 15, 0, 0, - (int16) 35000, -1, -2000, 15, 0, -1, 0, 0, - - // hull 14 == 180 - (int16) 35000, -1, 500, 20, 0, 0, 0, 0, - (int16) 45000, -1, -500, 60, 0, -1, 0, 0, - - // hull misc = 196 - (int16) 44000, -1, -4400, 10, 0, -1, 0, 0, - 0, -1, 0, 0, - - (int16) 53000, -1, -5300, 10, 0, -1, 0, 0, - 0, -1, 0, 0, - - (int16) 63000, -1, -6300, 10, 0, -1, 0, 0, - 0, -1, 0, 0, - - (int16) 44000, -1, -1375, 32, 0, -1, 0, 0, - 0, -1, 0, 0, - - (int16) 53000, -1, -1656, 32, 0, -1, 0, 0, - 0, -1, 0, 0, - - // hull 11 == 256 - (int16) 63000, -1, -1968, 32, 0, -1, 0, 0, - 0, -1, 0, 0, - - (int16) 44000, -1, - 733, 60, 0, -1, 0, 0, - 0, -1, 0, 0, - - (int16) 53000, -1, - 883, 60, 0, -1, 0, 0, - 0, -1, 0, 0, - - (int16) 63000, -1, -1050, 60, 0, -1, 0, 0, - 0, -1, 0, 0, - - (int16) 44000, -1, - 488, 90, 0, -1, 0, 0, - 0, -1, 0, 0, - - (int16) 53000, -1, - 588, 90, 0, -1, 0, 0, - 0, -1, 0, 0, - - (int16) 63000, -1, - 700, 90, 0, -1, 0, 0, - 0, -1, 0, 0 -}; - -static const uint16 freqmod_lengths[] = { - 0x1000, 0x1000, 0x20, 0x2000, 0x1000 -}; - -static const uint16 freqmod_offsets[] = { - 0, 0x100, 0x200, 0x302, 0x202 -}; - -static const int8 freqmod_table[0x502] = { - 0, 3, 6, 9, 12, 15, 18, 21, - 24, 27, 30, 33, 36, 39, 42, 45, - 48, 51, 54, 57, 59, 62, 65, 67, - 70, 73, 75, 78, 80, 82, 85, 87, - 89, 91, 94, 96, 98, 100, 102, 103, - 105, 107, 108, 110, 112, 113, 114, 116, - 117, 118, 119, 120, 121, 122, 123, 123, - 124, 125, 125, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 125, 125, - 124, 123, 123, 122, 121, 120, 119, 118, - 117, 116, 114, 113, 112, 110, 108, 107, - 105, 103, 102, 100, 98, 96, 94, 91, - 89, 87, 85, 82, 80, 78, 75, 73, - 70, 67, 65, 62, 59, 57, 54, 51, - 48, 45, 42, 39, 36, 33, 30, 27, - 24, 21, 18, 15, 12, 9, 6, 3, - 0, -3, -6, -9, -12, -15, -18, -21, - -24, -27, -30, -33, -36, -39, -42, -45, - -48, -51, -54, -57, -59, -62, -65, -67, - -70, -73, -75, -78, -80, -82, -85, -87, - -89, -91, -94, -96, -98,-100,-102,-103, - -105,-107,-108,-110,-112,-113,-114,-116, - -117,-118,-119,-120,-121,-122,-123,-123, - -124,-125,-125,-126,-126,-126,-126,-126, - -126,-126,-126,-126,-126,-126,-125,-125, - -124,-123,-123,-122,-121,-120,-119,-118, - -117,-116,-114,-113,-112,-110,-108,-107, - -105,-103,-102,-100, -98, -96, -94, -91, - -89, -87, -85, -82, -80, -78, -75, -73, - -70, -67, -65, -62, -59, -57, -54, -51, - -48, -45, -42, -39, -36, -33, -30, -27, - -24, -21, -18, -15, -12, -9, -6, -3, - - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, - -128,-127,-126,-125,-124,-123,-122,-121, - -120,-119,-118,-117,-116,-115,-114,-113, - -112,-111,-110,-109,-108,-107,-106,-105, - -104,-103,-102,-101,-100, -99, -98, -97, - -96, -95, -94, -93, -92, -91, -90, -89, - -88, -87, -86, -85, -84, -83, -82, -81, - -80, -79, -78, -77, -76, -75, -74, -73, - -72, -71, -70, -69, -68, -67, -66, -65, - -64, -63, -62, -61, -60, -59, -58, -57, - -56, -55, -54, -53, -52, -51, -50, -49, - -48, -47, -46, -45, -44, -43, -42, -41, - -40, -39, -38, -37, -36, -35, -34, -33, - -32, -31, -30, -29, -28, -27, -26, -25, - -24, -23, -22, -21, -20, -19, -18, -17, - -16, -15, -14, -13, -12, -11, -10, -9, - -8, -7, -6, -5, -4, -3, -2, -1, - - -120, 120, - - -120,-120,-120,-120,-120,-120,-120,-120, - -120,-120,-120,-120,-120,-120,-120,-120, - -120,-120,-120,-120,-120,-120,-120,-120, - -120,-120,-120,-120,-120,-120,-120,-120, - -120,-120,-120,-120,-120,-120,-120,-120, - -120,-120,-120,-120,-120,-120,-120,-120, - -120,-120,-120,-120,-120,-120,-120,-120, - -120,-120,-120,-120,-120,-120,-120,-120, - -120,-120,-120,-120,-120,-120,-120,-120, - -120,-120,-120,-120,-120,-120,-120,-120, - -120,-120,-120,-120,-120,-120,-120,-120, - -120,-120,-120,-120,-120,-120,-120,-120, - -120,-120,-120,-120,-120,-120,-120,-120, - -120,-120,-120,-120,-120,-120,-120,-120, - -120,-120,-120,-120,-120,-120,-120,-120, - -120,-120,-120,-120,-120,-120,-120,-120, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - - 41, 35, -66,-124, -31, 108, -42, -82, - 82,-112, 73, -15, -15, -69, -23, -21, - -77, -90, -37, 60,-121, 12, 62,-103, - 36, 94, 13, 28, 6, -73, 71, -34, - -77, 18, 77, -56, 67, -69,-117, -90, - 31, 3, 90, 125, 9, 56, 37, 31, - 93, -44, -53, -4,-106, -11, 69, 59, - 19, 13,-119, 10, 28, -37, -82, 50, - 32,-102, 80, -18, 64, 120, 54, -3, - 18, 73, 50, -10, -98, 125, 73, -36, - -83, 79, 20, -14, 68, 64, 102, -48, - 107, -60, 48, -73, 50, 59, -95, 34, - -10, 34,-111, -99, -31,-117, 31, -38, - -80, -54,-103, 2, -71, 114, -99, 73, - 44,-128, 126, -59,-103, -43, -23,-128, - -78, -22, -55, -52, 83, -65, 103, -42, - -65, 20, -42, 126, 45, -36,-114, 102, - -125, -17, 87, 73, 97, -1, 105,-113, - 97, -51, -47, 30, -99,-100, 22, 114, - 114, -26, 29, -16,-124, 79, 74, 119, - 2, -41, -24, 57, 44, 83, -53, -55, - 18, 30, 51, 116, -98, 12, -12, -43, - -44, -97, -44, -92, 89, 126, 53, -49, - 50, 34, -12, -52, -49, -45,-112, 45, - 72, -45,-113, 117, -26, -39, 29, 42, - -27, -64, -9, 43, 120,-127,-121, 68, - 14, 95, 80, 0, -44, 97,-115, -66, - 123, 5, 21, 7, 59, 51,-126, 31, - 24, 112,-110, -38, 100, 84, -50, -79, - -123, 62, 105, 21, -8, 70, 106, 4, - -106, 115, 14, -39, 22, 47, 103, 104, - -44, -9, 74, 74, -48, 87, 104, 118, - -6, 22, -69, 17, -83, -82, 36,-120, - 121, -2, 82, -37, 37, 67, -27, 60, - -12, 69, -45, -40, 40, -50, 11, -11, - -59, 96, 89, 61,-105, 39,-118, 89, - 118, 45, -48, -62, -55, -51, 104, -44, - 73, 106, 121, 37, 8, 97, 64, 20, - -79, 59, 106, -91, 17, 40, -63,-116, - -42, -87, 11,-121,-105,-116, 47, -15, - 21, 29,-102,-107, -63,-101, -31, -64, - 126, -23, -88,-102, -89,-122, -62, -75, - 84, -65,-102, -25, -39, 35, -47, 85, - -112, 56, 40, -47, -39, 108, -95, 102, - 94, 78, -31, 48,-100, -2, -39, 113, - -97, -30, -91, -30, 12,-101, -76, 71, - 101, 56, 42, 70,-119, -87,-126, 121, - 122, 118, 120, -62, 99, -79, 38, -33, - -38, 41, 109, 62, 98, -32,-106, 18, - 52, -65, 57, -90, 63,-119, 94, -15, - 109, 14, -29, 108, 40, -95, 30, 32, - 29, -53, -62, 3, 63, 65, 7,-124, - 15, 20, 5, 101, 27, 40, 97, -55, - -59, -25, 44,-114, 70, 54, 8, -36, - -13, -88,-115, -2, -66, -14, -21, 113, - -1, -96, -48, 59, 117, 6,-116, 126, - -121, 120, 115, 77, -48, -66,-126, -66, - -37, -62, 70, 65, 43,-116, -6, 48, - 127, 112, -16, -89, 84,-122, 50,-107, - -86, 91, 104, 19, 11, -26, -4, -11, - -54, -66, 125, -97,-119,-118, 65, 27, - -3, -72, 79, 104, -10, 114, 123, 20, - -103, -51, -45, 13, -16, 68, 58, -76, - -90, 102, 83, 51, 11, -53, -95, 16 -}; - -static const uint16 spk_freq_table[12] = { - 36484, 34436, 32503, 30679, 28957, 27332, - 25798, 24350, 22983, 21693, 20476, 19326 -}; - -static const uint16 pcjr_freq_table[12] = { - 65472, 61760, 58304, 55040, 52032, 49024, - 46272, 43648, 41216, 38912, 36736, 34624 -}; - - -Player_V2Base::Player_V2Base(ScummEngine *scumm, Audio::Mixer *mixer, bool pcjr) - : _vm(scumm), - _mixer(mixer), - _pcjr(pcjr), - _sampleRate(_mixer->getOutputRate()) { - - _isV3Game = (scumm->_game.version >= 3); - - _header_len = (scumm->_game.features & GF_OLD_BUNDLE) ? 4 : 6; - - // Initialize sound queue - _current_nr = _next_nr = 0; - _current_data = _next_data = 0; - - // Initialize channel code - for (int i = 0; i < 4; ++i) - clear_channel(i); - - _next_tick = 0; - _tick_len = (_sampleRate << FIXP_SHIFT) / FREQ_HZ; - - // Initialize V3 music timer - _music_timer_ctr = _music_timer = 0; - _ticks_per_music_timer = 65535; - - if (_pcjr) { - _freqs_table = pcjr_freq_table; - } else { - _freqs_table = spk_freq_table; - } -} - -Player_V2Base::~Player_V2Base() { -} - -void Player_V2Base::chainSound(int nr, byte *data) { - int offset = _header_len + (_pcjr ? 10 : 2); - - _current_nr = nr; - _current_data = data; - - for (int i = 0; i < 4; i++) { - clear_channel(i); - - _channels[i].d.music_script_nr = nr; - if (data) { - _channels[i].d.next_cmd = READ_LE_UINT16(data + offset + 2 * i); - if (_channels[i].d.next_cmd) { - _channels[i].d.time_left = 1; - } - } - } - _music_timer = 0; -} - -void Player_V2Base::chainNextSound() { - if (_next_nr) { - chainSound(_next_nr, _next_data); - _next_nr = 0; - _next_data = 0; - } -} - -// TODO: Merge stopAllSounds, stopSound() and startSound(), using some overriding -// perhaps? Player_V2CMS's implementations start like that of Player_V2 -// but then add some MIDI related stuff. - -void Player_V2Base::clear_channel(int i) { - ChannelInfo *channel = &_channels[i]; - memset(channel, 0, sizeof(ChannelInfo)); -} - -int Player_V2Base::getMusicTimer() { - if (_isV3Game) - return _music_timer; - else - return _channels[0].d.music_timer; -} - -void Player_V2Base::execute_cmd(ChannelInfo *channel) { - uint16 value; - int16 offset; - uint8 *script_ptr; - ChannelInfo * current_channel; - ChannelInfo * dest_channel; - - current_channel = channel; - - if (channel->d.next_cmd == 0) - goto check_stopped; - script_ptr = &_current_data[channel->d.next_cmd]; - - for (;;) { - uint8 opcode = *script_ptr++; - if (opcode >= 0xf8) { - switch (opcode) { - case 0xf8: // set hull curve - debug(7, "channels[%d]: hull curve %2d", - (uint)(channel - _channels), *script_ptr); - channel->d.hull_curve = hull_offsets[*script_ptr / 2]; - script_ptr++; - break; - - case 0xf9: // set freqmod curve - debug(7, "channels[%d]: freqmod curve %2d", - (uint)(channel - _channels), *script_ptr); - channel->d.freqmod_table = freqmod_offsets[*script_ptr / 4]; - channel->d.freqmod_modulo = freqmod_lengths[*script_ptr / 4]; - script_ptr++; - break; - - case 0xfd: // clear other channel - value = READ_LE_UINT16 (script_ptr) / sizeof (ChannelInfo); - debug(7, "clear channel %d", value); - script_ptr += 2; - // In Indy3, when traveling to Venice a command is - // issued to clear channel 4. So we introduce a 4th - // channel, which is never used. All OOB accesses are - // mapped to this channel. - // - // The original game had room for 8 channels, but only - // channels 0-3 are read, changes to other channels - // had no effect. - if (value >= ARRAYSIZE (_channels)) - value = 4; - channel = &_channels[value]; - // fall through - - case 0xfa: // clear current channel - if (opcode == 0xfa) - debug(7, "clear channel"); - channel->d.next_cmd = 0; - channel->d.base_freq = 0; - channel->d.freq_delta = 0; - channel->d.freq = 0; - channel->d.volume = 0; - channel->d.volume_delta = 0; - channel->d.inter_note_pause = 0; - channel->d.transpose = 0; - channel->d.hull_curve = 0; - channel->d.hull_offset = 0; - channel->d.hull_counter = 0; - channel->d.freqmod_table = 0; - channel->d.freqmod_offset = 0; - channel->d.freqmod_incr = 0; - channel->d.freqmod_multiplier = 0; - channel->d.freqmod_modulo = 0; - break; - - case 0xfb: // ret from subroutine - debug(7, "ret from sub"); - script_ptr = _retaddr; - break; - - case 0xfc: // call subroutine - offset = READ_LE_UINT16 (script_ptr); - debug(7, "subroutine %d", offset); - script_ptr += 2; - _retaddr = script_ptr; - script_ptr = _current_data + offset; - break; - - case 0xfe: // loop music - opcode = *script_ptr++; - offset = READ_LE_UINT16 (script_ptr); - script_ptr += 2; - debug(7, "loop if %d to %d", opcode, offset); - if (!channel->array[opcode / 2] || --channel->array[opcode/2]) - script_ptr += offset; - break; - - case 0xff: // set parameter - opcode = *script_ptr++; - value = READ_LE_UINT16 (script_ptr); - channel->array[opcode / 2] = value; - debug(7, "channels[%d]: set param %2d = %5d", - (uint)(channel - _channels), opcode, value); - script_ptr += 2; - if (opcode == 14) { - /* tempo var */ - _ticks_per_music_timer = 125; - } - if (opcode == 0) - goto end; - break; - } - } else { // opcode < 0xf8 - for (;;) { - int16 note, octave; - int is_last_note; - dest_channel = &_channels[(opcode >> 5) & 3]; - - if (!(opcode & 0x80)) { - - int tempo = channel->d.tempo; - if (!tempo) - tempo = 1; - channel->d.time_left = tempo * note_lengths[opcode & 0x1f]; - - note = *script_ptr++; - is_last_note = note & 0x80; - note &= 0x7f; - if (note == 0x7f) { - debug(8, "channels[%d]: pause %d", - (uint)(channel - _channels), channel->d.time_left); - goto end; - } - } else { - - channel->d.time_left = ((opcode & 7) << 8) | *script_ptr++; - - if ((opcode & 0x10)) { - debug(8, "channels[%d]: pause %d", - (uint)(channel - _channels), channel->d.time_left); - goto end; - } - - is_last_note = 0; - note = (*script_ptr++) & 0x7f; - } - - debug(8, "channels[%d]: @%04x note: %3d+%d len: %2d hull: %d mod: %d/%d/%d %s", - (uint)(dest_channel - channel), script_ptr ? (uint)(script_ptr - _current_data - 2) : 0, - note, (signed short) dest_channel->d.transpose, channel->d.time_left, - dest_channel->d.hull_curve, dest_channel->d.freqmod_table, - dest_channel->d.freqmod_incr,dest_channel->d.freqmod_multiplier, - is_last_note ? "last":""); - - uint16 myfreq; - dest_channel->d.time_left = channel->d.time_left; - dest_channel->d.note_length = - channel->d.time_left - dest_channel->d.inter_note_pause; - note += dest_channel->d.transpose; - while (note < 0) - note += 12; - octave = note / 12; - note = note % 12; - dest_channel->d.hull_offset = 0; - dest_channel->d.hull_counter = 1; - if (_pcjr && dest_channel == &_channels[3]) { - dest_channel->d.hull_curve = 196 + note * 12; - myfreq = 384 - 64 * octave; - } else { - myfreq = _freqs_table[note] >> octave; - } - dest_channel->d.freq = dest_channel->d.base_freq = myfreq; - if (is_last_note) - goto end; - opcode = *script_ptr++; - } - } - } - -end: - channel = current_channel; - if (channel->d.time_left) { - channel->d.next_cmd = script_ptr - _current_data; - return; - } - - channel->d.next_cmd = 0; - -check_stopped: - int i; - for (i = 0; i < 4; i++) { - if (_channels[i].d.time_left) - return; - } - - _current_nr = 0; - _current_data = 0; - chainNextSound(); -} - -void Player_V2Base::next_freqs(ChannelInfo *channel) { - channel->d.volume += channel->d.volume_delta; - channel->d.base_freq += channel->d.freq_delta; - - channel->d.freqmod_offset += channel->d.freqmod_incr; - if (channel->d.freqmod_offset > channel->d.freqmod_modulo) - channel->d.freqmod_offset -= channel->d.freqmod_modulo; - - channel->d.freq = - (int) (freqmod_table[channel->d.freqmod_table + (channel->d.freqmod_offset >> 4)]) - * (int) channel->d.freqmod_multiplier / 256 - + channel->d.base_freq; - - debug(9, "Freq: %d/%d, %d/%d/%d*%d %d", - channel->d.base_freq, (int16)channel->d.freq_delta, - channel->d.freqmod_table, channel->d.freqmod_offset, - channel->d.freqmod_incr, channel->d.freqmod_multiplier, - channel->d.freq); - - if (channel->d.note_length && !--channel->d.note_length) { - channel->d.hull_offset = 16; - channel->d.hull_counter = 1; - } - - if (!--channel->d.time_left) { - execute_cmd(channel); - } - - if (channel->d.hull_counter && !--channel->d.hull_counter) { - for (;;) { - const int16 *hull_ptr = hulls - + channel->d.hull_curve + channel->d.hull_offset / 2; - if (hull_ptr[1] == -1) { - channel->d.volume = hull_ptr[0]; - if (hull_ptr[0] == 0) - channel->d.volume_delta = 0; - channel->d.hull_offset += 4; - } else { - channel->d.volume_delta = hull_ptr[0]; - channel->d.hull_counter = hull_ptr[1]; - channel->d.hull_offset += 4; - break; - } - } - } -} - -void Player_V2Base::nextTick() { - for (int i = 0; i < 4; i++) { - if (!_channels[i].d.time_left) - continue; - next_freqs(&_channels[i]); - } - if (_music_timer_ctr++ >= _ticks_per_music_timer) { - _music_timer_ctr = 0; - _music_timer++; - } -} - - -} // End of namespace Scumm diff --git a/engines/scumm/player/v2base.h b/engines/scumm/player/v2base.h deleted file mode 100644 index eb9ed941ca..0000000000 --- a/engines/scumm/player/v2base.h +++ /dev/null @@ -1,145 +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 SCUMM_PLAYER_V2BASE_H -#define SCUMM_PLAYER_V2BASE_H - -#include "common/scummsys.h" -#include "common/mutex.h" -#include "scumm/music.h" -#include "audio/audiostream.h" -#include "audio/mixer.h" - -namespace Scumm { - -class ScummEngine; - - -#include "common/pack-start.h" // START STRUCT PACKING - -struct channel_data { - uint16 time_left; // 00 - uint16 next_cmd; // 02 - uint16 base_freq; // 04 - uint16 freq_delta; // 06 - uint16 freq; // 08 - uint16 volume; // 10 - uint16 volume_delta; // 12 - uint16 tempo; // 14 - uint16 inter_note_pause; // 16 - uint16 transpose; // 18 - uint16 note_length; // 20 - uint16 hull_curve; // 22 - uint16 hull_offset; // 24 - uint16 hull_counter; // 26 - uint16 freqmod_table; // 28 - uint16 freqmod_offset; // 30 - uint16 freqmod_incr; // 32 - uint16 freqmod_multiplier; // 34 - uint16 freqmod_modulo; // 36 - uint16 unknown[4]; // 38 - 44 - uint16 music_timer; // 46 - uint16 music_script_nr; // 48 -} PACKED_STRUCT; - -#include "common/pack-end.h" // END STRUCT PACKING - -/** - * Common base class for Player_V2 and Player_V2CMS. - */ -class Player_V2Base : public Audio::AudioStream, public MusicEngine { -public: - Player_V2Base(ScummEngine *scumm, Audio::Mixer *mixer, bool pcjr); - virtual ~Player_V2Base(); - - // MusicEngine API -// virtual void setMusicVolume(int vol); -// virtual void startSound(int sound); -// virtual void stopSound(int sound); -// virtual void stopAllSounds(); - virtual int getMusicTimer(); -// virtual int getSoundStatus(int sound) const; - - // AudioStream API -/* - int readBuffer(int16 *buffer, const int numSamples) { - do_mix(buffer, numSamples / 2); - return numSamples; - } -*/ - virtual bool isStereo() const { return true; } - virtual bool endOfData() const { return false; } - virtual int getRate() const { return _sampleRate; } - -protected: - enum { - FIXP_SHIFT = 16 - }; - - bool _isV3Game; - Audio::Mixer *_mixer; - Audio::SoundHandle _soundHandle; - ScummEngine *_vm; - - bool _pcjr; - int _header_len; - - const uint32 _sampleRate; - uint32 _next_tick; - uint32 _tick_len; - - int _current_nr; - byte *_current_data; - int _next_nr; - byte *_next_data; - byte *_retaddr; - - Common::Mutex _mutex; - - union ChannelInfo { - channel_data d; - uint16 array[sizeof(channel_data)/2]; - }; - - ChannelInfo _channels[5]; - -private: - int _music_timer; - int _music_timer_ctr; - int _ticks_per_music_timer; - - const uint16 *_freqs_table; - -protected: - virtual void nextTick(); - virtual void clear_channel(int i); - virtual void chainSound(int nr, byte *data); - virtual void chainNextSound(); - - void execute_cmd(ChannelInfo *channel); - void next_freqs(ChannelInfo *channel); -}; - - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/player/v2cms.cpp b/engines/scumm/player/v2cms.cpp deleted file mode 100644 index 30ca238860..0000000000 --- a/engines/scumm/player/v2cms.cpp +++ /dev/null @@ -1,787 +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/v2cms.h" -#include "scumm/scumm.h" -#include "audio/mididrv.h" -#include "audio/mixer.h" -#include "audio/softsynth/cms.h" - -namespace Scumm { - -Player_V2CMS::Player_V2CMS(ScummEngine *scumm, Audio::Mixer *mixer) - : Player_V2Base(scumm, mixer, true), _cmsVoicesBase(), _cmsVoices(), - _cmsChips(), _midiDelay(0), _octaveMask(0), _looping(0), _tempo(0), - _tempoSum(0), _midiData(0), _midiSongBegin(0), _musicTimer(0), - _musicTimerTicks(0), _voiceTimer(0), _loadedMidiSong(0), - _outputTableReady(0), _midiChannel(), _midiChannelUse() { - setMusicVolume(255); - - memset(_sfxFreq, 0xFF, sizeof(_sfxFreq)); - memset(_sfxAmpl, 0x00, sizeof(_sfxAmpl)); - memset(_sfxOctave, 0x66, sizeof(_sfxOctave)); - - _cmsVoices[0].amplitudeOutput = &_cmsChips[0].ampl[0]; - _cmsVoices[0].freqOutput = &_cmsChips[0].freq[0]; - _cmsVoices[0].octaveOutput = &_cmsChips[0].octave[0]; - _cmsVoices[1].amplitudeOutput = &_cmsChips[0].ampl[1]; - _cmsVoices[1].freqOutput = &_cmsChips[0].freq[1]; - _cmsVoices[1].octaveOutput = &_cmsChips[0].octave[0]; - _cmsVoices[2].amplitudeOutput = &_cmsChips[0].ampl[2]; - _cmsVoices[2].freqOutput = &_cmsChips[0].freq[2]; - _cmsVoices[2].octaveOutput = &_cmsChips[0].octave[1]; - _cmsVoices[3].amplitudeOutput = &_cmsChips[0].ampl[3]; - _cmsVoices[3].freqOutput = &_cmsChips[0].freq[3]; - _cmsVoices[3].octaveOutput = &_cmsChips[0].octave[1]; - _cmsVoices[4].amplitudeOutput = &_cmsChips[1].ampl[0]; - _cmsVoices[4].freqOutput = &_cmsChips[1].freq[0]; - _cmsVoices[4].octaveOutput = &_cmsChips[1].octave[0]; - _cmsVoices[5].amplitudeOutput = &_cmsChips[1].ampl[1]; - _cmsVoices[5].freqOutput = &_cmsChips[1].freq[1]; - _cmsVoices[5].octaveOutput = &_cmsChips[1].octave[0]; - _cmsVoices[6].amplitudeOutput = &_cmsChips[1].ampl[2]; - _cmsVoices[6].freqOutput = &_cmsChips[1].freq[2]; - _cmsVoices[6].octaveOutput = &_cmsChips[1].octave[1]; - _cmsVoices[7].amplitudeOutput = &_cmsChips[1].ampl[3]; - _cmsVoices[7].freqOutput = &_cmsChips[1].freq[3]; - _cmsVoices[7].octaveOutput = &_cmsChips[1].octave[1]; - - // inits the CMS Emulator like in the original - _cmsEmu = new CMSEmulator(_sampleRate); - for (int i = 0, cmsPort = 0x220; i < 2; cmsPort += 2, ++i) { - for (int off = 0; off < 13; ++off) { - _cmsEmu->portWrite(cmsPort+1, _cmsInitData[off*2]); - _cmsEmu->portWrite(cmsPort, _cmsInitData[off*2+1]); - } - } - - _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); -} - -Player_V2CMS::~Player_V2CMS() { - Common::StackLock lock(_mutex); - - _mixer->stopHandle(_soundHandle); - delete _cmsEmu; -} - -void Player_V2CMS::setMusicVolume(int vol) { -} - -int Player_V2CMS::getMusicTimer() { - return _midiData ? _musicTimer : Player_V2Base::getMusicTimer(); -} - -void Player_V2CMS::stopAllSounds() { - Common::StackLock lock(_mutex); - - for (int i = 0; i < 4; i++) { - clear_channel(i); - } - _next_nr = _current_nr = 0; - _next_data = _current_data = 0; - _midiData = 0; - _midiSongBegin = 0; - _midiDelay = 0; - _musicTimer = _musicTimerTicks = 0; - offAllChannels(); -} - -void Player_V2CMS::stopSound(int nr) { - Common::StackLock lock(_mutex); - - if (_next_nr == nr) { - _next_nr = 0; - _next_data = 0; - } - if (_current_nr == nr) { - for (int i = 0; i < 4; i++) { - clear_channel(i); - } - _current_nr = 0; - _current_data = 0; - chainNextSound(); - } - if (_loadedMidiSong == nr) { - _midiData = 0; - _midiSongBegin = 0; - _midiDelay = 0; - offAllChannels(); - } -} - -void Player_V2CMS::startSound(int nr) { - Common::StackLock lock(_mutex); - - byte *data = _vm->getResourceAddress(rtSound, nr); - assert(data); - - if (data[6] == 0x80) { - _musicTimer = _musicTimerTicks = 0; - loadMidiData(data, nr); - } else { - int cprio = _current_data ? *(_current_data + _header_len) : 0; - int prio = *(data + _header_len); - int nprio = _next_data ? *(_next_data + _header_len) : 0; - - int restartable = *(data + _header_len + 1); - - if (!_current_nr || cprio <= prio) { - int tnr = _current_nr; - int tprio = cprio; - byte *tdata = _current_data; - - chainSound(nr, data); - nr = tnr; - prio = tprio; - data = tdata; - restartable = data ? *(data + _header_len + 1) : 0; - } - - if (!_current_nr) { - nr = 0; - _next_nr = 0; - _next_data = 0; - } - - if (nr != _current_nr - && restartable - && (!_next_nr - || nprio <= prio)) { - - _next_nr = nr; - _next_data = data; - } - } -} - -void Player_V2CMS::loadMidiData(byte *data, int sound) { - memset(_midiChannelUse, 0, sizeof(_midiChannelUse)); - memset(_midiChannel, 0, sizeof(_midiChannel)); - - _tempo = data[7]; - _looping = data[8]; - - byte channels = data[14]; - byte curChannel = 0; - byte *voice2 = data + 23; - - for (; channels != 0; ++curChannel, --channels, voice2 += 16) { - if (*(data + 15 + curChannel)) { - byte channel = *(data + 15 + curChannel) - 1; - _midiChannelUse[channel] = 1; - - Voice *voiceDef = &_cmsVoicesBase[channel]; - - byte attackDecay = voice2[10]; - voiceDef->attack = _attackRate[attackDecay >> 4]; - voiceDef->decay = _decayRate[attackDecay & 0x0F]; - byte sustainRelease = voice2[11]; - voiceDef->sustain = _sustainRate[sustainRelease >> 4]; - voiceDef->release = _releaseRate[sustainRelease & 0x0F]; - - if (voice2[3] & 0x40) { - voiceDef->vibrato = 0x0301; - if (voice2[13] & 0x40) { - voiceDef->vibrato = 0x0601; - } - } else { - voiceDef->vibrato = 0; - } - - if (voice2[8] & 0x80) { - voiceDef->vibrato2 = 0x0506; - if (voice2[13] & 0x80) { - voiceDef->vibrato2 = 0x050C; - } - } else { - voiceDef->vibrato2 = 0; - } - - if ((voice2[8] & 0x0F) > 1) { - voiceDef->octadd = 0x01; - } else { - voiceDef->octadd = 0x00; - } - } - } - - for (int i = 0; i < 8; ++i) { - _cmsVoices[i].chanNumber = 0xFF; - _cmsVoices[i].curVolume = 0; - _cmsVoices[i].nextVoice = 0; - } - - _midiDelay = 0; - memset(_cmsChips, 0, sizeof(MusicChip)*2); - _midiData = data + 151; - _midiSongBegin = _midiData + data[9]; - - _loadedMidiSong = sound; -} - -int Player_V2CMS::getSoundStatus(int nr) const { - return _current_nr == nr || _next_nr == nr || _loadedMidiSong == nr; -} - -void Player_V2CMS::processMidiData() { - byte *currentData = _midiData; - byte command = 0x00; - int16 temp = 0; - - ++_musicTimerTicks; - if (_musicTimerTicks > 60) { - _musicTimerTicks = 0; - ++_musicTimer; - } - - if (!_midiDelay) { - while (true) { - if ((command = *currentData++) == 0xFF) { - if ((command = *currentData++) == 0x2F) { - if (_looping == 0) { - currentData = _midiData = _midiSongBegin; - continue; - } - _midiData = _midiSongBegin = 0; - _midiDelay = 0; - _loadedMidiSong = 0; - offAllChannels(); - return; - } else { - if (command == 0x58) { - currentData += 6; - } - } - } else { - _lastMidiCommand = command; - if (command < 0x90) { - clearNote(currentData); - } else { - playNote(currentData); - } - } - - temp = command = *currentData++; - if (command & 0x80) { - temp = (command & 0x7F) << 8; - command = *currentData++; - temp |= (command << 1); - temp >>= 1; - } - temp >>= 1; - int lastBit = temp & 1; - temp >>= 1; - temp += lastBit; - - if (temp) - break; - } - _midiData = currentData; - _midiDelay = temp; - } - - --_midiDelay; - if (_midiDelay < 0) - _midiDelay = 0; - - return; -} - -int Player_V2CMS::readBuffer(int16 *buffer, const int numSamples) { - Common::StackLock lock(_mutex); - - uint step = 1; - int len = numSamples / 2; - - // maybe this needs a complete rewrite - do { - if (!(_next_tick >> FIXP_SHIFT)) { - if (_midiData) { - --_voiceTimer; - if (!(_voiceTimer & 0x01)) - playVoice(); - - int newTempoSum = _tempo + _tempoSum; - _tempoSum = newTempoSum & 0xFF; - if (newTempoSum > 0xFF) - processMidiData(); - } else { - nextTick(); - play(); - } - _next_tick += _tick_len; - } - - step = len; - if (step > (_next_tick >> FIXP_SHIFT)) - step = (_next_tick >> FIXP_SHIFT); - _cmsEmu->readBuffer(buffer, step); - buffer += 2 * step; - _next_tick -= step << FIXP_SHIFT; - } while (len -= step); - - return numSamples; -} - -void Player_V2CMS::playVoice() { - if (_outputTableReady) { - playMusicChips(_cmsChips); - _outputTableReady = 0; - } - - _octaveMask = 0xF0; - Voice2 *voice = 0; - for (int i = 0; i < 8; ++i) { - voice = &_cmsVoices[i]; - _octaveMask = ~_octaveMask; - - if (voice->chanNumber != 0xFF) { - processChannel(voice); - } else { - if (!voice->curVolume) { - *(voice->amplitudeOutput) = 0; - } - - int volume = voice->curVolume - voice->releaseRate; - if (volume < 0) - volume = 0; - - voice->curVolume = volume; - *(voice->amplitudeOutput) = ((volume >> 4) | (volume & 0xF0)) & voice->channel; - ++_outputTableReady; - } - } -} - -void Player_V2CMS::processChannel(Voice2 *channel) { - ++_outputTableReady; - switch (channel->nextProcessState) { - case Voice2::kEnvelopeAttack: - processAttack(channel); - break; - - case Voice2::kEnvelopeDecay: - processDecay(channel); - break; - - case Voice2::kEnvelopeSustain: - processSustain(channel); - break; - - case Voice2::kEnvelopeRelease: - processRelease(channel); - break; - } -} - -void Player_V2CMS::processRelease(Voice2 *channel) { - int newVolume = channel->curVolume - channel->releaseRate; - if (newVolume < 0) - newVolume = 0; - - channel->curVolume = newVolume; - processVibrato(channel); -} - -void Player_V2CMS::processAttack(Voice2 *channel) { - int newVolume = channel->curVolume + channel->attackRate; - if (newVolume > channel->maxAmpl) { - channel->curVolume = channel->maxAmpl; - channel->nextProcessState = Voice2::kEnvelopeDecay; - } else { - channel->curVolume = newVolume; - } - - processVibrato(channel); -} - -void Player_V2CMS::processDecay(Voice2 *channel) { - int newVolume = channel->curVolume - channel->decayRate; - if (newVolume <= channel->sustainRate) { - channel->curVolume = channel->sustainRate; - channel->nextProcessState = Voice2::kEnvelopeSustain; - } else { - channel->curVolume = newVolume; - } - - processVibrato(channel); -} - -void Player_V2CMS::processSustain(Voice2 *channel) { - if (channel->unkVibratoRate) { - int16 volume = channel->curVolume + channel->unkRate; - if (volume & 0xFF00) { - volume = int8(volume >> 8); - volume = -volume; - } - - channel->curVolume = volume; - --channel->unkCount; - if (!channel->unkCount) { - channel->unkRate = -channel->unkRate; - channel->unkCount = (channel->unkVibratoDepth & 0x0F) << 1; - } - } - processVibrato(channel); -} - -void Player_V2CMS::processVibrato(Voice2 *channel) { - if (channel->vibratoRate) { - int16 temp = channel->curFreq + channel->curVibratoRate; - channel->curOctave += (temp & 0xFF00) >> 8; - channel->curFreq = temp & 0xFF; - - --channel->curVibratoUnk; - if (!channel->curVibratoUnk) { - channel->curVibratoRate = -channel->curVibratoRate; - channel->curVibratoUnk = (channel->vibratoDepth & 0x0F) << 1; - } - } - - byte *output = channel->amplitudeOutput; - *output = ((channel->curVolume >> 4) | (channel->curVolume & 0xF0)) & channel->channel; - output = channel->freqOutput; - *output = channel->curFreq; - output = channel->octaveOutput; - *output = (((channel->curOctave << 4) | (channel->curOctave & 0x0F)) & _octaveMask) | ((~_octaveMask) & *output); -} - -void Player_V2CMS::offAllChannels() { - for (int cmsPort = 0x220, i = 0; i < 2; cmsPort += 2, ++i) { - for (int off = 1; off <= 10; ++off) { - _cmsEmu->portWrite(cmsPort+1, _cmsInitData[off*2]); - _cmsEmu->portWrite(cmsPort, _cmsInitData[off*2+1]); - } - } -} - -Player_V2CMS::Voice2 *Player_V2CMS::getFreeVoice() { - Voice2 *curVoice = 0; - Voice2 *selected = 0; - uint8 volume = 0xFF; - - for (int i = 0; i < 8; ++i) { - curVoice = &_cmsVoices[i]; - - if (curVoice->chanNumber == 0xFF) { - if (!curVoice->curVolume) { - selected = curVoice; - break; - } - - if (curVoice->curVolume < volume) { - selected = curVoice; - volume = selected->curVolume; - } - } - } - - if (selected) { - selected->chanNumber = _lastMidiCommand & 0x0F; - - uint8 channel = selected->chanNumber; - Voice2 *oldChannel = _midiChannel[channel]; - _midiChannel[channel] = selected; - selected->nextVoice = oldChannel; - } - - return selected; -} - -void Player_V2CMS::playNote(byte *&data) { - byte channel = _lastMidiCommand & 0x0F; - if (_midiChannelUse[channel]) { - Voice2 *freeVoice = getFreeVoice(); - if (freeVoice) { - Voice *voice = &_cmsVoicesBase[freeVoice->chanNumber]; - freeVoice->attackRate = voice->attack; - freeVoice->decayRate = voice->decay; - freeVoice->sustainRate = voice->sustain; - freeVoice->releaseRate = voice->release; - freeVoice->octaveAdd = voice->octadd; - freeVoice->vibratoRate = freeVoice->curVibratoRate = voice->vibrato & 0xFF; - freeVoice->vibratoDepth = freeVoice->curVibratoUnk = voice->vibrato >> 8; - freeVoice->unkVibratoRate = freeVoice->unkRate = voice->vibrato2 & 0xFF; - freeVoice->unkVibratoDepth = freeVoice->unkCount = voice->vibrato2 >> 8; - freeVoice->maxAmpl = 0xFF; - - uint8 rate = freeVoice->attackRate; - uint8 volume = freeVoice->curVolume >> 1; - - if (rate < volume) - rate = volume; - - rate -= freeVoice->attackRate; - freeVoice->curVolume = rate; - freeVoice->playingNote = *data; - - int effectiveNote = freeVoice->playingNote + 3; - if (effectiveNote < 0 || effectiveNote >= ARRAYSIZE(_midiNotes)) { - warning("Player_V2CMS::playNote: Note %d out of bounds", effectiveNote); - effectiveNote = CLIP<int>(effectiveNote, 0, ARRAYSIZE(_midiNotes) - 1); - } - - int octave = _midiNotes[effectiveNote].baseOctave + freeVoice->octaveAdd - 3; - if (octave < 0) - octave = 0; - if (octave > 7) - octave = 7; - if (!octave) - ++octave; - freeVoice->curOctave = octave; - freeVoice->curFreq = _midiNotes[effectiveNote].frequency; - freeVoice->curVolume = 0; - freeVoice->nextProcessState = Voice2::kEnvelopeAttack; - if (!(_lastMidiCommand & 1)) - freeVoice->channel = 0xF0; - else - freeVoice->channel = 0x0F; - } - } - data += 2; -} - -Player_V2CMS::Voice2 *Player_V2CMS::getPlayVoice(byte param) { - byte channelNum = _lastMidiCommand & 0x0F; - Voice2 *curVoice = _midiChannel[channelNum]; - - if (curVoice) { - Voice2 *prevVoice = 0; - while (true) { - if (curVoice->playingNote == param) - break; - - prevVoice = curVoice; - curVoice = curVoice->nextVoice; - if (!curVoice) - return 0; - } - - if (prevVoice) - prevVoice->nextVoice = curVoice->nextVoice; - else - _midiChannel[channelNum] = curVoice->nextVoice; - } - - return curVoice; -} - -void Player_V2CMS::clearNote(byte *&data) { - Voice2 *voice = getPlayVoice(*data); - if (voice) { - voice->chanNumber = 0xFF; - voice->nextVoice = 0; - voice->nextProcessState = Voice2::kEnvelopeRelease; - } - data += 2; -} - -void Player_V2CMS::play() { - _octaveMask = 0xF0; - channel_data *chan = &_channels[0].d; - - byte noiseGen = 3; - - for (int i = 1; i <= 4; ++i) { - if (chan->time_left) { - uint16 freq = chan->freq; - - if (i == 4) { - if ((freq >> 8) & 0x40) { - noiseGen = freq & 0xFF; - } else { - noiseGen = 3; - _sfxFreq[0] = _sfxFreq[3]; - _sfxOctave[0] = (_sfxOctave[0] & 0xF0) | ((_sfxOctave[1] & 0xF0) >> 4); - } - } else { - if (freq == 0) { - freq = 0xFFC0; - } - - int cmsOct = 2; - int freqOct = 0x8000; - - while (true) { - if (freq >= freqOct) { - break; - } - freqOct >>= 1; - ++cmsOct; - if (cmsOct == 8) { - --cmsOct; - freq = 1024; - break; - } - } - byte oct = cmsOct << 4; - oct |= cmsOct; - - oct &= _octaveMask; - oct |= (~_octaveMask) & _sfxOctave[(i & 3) >> 1]; - _sfxOctave[(i & 3) >> 1] = oct; - - freq >>= -(cmsOct - 9); - _sfxFreq[i & 3] = (-(freq - 511)) & 0xFF; - } - _sfxAmpl[i & 3] = _volumeTable[chan->volume >> 12]; - } else { - _sfxAmpl[i & 3] = 0; - } - - chan = &_channels[i].d; - _octaveMask ^= 0xFF; - } - - // with the high nibble of the volumeReg value - // the right channels amplitude is set - // with the low value the left channels amplitude - _cmsEmu->portWrite(0x221, 0); - _cmsEmu->portWrite(0x220, _sfxAmpl[0]); - _cmsEmu->portWrite(0x221, 1); - _cmsEmu->portWrite(0x220, _sfxAmpl[1]); - _cmsEmu->portWrite(0x221, 2); - _cmsEmu->portWrite(0x220, _sfxAmpl[2]); - _cmsEmu->portWrite(0x221, 3); - _cmsEmu->portWrite(0x220, _sfxAmpl[3]); - _cmsEmu->portWrite(0x221, 8); - _cmsEmu->portWrite(0x220, _sfxFreq[0]); - _cmsEmu->portWrite(0x221, 9); - _cmsEmu->portWrite(0x220, _sfxFreq[1]); - _cmsEmu->portWrite(0x221, 10); - _cmsEmu->portWrite(0x220, _sfxFreq[2]); - _cmsEmu->portWrite(0x221, 11); - _cmsEmu->portWrite(0x220, _sfxFreq[3]); - _cmsEmu->portWrite(0x221, 0x10); - _cmsEmu->portWrite(0x220, _sfxOctave[0]); - _cmsEmu->portWrite(0x221, 0x11); - _cmsEmu->portWrite(0x220, _sfxOctave[1]); - _cmsEmu->portWrite(0x221, 0x14); - _cmsEmu->portWrite(0x220, 0x3E); - _cmsEmu->portWrite(0x221, 0x15); - _cmsEmu->portWrite(0x220, 0x01); - _cmsEmu->portWrite(0x221, 0x16); - _cmsEmu->portWrite(0x220, noiseGen); -} - -void Player_V2CMS::playMusicChips(const MusicChip *table) { - int cmsPort = 0x21E; - - do { - cmsPort += 2; - _cmsEmu->portWrite(cmsPort+1, 0); - _cmsEmu->portWrite(cmsPort, table->ampl[0]); - _cmsEmu->portWrite(cmsPort+1, 1); - _cmsEmu->portWrite(cmsPort, table->ampl[1]); - _cmsEmu->portWrite(cmsPort+1, 2); - _cmsEmu->portWrite(cmsPort, table->ampl[2]); - _cmsEmu->portWrite(cmsPort+1, 3); - _cmsEmu->portWrite(cmsPort, table->ampl[3]); - _cmsEmu->portWrite(cmsPort+1, 8); - _cmsEmu->portWrite(cmsPort, table->freq[0]); - _cmsEmu->portWrite(cmsPort+1, 9); - _cmsEmu->portWrite(cmsPort, table->freq[1]); - _cmsEmu->portWrite(cmsPort+1, 10); - _cmsEmu->portWrite(cmsPort, table->freq[2]); - _cmsEmu->portWrite(cmsPort+1, 11); - _cmsEmu->portWrite(cmsPort, table->freq[3]); - _cmsEmu->portWrite(cmsPort+1, 0x10); - _cmsEmu->portWrite(cmsPort, table->octave[0]); - _cmsEmu->portWrite(cmsPort+1, 0x11); - _cmsEmu->portWrite(cmsPort, table->octave[1]); - _cmsEmu->portWrite(cmsPort+1, 0x14); - _cmsEmu->portWrite(cmsPort, 0x3F); - _cmsEmu->portWrite(cmsPort+1, 0x15); - _cmsEmu->portWrite(cmsPort, 0x00); - ++table; - } while ((cmsPort & 2) == 0); -} - -const Player_V2CMS::MidiNote Player_V2CMS::_midiNotes[132] = { - { 3, 0 }, { 31, 0 }, { 58, 0 }, { 83, 0 }, - { 107, 0 }, { 130, 0 }, { 151, 0 }, { 172, 0 }, - { 191, 0 }, { 209, 0 }, { 226, 0 }, { 242, 0 }, - { 3, 1 }, { 31, 1 }, { 58, 1 }, { 83, 1 }, - { 107, 1 }, { 130, 1 }, { 151, 1 }, { 172, 1 }, - { 191, 1 }, { 209, 1 }, { 226, 1 }, { 242, 1 }, - { 3, 2 }, { 31, 2 }, { 58, 2 }, { 83, 2 }, - { 107, 2 }, { 130, 2 }, { 151, 2 }, { 172, 2 }, - { 191, 2 }, { 209, 2 }, { 226, 2 }, { 242, 2 }, - { 3, 3 }, { 31, 3 }, { 58, 3 }, { 83, 3 }, - { 107, 3 }, { 130, 3 }, { 151, 3 }, { 172, 3 }, - { 191, 3 }, { 209, 3 }, { 226, 3 }, { 242, 3 }, - { 3, 4 }, { 31, 4 }, { 58, 4 }, { 83, 4 }, - { 107, 4 }, { 130, 4 }, { 151, 4 }, { 172, 4 }, - { 191, 4 }, { 209, 4 }, { 226, 4 }, { 242, 4 }, - { 3, 5 }, { 31, 5 }, { 58, 5 }, { 83, 5 }, - { 107, 5 }, { 130, 5 }, { 151, 5 }, { 172, 5 }, - { 191, 5 }, { 209, 5 }, { 226, 5 }, { 242, 5 }, - { 3, 6 }, { 31, 6 }, { 58, 6 }, { 83, 6 }, - { 107, 6 }, { 130, 6 }, { 151, 6 }, { 172, 6 }, - { 191, 6 }, { 209, 6 }, { 226, 6 }, { 242, 6 }, - { 3, 7 }, { 31, 7 }, { 58, 7 }, { 83, 7 }, - { 107, 7 }, { 130, 7 }, { 151, 7 }, { 172, 7 }, - { 191, 7 }, { 209, 7 }, { 226, 7 }, { 242, 7 }, - { 3, 8 }, { 31, 8 }, { 58, 8 }, { 83, 8 }, - { 107, 8 }, { 130, 8 }, { 151, 8 }, { 172, 8 }, - { 191, 8 }, { 209, 8 }, { 226, 8 }, { 242, 8 }, - { 3, 9 }, { 31, 9 }, { 58, 9 }, { 83, 9 }, - { 107, 9 }, { 130, 9 }, { 151, 9 }, { 172, 9 }, - { 191, 9 }, { 209, 9 }, { 226, 9 }, { 242, 9 }, - { 3, 10 }, { 31, 10 }, { 58, 10 }, { 83, 10 }, - { 107, 10 }, { 130, 10 }, { 151, 10 }, { 172, 10 }, - { 191, 10 }, { 209, 10 }, { 226, 10 }, { 242, 10 } -}; - -const byte Player_V2CMS::_attackRate[16] = { - 0, 2, 4, 7, 14, 26, 48, 82, - 128, 144, 160, 176, 192, 208, 224, 255 -}; - -const byte Player_V2CMS::_decayRate[16] = { - 0, 1, 2, 3, 4, 6, 12, 24, - 48, 96, 192, 215, 255, 255, 255, 255 -}; - -const byte Player_V2CMS::_sustainRate[16] = { - 255, 180, 128, 96, 80, 64, 56, 48, - 42, 36, 32, 28, 24, 20, 16, 0 -}; - -const byte Player_V2CMS::_releaseRate[16] = { - 0, 1, 2, 4, 6, 9, 14, 22, - 36, 56, 80, 100, 120, 140, 160, 255 -}; - -const byte Player_V2CMS::_volumeTable[16] = { - 0x00, 0x10, 0x10, 0x11, 0x11, 0x21, 0x22, 0x22, - 0x33, 0x44, 0x55, 0x66, 0x88, 0xAA, 0xCC, 0xFF -}; - -const byte Player_V2CMS::_cmsInitData[26] = { - 0x1C, 0x02, - 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, - 0x14, 0x3F, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1C, 0x01 -}; - -} // End of namespace Scumm diff --git a/engines/scumm/player/v2cms.h b/engines/scumm/player/v2cms.h deleted file mode 100644 index d022a64a5f..0000000000 --- a/engines/scumm/player/v2cms.h +++ /dev/null @@ -1,177 +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 SCUMM_PLAYER_V2CMS_H -#define SCUMM_PLAYER_V2CMS_H - -#include "scumm/player/v2base.h" // for channel_data - -class CMSEmulator; - -namespace Scumm { - -/** - * Scumm V2 CMS/Gameblaster MIDI driver. - */ -class Player_V2CMS : public Player_V2Base { -public: - Player_V2CMS(ScummEngine *scumm, Audio::Mixer *mixer); - virtual ~Player_V2CMS(); - - // MusicEngine API - virtual void setMusicVolume(int vol); - virtual void startSound(int sound); - virtual void stopSound(int sound); - virtual void stopAllSounds(); - virtual int getMusicTimer(); - virtual int getSoundStatus(int sound) const; - - // AudioStream API - virtual int readBuffer(int16 *buffer, const int numSamples); - virtual bool isStereo() const { return true; } - -private: - struct Voice { - byte attack; - byte decay; - byte sustain; - byte release; - byte octadd; - int16 vibrato; - int16 vibrato2; - int16 noise; - }; - - struct Voice2 { - byte *amplitudeOutput; - byte *freqOutput; - byte *octaveOutput; - - uint8 channel; - int8 sustainLevel; - uint8 attackRate; - uint8 maxAmpl; - uint8 decayRate; - uint8 sustainRate; - uint8 releaseRate; - uint8 releaseTime; - int8 vibratoRate; - int8 vibratoDepth; - - int8 curVibratoRate; - int8 curVibratoUnk; - - int8 unkVibratoRate; - int8 unkVibratoDepth; - - int8 unkRate; - int8 unkCount; - - enum EnvelopeState { - kEnvelopeAttack, - kEnvelopeDecay, - kEnvelopeSustain, - kEnvelopeRelease - }; - - EnvelopeState nextProcessState; - uint8 curVolume; - uint8 curOctave; - uint8 curFreq; - - int8 octaveAdd; - - int8 playingNote; - Voice2 *nextVoice; - - byte chanNumber; - }; - - struct MusicChip { - byte ampl[4]; - byte freq[4]; - byte octave[2]; - }; - - Voice _cmsVoicesBase[16]; - Voice2 _cmsVoices[8]; - MusicChip _cmsChips[2]; - - uint8 _tempo; - uint8 _tempoSum; - byte _looping; - byte _octaveMask; - int16 _midiDelay; - Voice2 *_midiChannel[16]; - byte _midiChannelUse[16]; - byte *_midiData; - byte *_midiSongBegin; - - int _loadedMidiSong; - - byte _sfxFreq[4], _sfxAmpl[4], _sfxOctave[2]; - - byte _lastMidiCommand; - uint _outputTableReady; - byte _voiceTimer; - - int _musicTimer, _musicTimerTicks; - - void loadMidiData(byte *data, int sound); - void play(); - - void processChannel(Voice2 *channel); - void processRelease(Voice2 *channel); - void processAttack(Voice2 *channel); - void processDecay(Voice2 *channel); - void processSustain(Voice2 *channel); - void processVibrato(Voice2 *channel); - - void playMusicChips(const MusicChip *table); - void playNote(byte *&data); - void clearNote(byte *&data); - void offAllChannels(); - void playVoice(); - void processMidiData(); - - Voice2 *getFreeVoice(); - Voice2 *getPlayVoice(byte param); - - struct MidiNote { - byte frequency; - byte baseOctave; - }; - - static const MidiNote _midiNotes[132]; - static const byte _attackRate[16]; - static const byte _decayRate[16]; - static const byte _sustainRate[16]; - static const byte _releaseRate[16]; - static const byte _volumeTable[16]; - static const byte _cmsInitData[26]; - - CMSEmulator *_cmsEmu; -}; - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/player/v3a.cpp b/engines/scumm/player/v3a.cpp deleted file mode 100644 index b91bd49e6e..0000000000 --- a/engines/scumm/player/v3a.cpp +++ /dev/null @@ -1,357 +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 "engines/engine.h" -#include "scumm/player/v3a.h" -#include "scumm/scumm.h" - -namespace Scumm { - -static const uint16 note_freqs[4][12] = { - {0x06B0, 0x0650, 0x05F4, 0x05A0, 0x054C, 0x0500, 0x04B8, 0x0474, 0x0434, 0x03F8, 0x03C0, 0x0388}, - {0x0358, 0x0328, 0x02FA, 0x02D0, 0x02A6, 0x0280, 0x025C, 0x023A, 0x021A, 0x01FC, 0x01E0, 0x01C4}, - {0x01AC, 0x0194, 0x017D, 0x0168, 0x0153, 0x0140, 0x012E, 0x011D, 0x010D, 0x00FE, 0x00F0, 0x00E2}, - {0x00D6, 0x00CA, 0x00BE, 0x00B4, 0x00A9, 0x00A0, 0x0097, 0x008E, 0x0086, 0x007F, 0x00F0, 0x00E2} -}; - -Player_V3A::Player_V3A(ScummEngine *scumm, Audio::Mixer *mixer) { - int i; - _vm = scumm; - for (i = 0; i < V3A_MAXMUS; i++) { - _mus[i].id = 0; - _mus[i].dur = 0; - } - for (i = 0; i < V3A_MAXSFX; i++) { - _sfx[i].id = 0; - _sfx[i].dur = 0; - } - - _curSong = 0; - _songData = NULL; - _songPtr = 0; - _songDelay = 0; - - _music_timer = 0; - - _isinit = false; - - _mod = new Player_MOD(mixer); - _mod->setUpdateProc(update_proc, this, 60); -} - -Player_V3A::~Player_V3A() { - int i; - delete _mod; - if (_isinit) { - for (i = 0; _wavetable[i] != NULL; i++) { - for (int j = 0; j < 6; j++) { - free(_wavetable[i]->_idat[j]); - free(_wavetable[i]->_ldat[j]); - } - free(_wavetable[i]); - } - free(_wavetable); - } -} - -void Player_V3A::setMusicVolume (int vol) { - _mod->setMusicVolume(vol); -} - -int Player_V3A::getMusChan (int id) const { - int i; - for (i = 0; i < V3A_MAXMUS; i++) { - if (_mus[i].id == id) - break; - } - if (i == V3A_MAXMUS) { - if (id == 0) - warning("player_v3a - out of music channels"); - return -1; - } - return i; -} -int Player_V3A::getSfxChan (int id) const { - int i; - for (i = 0; i < V3A_MAXSFX; i++) { - if (_sfx[i].id == id) - break; - } - if (i == V3A_MAXSFX) { - if (id == 0) - warning("player_v3a - out of sfx channels"); - return -1; - } - return i; -} - -void Player_V3A::stopAllSounds() { - int i; - for (i = 0; i < V3A_MAXMUS; i++) { - if (_mus[i].id) - _mod->stopChannel(_mus[i].id); - _mus[i].id = 0; - _mus[i].dur = 0; - } - _curSong = 0; - _songPtr = 0; - _songDelay = 0; - _songData = NULL; - for (i = 0; i < V3A_MAXSFX; i++) { - if (_sfx[i].id) - _mod->stopChannel(_sfx[i].id | 0x100); - _sfx[i].id = 0; - _sfx[i].dur = 0; - } -} - -void Player_V3A::stopSound(int nr) { - int i; - if (nr == 0) { // Amiga Loom does this near the end, when Chaos casts SILENCE on Hetchel - stopAllSounds(); - return; - } - if (nr == _curSong) { - for (i = 0; i < V3A_MAXMUS; i++) { - if (_mus[i].id) - _mod->stopChannel(_mus[i].id); - _mus[i].id = 0; - _mus[i].dur = 0; - } - _curSong = 0; - _songPtr = 0; - _songDelay = 0; - _songData = NULL; - } else { - i = getSfxChan(nr); - if (i != -1) { - _mod->stopChannel(nr | 0x100); - _sfx[i].id = 0; - _sfx[i].dur = 0; - } - } -} - -void Player_V3A::startSound(int nr) { - assert(_vm); - byte *data = _vm->getResourceAddress(rtSound, nr); - assert(data); - - if ((_vm->_game.id != GID_INDY3) && (_vm->_game.id != GID_LOOM)) - error("player_v3a - unknown game"); - - if (!_isinit) { - int i; - unsigned char *ptr; - int offset = 4; - int numInstruments; - - if (_vm->_game.id == GID_INDY3) { - ptr = _vm->getResourceAddress(rtSound, 83); - numInstruments = 12; - } else { - ptr = _vm->getResourceAddress(rtSound, 79); - numInstruments = 9; - } - assert(ptr); - _wavetable = (instData **)malloc((numInstruments + 1) * sizeof(void *)); - for (i = 0; i < numInstruments; i++) { - _wavetable[i] = (instData *)malloc(sizeof(instData)); - for (int j = 0; j < 6; j++) { - int off, len; - off = READ_BE_UINT16(ptr + offset + 0); - _wavetable[i]->_ilen[j] = len = READ_BE_UINT16(ptr + offset + 2); - if (len) { - _wavetable[i]->_idat[j] = (char *)malloc(len); - memcpy(_wavetable[i]->_idat[j],ptr + off,len); - } else _wavetable[i]->_idat[j] = NULL; - off = READ_BE_UINT16(ptr + offset + 4); - _wavetable[i]->_llen[j] = len = READ_BE_UINT16(ptr + offset + 6); - if (len) { - _wavetable[i]->_ldat[j] = (char *)malloc(len); - memcpy(_wavetable[i]->_ldat[j],ptr + off,len); - } else _wavetable[i]->_ldat[j] = NULL; - _wavetable[i]->_oct[j] = READ_BE_UINT16(ptr + offset + 8); - offset += 10; - } - if (_vm->_game.id == GID_INDY3) { - _wavetable[i]->_pitadjust = 0; - offset += 2; - } else { - _wavetable[i]->_pitadjust = READ_BE_UINT16(ptr + offset + 2); - offset += 4; - } - } - _wavetable[i] = NULL; - _isinit = true; - } - - if (getSoundStatus(nr)) - stopSound(nr); // if a sound is playing, restart it - - if (data[26]) { - if (_curSong) - stopSound(_curSong); - _curSong = nr; - _songData = data; - _songPtr = 0x1C; - _songDelay = 1; - _music_timer = 0; - } else { - int size = READ_BE_UINT16(data + 12); - int rate = 3579545 / READ_BE_UINT16(data + 20); - char *sound = (char *)malloc(size); - int vol = (data[24] << 1) | (data[24] >> 5); // if I boost this to 0-255, it gets too loud and starts to clip - memcpy(sound, data + READ_BE_UINT16(data + 8), size); - int loopStart = 0, loopEnd = 0; - int loopcount = data[27]; - if (loopcount > 1) { - loopStart = READ_BE_UINT16(data + 10) - READ_BE_UINT16(data + 8); - loopEnd = READ_BE_UINT16(data + 14); - } - int i = getSfxChan(); - if (i == -1) { - free(sound); - return; - } - _sfx[i].id = nr; - _sfx[i].dur = 1 + loopcount * 60 * size / rate; - if (READ_BE_UINT16(data + 16)) { - _sfx[i].rate = READ_BE_UINT16(data + 20) << 16; - _sfx[i].delta = (int32)READ_BE_UINT32(data + 32); - _sfx[i].dur = READ_BE_UINT32(data + 40); - } else { - _sfx[i].delta = 0; - } - _mod->startChannel(nr | 0x100, sound, size, rate, vol, loopStart, loopEnd); - } -} - -void Player_V3A::update_proc(void *param) { - ((Player_V3A *)param)->playMusic(); -} - -void Player_V3A::playMusic() { - int i; - for (i = 0; i < V3A_MAXMUS; i++) { - if (_mus[i].id) { - _mus[i].dur--; - if (_mus[i].dur) - continue; - _mod->stopChannel(_mus[i].id); - _mus[i].id = 0; - } - } - for (i = 0; i < V3A_MAXSFX; i++) { - if (_sfx[i].id) { - if (_sfx[i].delta) { - uint16 oldrate = _sfx[i].rate >> 16; - _sfx[i].rate += _sfx[i].delta; - if (_sfx[i].rate < (55 << 16)) - _sfx[i].rate = 55 << 16; // at rates below 55, frequency - uint16 newrate = _sfx[i].rate >> 16; // exceeds 65536, which is bad - if (oldrate != newrate) - _mod->setChannelFreq(_sfx[i].id | 0x100, 3579545 / newrate); - } - _sfx[i].dur--; - if (_sfx[i].dur) - continue; - _mod->stopChannel(_sfx[i].id | 0x100); - _sfx[i].id = 0; - } - } - - _music_timer++; - if (!_curSong) - return; - if (_songDelay && --_songDelay) - return; - if (_songPtr == 0) { - // at the end of the song, and it wasn't looped - kill it - _curSong = 0; - return; - } - while (1) { - int inst, pit, vol, dur, oct; - inst = _songData[_songPtr++]; - if ((inst & 0xF0) != 0x80) { - // tune is at the end - figure out what's still playing - // and see how long we have to wait until we stop/restart - for (i = 0; i < V3A_MAXMUS; i++) { - if (_songDelay < _mus[i].dur) - _songDelay = _mus[i].dur; - } - if (inst == 0xFB) // it's a looped song, restart it afterwards - _songPtr = 0x1C; - else _songPtr = 0; // otherwise, terminate it - break; - } - inst &= 0xF; - pit = _songData[_songPtr++]; - vol = _songData[_songPtr++] & 0x7F; // if I boost this to 0-255, it gets too loud and starts to clip - dur = _songData[_songPtr++]; - if (pit == 0) { - _songDelay = dur; - break; - } - pit += _wavetable[inst]->_pitadjust; - oct = (pit / 12) - 2; - pit = pit % 12; - if (oct < 0) - oct = 0; - if (oct > 5) - oct = 5; - int rate = 3579545 / note_freqs[_wavetable[inst]->_oct[oct]][pit]; - if (!_wavetable[inst]->_llen[oct]) - dur = _wavetable[inst]->_ilen[oct] * 60 / rate; - char *data = (char *)malloc(_wavetable[inst]->_ilen[oct] + _wavetable[inst]->_llen[oct]); - if (_wavetable[inst]->_idat[oct]) - memcpy(data, _wavetable[inst]->_idat[oct], _wavetable[inst]->_ilen[oct]); - if (_wavetable[inst]->_ldat[oct]) - memcpy(data + _wavetable[inst]->_ilen[oct], _wavetable[inst]->_ldat[oct], _wavetable[inst]->_llen[oct]); - - i = getMusChan(); - if (i == -1) { - free(data); - return; - } - _mus[i].id = i + 1; - _mus[i].dur = dur + 1; - _mod->startChannel(_mus[i].id, data, _wavetable[inst]->_ilen[oct] + _wavetable[inst]->_llen[oct], rate, vol, - _wavetable[inst]->_ilen[oct], _wavetable[inst]->_ilen[oct] + _wavetable[inst]->_llen[oct]); - } -} - -int Player_V3A::getMusicTimer() { - return _music_timer / 30; -} - -int Player_V3A::getSoundStatus(int nr) const { - if (nr == _curSong) - return 1; - if (getSfxChan(nr) != -1) - return 1; - return 0; -} - -} // End of namespace Scumm diff --git a/engines/scumm/player/v3a.h b/engines/scumm/player/v3a.h deleted file mode 100644 index 0869c3398c..0000000000 --- a/engines/scumm/player/v3a.h +++ /dev/null @@ -1,101 +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 SCUMM_PLAYER_V3A_H -#define SCUMM_PLAYER_V3A_H - -#include "common/scummsys.h" -#include "scumm/music.h" -#include "scumm/player/mod.h" - -class Mixer; - -namespace Scumm { - -class ScummEngine; - -/** - * Scumm V3 Amiga sound/music driver. - */ -class Player_V3A : public MusicEngine { -public: - Player_V3A(ScummEngine *scumm, Audio::Mixer *mixer); - virtual ~Player_V3A(); - - virtual void setMusicVolume(int vol); - virtual void startSound(int sound); - virtual void stopSound(int sound); - virtual void stopAllSounds(); - virtual int getMusicTimer(); - virtual int getSoundStatus(int sound) const; - -private: - enum { - V3A_MAXMUS = 24, - V3A_MAXSFX = 16 - }; - - struct musChan { - int id; - int dur; - }; - - struct sfxChan { - int id; - int dur; - uint32 rate; - int32 delta; - }; - - struct instData { - char *_idat[6]; - uint16 _ilen[6]; - char *_ldat[6]; - uint16 _llen[6]; - uint16 _oct[6]; - int16 _pitadjust; - }; - - ScummEngine *_vm; - Player_MOD *_mod; - - musChan _mus[V3A_MAXMUS]; - sfxChan _sfx[V3A_MAXSFX]; - - int _curSong; - uint8 *_songData; - uint16 _songPtr; - uint16 _songDelay; - int _music_timer; - bool _isinit; - - instData **_wavetable; - - int getMusChan (int id = 0) const; - int getSfxChan (int id = 0) const; - static void update_proc(void *param); - void playMusic(); -}; - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/player/v3m.cpp b/engines/scumm/player/v3m.cpp deleted file mode 100644 index b910b36a18..0000000000 --- a/engines/scumm/player/v3m.cpp +++ /dev/null @@ -1,214 +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. - * - */ - -/* - We have the following information from Lars Christensen (lechimp) and - Jamieson Christian (jamieson630): - - RESOURCE DATA - LE 2 bytes Resource size - 2 bytes Unknown - 2 bytes 'so' - 14 bytes Unknown - BE 2 bytes Instrument for Stream 1 - BE 2 bytes Instrument for Stream 2 - BE 2 bytes Instrument for Stream 3 - BE 2 bytes Instrument for Stream 4 - BE 2 bytes Instrument for Stream 5 - BE 2 bytes Offset to Stream 1 - BE 2 bytes Offset to Stream 2 - BE 2 bytes Offset to Stream 3 - BE 2 bytes Offset to Stream 4 - BE 2 bytes Offset to Stream 5 - ? bytes The streams - - STREAM DATA - BE 2 bytes Unknown (always 1?) - 2 bytes Unknown (always 0?) - BE 2 bytes Number of events in stream - ? bytes Stream data - - Each stream event is exactly 3 bytes, therefore one can - assert that numEvents == (streamSize - 6) / 3. The - polyphony of a stream appears to be 1; in other words, only - one note at a time can be playing in each stream. The next - event is not executed until the current note (or rest) is - finished playing; therefore, note duration also serves as the - time delta between events. - - FOR EACH EVENTS - BE 2 bytes Note duration - 1 byte Note number to play (0 = rest/silent) - - Oh, and quick speculation -- Stream 1 may be used for a - single-voice interleaved version of the music, where Stream 2- - 5 represent a version of the music in up to 4-voice - polyphony, one voice per stream. I postulate thus because - the first stream of the Mac Loom theme music contains - interleaved voices, whereas the second stream seemed to - contain only the pizzicato bottom-end harp. Stream 5, in this - example, is empty, so if my speculation is correct, this - particular musical number supports 3-voice polyphony at - most. I must check out Streams 3 and 4 to see what they - contain. - - ========== - - The instruments appear to be identified by their resource IDs: - - 1000 Dual Harp - 10895 harp1 - 11445 strings1 - 11548 silent - 13811 staff1 - 15703 brass1 - 16324 flute1 - 25614 accordian 1 - 28110 f horn1 - 29042 bassoon1 -*/ - -#include "common/macresman.h" -#include "common/translation.h" -#include "engines/engine.h" -#include "gui/message.h" -#include "scumm/player/v3m.h" -#include "scumm/scumm.h" - -namespace Scumm { - -Player_V3M::Player_V3M(ScummEngine *scumm, Audio::Mixer *mixer) - : Player_Mac(scumm, mixer, 5, 0x1E, true) { - assert(_vm->_game.id == GID_LOOM); - - // Channel 0 seems to be what was played on low-end macs, that couldn't - // handle multi-channel music and play the game at the same time. I'm - // not sure if stream 4 is ever used, but let's use it just in case. -} - -// \xAA is a trademark glyph in Mac OS Roman. We try that, but also the Windows -// version, the UTF-8 version, and just plain without in case the file system -// can't handle exotic characters like that. - -static const char *loomFileNames[] = { - "Loom\xAA", - "Loom\x99", - "Loom\xE2\x84\xA2", - "Loom" -}; - -bool Player_V3M::checkMusicAvailable() { - Common::MacResManager resource; - - for (int i = 0; i < ARRAYSIZE(loomFileNames); i++) { - if (resource.exists(loomFileNames[i])) { - return true; - } - } - - GUI::MessageDialog dialog(_( - "Could not find the 'Loom' Macintosh executable to read the\n" - "instruments from. Music will be disabled."), _("OK")); - dialog.runModal(); - return false; -} - -bool Player_V3M::loadMusic(const byte *ptr) { - Common::MacResManager resource; - bool found = false; - - for (int i = 0; i < ARRAYSIZE(loomFileNames); i++) { - if (resource.open(loomFileNames[i])) { - found = true; - break; - } - } - - if (!found) { - return false; - } - - if (ptr[4] != 's' || ptr[5] != 'o') { - // Like the original we ignore all sound resources which do not have - // a 'so' tag in them. - // See bug #3602239 ("Mac Loom crashes using opening spell on - // gravestone") for a case where this is required. Loom Mac tries to - // play resource 11 here. This resource is no Mac sound resource - // though, it is a PC Speaker resource. A test with the original - // interpreter also has shown that no sound is played while the - // screen is shaking. - debug(5, "Player_V3M::loadMusic: Skipping unknown music type %02X%02X", ptr[4], ptr[5]); - resource.close(); - return false; - } - - uint i; - for (i = 0; i < 5; i++) { - int instrument = READ_BE_UINT16(ptr + 20 + 2 * i); - int offset = READ_BE_UINT16(ptr + 30 + 2 * i); - - _channel[i]._looped = false; - _channel[i]._length = READ_BE_UINT16(ptr + offset + 4) * 3; - _channel[i]._data = ptr + offset + 6; - _channel[i]._pos = 0; - _channel[i]._pitchModifier = 0; - _channel[i]._velocity = 0; - _channel[i]._remaining = 0; - _channel[i]._notesLeft = true; - - Common::SeekableReadStream *stream = resource.getResource(RES_SND, instrument); - if (_channel[i].loadInstrument(stream)) { - debug(6, "Player_V3M::loadMusic: Channel %d - Loaded Instrument %d (%s)", i, instrument, resource.getResName(RES_SND, instrument).c_str()); - } else { - resource.close(); - return false; - } - } - - resource.close(); - return true; -} - -bool Player_V3M::getNextNote(int ch, uint32 &samples, int &pitchModifier, byte &velocity) { - _channel[ch]._instrument.newNote(); - if (_channel[ch]._pos >= _channel[ch]._length) { - if (!_channel[ch]._looped) { - _channel[ch]._notesLeft = false; - return false; - } - _channel[ch]._pos = 0; - } - uint16 duration = READ_BE_UINT16(&_channel[ch]._data[_channel[ch]._pos]); - byte note = _channel[ch]._data[_channel[ch]._pos + 2]; - samples = durationToSamples(duration); - if (note > 0) { - pitchModifier = noteToPitchModifier(note, &_channel[ch]._instrument); - velocity = 127; - } else { - pitchModifier = 0; - velocity = 0; - } - _channel[ch]._pos += 3; - return true; -} - -} // End of namespace Scumm diff --git a/engines/scumm/player/v3m.h b/engines/scumm/player/v3m.h deleted file mode 100644 index 609ab8a9d7..0000000000 --- a/engines/scumm/player/v3m.h +++ /dev/null @@ -1,54 +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 SCUMM_PLAYER_V3M_H -#define SCUMM_PLAYER_V3M_H - -#include "common/scummsys.h" -#include "common/util.h" -#include "common/mutex.h" -#include "scumm/music.h" -#include "scumm/player/mac.h" -#include "audio/audiostream.h" -#include "audio/mixer.h" - -class Mixer; - -namespace Scumm { - -class ScummEngine; - -/** - * Scumm V3 Macintosh music driver. - */ -class Player_V3M : public Player_Mac { -public: - Player_V3M(ScummEngine *scumm, Audio::Mixer *mixer); - - virtual bool checkMusicAvailable(); - virtual bool loadMusic(const byte *ptr); - virtual bool getNextNote(int ch, uint32 &samples, int &pitchModifier, byte &velocity); -}; - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/player/v4a.cpp b/engines/scumm/player/v4a.cpp deleted file mode 100644 index de1301ee4c..0000000000 --- a/engines/scumm/player/v4a.cpp +++ /dev/null @@ -1,190 +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 "engines/engine.h" -#include "scumm/player/v4a.h" -#include "scumm/scumm.h" - -#include "common/file.h" - -namespace Scumm { - -Player_V4A::Player_V4A(ScummEngine *scumm, Audio::Mixer *mixer) - : _vm(scumm), - _mixer(mixer), - _tfmxMusic(_mixer->getOutputRate(), true), - _tfmxSfx(_mixer->getOutputRate(), true), - _musicHandle(), - _sfxHandle(), - _musicId(), - _sfxSlots(), - _initState(0), - _signal(0) { - - assert(scumm); - assert(mixer); - assert(_vm->_game.id == GID_MONKEY_VGA); - _tfmxMusic.setSignalPtr(&_signal, 1); -} - -bool Player_V4A::init() { - if (_vm->_game.id != GID_MONKEY_VGA) - error("player_v4a - unknown game"); - - Common::File fileMdat, fileSample; - - if (fileMdat.open("music.dat") && fileSample.open("sample.dat")) { - // explicitly request that no instance delets the resources automatically - if (_tfmxMusic.load(fileMdat, fileSample, false)) { - _tfmxSfx.setModuleData(_tfmxMusic); - return true; - } - } else - warning("player_v4a: couldnt load one of the music resources: music.dat, sample.dat"); - - return false; -} - -Player_V4A::~Player_V4A() { - _mixer->stopHandle(_musicHandle); - _mixer->stopHandle(_sfxHandle); - _tfmxMusic.freeResources(); -} - -void Player_V4A::setMusicVolume(int vol) { - debug(5, "player_v4a: setMusicVolume %i", vol); -} - -void Player_V4A::stopAllSounds() { - debug(5, "player_v4a: stopAllSounds"); - if (_initState > 0) { - _tfmxMusic.stopSong(); - _signal = 0; - _musicId = 0; - - _tfmxSfx.stopSong(); - clearSfxSlots(); - } else - _mixer->stopHandle(_musicHandle); -} - -void Player_V4A::stopSound(int nr) { - debug(5, "player_v4a: stopSound %d", nr); - if (nr == 0) - return; - if (nr == _musicId) { - _musicId = 0; - if (_initState > 0) - _tfmxMusic.stopSong(); - else - _mixer->stopHandle(_musicHandle); - _signal = 0; - } else { - const int chan = getSfxChan(nr); - if (chan != -1) { - setSfxSlot(chan, 0); - _tfmxSfx.stopMacroEffect(chan); - } - } -} - -void Player_V4A::startSound(int nr) { - static const int8 monkeyCommands[52] = { - -1, -2, -3, -4, -5, -6, -7, -8, - -9, -10, -11, -12, -13, -14, 18, 17, - -17, -18, -19, -20, -21, -22, -23, -24, - -25, -26, -27, -28, -29, -30, -31, -32, - -33, 16, -35, 0, 1, 2, 3, 7, - 8, 10, 11, 4, 5, 14, 15, 12, - 6, 13, 9, 19 - }; - - const byte *ptr = _vm->getResourceAddress(rtSound, nr); - assert(ptr); - - const int val = ptr[9]; - if (val < 0 || val >= ARRAYSIZE(monkeyCommands)) { - warning("player_v4a: illegal Songnumber %i", val); - return; - } - - if (!_initState) - _initState = init() ? 1 : -1; - - if (_initState < 0) - return; - - int index = monkeyCommands[val]; - const byte type = ptr[6]; - if (index < 0) { // SoundFX - index = -index - 1; - debug(3, "player_v4a: play %d: custom %i - %02X", nr, index, type); - - // start an empty Song so timing is setup - if (_tfmxSfx.getSongIndex() < 0) - _tfmxSfx.doSong(0x18); - - const int chan = _tfmxSfx.doSfx((uint16)index); - if (chan >= 0 && chan < ARRAYSIZE(_sfxSlots)) - setSfxSlot(chan, nr, type); - else - warning("player_v4a: custom %i is not of required type", index); - - // the Tfmx-player never "ends" the output by itself, so this should be threadsafe - if (!_mixer->isSoundHandleActive(_sfxHandle)) - _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, &_tfmxSfx, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO); - - } else { // Song - debug(3, "player_v4a: play %d: song %i - %02X", nr, index, type); - if (ptr[6] != 0x7F) - warning("player_v4a: Song has wrong type"); - - _tfmxMusic.doSong(index); - _signal = 2; - - // the Tfmx-player never "ends" the output by itself, so this should be threadsafe - if (!_mixer->isSoundHandleActive(_musicHandle)) - _mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, &_tfmxMusic, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO); - _musicId = nr; - } -} - -int Player_V4A::getMusicTimer() { - // A workaround if the modplayer couldnt load the datafiles - just return a number big enough to pass all tests - if (_initState < 0) - return 2000; - if (_musicId) { - // The titlesong (and a few others) is running with ~70 ticks per second and the scale seems to be based on that. - // The Game itself doesnt get the timing from the Tfmx Player however, so we just use the elapsed time - // 357 ~ 1000 * 25 * (1 / 70) - return _mixer->getSoundElapsedTime(_musicHandle) / 357; - } - return 0; -} - -int Player_V4A::getSoundStatus(int nr) const { - // For music the game queues a variable the Tfmx Player sets through a special command. - // For sfx there seems to be no way to queue them, and the game doesnt try to. - return (nr == _musicId) ? _signal : 0; -} - -} // End of namespace Scumm diff --git a/engines/scumm/player/v4a.h b/engines/scumm/player/v4a.h deleted file mode 100644 index d01c70f295..0000000000 --- a/engines/scumm/player/v4a.h +++ /dev/null @@ -1,96 +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 SCUMM_PLAYER_V4A_H -#define SCUMM_PLAYER_V4A_H - -#include "common/scummsys.h" -#include "common/util.h" -#include "scumm/music.h" -#include "audio/mixer.h" -#include "audio/mods/tfmx.h" - -class Mixer; - -namespace Scumm { - -class ScummEngine; - -/** - * Scumm V4 Amiga sound/music driver. - */ -class Player_V4A : public MusicEngine { -public: - Player_V4A(ScummEngine *scumm, Audio::Mixer *mixer); - virtual ~Player_V4A(); - - virtual void setMusicVolume(int vol); - virtual void startSound(int sound); - virtual void stopSound(int sound); - virtual void stopAllSounds(); - virtual int getMusicTimer(); - virtual int getSoundStatus(int sound) const; - -private: - ScummEngine *const _vm; - Audio::Mixer *const _mixer; - - Audio::Tfmx _tfmxMusic; - Audio::Tfmx _tfmxSfx; - Audio::SoundHandle _musicHandle; - Audio::SoundHandle _sfxHandle; - - int _musicId; - uint16 _signal; - - struct SfxChan { - int id; -// byte type; - } _sfxSlots[4]; - - int8 _initState; // < 0: failed, 0: uninitialized, > 0: initialized - - int getSfxChan(int id) const { - for (int i = 0; i < ARRAYSIZE(_sfxSlots); ++i) - if (_sfxSlots[i].id == id) - return i; - return -1; - } - - void setSfxSlot(int channel, int id, byte type = 0) { - _sfxSlots[channel].id = id; -// _sfxSlots[channel].type = type; - } - - void clearSfxSlots() { - for (int i = 0; i < ARRAYSIZE(_sfxSlots); ++i){ - _sfxSlots[i].id = 0; -// _sfxSlots[i].type = 0; - } - } - - bool init(); -}; - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/player/v5m.cpp b/engines/scumm/player/v5m.cpp deleted file mode 100644 index 8a2b7f6814..0000000000 --- a/engines/scumm/player/v5m.cpp +++ /dev/null @@ -1,246 +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. - * - */ - -/* - From Markus Magnuson (superqult) we got this information: - Mac0 - --- - 4 bytes - 'SOUN' - BE 4 bytes - block length - - 4 bytes - 'Mac0' - BE 4 bytes - (blockLength - 27) - 28 bytes - ??? - - do this three times (once for each channel): - 4 bytes - 'Chan' - BE 4 bytes - channel length - 4 bytes - instrument name (e.g. 'MARI') - - do this for ((chanLength-24)/4) times: - 2 bytes - note duration - 1 byte - note value - 1 byte - note velocity - - 4 bytes - ??? - 4 bytes - 'Loop'/'Done' - 4 bytes - ??? - - 1 byte - 0x09 - --- - - The instruments presumably correspond to the snd resource names in the - Monkey Island executable: - - Instruments - "MARI" - MARIMBA - "PLUC" - PLUCK - "HARM" - HARMONIC - "PIPE" - PIPEORGAN - "TROM" - TROMBONE - "STRI" - STRINGS - "HORN" - HORN - "VIBE" - VIBES - "SHAK" - SHAKUHACHI - "PANP" - PANPIPE - "WHIS" - WHISTLE - "ORGA" - ORGAN3 - "BONG" - BONGO - "BASS" - BASS - - --- - - Note values <= 1 are silent. -*/ - -#include "common/macresman.h" -#include "common/translation.h" -#include "engines/engine.h" -#include "gui/message.h" -#include "scumm/player/v5m.h" -#include "scumm/scumm.h" - -namespace Scumm { - -Player_V5M::Player_V5M(ScummEngine *scumm, Audio::Mixer *mixer) - : Player_Mac(scumm, mixer, 3, 0x07, false) { - assert(_vm->_game.id == GID_MONKEY); -} - -// Try both with and without underscore in the filename, because hfsutils may -// turn the space into an underscore. At least, it did for me. - -static const char *monkeyIslandFileNames[] = { - "Monkey Island", - "Monkey_Island" -}; - -bool Player_V5M::checkMusicAvailable() { - Common::MacResManager resource; - - for (int i = 0; i < ARRAYSIZE(monkeyIslandFileNames); i++) { - if (resource.exists(monkeyIslandFileNames[i])) { - return true; - } - } - - GUI::MessageDialog dialog(_( - "Could not find the 'Monkey Island' Macintosh executable to read the\n" - "instruments from. Music will be disabled."), _("OK")); - dialog.runModal(); - return false; -} - -bool Player_V5M::loadMusic(const byte *ptr) { - Common::MacResManager resource; - bool found = false; - uint i; - - for (i = 0; i < ARRAYSIZE(monkeyIslandFileNames); i++) { - if (resource.open(monkeyIslandFileNames[i])) { - found = true; - break; - } - } - - if (!found) { - return false; - } - - ptr += 8; - // TODO: Decipher the unknown bytes in the header. For now, skip 'em - ptr += 28; - - Common::MacResIDArray idArray = resource.getResIDArray(RES_SND); - - // Load the three channels and their instruments - for (i = 0; i < 3; i++) { - assert(READ_BE_UINT32(ptr) == MKTAG('C', 'h', 'a', 'n')); - uint32 len = READ_BE_UINT32(ptr + 4); - uint32 instrument = READ_BE_UINT32(ptr + 8); - - _channel[i]._length = len - 20; - _channel[i]._data = ptr + 12; - _channel[i]._looped = (READ_BE_UINT32(ptr + len - 8) == MKTAG('L', 'o', 'o', 'p')); - _channel[i]._pos = 0; - _channel[i]._pitchModifier = 0; - _channel[i]._velocity = 0; - _channel[i]._remaining = 0; - _channel[i]._notesLeft = true; - - for (uint j = 0; j < idArray.size(); j++) { - Common::String name = resource.getResName(RES_SND, idArray[j]); - if (instrument == READ_BE_UINT32(name.c_str())) { - debug(6, "Player_V5M::loadMusic: Channel %d: Loading instrument '%s'", i, name.c_str()); - Common::SeekableReadStream *stream = resource.getResource(RES_SND, idArray[j]); - - if (!_channel[i].loadInstrument(stream)) { - resource.close(); - return false; - } - - break; - } - } - - ptr += len; - } - - resource.close(); - - // The last note of each channel is just zeroes. We will adjust this - // note so that all the channels end at the same time. - - uint32 samples[3]; - uint32 maxSamples = 0; - for (i = 0; i < 3; i++) { - samples[i] = 0; - for (uint j = 0; j < _channel[i]._length; j += 4) { - samples[i] += durationToSamples(READ_BE_UINT16(&_channel[i]._data[j])); - } - if (samples[i] > maxSamples) { - maxSamples = samples[i]; - } - } - - for (i = 0; i < 3; i++) { - _lastNoteSamples[i] = maxSamples - samples[i]; - } - - return true; -} - -bool Player_V5M::getNextNote(int ch, uint32 &samples, int &pitchModifier, byte &velocity) { - if (_channel[ch]._pos >= _channel[ch]._length) { - if (!_channel[ch]._looped) { - _channel[ch]._notesLeft = false; - return false; - } - // FIXME: Jamieson630: The jump seems to be happening - // too quickly! There should maybe be a pause after - // the last Note Off? But I couldn't find one in the - // MI1 Lookout music, where I was hearing problems. - _channel[ch]._pos = 0; - } - uint16 duration = READ_BE_UINT16(&_channel[ch]._data[_channel[ch]._pos]); - byte note = _channel[ch]._data[_channel[ch]._pos + 2]; - samples = durationToSamples(duration); - - if (note != 1) { - _channel[ch]._instrument.newNote(); - } - - if (note > 1) { - pitchModifier = noteToPitchModifier(note, &_channel[ch]._instrument); - velocity = _channel[ch]._data[_channel[ch]._pos + 3]; - } else if (note == 1) { - // This is guesswork, but Monkey Island uses two different - // "special" note values: 0, which is clearly a rest, and 1 - // which is... I thought at first it was a "soft" key off, to - // fade out the note, but listening to the music in a Mac - // emulator (which unfortunately doesn't work all that well), - // I hear no trace of fading out. - // - // It could mean "change the volume on the current note", but - // I can't hear that either, and it always seems to use the - // exact same velocity on this note. - // - // So it appears it really just is a "hold the current note", - // but why? Couldn't they just have made the original note - // longer? - - pitchModifier = _channel[ch]._pitchModifier; - velocity = _channel[ch]._velocity; - } else { - pitchModifier = 0; - velocity = 0; - } - - _channel[ch]._pos += 4; - - if (_channel[ch]._pos >= _channel[ch]._length) { - samples = _lastNoteSamples[ch]; - } - return true; -} - -} // End of namespace Scumm diff --git a/engines/scumm/player/v5m.h b/engines/scumm/player/v5m.h deleted file mode 100644 index ed51943226..0000000000 --- a/engines/scumm/player/v5m.h +++ /dev/null @@ -1,57 +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 SCUMM_PLAYER_V5M_H -#define SCUMM_PLAYER_V5M_H - -#include "common/scummsys.h" -#include "common/util.h" -#include "common/mutex.h" -#include "scumm/music.h" -#include "scumm/player/mac.h" -#include "audio/audiostream.h" -#include "audio/mixer.h" - -class Mixer; - -namespace Scumm { - -class ScummEngine; - -/** - * Scumm V5 Macintosh music driver. - */ -class Player_V5M : public Player_Mac { -public: - Player_V5M(ScummEngine *scumm, Audio::Mixer *mixer); - - virtual bool checkMusicAvailable(); - virtual bool loadMusic(const byte *ptr); - virtual bool getNextNote(int ch, uint32 &samples, int &pitchModifier, byte &velocity); - -private: - uint32 _lastNoteSamples[3]; -}; - -} // End of namespace Scumm - -#endif |