diff options
author | Johannes Schickel | 2014-06-04 01:49:31 +0200 |
---|---|---|
committer | Johannes Schickel | 2014-06-04 01:49:31 +0200 |
commit | a6ec34f4242ebb4cc3e0795e4186729302b43b9c (patch) | |
tree | 0e80d12c6f6f1c6324a6971f2bcdd1d53781dff5 /engines/scumm | |
parent | f78e12cd5c5abd99a0e505e77bbadeb3398f9c06 (diff) | |
download | scummvm-rg350-a6ec34f4242ebb4cc3e0795e4186729302b43b9c.tar.gz scummvm-rg350-a6ec34f4242ebb4cc3e0795e4186729302b43b9c.tar.bz2 scummvm-rg350-a6ec34f4242ebb4cc3e0795e4186729302b43b9c.zip |
SCUMM: Let music in AD code use the same HW channel allocation as SFX.
Diffstat (limited to 'engines/scumm')
-rw-r--r-- | engines/scumm/players/player_ad.cpp | 102 | ||||
-rw-r--r-- | engines/scumm/players/player_ad.h | 19 |
2 files changed, 83 insertions, 38 deletions
diff --git a/engines/scumm/players/player_ad.cpp b/engines/scumm/players/player_ad.cpp index 6c3c7f9458..6083283de5 100644 --- a/engines/scumm/players/player_ad.cpp +++ b/engines/scumm/players/player_ad.cpp @@ -71,6 +71,12 @@ Player_AD::Player_AD(ScummEngine *scumm, Audio::Mixer *mixer) } memset(_hwChannels, 0, sizeof(_hwChannels)); + _numHWChannels = ARRAYSIZE(_hwChannels); + + memset(_voiceChannels, 0, sizeof(_voiceChannels)); + for (int i = 0; i < ARRAYSIZE(_voiceChannels); ++i) { + _voiceChannels[i].hardwareChannel = -1; + } } Player_AD::~Player_AD() { @@ -163,6 +169,13 @@ void Player_AD::stopAllSounds() { // Stop the music playback _curOffset = 0; + // Stop all music voice channels + for (int i = 0; i < ARRAYSIZE(_voiceChannels); ++i) { + if (_voiceChannels[i].lastEvent) { + noteOff(i); + } + } + // Stop all the sfx playback for (int i = 0; i < ARRAYSIZE(_sfx); ++i) { stopSfx(&_sfx[i]); @@ -250,7 +263,7 @@ void Player_AD::setupVolume() { int Player_AD::allocateHWChannel(int priority, SfxSlot *owner) { // First pass: Check whether there's any unallocated channel - for (int i = 0; i < ARRAYSIZE(_hwChannels); ++i) { + for (int i = 0; i < _numHWChannels; ++i) { if (!_hwChannels[i].allocated) { _hwChannels[i].allocated = true; _hwChannels[i].priority = priority; @@ -260,7 +273,7 @@ int Player_AD::allocateHWChannel(int priority, SfxSlot *owner) { } // Second pass: Reassign channels based on priority - for (int i = 0; i < ARRAYSIZE(_hwChannels); ++i) { + for (int i = 0; i < _numHWChannels; ++i) { if (_hwChannels[i].priority <= priority) { // In case the HW channel belongs to a SFX we will completely // stop playback of that SFX. @@ -285,6 +298,15 @@ void Player_AD::freeHWChannel(int channel) { _hwChannels[channel].sfxOwner = nullptr; } +void Player_AD::limitHWChannels(int newCount) { + for (int i = newCount; i < ARRAYSIZE(_hwChannels); ++i) { + if (_hwChannels[i].allocated) { + freeHWChannel(i); + } + } + _numHWChannels = newCount; +} + void Player_AD::writeReg(int r, int v) { if (r >= 0 && r < ARRAYSIZE(_registerBackUpTable)) { _registerBackUpTable[r] = v; @@ -327,26 +349,23 @@ const int Player_AD::_operatorOffsetTable[18] = { 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; + bool hasRhythmData = false; uint instruments = _musicData[10]; for (uint i = 0; i < instruments; ++i) { const int instrIndex = _musicData[11 + i] - 1; if (0 <= instrIndex && instrIndex < 16) { _instrumentOffset[instrIndex] = i * 16 + 16 + 3; - _voiceChannels |= _musicData[_instrumentOffset[instrIndex] + 13]; + hasRhythmData |= (_musicData[_instrumentOffset[instrIndex] + 13] != 0); } } - if (_voiceChannels) { + if (hasRhythmData) { _mdvdrState = 0x20; - _voiceChannels = 6; + limitHWChannels(6); } else { _mdvdrState = 0; - _voiceChannels = 9; + limitHWChannels(9); } _curOffset = 0x93; @@ -428,12 +447,11 @@ void Player_AD::updateMusic() { if (_musicData[instrOffset + 13] != 0) { setupRhythm(_musicData[instrOffset + 13], instrOffset); } else { - int channel = findFreeChannel(); + int channel = allocateVoiceChannel(); if (channel != -1) { - noteOff(channel); - setupChannel(channel, _musicData + instrOffset); - _channelLastEvent[channel] = command + 0x90; - _channelFrequency[channel] = _musicData[_curOffset]; + setupChannel(_voiceChannels[channel].hardwareChannel, _musicData + instrOffset); + _voiceChannels[channel].lastEvent = command + 0x90; + _voiceChannels[channel].frequency = _musicData[_curOffset]; setupFrequency(channel, _musicData[_curOffset]); } } @@ -445,8 +463,8 @@ void Player_AD::updateMusic() { // 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) { + for (int i = 0; i < ARRAYSIZE(_voiceChannels); ++i) { + if (_voiceChannels[i].frequency == note && _voiceChannels[i].lastEvent == command) { channel = i; break; } @@ -495,18 +513,9 @@ void Player_AD::updateMusic() { } 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; + VoiceChannel &vChannel = _voiceChannels[channel]; + writeReg(0xB0 + vChannel.hardwareChannel, vChannel.b0Reg & 0xDF); + freeVoiceChannel(channel); } void Player_AD::setupFrequency(uint channel, int8 frequency) { @@ -521,13 +530,14 @@ void Player_AD::setupFrequency(uint channel, int8 frequency) { ++octave; } + VoiceChannel &vChannel = _voiceChannels[channel]; const uint noteFrequency = _noteFrequencies[frequency]; octave <<= 2; octave |= noteFrequency >> 8; octave |= 0x20; - writeReg(0xA0 + channel, noteFrequency & 0xFF); - _channelB0Reg[channel] = octave; - writeReg(0xB0 + channel, octave); + writeReg(0xA0 + vChannel.hardwareChannel, noteFrequency & 0xFF); + vChannel.b0Reg = octave; + writeReg(0xB0 + vChannel.hardwareChannel, octave); } void Player_AD::setupRhythm(uint rhythmInstr, uint instrOffset) { @@ -548,6 +558,34 @@ void Player_AD::setupRhythm(uint rhythmInstr, uint instrOffset) { } } +int Player_AD::allocateVoiceChannel() { + for (int i = 0; i < ARRAYSIZE(_voiceChannels); ++i) { + if (!_voiceChannels[i].lastEvent) { + // 256 makes sure it's a higher prority than any SFX + _voiceChannels[i].hardwareChannel = allocateHWChannel(256); + if (_voiceChannels[i].hardwareChannel != -1) { + return i; + } else { + // No free HW channels => cancel + return -1; + } + } + } + + return -1; +} + +void Player_AD::freeVoiceChannel(uint channel) { + VoiceChannel &vChannel = _voiceChannels[channel]; + assert(vChannel.hardwareChannel != -1); + + freeHWChannel(vChannel.hardwareChannel); + vChannel.hardwareChannel = -1; + vChannel.lastEvent = 0; + vChannel.b0Reg = 0; + vChannel.frequency = 0; +} + const uint Player_AD::_noteFrequencies[12] = { 0x200, 0x21E, 0x23F, 0x261, 0x285, 0x2AB, 0x2D4, 0x300, diff --git a/engines/scumm/players/player_ad.h b/engines/scumm/players/player_ad.h index 8994be7ec3..f8504c4473 100644 --- a/engines/scumm/players/player_ad.h +++ b/engines/scumm/players/player_ad.h @@ -87,9 +87,11 @@ private: int priority; SfxSlot *sfxOwner; } _hwChannels[9]; + int _numHWChannels; int allocateHWChannel(int priority, SfxSlot *owner = nullptr); void freeHWChannel(int channel); + void limitHWChannels(int newCount); // AdLib register utilities uint8 _registerBackUpTable[256]; @@ -105,7 +107,6 @@ private: void startMusic(); void updateMusic(); void noteOff(uint channel); - int findFreeChannel(); void setupFrequency(uint channel, int8 frequency); void setupRhythm(uint rhythmInstr, uint instrOffset); @@ -117,13 +118,19 @@ private: bool _loopFlag; uint _musicLoopStart; uint _instrumentOffset[16]; - uint _channelLastEvent[9]; - uint _channelFrequency[9]; - uint _channelB0Reg[9]; + + struct VoiceChannel { + uint lastEvent; + uint frequency; + uint b0Reg; + + int hardwareChannel; + } _voiceChannels[9]; + int allocateVoiceChannel(); + void freeVoiceChannel(uint channel); uint _mdvdrState; - uint _voiceChannels; - + uint _curOffset; uint _nextEventTimer; |