aboutsummaryrefslogtreecommitdiff
path: root/engines/agi/sound_pcjr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/agi/sound_pcjr.cpp')
-rw-r--r--engines/agi/sound_pcjr.cpp166
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