1
0

public release of panzgb

This commit is contained in:
2025-11-24 13:37:49 +01:00
commit d08fbfe1aa
18 changed files with 3827 additions and 0 deletions

277
lib/gb-sound.c Executable file
View File

@@ -0,0 +1,277 @@
#include "gb-impl.h"
#include "gb-sound.h"
void increase_sound_timers(gb *cpu) {
if (CHANNEL_1_LENGTH_ENABLED != 0) {
cpu->channel_1.length_timer++;
if (cpu->channel_1.length_timer >= 64) {
cpu->memory[0xFF26] = cpu->memory[0xFF26] & 0xFE;
}
}
if(CHANNEL_2_LENGTH_ENABLED != 0){
cpu->channel_2.length_timer++;
if(cpu->channel_2.length_timer >= 64) {
cpu->memory[0xFF26] = cpu->memory[0xFF26] & 0xFD;
}
}
if(CHANNEL_3_LENGTH_ENABLED != 0){
cpu->channel_3.length_timer++;
if(cpu->channel_3.length_timer >= 256) {
cpu->memory[0xFF26] = cpu->memory[0xFF26] & 0xFB;
}
}
if(CHANNEL_4_LENGTH_ENABLED != 0){
cpu->channel_4.length_timer++;
if(cpu->channel_4.length_timer >= 64) {
cpu->memory[0xFF26] = cpu->memory[0xFF26] & 0xF7;
}
}
}
void increase_vol_envelope(gb *cpu){
if (cpu->channel_1.env_sweep_pace != 0) {
cpu->channel_1.env_vol += (cpu->channel_1.env_sweep_pace == 0) ? -1 : 1;
if (cpu->channel_1.env_vol < 0) cpu->channel_1.env_vol = 0;
if (cpu->channel_1.env_vol > 15) cpu->channel_1.env_vol = 15;
}
if(cpu->channel_2.env_sweep_pace !=0) {
cpu->channel_2.env_vol += (cpu->channel_2.env_dir == 0) ? -1 : 1;
if (cpu->channel_2.env_vol < 0) cpu->channel_2.env_vol = 0;
if (cpu->channel_2.env_vol > 15) cpu->channel_2.env_vol = 15;
}
if(cpu->channel_4.env_sweep_pace !=0) {
cpu->channel_4.env_vol += (cpu->channel_4.env_dir == 0) ? -1 : 1;
if (cpu->channel_4.env_vol < 0) cpu->channel_4.env_vol = 0;
if (cpu->channel_4.env_vol > 15) cpu->channel_4.env_vol = 15;
}
}
void increase_sweep(gb *cpu){
if(CHANNEL_1_SWEEP_PACE !=0) {
WORD newPeriod = CHANNEL_1_PERIOD_CLOCK;
newPeriod = CHANNEL_1_SWEEP_DIR != 0? newPeriod - (CHANNEL_1_PERIOD_CLOCK >> CHANNEL_1_SWEEP_STEP) : newPeriod + (CHANNEL_1_PERIOD_CLOCK >> CHANNEL_1_SWEEP_STEP);
NR13 = newPeriod & 0xFF;
NR14 = (NR14 & 0xF8) | (newPeriod >> 8);
}
}
void handleSound(gb *cpu, BYTE clocks) {
BYTE s = 0;
if (AUDIO_OFF)
return;
cpu->channel_1.period_clock -= clocks;
if (cpu->channel_1.period_clock < 0) {
s = squareWave[CHANNEL_1_WAVE][cpu->channel_1.pos & 7];
cpu->channel_1.pos++;
cpu->channel_1.period_clock += (2048 - CHANNEL_1_PERIOD_CLOCK) *4;
s *= cpu->channel_1.env_vol;
if (CHANNEL_1_ON != 0 && CHANNEL_1_RIGHT_ACTIVE != 0) cpu->rightSoundBuffer += s;
if (CHANNEL_1_ON != 0 && CHANNEL_1_LEFT_ACTIVE != 0) cpu->leftSoundBuffer += s;
}
cpu->channel_2.period_clock -= clocks;
if(cpu->channel_2.period_clock < 0) {
s = squareWave[CHANNEL_2_WAVE][cpu->channel_2.pos & 7];
cpu->channel_2.pos++;
cpu->channel_2.period_clock += (2048 - CHANNEL_2_PERIOD_CLOCK) *4;
s *= cpu->channel_2.env_vol;
if (CHANNEL_2_ON != 0 && CHANNEL_2_RIGHT_ACTIVE != 0) cpu->rightSoundBuffer += s;
if (CHANNEL_2_ON != 0 && CHANNEL_2_LEFT_ACTIVE !=0) cpu->leftSoundBuffer += s;
}
cpu->channel_3.period_clock -= clocks;
if(cpu->channel_3.period_clock < 0) {
s = CHANNEL_3_WAVE[cpu->channel_3.pos / 2] &0xFF;
//If pos is even, we need the upper nibble, otherwise the lower one
s = cpu->channel_3.pos % 2 == 0 ? s >> 4 : s & 0xF;
cpu-> channel_3.pos = cpu->channel_3.pos++ &0x1F;
cpu->channel_3.period_clock += (2048 - CHANNEL_3_PERIOD_CLOCK) *2;
if(CHANNEL_3_OUTPUT_LEVEL == 0) {
s = 0;
} else {
s >>= CHANNEL_3_OUTPUT_LEVEL -1;
}
if (CHANNEL_3_ON != 0 && CHANNEL_3_RIGHT_ACTIVE != 0) cpu->rightSoundBuffer += s;
if (CHANNEL_3_ON != 0 && CHANNEL_3_LEFT_ACTIVE !=0) cpu->leftSoundBuffer += s;
}
cpu->channel_4.period_clock -= clocks;
if(cpu->channel_4.period_clock <= 0) {
s = noise[cpu->channel_4.pos & 0xF] & 0x1;
s *= cpu->channel_4.env_vol;
cpu->channel_4.pos++;
cpu->channel_4.period_clock += CHANNEL_4_FREQ_MULTIPLIER;
if (CHANNEL_4_ON != 0 && CHANNEL_4_RIGHT_ACTIVE != 0) cpu->rightSoundBuffer += s;
if (CHANNEL_4_ON != 0 && CHANNEL_4_LEFT_ACTIVE != 0) cpu->leftSoundBuffer += s;
}
cpu->soundFrameClock -= clocks;
if(cpu->soundFrameClock <= 0){
cpu->soundFrameClock += 8192; //512 hz
switch (cpu->soundFramePos) {
case 0:
case 4:
increase_sound_timers(cpu);
break;
case 2:
case 6:
increase_sound_timers(cpu);
//increase sweep
break;
case 7:
increase_vol_envelope(cpu);
break;
default:
break;
}
cpu->soundFramePos = cpu->soundFramePos++ & 0x7;
}
cpu->soundMasterClock -= clocks;
if (cpu->soundMasterClock <= 0) {
cpu->soundMasterClock += GB_CLOCK / 44100;
cpu->leftSoundBuffer *= VOLUME_LEFT;
cpu->rightSoundBuffer *= VOLUME_RIGHT;
if (cpu->leftSoundBuffer > 127) cpu->leftSoundBuffer = 127;
else if (cpu->leftSoundBuffer < -128) cpu->leftSoundBuffer = -128;
if (cpu->rightSoundBuffer > 127) cpu->rightSoundBuffer = 127;
else if (cpu->rightSoundBuffer < -128) cpu->rightSoundBuffer = -128;
cpu->soundData[cpu->numerOfBytes++] = cpu->leftSoundBuffer + 128;
cpu->soundData[cpu->numerOfBytes++] = cpu->rightSoundBuffer + 128;
cpu->leftSoundBuffer = 0;
cpu->rightSoundBuffer = 0;
}
}
void writeSoundRegistry(gb *cpu, WORD addr, BYTE data){
if(addr == 0xFF11) {
BYTE lengthTimer = data &0x3F;
cpu->channel_1.length_timer = lengthTimer;
cpu->memory[addr] = data;
}
else if(addr == 0xFF12) {
cpu->memory[addr] = data;
if((data & 0xF8) == 0){
cpu->memory[0xFF26] = cpu->memory[0xFF26] & 0xFE;
}
}
else if(addr == 0xFF13) {
cpu->memory[addr] = data;
}
else if(addr == 0xFF14) {
BYTE triggering = data &0x80;
if(triggering != 0) {
cpu->memory[0xFF26] = cpu->memory[0xFF26] | 0x1;
cpu->channel_1.pos = 0;
cpu->channel_1.period_clock = (2048 - CHANNEL_1_PERIOD_CLOCK) *4;
cpu->channel_1.length_timer = NR11 & 0x3F;
cpu->channel_1.env_vol = NR12 >> 4;
cpu->channel_1.env_dir = (NR12 & 0x8) >> 4;
cpu->channel_1.env_sweep_pace = NR12 & 0x7;
}
cpu->memory[addr] = data;
}
else if(addr == 0xFF16) {
BYTE lengthTimer = data &0x3F;
cpu->channel_2.length_timer = lengthTimer;
cpu->memory[addr] = data;
}
else if(addr == 0xFF17) {
cpu->memory[addr] = data;
if((data & 0xF8) == 0){
cpu->memory[0xFF26] = cpu->memory[0xFF26] & 0xFD;
}
}
else if(addr == 0xFF18) {
cpu->memory[addr] = data;
}
else if(addr == 0xFF19) {
BYTE triggering = data &0x80;
if(triggering != 0) {
cpu->channel_2.pos = 0;
cpu->channel_2.period_clock = (2048 - CHANNEL_2_PERIOD_CLOCK) *4;
cpu->channel_2.length_timer = NR21 & 0x3F;
cpu->channel_2.env_vol = NR22 >> 4;
cpu->channel_2.env_dir = (NR22 & 0x8) >> 4;
cpu->channel_2.env_sweep_pace = NR22 & 0x7;
cpu->memory[0xFF26] = cpu->memory[0xFF26] | 0x2;
}
cpu->memory[addr] = data;
}
else if(addr == 0xFF1A) {
BYTE on = data & 0x80;
if(on == 0) {
cpu->memory[0xFF26] = cpu->memory[0xFF26] & 0xFB;
}
cpu->memory[addr] = data;
}
else if(addr == 0xFF1B) {
cpu->channel_3.length_timer = data;
cpu->memory[addr] = data;
}
else if(addr == 0xFF1C) {
cpu->memory[addr] = data;
}
else if(addr == 0xFF1D) {
cpu->memory[addr] = data;
}
else if(addr == 0xFF1E) {
BYTE triggering = data &0x80;
if(triggering != 0) {
cpu->channel_3.pos = 1;
cpu->channel_3.period_clock = (2048 - CHANNEL_3_PERIOD_CLOCK) *2;
cpu->channel_3.length_timer = NR32;
cpu->memory[0xFF26] = cpu->memory[0xFF26] | 0x4;
}
cpu->memory[addr] = data;
}
else if(addr == 0xFF41) {
BYTE lengthTimer = data &0x3F;
cpu->channel_4.length_timer = lengthTimer;
cpu->memory[addr] = data;
}
else if(addr == 0xFF42) {
cpu->memory[addr] = data;
if((data & 0xF8) == 0){
cpu->memory[0xFF26] = cpu->memory[0xFF26] & 0xF7;
}
}
else if(addr == 0xFF43) {
cpu->memory[addr] = data;
}
else if(addr == 0xFF44) {
BYTE triggering = data &0x80;
if(triggering != 0) {
cpu->channel_4.env_vol = NR42 >> 4;
cpu->channel_4.length_timer = NR41 & 0x3F;
cpu->channel_4.pos = 0;
cpu->channel_4.env_dir = (NR42 & 0x8) >> 4;
cpu->channel_4.env_sweep_pace = NR42 & 0x7;
cpu->channel_4.period_clock = 0;
cpu->memory[0xFF26] = cpu->memory[0xFF26] | 0x8;
}
cpu->memory[addr] = data;
}
else if(addr == 0xFF26) {
BYTE val = data & 0x80;
cpu->memory[addr] = val | cpu->memory[addr];
}
else {
cpu->memory[addr] = data;
}
}