From: kub Date: Fri, 24 Sep 2021 16:31:19 +0000 (+0200) Subject: sound, fix psg audio X-Git-Tag: v2.00~486 X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=af01b1b16f4614c9f629ee4520c2bf28a985eb6a;p=picodrive.git sound, fix psg audio --- diff --git a/pico/sound/sn76496.c b/pico/sound/sn76496.c index 4507507c..b4a8847f 100644 --- a/pico/sound/sn76496.c +++ b/pico/sound/sn76496.c @@ -22,7 +22,7 @@ #include "sn76496.h" -#define MAX_OUTPUT 0x47ff // was 0x7fff +#define MAX_OUTPUT 0x4800 // was 0x7fff #define STEP 0x10000 @@ -31,22 +31,15 @@ /* bit0 = output */ /* noise feedback for white noise mode (verified on real SN76489 by John Kortink) */ -#define FB_WNOISE 0x14002 /* (16bits) bit16 = bit0(out) ^ bit2 ^ bit15 */ +#define FB_WNOISE_T 0x3000 /* (15bits) bit15 = bit1 ^ bit2, TI */ +#define FB_WNOISE_S 0x9000 /* (16bits) bit16 = bit0 ^ bit3, Sega PSG */ /* noise feedback for periodic noise mode */ -//#define FB_PNOISE 0x10000 /* 16bit rorate */ -#define FB_PNOISE 0x08000 /* JH 981127 - fixes Do Run Run */ +#define FB_PNOISE_T 0x4000 /* 15bit rotate for TI */ +#define FB_PNOISE_S 0x8000 /* 16bit rotate for Sega PSG */ -/* -0x08000 is definitely wrong. The Master System conversion of Marble Madness -uses periodic noise as a baseline. With a 15-bit rotate, the bassline is -out of tune. -The 16-bit rotate has been confirmed against a real PAL Sega Master System 2. -Hope that helps the System E stuff, more news on the PSG as and when! -*/ - -/* noise generator start preset (for periodic noise) */ -#define NG_PRESET 0x0f35 +#define FB_WNOISE FB_WNOISE_S /* Sega */ +#define FB_PNOISE FB_PNOISE_S struct SN76496 @@ -58,7 +51,7 @@ struct SN76496 int Register[8]; /* registers */ int LastRegister; /* last register written */ int Volume[4]; /* volume of voice 0-2 and noise */ - unsigned int RNG; /* noise generator */ + unsigned int RNG; /* noise generator */ int NoiseFB; /* noise feedback mask */ int Period[4]; int Count[4]; @@ -97,6 +90,7 @@ void SN76496Write(int data) case 4: /* tone 2 : frequency */ R->Period[c] = R->UpdateStep * data; if (R->Period[c] == 0) R->Period[c] = R->UpdateStep; + R->Count[c] = 0; if (r == 4) { /* update noise shift frequency */ @@ -115,10 +109,11 @@ void SN76496Write(int data) R->NoiseFB = (n & 4) ? FB_WNOISE : FB_PNOISE; n &= 3; /* N/512,N/1024,N/2048,Tone #3 output */ - R->Period[3] = (n == 3) ? 2 * R->Period[2] : (R->UpdateStep << (5 + n)); + R->Period[3] = (n == 3) ? 2 * R->Period[2] : (R->UpdateStep << (4 + n)); + R->Count[3] = 0; /* reset noise shifter */ - R->RNG = NG_PRESET; + R->RNG = FB_PNOISE; R->Output[3] = R->RNG & 1; break; } @@ -138,18 +133,6 @@ void SN76496Update(short *buffer, int length, int stereo) int i; struct SN76496 *R = &ono_sn; - /* If the volume is 0, increase the counter */ - for (i = 0;i < 4;i++) - { - if (R->Volume[i] == 0) - { - /* note that I do count += length, NOT count = length + 1. You might think */ - /* it's the same since the volume is 0, but doing the latter could cause */ - /* interferencies when the program is rapidly modulating the volume. */ - if (R->Count[i] <= length*STEP) R->Count[i] += length*STEP; - } - } - while (length > 0) { int vol[4]; @@ -173,13 +156,16 @@ void SN76496Update(short *buffer, int length, int stereo) /* If we exit the loop in the middle, Output[i] has to be inverted */ /* and vol[i] incremented only if the exit status of the square */ /* wave is 1. */ - left = 0; - while (R->Count[i] <= 0) + if (R->Count[i] < -2*R->Period[i]) { + /* Cut of anything above the Nyquist freqency */ + /* It will only create aliasing anyway */ + vol[i] += STEP/2; // mean value + R->Count[i] = R->Output[i] = 0; + } + while (R->Count[i] < 0) { - if (R->Count[i] + R->Period[i]*4 < R->Period[i]) - left+= 4, R->Count[i] += R->Period[i]*4; - else left++, R->Count[i] += R->Period[i]; - if (R->Count[i] > 0) + R->Count[i] += R->Period[i]; + if (R->Count[i] >= 0) { R->Output[i] ^= 1; if (R->Output[i]) vol[i] += R->Period[i]; @@ -189,12 +175,10 @@ void SN76496Update(short *buffer, int length, int stereo) vol[i] += R->Period[i]; } if (R->Output[i]) vol[i] -= R->Count[i]; - /* Cut of anything above the sample freqency. It will only create */ - /* aliasing and hearable distortions anyway. */ - if (left > 1) vol[i] = STEP/2; } left = STEP; + if (R->Output[3]) vol[3] += R->Count[3]; do { int nextevent; @@ -202,27 +186,29 @@ void SN76496Update(short *buffer, int length, int stereo) if (R->Count[3] < left) nextevent = R->Count[3]; else nextevent = left; - if (R->Output[3]) vol[3] += R->Count[3]; R->Count[3] -= nextevent; if (R->Count[3] <= 0) { - if (R->RNG & 1) R->RNG ^= R->NoiseFB; - R->RNG >>= 1; R->Output[3] = R->RNG & 1; + R->RNG >>= 1; + if (R->Output[3]) + { + R->RNG ^= R->NoiseFB; + vol[3] += R->Period[3]; + } R->Count[3] += R->Period[3]; - if (R->Output[3]) vol[3] += R->Period[3]; } - if (R->Output[3]) vol[3] -= R->Count[3]; left -= nextevent; } while (left > 0); + if (R->Output[3]) vol[3] -= R->Count[3]; out = vol[0] * R->Volume[0] + vol[1] * R->Volume[1] + vol[2] * R->Volume[2] + vol[3] * R->Volume[3]; if (out > MAX_OUTPUT * STEP) out = MAX_OUTPUT * STEP; - if ((out /= STEP)) // will be optimized to shift; max 0x47ff = 18431 + if ((out /= STEP)) // will be optimized to shift; max 0x4800 = 18432 *buffer += out; if(stereo) buffer+=2; // only left for stereo, to be mixed to right later else buffer++; @@ -254,7 +240,7 @@ static void SN76496_set_gain(struct SN76496 *R,int gain) gain &= 0xff; /* increase max output basing on gain (0.2 dB per step) */ - out = MAX_OUTPUT / 3; + out = MAX_OUTPUT / 4.0; while (gain-- > 0) out *= 1.023292992; /* = (10 ^ (0.2/20)) */ @@ -262,7 +248,7 @@ static void SN76496_set_gain(struct SN76496 *R,int gain) for (i = 0;i < 15;i++) { /* limit volume to avoid clipping */ - if (out > MAX_OUTPUT / 3) R->VolTable[i] = MAX_OUTPUT / 3; + if (out > MAX_OUTPUT / 4) R->VolTable[i] = MAX_OUTPUT / 4; else R->VolTable[i] = out; out /= 1.258925412; /* = 10 ^ (2/20) = 2dB */ @@ -294,10 +280,10 @@ int SN76496_init(int clock,int sample_rate) for (i = 0;i < 4;i++) { - R->Output[i] = 0; - R->Period[i] = R->Count[i] = R->UpdateStep; + R->Volume[i] = R->Output[i] = R->Count[i] = 0; + R->Period[i] = R->UpdateStep; } - R->RNG = NG_PRESET; + R->RNG = FB_PNOISE; R->Output[3] = R->RNG & 1; // added