AGI: Add a layer of abstraction between the sound chip and the two players

This commit is contained in:
Jussi Pitkanen
2011-08-13 23:26:36 +01:00
committed by Eugene Sandulenko
parent 8183103777
commit 24bb5da228
2 changed files with 74 additions and 122 deletions
+69 -113
View File
@@ -220,12 +220,12 @@ int SoundGenPCJr::volumeCalc(SndGenChan *chan) {
return attenuation;
}
int SoundGenPCJr::getNextNote(int ch, Tone *tone)
int SoundGenPCJr::getNextNote(int ch)
{
if (_vm->getVersion() > 0x2001)
return getNextNote_v2(ch, tone);
return getNextNote_v2(ch);
else
return getNextNote_v1(ch, tone);
return getNextNote_v1(ch);
return -1;
}
@@ -234,13 +234,11 @@ int SoundGenPCJr::getNextNote(int ch, Tone *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_v2(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))
@@ -251,7 +249,7 @@ int SoundGenPCJr::getNextNote_v2(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
@@ -259,58 +257,32 @@ int SoundGenPCJr::getNextNote_v2(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;
// attenuation (volume)
chan->attenuation = data[4] & 0xF;
// frequency
if (ch < (CHAN_MAX - 1)) {
chan->freqCount = (uint16)data[2] & 0x3F;
chan->freqCount <<= 4;
chan->freqCount |= data[3] & 0x0F;
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;
}
}
break;
}
_tchannel[ch].genTypePrev = -1;
_tchannel[ch].freqCountPrev = -1;
// 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]);
// 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
@@ -319,17 +291,17 @@ int SoundGenPCJr::getNextNote_v2(int ch, Tone *tone) {
return -1;
}
chan->duration--;
return 0;
}
int SoundGenPCJr::getNextNote_v1(int ch, Tone *tone)
{
static bool fetched[4] = { false, false, false, false };
int SoundGenPCJr::getNextNote_v1(int ch) {
static int channels = 4;
static int duration = 0;
byte *data = _v1data;
uint32 len = _v1size;
int reg = 0;
if (len <= 0 || data == NULL) {
_channel[ch].avail = 0;
@@ -339,60 +311,22 @@ int SoundGenPCJr::getNextNote_v1(int ch, Tone *tone)
}
// Get previously fetched data if possible
if (fetched[ch]) {
fetched[ch] = false;
tone->freqCount = _channel[ch].freqCount;
tone->atten = _channel[ch].attenuation;
tone->type = _channel[ch].genType;
if (channels > 0) {
channels--;
return 0;
}
channels = 4;
// In the V1 player the default duration for a row is 2 ticks
if (duration > 0) {
duration--;
tone->freqCount = _channel[ch].freqCount;
tone->atten = _channel[ch].attenuation;
tone->type = _channel[ch].genType;
return 0;
}
duration = 2 * CHAN_MAX;
// Otherwise fetch a row of data for all channels
fetched[0] = fetched[1] = fetched[2] = fetched[3] = true;
while (*data) {
if ((*data & 0x90) == 0x90) {
reg = (*data >> 5) & 0x3;
_channel[reg].attenuation = *data & 0xF;
} else if ((*data & 0xF0) == 0xE0) {
_channel[3].genType = (data[3] & 0x4) ? kGenWhite : kGenPeriod;
int noiseFreq = data[3] & 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 (*data & 0x80) {
reg = (*data >> 5) & 0x3;
_channel[reg].freqCount = *data & 0xF;
_channel[reg].genType = kGenTone;
} else {
_channel[reg].freqCount |= (*data & 0x3F) << 4;
}
writeData(*data);
data++;
len--;
}
@@ -402,13 +336,43 @@ int SoundGenPCJr::getNextNote_v1(int ch, Tone *tone)
_v1data = data;
_v1size = len;
tone->freqCount = _channel[ch].freqCount;
tone->atten = _channel[ch].attenuation;
tone->type = _channel[ch].genType;
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
@@ -444,7 +408,6 @@ const int16 volTable[16] = {
// fill buff
int SoundGenPCJr::chanGen(int chan, int16 *stream, int len) {
ToneChan *tpcm;
Tone toneNew;
int fillSize;
int retVal;
@@ -452,20 +415,13 @@ int SoundGenPCJr::chanGen(int chan, int16 *stream, int len) {
retVal = -1;
debugC(5, kDebugLevelSound, "chanGen()");
while (len > 0) {
if (tpcm->noteCount <= 0) {
// get new tone data
tpcm->avail=1;
debugC(5, kDebugLevelSound, "new note data (avail=%d)", tpcm->avail);
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
+5 -9
View File
@@ -71,12 +71,6 @@ struct ToneChan {
int feedback; /* noise feedback mask */
};
struct Tone {
int freqCount;
int atten;
GenType type;
};
class SoundGenPCJr : public SoundGen, public Audio::AudioStream {
public:
SoundGenPCJr(AgiEngine *vm, Audio::Mixer *pMixer);
@@ -102,11 +96,13 @@ public:
}
private:
int getNextNote(int ch, Tone *tone);
int getNextNote_v2(int ch, Tone *tone);
int getNextNote_v1(int ch, Tone *tone);
int getNextNote(int ch);
int getNextNote_v2(int ch);
int getNextNote_v1(int ch);
int volumeCalc(SndGenChan *chan);
void writeData(uint8 val);
int chanGen(int chan, int16 *stream, int len);
int fillNoise(ToneChan *t, int16 *buf, int len);