- [NEW] Canal 4 (ruido) implementat. Encara no sona be

This commit is contained in:
2025-01-29 23:01:08 +01:00
parent 03631bf235
commit b9de64d113

71
APU.cpp
View File

@@ -26,6 +26,7 @@ namespace APU
#define DAC1_enabled ((NR12&0xf8)!=0)
#define DAC2_enabled ((NR22&0xf8)!=0)
#define DAC3_enabled ((NR30&0x80)!=0)
#define DAC4_enabled ((NR42&0xf8)!=0)
uint8_t duty_cycles[4][8] = {
{1, 1, 1, 1, 1, 1, 1, 0},
@@ -74,6 +75,7 @@ namespace APU
uint8_t NR52 = 0; // 0xff26 - Sound on/off
// 0xff27-0xff2f - Not used?
uint8_t WaveRAM[16]; // 0xff30-0xff3f
uint16_t LFSR = 0;
void audioCallback(void * userdata, uint8_t * stream, int len)
@@ -127,6 +129,17 @@ namespace APU
NR51 = 0;
NR52 = 0;
CH1.duty_cycle = 0;
LFSR = 0;
for (int i=0; i<16; ++i) WaveRAM[i]=0;
}
uint8_t getLFSR()
{
LFSR = (LFSR&0x7fff) | ( (LFSR&1)==((LFSR>>1)&1) ? 0x8000 : 0x0000 );
if (NR43&0x08) LFSR = (LFSR&0xff7f) | ((LFSR>>8)&0x0080);
LFSR=LFSR>>1;
return LFSR&1;
}
void triggerCH1()
@@ -159,6 +172,17 @@ namespace APU
// sweep does several things (check documentation)
}
void triggerCH4()
{
CH4.enabled = true;
CH4.length_timer=NR41&0x3f;
uint8_t clock_shift = ((NR43&0xf0)>>4);// if (clock_shift==0) clock_shift = 1;
CH4.period_divider = clock_shift << (NR43&0x07);
// envelope timer is reset
CH4.volume = NR42>>4;
// sweep does several things (check documentation)
}
uint8_t readRegister(uint16_t address)
{
switch(address)
@@ -180,6 +204,11 @@ namespace APU
case 0xff1d: return 0x00; break;
case 0xff1e: return NR34 & 0x40; break;
case 0xff20: return 0x00; break;
case 0xff21: return NR42; break;
case 0xff22: return NR43; break;
case 0xff23: return NR44 & 0x40; break;
case 0xff24: return NR50; break;
case 0xff25: return NR51; break;
case 0xff26: return NR52; break;
@@ -227,6 +256,11 @@ namespace APU
case 0xff1d: NR33 = value; break;
case 0xff1e: NR34 = value; CH3.length_enable=(value&0x40); if (value&0x80) triggerCH3(); break;
case 0xff20: NR41 = value; CH1.length_timer=NR11&0x3f; CH1.duty_cycle = NR11>>6; break;
case 0xff21: NR42 = value; break;
case 0xff22: NR43 = value; break;
case 0xff23: NR44 = value; CH4.length_enable=(value&0x40); if (value&0x80) triggerCH4(); break;
case 0xff24: NR50 = value; break;
case 0xff25: NR51 = value; break;
case 0xff26: if (value&0x80) reset(); NR52 = (value&0x80) | (NR52 & 0x0f); break;
@@ -284,6 +318,14 @@ namespace APU
CH3.length_timer++;
}
}
if (CH4.enabled && CH4.length_enable) {
if (CH4.length_timer==63) {
CH4.enabled = false;
CH4.length_timer=0;
} else {
CH4.length_timer++;
}
}
}
DIVAPU_CH1_freq_sweep++;
if (DIVAPU_CH1_freq_sweep==4) {
@@ -315,13 +357,23 @@ namespace APU
}
}
}
// Do the envelope sweep thing
if ( CH4.enabled && (NR42&0x7) ) { // If sweep pace != 0, envelope sweep is enabled
CH4.envelope_sweep_timer++;
if ( CH4.envelope_sweep_timer == (NR42&0x07) ) { // if timer == envelope sweep, increase or decrease volume
CH4.envelope_sweep_timer=0;
if (NR42&0x8) { // bit set increases, reset decreases
if (CH4.volume<0x0f) CH4.volume++;
} else {
if (CH4.volume>0) CH4.volume--;
}
}
}
}
}
uint32_t dots = 0;
uint32_t dotsCH3 = 0;
uint32_t dotsCH4 = 0;
void update(uint32_t dt)
{
dots += dt;
@@ -350,6 +402,16 @@ namespace APU
if (CH3.duty_step==32) CH3.duty_step=0;
}
}
dotsCH4 += dt;
while (dotsCH4>=16) {
dotsCH4 -= 16;
CH4.period_divider--;
if (CH4.period_divider==0) {
uint8_t clock_shift = ((NR43&0xf0)>>3); if (clock_shift==0) clock_shift = 1;
CH4.period_divider = clock_shift << (NR43&0x07);
CH4.duty_step=getLFSR();
}
}
t_sound += dt;
samples_t += dt;
@@ -369,7 +431,10 @@ namespace APU
sampleCH3 = CH3.volume==0 ? 0 : CH3.volume==1 ? actual_sample : CH3.volume==2 ? actual_sample>>1 : actual_sample>>2;
}
uint8_t sample = (sampleCH1+sampleCH2+sampleCH3)&0xff;
uint16_t sampleCH4 = 0;
if (apu_enabled && DAC4_enabled) sampleCH4 = (CH4.duty_step*CH4.volume)<<2;
uint8_t sample = (sampleCH1+sampleCH2+sampleCH3+sampleCH4)&0xff;
sound_buffer[(sound_pos++)&(AUDIO_BUFFER_SIZE-1)] = sample;
audio_viewer::addsample(sample);