mirror of https://github.com/mgba-emu/mgba.git
GB Audio: Minor channel 3 revamp
This commit is contained in:
parent
b92482520c
commit
bbd0453c9c
106
src/gb/audio.c
106
src/gb/audio.c
|
@ -23,11 +23,11 @@ static void _updateEnvelope(struct GBAudioEnvelope* envelope);
|
|||
static bool _updateSweep(struct GBAudioChannel1* ch, bool initial);
|
||||
static int32_t _updateChannel1(struct GBAudioChannel1* 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 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->left = 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->masterVolume = GB_AUDIO_VOLUME_MAX;
|
||||
audio->nr52 = nr52;
|
||||
audio->style = style;
|
||||
}
|
||||
|
||||
void GBAudioDeinit(struct GBAudio* audio) {
|
||||
|
@ -156,10 +157,10 @@ void GBAudioWriteNR14(struct GBAudio* audio, uint8_t value) {
|
|||
--audio->ch1.control.length;
|
||||
}
|
||||
}
|
||||
audio->nextEvent = audio->eventDiff;
|
||||
audio->nextEvent = audio->p->cpu->cycles;
|
||||
if (audio->p) {
|
||||
// TODO: Don't need p
|
||||
audio->p->cpu->nextEvent = audio->eventDiff;
|
||||
audio->p->cpu->nextEvent = audio->nextEvent;
|
||||
}
|
||||
}
|
||||
*audio->nr52 &= ~0x0001;
|
||||
|
@ -212,10 +213,10 @@ void GBAudioWriteNR24(struct GBAudio* audio, uint8_t value) {
|
|||
--audio->ch2.control.length;
|
||||
}
|
||||
}
|
||||
audio->nextEvent = audio->eventDiff;
|
||||
audio->nextEvent = audio->p->cpu->cycles;
|
||||
if (audio->p) {
|
||||
// TODO: Don't need p
|
||||
audio->p->cpu->nextEvent = audio->eventDiff;
|
||||
audio->p->cpu->nextEvent = audio->nextEvent;
|
||||
}
|
||||
}
|
||||
*audio->nr52 &= ~0x0002;
|
||||
|
@ -254,6 +255,7 @@ void GBAudioWriteNR34(struct GBAudio* audio, uint8_t value) {
|
|||
audio->playingCh3 = false;
|
||||
}
|
||||
}
|
||||
bool wasEnable = audio->playingCh3;
|
||||
if (GBAudioRegisterControlIsRestart(value << 8)) {
|
||||
audio->playingCh3 = audio->ch3.enable;
|
||||
if (!audio->ch3.length) {
|
||||
|
@ -262,16 +264,29 @@ void GBAudioWriteNR34(struct GBAudio* audio, uint8_t value) {
|
|||
--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->nextEvent == INT_MAX) {
|
||||
audio->eventDiff = 0;
|
||||
}
|
||||
audio->nextCh3 = audio->eventDiff;
|
||||
audio->nextEvent = audio->eventDiff;
|
||||
audio->nextCh3 = audio->eventDiff + audio->p->cpu->cycles + 2 + 2 * (2048 - audio->ch3.rate);
|
||||
audio->ch3.readable = false;
|
||||
audio->nextEvent = audio->p->cpu->cycles;
|
||||
if (audio->p) {
|
||||
// TODO: Don't need p
|
||||
audio->p->cpu->nextEvent = audio->eventDiff;
|
||||
audio->p->cpu->nextEvent = audio->nextEvent;
|
||||
}
|
||||
}
|
||||
*audio->nr52 &= ~0x0004;
|
||||
|
@ -328,10 +343,10 @@ void GBAudioWriteNR44(struct GBAudio* audio, uint8_t value) {
|
|||
--audio->ch4.length;
|
||||
}
|
||||
}
|
||||
audio->nextEvent = audio->eventDiff;
|
||||
audio->nextEvent = audio->p->cpu->cycles;
|
||||
if (audio->p) {
|
||||
// TODO: Don't need p
|
||||
audio->p->cpu->nextEvent = audio->eventDiff;
|
||||
audio->p->cpu->nextEvent = audio->nextEvent;
|
||||
}
|
||||
}
|
||||
*audio->nr52 &= ~0x0008;
|
||||
|
@ -494,8 +509,18 @@ int32_t GBAudioProcessEvents(struct GBAudio* audio, int32_t cycles) {
|
|||
|
||||
if (audio->playingCh3) {
|
||||
audio->nextCh3 -= audio->eventDiff;
|
||||
audio->fadeCh3 -= audio->eventDiff;
|
||||
if (audio->fadeCh3 <= 0) {
|
||||
audio->ch3.readable = false;
|
||||
audio->fadeCh3 = INT_MAX;
|
||||
}
|
||||
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) {
|
||||
audio->nextEvent = audio->nextCh3;
|
||||
|
@ -741,10 +766,8 @@ static int32_t _updateChannel2(struct GBAudioChannel2* ch) {
|
|||
return timing;
|
||||
}
|
||||
|
||||
static int32_t _updateChannel3(struct GBAudioChannel3* ch) {
|
||||
static int32_t _updateChannel3(struct GBAudioChannel3* ch, enum GBAudioStyle style) {
|
||||
int i;
|
||||
int start;
|
||||
int end;
|
||||
int volume;
|
||||
switch (ch->volume) {
|
||||
case 0:
|
||||
|
@ -763,25 +786,42 @@ static int32_t _updateChannel3(struct GBAudioChannel3* ch) {
|
|||
volume = 3;
|
||||
break;
|
||||
}
|
||||
if (ch->size) {
|
||||
start = 7;
|
||||
end = 0;
|
||||
} else if (ch->bank) {
|
||||
start = 7;
|
||||
end = 4;
|
||||
} else {
|
||||
start = 3;
|
||||
end = 0;
|
||||
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) {
|
||||
start = 7;
|
||||
end = 0;
|
||||
} else if (ch->bank) {
|
||||
start = 7;
|
||||
end = 4;
|
||||
} else {
|
||||
start = 3;
|
||||
end = 0;
|
||||
}
|
||||
uint32_t bitsCarry = ch->wavedata32[end] & 0x000000F0;
|
||||
uint32_t bits;
|
||||
for (i = start; i >= end; --i) {
|
||||
bits = ch->wavedata32[i] & 0x000000F0;
|
||||
ch->wavedata32[i] = ((ch->wavedata32[i] & 0x0F0F0F0F) << 4) | ((ch->wavedata32[i] & 0xF0F0F000) >> 12);
|
||||
ch->wavedata32[i] |= bitsCarry << 20;
|
||||
bitsCarry = bits;
|
||||
}
|
||||
ch->sample = bitsCarry >> 4;
|
||||
break;
|
||||
}
|
||||
uint32_t bitsCarry = ch->wavedata[end] & 0x000000F0;
|
||||
uint32_t bits;
|
||||
for (i = start; i >= end; --i) {
|
||||
bits = ch->wavedata[i] & 0x000000F0;
|
||||
ch->wavedata[i] = ((ch->wavedata[i] & 0x0F0F0F0F) << 4) | ((ch->wavedata[i] & 0xF0F0F000) >> 12);
|
||||
ch->wavedata[i] |= bitsCarry << 20;
|
||||
bitsCarry = bits;
|
||||
}
|
||||
ch->sample = bitsCarry >> 4;
|
||||
ch->sample -= 8;
|
||||
ch->sample *= volume * 4;
|
||||
return 2 * (2048 - ch->rate);
|
||||
|
|
|
@ -119,7 +119,12 @@ struct GBAudioChannel3 {
|
|||
int rate;
|
||||
bool stop;
|
||||
|
||||
uint32_t wavedata[8];
|
||||
int window;
|
||||
bool readable;
|
||||
union {
|
||||
uint32_t wavedata32[8];
|
||||
uint8_t wavedata8[16];
|
||||
};
|
||||
int8_t sample;
|
||||
};
|
||||
|
||||
|
@ -136,6 +141,13 @@ struct GBAudioChannel4 {
|
|||
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 GB* p;
|
||||
struct GBAudioChannel1 ch1;
|
||||
|
@ -174,10 +186,12 @@ struct GBAudio {
|
|||
int32_t nextSample;
|
||||
|
||||
int32_t sampleInterval;
|
||||
enum GBAudioStyle style;
|
||||
|
||||
int32_t nextCh1;
|
||||
int32_t nextCh2;
|
||||
int32_t nextCh3;
|
||||
int32_t fadeCh3;
|
||||
int32_t nextCh4;
|
||||
bool enable;
|
||||
|
||||
|
@ -186,7 +200,7 @@ struct GBAudio {
|
|||
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 GBAudioReset(struct GBAudio* audio);
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ static void GBInit(void* cpu, struct mCPUComponent* component) {
|
|||
GBVideoInit(&gb->video);
|
||||
|
||||
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;
|
||||
|
||||
|
|
46
src/gb/io.c
46
src/gb/io.c
|
@ -243,7 +243,9 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
|
|||
case REG_WAVE_D:
|
||||
case REG_WAVE_E:
|
||||
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;
|
||||
case REG_JOYP:
|
||||
case REG_TIMA:
|
||||
|
@ -318,6 +320,32 @@ uint8_t GBIORead(struct GB* gb, unsigned address) {
|
|||
break;
|
||||
case REG_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_NR10:
|
||||
case REG_NR11:
|
||||
|
@ -336,22 +364,6 @@ uint8_t GBIORead(struct GB* gb, unsigned address) {
|
|||
case REG_NR50:
|
||||
case REG_NR51:
|
||||
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_TIMA:
|
||||
case REG_TMA:
|
||||
|
|
|
@ -28,7 +28,7 @@ void GBAAudioInit(struct GBAAudio* audio, size_t samples) {
|
|||
#ifdef __BIG_ENDIAN__
|
||||
++n52;
|
||||
#endif
|
||||
GBAudioInit(&audio->psg, 0, nr52);
|
||||
GBAudioInit(&audio->psg, 0, nr52, GB_AUDIO_GBA);
|
||||
audio->samples = samples;
|
||||
audio->psg.clockRate = GBA_ARM7TDMI_FREQUENCY;
|
||||
// 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) {
|
||||
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) {
|
||||
|
@ -353,7 +353,7 @@ void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState*
|
|||
STORE_32(ch2Flags, 0, &state->audio.ch2.envelope);
|
||||
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_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);
|
||||
|
||||
// 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_32(audio->psg.nextCh3, 0, &state->audio.ch3.nextEvent);
|
||||
|
||||
|
|
|
@ -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_X, 0, 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) {
|
||||
cpu->memory.store16(cpu, BASE_IO | 0x00, 0, 0);
|
||||
|
|
Loading…
Reference in New Issue