diff options
Diffstat (limited to 'engines/agi/sound_pcjr.cpp')
-rw-r--r-- | engines/agi/sound_pcjr.cpp | 166 |
1 files changed, 111 insertions, 55 deletions
diff --git a/engines/agi/sound_pcjr.cpp b/engines/agi/sound_pcjr.cpp index fdebf16b1a..d21baa450f 100644 --- a/engines/agi/sound_pcjr.cpp +++ b/engines/agi/sound_pcjr.cpp @@ -102,7 +102,7 @@ const int8 dissolveDataV3[] = { }; -SoundGenPCJr::SoundGenPCJr(AgiEngine *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMixer) { +SoundGenPCJr::SoundGenPCJr(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMixer) { _chanAllocated = 10240; // preallocate something which will most likely fit _chanData = (int16 *)malloc(_chanAllocated << 1); @@ -126,6 +126,9 @@ SoundGenPCJr::SoundGenPCJr(AgiEngine *vm, Audio::Mixer *pMixer) : SoundGen(vm, p memset(_tchannel, 0, sizeof(_tchannel)); _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); + + _v1data = NULL; + _v1size = 0; } SoundGenPCJr::~SoundGenPCJr() { @@ -153,6 +156,9 @@ void SoundGenPCJr::play(int resnum) { _tchannel[i].genType = kGenTone; _tchannel[i].genTypePrev = -1; } + + _v1data = pcjrSound->getData() + 1; + _v1size = pcjrSound->getLength() - 1; } void SoundGenPCJr::stop(void) { @@ -201,7 +207,7 @@ int SoundGenPCJr::volumeCalc(SndGenChan *chan) { chan->attenuationCopy = attenuation; attenuation &= 0x0F; - attenuation += _vm->getvar(vVolume); + attenuation += _mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType) / 17; if (attenuation > 0x0F) attenuation = 0x0F; } @@ -214,16 +220,25 @@ int SoundGenPCJr::volumeCalc(SndGenChan *chan) { return attenuation; } +int SoundGenPCJr::getNextNote(int ch) +{ + if (_vm->getVersion() > 0x2001) + return getNextNote_v2(ch); + else + return getNextNote_v1(ch); + + return -1; +} + // read the next channel data.. fill it in *tone // if tone isn't touched.. it should be inited so it just plays silence // return 0 if it's passing more data // return -1 if it's passing nothing (end of data) -int SoundGenPCJr::getNextNote(int ch, Tone *tone) { +int SoundGenPCJr::getNextNote_v2(int ch) { ToneChan *tpcm; SndGenChan *chan; const byte *data; - assert(tone); assert(ch < CHAN_MAX); if (!_vm->getflag(fSoundOn)) @@ -234,7 +249,7 @@ int SoundGenPCJr::getNextNote(int ch, Tone *tone) { if (!chan->avail) return -1; - while ((chan->duration == 0) && (chan->duration != 0xFFFF)) { + while (chan->duration <= 0) { data = chan->data; // read the duration of the note @@ -242,58 +257,32 @@ int SoundGenPCJr::getNextNote(int ch, Tone *tone) { // if it's 0 then it's not going to be played // if it's 0xFFFF then the channel data has finished. - if ((chan->duration != 0) && (chan->duration != 0xFFFF)) { + if ((chan->duration == 0) || (chan->duration == 0xFFFF)) { tpcm->genTypePrev = -1; tpcm->freqCountPrev = -1; - // only tone channels dissolve - if ((ch != 3) && (_dissolveMethod != 0)) // != noise?? - chan->dissolveCount = 0; + break; + } - // attenuation (volume) - chan->attenuation = data[4] & 0xF; + _tchannel[ch].genTypePrev = -1; + _tchannel[ch].freqCountPrev = -1; - // frequency - if (ch < (CHAN_MAX - 1)) { - chan->freqCount = (uint16)data[2] & 0x3F; - chan->freqCount <<= 4; - chan->freqCount |= data[3] & 0x0F; + // only tone channels dissolve + if ((ch != 3) && (_dissolveMethod != 0)) // != noise?? + chan->dissolveCount = 0; + + // attenuation (volume) + writeData(data[4]); + + // frequency + writeData(data[3]); + writeData(data[2]); - chan->genType = kGenTone; - } else { - int noiseFreq; - - // check for white noise (1) or periodic (0) - chan->genType = (data[3] & 0x04) ? kGenWhite : kGenPeriod; - - noiseFreq = data[3] & 0x03; - - switch (noiseFreq) { - case 0: - chan->freqCount = 32; - break; - case 1: - chan->freqCount = 64; - break; - case 2: - chan->freqCount = 128; - break; - case 3: - chan->freqCount = _channel[2].freqCount * 2; - break; - } - } - } // data now points to the next data seg-a-ment chan->data += 5; } - if (chan->duration != 0xFFFF) { - tone->freqCount = chan->freqCount; - tone->atten = volumeCalc(chan); // calc volume, sent vol is different from saved vol - tone->type = chan->genType; - chan->duration--; - } else { + if (chan->duration == 0xFFFF) { // kill channel chan->avail = 0; chan->attenuation = 0x0F; // silent @@ -302,9 +291,80 @@ int SoundGenPCJr::getNextNote(int ch, Tone *tone) { return -1; } + chan->duration--; + return 0; } +int SoundGenPCJr::getNextNote_v1(int ch) { + static int duration = 0; + + byte *data = _v1data; + uint32 len = _v1size; + + if (len <= 0 || data == NULL) { + _channel[ch].avail = 0; + _channel[ch].attenuation = 0x0F; + _channel[ch].attenuationCopy = 0x0F; + return -1; + } + + // In the V1 player the default duration for a row is 3 ticks + if (duration > 0) { + duration--; + return 0; + } + duration = 3 * CHAN_MAX; + + // Otherwise fetch a row of data for all channels + while (*data) { + writeData(*data); + data++; + len--; + } + data++; + len--; + + _v1data = data; + _v1size = len; + + return 0; +} + +void SoundGenPCJr::writeData(uint8 val) { + static int reg = 0; + + debugC(5, kDebugLevelSound, "writeData(%.2X)", val); + + if ((val & 0x90) == 0x90) { + reg = (val >> 5) & 0x3; + _channel[reg].attenuation = val & 0xF; + } else if ((val & 0xF0) == 0xE0) { + _channel[3].genType = (val & 0x4) ? kGenWhite : kGenPeriod; + int noiseFreq = val & 0x03; + switch (noiseFreq) { + case 0: + _channel[3].freqCount = 32; + break; + case 1: + _channel[3].freqCount = 64; + break; + case 2: + _channel[3].freqCount = 128; + break; + case 3: + _channel[3].freqCount = _channel[2].freqCount * 2; + break; + } + } else if (val & 0x80) { + reg = (val >> 5) & 0x3; + _channel[reg].freqCount = val & 0xF; + _channel[reg].genType = kGenTone; + } else { + _channel[reg].freqCount |= (val & 0x3F) << 4; + } +} + // Formulas for noise generator // bit0 = output @@ -340,7 +400,6 @@ const int16 volTable[16] = { // fill buff int SoundGenPCJr::chanGen(int chan, int16 *stream, int len) { ToneChan *tpcm; - Tone toneNew; int fillSize; int retVal; @@ -351,13 +410,10 @@ int SoundGenPCJr::chanGen(int chan, int16 *stream, int len) { while (len > 0) { if (tpcm->noteCount <= 0) { // get new tone data - toneNew.freqCount = 0; - toneNew.atten = 0xF; - toneNew.type = kGenTone; - if ((tpcm->avail) && (getNextNote(chan, &toneNew) == 0)) { - tpcm->atten = toneNew.atten; - tpcm->freqCount = toneNew.freqCount; - tpcm->genType = toneNew.type; + if ((tpcm->avail) && (getNextNote(chan) == 0)) { + tpcm->atten = _channel[chan].attenuation; + tpcm->freqCount = _channel[chan].freqCount; + tpcm->genType = _channel[chan].genType; // setup counters 'n stuff // SAMPLE_RATE samples per sec.. tone changes 60 times per sec |