GB Audio: Minor channel 3 revamp

This commit is contained in:
Jeffrey Pfau 2016-02-13 19:37:34 -08:00
parent b92482520c
commit bbd0453c9c
6 changed files with 124 additions and 58 deletions

View File

@ -23,11 +23,11 @@ static void _updateEnvelope(struct GBAudioEnvelope* envelope);
static bool _updateSweep(struct GBAudioChannel1* ch, bool initial); static bool _updateSweep(struct GBAudioChannel1* ch, bool initial);
static int32_t _updateChannel1(struct GBAudioChannel1* ch); static int32_t _updateChannel1(struct GBAudioChannel1* ch);
static int32_t _updateChannel2(struct GBAudioChannel2* ch); static int32_t _updateChannel2(struct GBAudioChannel2* ch);
static int32_t _updateChannel3(struct GBAudioChannel3* ch); static int32_t _updateChannel3(struct GBAudioChannel3* ch, enum GBAudioStyle style);
static int32_t _updateChannel4(struct GBAudioChannel4* ch); static int32_t _updateChannel4(struct GBAudioChannel4* ch);
static void _sample(struct GBAudio* audio, int32_t cycles); static void _sample(struct GBAudio* audio, int32_t cycles);
void GBAudioInit(struct GBAudio* audio, size_t samples, uint8_t* nr52) { void GBAudioInit(struct GBAudio* audio, size_t samples, uint8_t* nr52, enum GBAudioStyle style) {
audio->samples = samples; audio->samples = samples;
audio->left = blip_new(BLIP_BUFFER_SIZE); audio->left = blip_new(BLIP_BUFFER_SIZE);
audio->right = blip_new(BLIP_BUFFER_SIZE); audio->right = blip_new(BLIP_BUFFER_SIZE);
@ -41,6 +41,7 @@ void GBAudioInit(struct GBAudio* audio, size_t samples, uint8_t* nr52) {
audio->forceDisableCh[3] = false; audio->forceDisableCh[3] = false;
audio->masterVolume = GB_AUDIO_VOLUME_MAX; audio->masterVolume = GB_AUDIO_VOLUME_MAX;
audio->nr52 = nr52; audio->nr52 = nr52;
audio->style = style;
} }
void GBAudioDeinit(struct GBAudio* audio) { void GBAudioDeinit(struct GBAudio* audio) {
@ -156,10 +157,10 @@ void GBAudioWriteNR14(struct GBAudio* audio, uint8_t value) {
--audio->ch1.control.length; --audio->ch1.control.length;
} }
} }
audio->nextEvent = audio->eventDiff; audio->nextEvent = audio->p->cpu->cycles;
if (audio->p) { if (audio->p) {
// TODO: Don't need p // TODO: Don't need p
audio->p->cpu->nextEvent = audio->eventDiff; audio->p->cpu->nextEvent = audio->nextEvent;
} }
} }
*audio->nr52 &= ~0x0001; *audio->nr52 &= ~0x0001;
@ -212,10 +213,10 @@ void GBAudioWriteNR24(struct GBAudio* audio, uint8_t value) {
--audio->ch2.control.length; --audio->ch2.control.length;
} }
} }
audio->nextEvent = audio->eventDiff; audio->nextEvent = audio->p->cpu->cycles;
if (audio->p) { if (audio->p) {
// TODO: Don't need p // TODO: Don't need p
audio->p->cpu->nextEvent = audio->eventDiff; audio->p->cpu->nextEvent = audio->nextEvent;
} }
} }
*audio->nr52 &= ~0x0002; *audio->nr52 &= ~0x0002;
@ -254,6 +255,7 @@ void GBAudioWriteNR34(struct GBAudio* audio, uint8_t value) {
audio->playingCh3 = false; audio->playingCh3 = false;
} }
} }
bool wasEnable = audio->playingCh3;
if (GBAudioRegisterControlIsRestart(value << 8)) { if (GBAudioRegisterControlIsRestart(value << 8)) {
audio->playingCh3 = audio->ch3.enable; audio->playingCh3 = audio->ch3.enable;
if (!audio->ch3.length) { if (!audio->ch3.length) {
@ -262,16 +264,29 @@ void GBAudioWriteNR34(struct GBAudio* audio, uint8_t value) {
--audio->ch3.length; --audio->ch3.length;
} }
} }
if (audio->style == GB_AUDIO_DMG && wasEnable && audio->playingCh3 && audio->ch3.readable) {
if (audio->ch3.window < 8) {
audio->ch3.wavedata8[0] = audio->ch3.wavedata8[audio->ch3.window >> 1];
} else {
audio->ch3.wavedata8[0] = audio->ch3.wavedata8[((audio->ch3.window >> 1) & ~3)];
audio->ch3.wavedata8[1] = audio->ch3.wavedata8[((audio->ch3.window >> 1) & ~3) + 1];
audio->ch3.wavedata8[2] = audio->ch3.wavedata8[((audio->ch3.window >> 1) & ~3) + 2];
audio->ch3.wavedata8[3] = audio->ch3.wavedata8[((audio->ch3.window >> 1) & ~3) + 3];
}
}
audio->ch3.window = 0;
} }
if (audio->playingCh3) { if (audio->playingCh3) {
if (audio->nextEvent == INT_MAX) { if (audio->nextEvent == INT_MAX) {
audio->eventDiff = 0; audio->eventDiff = 0;
} }
audio->nextCh3 = audio->eventDiff; audio->nextCh3 = audio->eventDiff + audio->p->cpu->cycles + 2 + 2 * (2048 - audio->ch3.rate);
audio->nextEvent = audio->eventDiff; audio->ch3.readable = false;
audio->nextEvent = audio->p->cpu->cycles;
if (audio->p) { if (audio->p) {
// TODO: Don't need p // TODO: Don't need p
audio->p->cpu->nextEvent = audio->eventDiff; audio->p->cpu->nextEvent = audio->nextEvent;
} }
} }
*audio->nr52 &= ~0x0004; *audio->nr52 &= ~0x0004;
@ -328,10 +343,10 @@ void GBAudioWriteNR44(struct GBAudio* audio, uint8_t value) {
--audio->ch4.length; --audio->ch4.length;
} }
} }
audio->nextEvent = audio->eventDiff; audio->nextEvent = audio->p->cpu->cycles;
if (audio->p) { if (audio->p) {
// TODO: Don't need p // TODO: Don't need p
audio->p->cpu->nextEvent = audio->eventDiff; audio->p->cpu->nextEvent = audio->nextEvent;
} }
} }
*audio->nr52 &= ~0x0008; *audio->nr52 &= ~0x0008;
@ -494,8 +509,18 @@ int32_t GBAudioProcessEvents(struct GBAudio* audio, int32_t cycles) {
if (audio->playingCh3) { if (audio->playingCh3) {
audio->nextCh3 -= audio->eventDiff; audio->nextCh3 -= audio->eventDiff;
audio->fadeCh3 -= audio->eventDiff;
if (audio->fadeCh3 <= 0) {
audio->ch3.readable = false;
audio->fadeCh3 = INT_MAX;
}
if (audio->nextCh3 <= 0) { if (audio->nextCh3 <= 0) {
audio->nextCh3 += _updateChannel3(&audio->ch3); audio->fadeCh3 = audio->nextCh3 + 2;
audio->nextCh3 += _updateChannel3(&audio->ch3, audio->style);
audio->ch3.readable = true;
}
if (audio->fadeCh3 < audio->nextEvent) {
audio->nextEvent = audio->fadeCh3;
} }
if (audio->nextCh3 < audio->nextEvent) { if (audio->nextCh3 < audio->nextEvent) {
audio->nextEvent = audio->nextCh3; audio->nextEvent = audio->nextCh3;
@ -741,10 +766,8 @@ static int32_t _updateChannel2(struct GBAudioChannel2* ch) {
return timing; return timing;
} }
static int32_t _updateChannel3(struct GBAudioChannel3* ch) { static int32_t _updateChannel3(struct GBAudioChannel3* ch, enum GBAudioStyle style) {
int i; int i;
int start;
int end;
int volume; int volume;
switch (ch->volume) { switch (ch->volume) {
case 0: case 0:
@ -763,6 +786,21 @@ static int32_t _updateChannel3(struct GBAudioChannel3* ch) {
volume = 3; volume = 3;
break; break;
} }
switch (style) {
int start;
int end;
case GB_AUDIO_DMG:
default:
++ch->window;
ch->window &= 0x1F;
ch->sample = ch->wavedata8[ch->window >> 1];
if (ch->window & 1) {
ch->sample &= 0xF;
} else {
ch->sample >>= 4;
}
break;
case GB_AUDIO_GBA:
if (ch->size) { if (ch->size) {
start = 7; start = 7;
end = 0; end = 0;
@ -773,15 +811,17 @@ static int32_t _updateChannel3(struct GBAudioChannel3* ch) {
start = 3; start = 3;
end = 0; end = 0;
} }
uint32_t bitsCarry = ch->wavedata[end] & 0x000000F0; uint32_t bitsCarry = ch->wavedata32[end] & 0x000000F0;
uint32_t bits; uint32_t bits;
for (i = start; i >= end; --i) { for (i = start; i >= end; --i) {
bits = ch->wavedata[i] & 0x000000F0; bits = ch->wavedata32[i] & 0x000000F0;
ch->wavedata[i] = ((ch->wavedata[i] & 0x0F0F0F0F) << 4) | ((ch->wavedata[i] & 0xF0F0F000) >> 12); ch->wavedata32[i] = ((ch->wavedata32[i] & 0x0F0F0F0F) << 4) | ((ch->wavedata32[i] & 0xF0F0F000) >> 12);
ch->wavedata[i] |= bitsCarry << 20; ch->wavedata32[i] |= bitsCarry << 20;
bitsCarry = bits; bitsCarry = bits;
} }
ch->sample = bitsCarry >> 4; ch->sample = bitsCarry >> 4;
break;
}
ch->sample -= 8; ch->sample -= 8;
ch->sample *= volume * 4; ch->sample *= volume * 4;
return 2 * (2048 - ch->rate); return 2 * (2048 - ch->rate);

View File

@ -119,7 +119,12 @@ struct GBAudioChannel3 {
int rate; int rate;
bool stop; bool stop;
uint32_t wavedata[8]; int window;
bool readable;
union {
uint32_t wavedata32[8];
uint8_t wavedata8[16];
};
int8_t sample; int8_t sample;
}; };
@ -136,6 +141,13 @@ struct GBAudioChannel4 {
int8_t sample; int8_t sample;
}; };
enum GBAudioStyle {
GB_AUDIO_DMG,
GB_AUDIO_CGB,
GB_AUDIO_AGB, // GB in GBA
GB_AUDIO_GBA, // GBA PSG
};
struct GBAudio { struct GBAudio {
struct GB* p; struct GB* p;
struct GBAudioChannel1 ch1; struct GBAudioChannel1 ch1;
@ -174,10 +186,12 @@ struct GBAudio {
int32_t nextSample; int32_t nextSample;
int32_t sampleInterval; int32_t sampleInterval;
enum GBAudioStyle style;
int32_t nextCh1; int32_t nextCh1;
int32_t nextCh2; int32_t nextCh2;
int32_t nextCh3; int32_t nextCh3;
int32_t fadeCh3;
int32_t nextCh4; int32_t nextCh4;
bool enable; bool enable;
@ -186,7 +200,7 @@ struct GBAudio {
int masterVolume; int masterVolume;
}; };
void GBAudioInit(struct GBAudio* audio, size_t samples, uint8_t* nr52); void GBAudioInit(struct GBAudio* audio, size_t samples, uint8_t* nr52, enum GBAudioStyle style);
void GBAudioDeinit(struct GBAudio* audio); void GBAudioDeinit(struct GBAudio* audio);
void GBAudioReset(struct GBAudio* audio); void GBAudioReset(struct GBAudio* audio);

View File

@ -45,7 +45,7 @@ static void GBInit(void* cpu, struct mCPUComponent* component) {
GBVideoInit(&gb->video); GBVideoInit(&gb->video);
gb->audio.p = gb; gb->audio.p = gb;
GBAudioInit(&gb->audio, 2048, &gb->memory.io[REG_NR52]); // TODO: Remove magic constant GBAudioInit(&gb->audio, 2048, &gb->memory.io[REG_NR52], GB_AUDIO_DMG); // TODO: Remove magic constant
gb->timer.p = gb; gb->timer.p = gb;

View File

@ -243,7 +243,9 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
case REG_WAVE_D: case REG_WAVE_D:
case REG_WAVE_E: case REG_WAVE_E:
case REG_WAVE_F: case REG_WAVE_F:
((uint8_t*) gb->audio.ch3.wavedata)[address - REG_WAVE_0] = value; // TODO: Big endian if (!gb->audio.playingCh3 || gb->audio.ch3.readable) {
gb->audio.ch3.wavedata8[address - REG_WAVE_0] = value;
}
break; break;
case REG_JOYP: case REG_JOYP:
case REG_TIMA: case REG_TIMA:
@ -318,6 +320,32 @@ uint8_t GBIORead(struct GB* gb, unsigned address) {
break; break;
case REG_IE: case REG_IE:
return gb->memory.ie; return gb->memory.ie;
case REG_WAVE_0:
case REG_WAVE_1:
case REG_WAVE_2:
case REG_WAVE_3:
case REG_WAVE_4:
case REG_WAVE_5:
case REG_WAVE_6:
case REG_WAVE_7:
case REG_WAVE_8:
case REG_WAVE_9:
case REG_WAVE_A:
case REG_WAVE_B:
case REG_WAVE_C:
case REG_WAVE_D:
case REG_WAVE_E:
case REG_WAVE_F:
if (gb->audio.playingCh3) {
if (gb->audio.ch3.readable) {
return gb->audio.ch3.wavedata8[gb->audio.ch3.window >> 1];
} else {
return 0xFF;
}
} else {
return gb->audio.ch3.wavedata8[address - REG_WAVE_0];
}
break;
case REG_IF: case REG_IF:
case REG_NR10: case REG_NR10:
case REG_NR11: case REG_NR11:
@ -336,22 +364,6 @@ uint8_t GBIORead(struct GB* gb, unsigned address) {
case REG_NR50: case REG_NR50:
case REG_NR51: case REG_NR51:
case REG_NR52: case REG_NR52:
case REG_WAVE_0:
case REG_WAVE_1:
case REG_WAVE_2:
case REG_WAVE_3:
case REG_WAVE_4:
case REG_WAVE_5:
case REG_WAVE_6:
case REG_WAVE_7:
case REG_WAVE_8:
case REG_WAVE_9:
case REG_WAVE_A:
case REG_WAVE_B:
case REG_WAVE_C:
case REG_WAVE_D:
case REG_WAVE_E:
case REG_WAVE_F:
case REG_DIV: case REG_DIV:
case REG_TIMA: case REG_TIMA:
case REG_TMA: case REG_TMA:

View File

@ -28,7 +28,7 @@ void GBAAudioInit(struct GBAAudio* audio, size_t samples) {
#ifdef __BIG_ENDIAN__ #ifdef __BIG_ENDIAN__
++n52; ++n52;
#endif #endif
GBAudioInit(&audio->psg, 0, nr52); GBAudioInit(&audio->psg, 0, nr52, GB_AUDIO_GBA);
audio->samples = samples; audio->samples = samples;
audio->psg.clockRate = GBA_ARM7TDMI_FREQUENCY; audio->psg.clockRate = GBA_ARM7TDMI_FREQUENCY;
// Guess too large; we hang producing extra samples if we guess too low // Guess too large; we hang producing extra samples if we guess too low
@ -209,7 +209,7 @@ void GBAAudioWriteSOUNDBIAS(struct GBAAudio* audio, uint16_t value) {
} }
void GBAAudioWriteWaveRAM(struct GBAAudio* audio, int address, uint32_t value) { void GBAAudioWriteWaveRAM(struct GBAAudio* audio, int address, uint32_t value) {
audio->psg.ch3.wavedata[address | (!audio->psg.ch3.bank * 4)] = value; audio->psg.ch3.wavedata32[address | (!audio->psg.ch3.bank * 4)] = value;
} }
void GBAAudioWriteFIFO(struct GBAAudio* audio, int address, uint32_t value) { void GBAAudioWriteFIFO(struct GBAAudio* audio, int address, uint32_t value) {
@ -353,7 +353,7 @@ void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState*
STORE_32(ch2Flags, 0, &state->audio.ch2.envelope); STORE_32(ch2Flags, 0, &state->audio.ch2.envelope);
STORE_32(audio->psg.nextCh2, 0, &state->audio.ch2.nextEvent); STORE_32(audio->psg.nextCh2, 0, &state->audio.ch2.nextEvent);
memcpy(state->audio.ch3.wavebanks, audio->psg.ch3.wavedata, sizeof(state->audio.ch3.wavebanks)); memcpy(state->audio.ch3.wavebanks, audio->psg.ch3.wavedata32, sizeof(state->audio.ch3.wavebanks));
STORE_16(audio->psg.ch3.length, 0, &state->audio.ch3.length); STORE_16(audio->psg.ch3.length, 0, &state->audio.ch3.length);
STORE_32(audio->psg.nextCh3, 0, &state->audio.ch3.nextEvent); STORE_32(audio->psg.nextCh3, 0, &state->audio.ch3.nextEvent);
@ -407,7 +407,7 @@ void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState
LOAD_32(audio->psg.nextCh2, 0, &state->audio.ch2.nextEvent); LOAD_32(audio->psg.nextCh2, 0, &state->audio.ch2.nextEvent);
// TODO: Big endian? // TODO: Big endian?
memcpy(audio->psg.ch3.wavedata, state->audio.ch3.wavebanks, sizeof(audio->psg.ch3.wavedata)); memcpy(audio->psg.ch3.wavedata32, state->audio.ch3.wavebanks, sizeof(audio->psg.ch3.wavedata32));
LOAD_16(audio->psg.ch3.length, 0, &state->audio.ch3.length); LOAD_16(audio->psg.ch3.length, 0, &state->audio.ch3.length);
LOAD_32(audio->psg.nextCh3, 0, &state->audio.ch3.nextEvent); LOAD_32(audio->psg.nextCh3, 0, &state->audio.ch3.nextEvent);

View File

@ -87,7 +87,7 @@ static void _RegisterRamReset(struct GBA* gba) {
cpu->memory.store16(cpu, BASE_IO | REG_SOUNDCNT_HI, 0, 0); cpu->memory.store16(cpu, BASE_IO | REG_SOUNDCNT_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_SOUNDCNT_X, 0, 0); cpu->memory.store16(cpu, BASE_IO | REG_SOUNDCNT_X, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_SOUNDBIAS, 0x200, 0); cpu->memory.store16(cpu, BASE_IO | REG_SOUNDBIAS, 0x200, 0);
memset(gba->audio.psg.ch3.wavedata, 0, sizeof(gba->audio.psg.ch3.wavedata)); memset(gba->audio.psg.ch3.wavedata32, 0, sizeof(gba->audio.psg.ch3.wavedata32));
} }
if (registers & 0x80) { if (registers & 0x80) {
cpu->memory.store16(cpu, BASE_IO | 0x00, 0, 0); cpu->memory.store16(cpu, BASE_IO | 0x00, 0, 0);