aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm/player_sid.cpp
diff options
context:
space:
mode:
authorFilippos Karapetis2013-11-01 06:57:20 +0200
committerFilippos Karapetis2013-11-01 06:57:53 +0200
commit651bf899399de2b5c2d8e62a5bb4964b037950d2 (patch)
tree103dfc3e6677e7d5c26e13e8866648782f226247 /engines/scumm/player_sid.cpp
parent37d4316a4014970171dfea8fc19f8c9e978e9102 (diff)
downloadscummvm-rg350-651bf899399de2b5c2d8e62a5bb4964b037950d2.tar.gz
scummvm-rg350-651bf899399de2b5c2d8e62a5bb4964b037950d2.tar.bz2
scummvm-rg350-651bf899399de2b5c2d8e62a5bb4964b037950d2.zip
SCUMM: Move all players to a separate "player" directory
There are 34 player .cpp/.h player files, so they have been placed in their own directory, to logically separate them from the rest of the engine
Diffstat (limited to 'engines/scumm/player_sid.cpp')
-rw-r--r--engines/scumm/player_sid.cpp1384
1 files changed, 0 insertions, 1384 deletions
diff --git a/engines/scumm/player_sid.cpp b/engines/scumm/player_sid.cpp
deleted file mode 100644
index 7a609364e5..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