mirror of https://github.com/mgba-emu/mgba.git
DS Audio: First pass at ADPCM
This commit is contained in:
parent
414152d148
commit
fd2869603a
|
@ -49,10 +49,10 @@ struct DSAudioChannel {
|
|||
int adpcmOffset;
|
||||
|
||||
int16_t adpcmStartSample;
|
||||
unsigned adpcmStartIndex;
|
||||
int adpcmStartIndex;
|
||||
|
||||
int16_t adpcmSample;
|
||||
unsigned adpcmIndex;
|
||||
int adpcmIndex;
|
||||
|
||||
bool enable;
|
||||
};
|
||||
|
|
|
@ -19,6 +19,21 @@ static void _updateChannel(struct mTiming* timing, void* user, uint32_t cyclesLa
|
|||
static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate);
|
||||
static void _updateMixer(struct DSAudio*);
|
||||
|
||||
static const int _adpcmIndexTable[8] = {
|
||||
-1, -1, -1, -1, 2, 4, 6, 8
|
||||
};
|
||||
|
||||
static const uint16_t _adpcmTable[89] = {
|
||||
0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x0010, 0x0011, 0x0013, 0x0015,
|
||||
0x0017, 0x0019, 0x001C, 0x001F, 0x0022, 0x0025, 0x0029, 0x002D, 0x0032, 0x0037, 0x003C, 0x0042,
|
||||
0x0049, 0x0050, 0x0058, 0x0061, 0x006B, 0x0076, 0x0082, 0x008F, 0x009D, 0x00AD, 0x00BE, 0x00D1,
|
||||
0x00E6, 0x00FD, 0x0117, 0x0133, 0x0151, 0x0173, 0x0198, 0x01C1, 0x01EE, 0x0220, 0x0256, 0x0292,
|
||||
0x02D4, 0x031C, 0x036C, 0x03C3, 0x0424, 0x048E, 0x0502, 0x0583, 0x0610, 0x06AB, 0x0756, 0x0812,
|
||||
0x08E0, 0x09C3, 0x0ABD, 0x0BD0, 0x0CFF, 0x0E4C, 0x0FBA, 0x114C, 0x1307, 0x14EE, 0x1706, 0x1954,
|
||||
0x1BDC, 0x1EA5, 0x21B6, 0x2515, 0x28CA, 0x2CDF, 0x315B, 0x364B, 0x3BB9, 0x41B2, 0x4844, 0x4F7E,
|
||||
0x5771, 0x602F, 0x69CE, 0x7462, 0x7FFF
|
||||
};
|
||||
|
||||
void DSAudioInit(struct DSAudio* audio, size_t samples) {
|
||||
audio->samples = samples;
|
||||
audio->left = blip_new(BLIP_BUFFER_SIZE);
|
||||
|
@ -79,6 +94,11 @@ void DSAudioReset(struct DSAudio* audio) {
|
|||
audio->ch[ch].length = 0;
|
||||
audio->ch[ch].offset = 0;
|
||||
audio->ch[ch].sample = 0;
|
||||
audio->ch[ch].adpcmOffset = 0;
|
||||
audio->ch[ch].adpcmStartSample = 0;
|
||||
audio->ch[ch].adpcmStartIndex = 0;
|
||||
audio->ch[ch].adpcmSample = 0;
|
||||
audio->ch[ch].adpcmIndex = 0;
|
||||
}
|
||||
|
||||
blip_clear(audio->left);
|
||||
|
@ -113,7 +133,7 @@ void DSAudioWriteSOUNDCNT_HI(struct DSAudio* audio, int chan, uint16_t value) {
|
|||
ch->repeat = DSRegisterSOUNDxCNTGetRepeat(reg);
|
||||
ch->format = DSRegisterSOUNDxCNTGetFormat(reg);
|
||||
|
||||
if (ch->format >= 2) {
|
||||
if (ch->format > 2) {
|
||||
mLOG(DS_AUDIO, STUB, "Unimplemented audio format %i", ch->format);
|
||||
}
|
||||
|
||||
|
@ -123,6 +143,12 @@ void DSAudioWriteSOUNDCNT_HI(struct DSAudio* audio, int chan, uint16_t value) {
|
|||
ch->offset = 0;
|
||||
mTimingDeschedule(&audio->p->ds7.timing, &ch->updateEvent);
|
||||
mTimingSchedule(&audio->p->ds7.timing, &ch->updateEvent, 0);
|
||||
if (ch->format == 2) {
|
||||
uint32_t header = audio->p->ds7.cpu->memory.load32(audio->p->ds7.cpu, ch->source, NULL);
|
||||
ch->offset += 4;
|
||||
ch->adpcmStartSample = header &= 0xFFFF;
|
||||
ch->adpcmStartIndex = header >> 16;
|
||||
}
|
||||
}
|
||||
ch->enable = DSRegisterSOUNDxCNTIsBusy(reg);
|
||||
}
|
||||
|
@ -165,6 +191,41 @@ static void _updateMixer(struct DSAudio* audio) {
|
|||
audio->sampleRight = sampleRight >> 6;
|
||||
}
|
||||
|
||||
static void _updateAdpcm(struct DSAudioChannel* ch, int sample) {
|
||||
if (ch->adpcmIndex < 0) {
|
||||
ch->adpcmIndex = 0;
|
||||
} else if (ch->adpcmIndex > 88) {
|
||||
ch->adpcmIndex = 88;
|
||||
}
|
||||
int16_t diff = _adpcmTable[ch->adpcmIndex] >> 3;
|
||||
if (sample & 1) {
|
||||
diff += _adpcmTable[ch->adpcmIndex] >> 2;
|
||||
}
|
||||
if (sample & 2) {
|
||||
diff += _adpcmTable[ch->adpcmIndex] >> 1;
|
||||
}
|
||||
if (sample & 4) {
|
||||
diff += _adpcmTable[ch->adpcmIndex];
|
||||
}
|
||||
if (sample & 8) {
|
||||
int32_t newSample = ch->adpcmSample - diff;
|
||||
if (newSample < -0x7FFF) {
|
||||
ch->adpcmSample = -0x7FFF;
|
||||
} else {
|
||||
ch->adpcmSample = newSample;
|
||||
}
|
||||
} else {
|
||||
int32_t newSample = ch->adpcmSample + diff;
|
||||
if (newSample > 0x7FFF) {
|
||||
ch->adpcmSample = 0x7FFF;
|
||||
} else {
|
||||
ch->adpcmSample = newSample;
|
||||
}
|
||||
}
|
||||
ch->sample = ch->adpcmSample;
|
||||
ch->adpcmIndex += _adpcmIndexTable[sample & 0x7];
|
||||
}
|
||||
|
||||
static void _updateChannel(struct mTiming* timing, void* user, uint32_t cyclesLate) {
|
||||
struct DSAudioChannel* ch = user;
|
||||
struct ARMCore* cpu = ch->p->p->ds7.cpu;
|
||||
|
@ -178,8 +239,13 @@ static void _updateChannel(struct mTiming* timing, void* user, uint32_t cyclesLa
|
|||
ch->offset += 2;
|
||||
break;
|
||||
case 2:
|
||||
// TODO
|
||||
ch->enable = false;
|
||||
_updateAdpcm(ch, (cpu->memory.load8(cpu, ch->offset + ch->source, NULL) >> ch->adpcmOffset) & 0xF);
|
||||
ch->offset += ch->adpcmOffset >> 2;
|
||||
ch->adpcmOffset ^= 4;
|
||||
if (ch->offset == ch->loopPoint) {
|
||||
ch->adpcmStartSample = ch->adpcmSample;
|
||||
ch->adpcmStartIndex = ch->adpcmIndex;
|
||||
}
|
||||
break;
|
||||
}
|
||||
_updateMixer(ch->p);
|
||||
|
@ -193,6 +259,10 @@ static void _updateChannel(struct mTiming* timing, void* user, uint32_t cyclesLa
|
|||
if (ch->offset >= ch->length) {
|
||||
ch->enable = false;
|
||||
ch->p->p->memory.io7[(DS7_REG_SOUND0CNT_HI + (ch->index << 4)) >> 1] &= 0x7FFF;
|
||||
if (ch->format == 2) {
|
||||
ch->adpcmSample = ch->adpcmStartSample;
|
||||
ch->adpcmIndex = ch->adpcmStartIndex;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue