278 lines
9.3 KiB
C
Executable File
278 lines
9.3 KiB
C
Executable File
#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;
|
|
}
|
|
}
|
|
|