[Core/Sound] fixed PSG noise channel bug

This commit is contained in:
EkeEke 2017-09-19 12:21:41 +02:00
parent 3a0ec7e895
commit 31906b20cf
3 changed files with 59 additions and 93 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 MiB

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 MiB

After

Width:  |  Height:  |  Size: 3.4 MiB

View File

@ -151,7 +151,6 @@ int psg_context_save(uint8 *state)
save_param(psg.freqInc,sizeof(psg.freqInc)); save_param(psg.freqInc,sizeof(psg.freqInc));
save_param(psg.freqCounter,sizeof(psg.freqCounter)); save_param(psg.freqCounter,sizeof(psg.freqCounter));
save_param(psg.polarity,sizeof(psg.polarity)); save_param(psg.polarity,sizeof(psg.polarity));
save_param(psg.chanDelta,sizeof(psg.chanDelta));
save_param(psg.chanOut,sizeof(psg.chanOut)); save_param(psg.chanOut,sizeof(psg.chanOut));
return bufferptr; return bufferptr;
@ -159,34 +158,29 @@ int psg_context_save(uint8 *state)
int psg_context_load(uint8 *state) int psg_context_load(uint8 *state)
{ {
int chanOut[4][2], delta[2]; int delta[2];
int i, bufferptr = 0; int i, bufferptr = 0;
/* get current tone channels output */ /* initialize delta with current noise channel output */
if (psg.noiseShiftValue & 1)
{
delta[0] = -psg.chanOut[3][0];
delta[1] = -psg.chanOut[3][1];
}
else
{
delta[0] = 0;
delta[1] = 0;
}
/* add current tone channels output */
for (i=0; i<3; i++) for (i=0; i<3; i++)
{ {
if (psg.polarity[i] > 0) if (psg.polarity[i] > 0)
{ {
chanOut[i][0] = psg.chanOut[i][0]; delta[0] -= psg.chanOut[i][0];
chanOut[i][1] = psg.chanOut[i][1]; delta[1] -= psg.chanOut[i][1];
} }
else
{
chanOut[i][0] = 0;
chanOut[i][1] = 0;
}
}
/* get current noise channel output */
if (psg.noiseShiftValue & 1)
{
chanOut[3][0] = psg.chanOut[3][0];
chanOut[3][1] = psg.chanOut[3][1];
}
else
{
chanOut[3][0] = 0;
chanOut[3][1] = 0;
} }
load_param(&psg.clocks,sizeof(psg.clocks)); load_param(&psg.clocks,sizeof(psg.clocks));
@ -196,46 +190,22 @@ int psg_context_load(uint8 *state)
load_param(psg.freqInc,sizeof(psg.freqInc)); load_param(psg.freqInc,sizeof(psg.freqInc));
load_param(psg.freqCounter,sizeof(psg.freqCounter)); load_param(psg.freqCounter,sizeof(psg.freqCounter));
load_param(psg.polarity,sizeof(psg.polarity)); load_param(psg.polarity,sizeof(psg.polarity));
load_param(psg.chanDelta,sizeof(psg.chanDelta));
load_param(psg.chanOut,sizeof(psg.chanOut)); load_param(psg.chanOut,sizeof(psg.chanOut));
/* apply any pending channel volume variation */ /* add noise channel output variation */
for (i=0; i<4; i++)
{
psg.chanOut[i][0] += psg.chanDelta[i][0];
psg.chanOut[i][1] += psg.chanDelta[i][1];
psg.chanDelta[i][0] = 0;
psg.chanDelta[i][1] = 0;
}
/* calculate noise channel output variations */
if (psg.noiseShiftValue & 1) if (psg.noiseShiftValue & 1)
{ {
/* channel output is high */ delta[0] += psg.chanOut[3][0];
delta[0] = psg.chanOut[3][0] - chanOut[3][0]; delta[1] += psg.chanOut[3][1];
delta[1] = psg.chanOut[3][0] - chanOut[3][1];
}
else
{
/* channel output is low */
delta[0] = -chanOut[3][0];
delta[1] = -chanOut[3][1];
} }
/* add tone channels output variations */ /* add tone channels output variation */
for (i=0; i<3; i++) for (i=0; i<3; i++)
{ {
if (psg.polarity[i] > 0) if (psg.polarity[i] > 0)
{ {
/* channel output is high */ delta[0] += psg.chanOut[i][0];
delta[0] += (psg.chanOut[i][0] - chanOut[i][0]); delta[1] += psg.chanOut[i][1];
delta[1] += (psg.chanOut[i][0] - chanOut[i][1]);
}
else
{
/* channel output is low */
delta[0] -= chanOut[i][0];
delta[1] -= chanOut[i][1];
} }
} }
@ -317,7 +287,7 @@ void psg_write(unsigned int clocks, unsigned int data)
case 6: /* Noise control */ case 6: /* Noise control */
{ {
/* noise signal generator frequency (----?xxx) */ /* noise signal generator frequency (-----?xx) */
int noiseFreq = (data & 0x03); int noiseFreq = (data & 0x03);
if (noiseFreq == 0x03) if (noiseFreq == 0x03)
@ -336,8 +306,8 @@ void psg_write(unsigned int clocks, unsigned int data)
if (psg.noiseShiftValue & 1) if (psg.noiseShiftValue & 1)
{ {
/* high to low transition will be applied at next internal cycle update */ /* high to low transition will be applied at next internal cycle update */
psg.chanDelta[3][0] = -psg.chanOut[3][0]; psg.chanDelta[3][0] -= psg.chanOut[3][0];
psg.chanDelta[3][1] = -psg.chanOut[3][1]; psg.chanDelta[3][1] -= psg.chanOut[3][1];
} }
/* reset noise shift register value (noise channel output is forced low) */ /* reset noise shift register value (noise channel output is forced low) */
@ -348,48 +318,56 @@ void psg_write(unsigned int clocks, unsigned int data)
case 7: /* Noise channel attenuation */ case 7: /* Noise channel attenuation */
{ {
int chanOut[2];
/* convert 4-bit attenuation value (----xxxx) to 16-bit volume value */ /* convert 4-bit attenuation value (----xxxx) to 16-bit volume value */
data = chanVolume[data & 0x0f]; data = chanVolume[data & 0x0f];
/* channel pre-amplification */
chanOut[0] = (data * psg.chanAmp[3][0]) / 100;
chanOut[1] = (data * psg.chanAmp[3][1]) / 100;
/* check noise shift register output */ /* check noise shift register output */
if (psg.noiseShiftValue & 1) if (psg.noiseShiftValue & 1)
{ {
/* channel output is high, volume variation will be applied at next internal cycle update */ /* channel output is high, volume variation will be applied at next internal cycle update */
psg.chanDelta[3][0] = ((data * psg.chanAmp[3][0]) / 100) - psg.chanOut[3][0]; psg.chanDelta[3][0] += (chanOut[0] - psg.chanOut[3][0]);
psg.chanDelta[3][1] = ((data * psg.chanAmp[3][1]) / 100) - psg.chanOut[3][1]; psg.chanDelta[3][1] += (chanOut[1] - psg.chanOut[3][1]);
}
else
{
/* channel output is low, volume variation will be applied at next transition */
psg.chanOut[3][0] = (data * psg.chanAmp[3][0]) / 100;
psg.chanOut[3][1] = (data * psg.chanAmp[3][1]) / 100;
} }
/* update channel volume */
psg.chanOut[3][0] = chanOut[0];
psg.chanOut[3][1] = chanOut[1];
break; break;
} }
default: /* Tone channels attenuation */ default: /* Tone channels attenuation */
{ {
int chanOut[2];
/* channel number (0-2) */ /* channel number (0-2) */
int i = index >> 1; int i = index >> 1;
/* convert 4-bit attenuation value (----xxxx) to 16-bit volume value */ /* convert 4-bit attenuation value (----xxxx) to 16-bit volume value */
data = chanVolume[data & 0x0f]; data = chanVolume[data & 0x0f];
/* channel pre-amplification */
chanOut[0] = (data * psg.chanAmp[i][0]) / 100;
chanOut[1] = (data * psg.chanAmp[i][1]) / 100;
/* check tone generator polarity */ /* check tone generator polarity */
if (psg.polarity[i] > 0) if (psg.polarity[i] > 0)
{ {
/* channel output is high, volume variation will be applied at next internal cycle update */ /* channel output is high, volume variation will be applied at next internal cycle update */
psg.chanDelta[i][0] = ((data * psg.chanAmp[i][0]) / 100) - psg.chanOut[i][0]; psg.chanDelta[i][0] += (chanOut[0] - psg.chanOut[i][0]);
psg.chanDelta[i][1] = ((data * psg.chanAmp[i][1]) / 100) - psg.chanOut[i][1]; psg.chanDelta[i][1] += (chanOut[1] - psg.chanOut[i][1]);
}
else
{
/* channel output is low, volume variation will be applied at next transition */
psg.chanOut[i][0] = (data * psg.chanAmp[i][0]) / 100;
psg.chanOut[i][1] = (data * psg.chanAmp[i][1]) / 100;
} }
/* update channel volume */
psg.chanOut[i][0] = chanOut[0];
psg.chanOut[i][1] = chanOut[1];
break; break;
} }
} }
@ -428,14 +406,8 @@ void psg_config(unsigned int clocks, unsigned int preamp, unsigned int panning)
if (psg.polarity[i] > 0) if (psg.polarity[i] > 0)
{ {
/* channel output is high, volume variation will be applied at next internal cycle update */ /* channel output is high, volume variation will be applied at next internal cycle update */
psg.chanDelta[i][0] = ((volume * psg.chanAmp[i][0]) / 100) - psg.chanOut[i][0]; psg.chanDelta[i][0] += (((volume * psg.chanAmp[i][0]) / 100) - psg.chanOut[i][0]);
psg.chanDelta[i][1] = ((volume * psg.chanAmp[i][1]) / 100) - psg.chanOut[i][1]; psg.chanDelta[i][1] += (((volume * psg.chanAmp[i][1]) / 100) - psg.chanOut[i][1]);
}
else
{
/* channel output is low, volume variation will be applied at next transition*/
psg.chanOut[i][0] = (volume * psg.chanAmp[i][0]) / 100;
psg.chanOut[i][1] = (volume * psg.chanAmp[i][1]) / 100;
} }
} }
@ -446,16 +418,14 @@ void psg_config(unsigned int clocks, unsigned int preamp, unsigned int panning)
if (psg.noiseShiftValue & 1) if (psg.noiseShiftValue & 1)
{ {
/* channel output is high, volume variation will be applied at next internal cycle update */ /* channel output is high, volume variation will be applied at next internal cycle update */
psg.chanDelta[3][0] = ((volume * psg.chanAmp[3][0]) / 100) - psg.chanOut[3][0]; psg.chanDelta[3][0] += (((volume * psg.chanAmp[3][0]) / 100) - psg.chanOut[3][0]);
psg.chanDelta[3][1] = ((volume * psg.chanAmp[3][1]) / 100) - psg.chanOut[3][1]; psg.chanDelta[3][1] += (((volume * psg.chanAmp[3][1]) / 100) - psg.chanOut[3][1]);
}
else
{
/* channel output is low, volume variation will be applied at next transition */
psg.chanOut[3][0] = (volume * psg.chanAmp[3][0]) / 100;
psg.chanOut[3][1] = (volume * psg.chanAmp[3][1]) / 100;
} }
} }
/* update channel volume */
psg.chanOut[i][0] = (volume * psg.chanAmp[i][0]) / 100;
psg.chanOut[i][1] = (volume * psg.chanAmp[i][1]) / 100;
} }
} }
@ -501,10 +471,6 @@ static void psg_update(unsigned int clocks)
blip_add_delta_fast(snd.blips[0], psg.clocks, psg.chanDelta[i][0], psg.chanDelta[i][1]); blip_add_delta_fast(snd.blips[0], psg.clocks, psg.chanDelta[i][0], psg.chanDelta[i][1]);
} }
/* update channel volume */
psg.chanOut[i][0] += psg.chanDelta[i][0];
psg.chanOut[i][1] += psg.chanDelta[i][1];
/* clear pending channel volume variations */ /* clear pending channel volume variations */
psg.chanDelta[i][0] = 0; psg.chanDelta[i][0] = 0;
psg.chanDelta[i][1] = 0; psg.chanDelta[i][1] = 0;
@ -558,14 +524,14 @@ static void psg_update(unsigned int clocks)
/* current shift register output */ /* current shift register output */
int shiftOutput = shiftValue & 0x01; int shiftOutput = shiftValue & 0x01;
/* White noise (----1xxx) */ /* White noise (-----1xx) */
if (psg.regs[6] & 0x04) if (psg.regs[6] & 0x04)
{ {
/* shift and apply XOR feedback network */ /* shift and apply XOR feedback network */
shiftValue = (shiftValue >> 1) | (noiseFeedback[shiftValue & psg.noiseBitMask] << psg.noiseShiftWidth); shiftValue = (shiftValue >> 1) | (noiseFeedback[shiftValue & psg.noiseBitMask] << psg.noiseShiftWidth);
} }
/* Periodic noise (----0xxx) */ /* Periodic noise (-----0xx) */
else else
{ {
/* shift and feedback current output */ /* shift and feedback current output */