diff --git a/src/burn/snd/sn76496.cpp b/src/burn/snd/sn76496.cpp index e59d39390..6326dfc44 100644 --- a/src/burn/snd/sn76496.cpp +++ b/src/burn/snd/sn76496.cpp @@ -177,6 +177,131 @@ void SN76496Update(INT32 Num, INT16* pSoundBuf, INT32 Length) } } +void SN76496UpdateToBuffer(INT32 Num, INT16* pSoundBuf, INT32 Length) +{ +#if defined FBA_DEBUG + if (!DebugSnd_SN76496Initted) bprintf(PRINT_ERROR, _T("SN76496Update called without init\n")); + if (Num > NumChips) bprintf(PRINT_ERROR, _T("SN76496Update called with invalid chip %x\n"), Num); +#endif + + INT32 i; + struct SN76496 *R = Chip0; + + if (Num >= MAX_SN76496_CHIPS) return; + + if (Num == 1) R = Chip1; + if (Num == 2) R = Chip2; + if (Num == 3) R = Chip3; + if (Num == 4) R = Chip4; + + /* 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) + { + INT32 Vol[4]; + UINT32 Out; + INT32 Left; + + + /* vol[] keeps track of how long each square wave stays */ + /* in the 1 position during the sample period. */ + Vol[0] = Vol[1] = Vol[2] = Vol[3] = 0; + + for (i = 0;i < 3;i++) + { + if (R->Output[i]) Vol[i] += R->Count[i]; + R->Count[i] -= STEP; + /* Period[i] is the half period of the square wave. Here, in each */ + /* loop I add Period[i] twice, so that at the end of the loop the */ + /* square wave is in the same status (0 or 1) it was at the start. */ + /* vol[i] is also incremented by Period[i], since the wave has been 1 */ + /* exactly half of the time, regardless of the initial position. */ + /* 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. */ + while (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]; + break; + } + R->Count[i] += R->Period[i]; + Vol[i] += R->Period[i]; + } + if (R->Output[i]) Vol[i] -= R->Count[i]; + } + + Left = STEP; + do + { + INT32 NextEvent; + + + 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->NoiseMode == 1) /* White Noise Mode */ + { + if (((R->RNG & R->WhitenoiseTaps) != R->WhitenoiseTaps) && ((R->RNG & R->WhitenoiseTaps) != 0)) /* crappy xor! */ + { + R->RNG >>= 1; + R->RNG |= R->FeedbackMask; + } + else + { + R->RNG >>= 1; + } + R->Output[3] = R->WhitenoiseInvert ? !(R->RNG & 1) : R->RNG & 1; + } + else /* Periodic noise mode */ + { + if (R->RNG & 1) + { + R->RNG >>= 1; + R->RNG |= R->FeedbackMask; + } + else + { + R->RNG >>= 1; + } + R->Output[3] = R->RNG & 1; + } + 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); + + 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; + + pSoundBuf[0] = BURN_SND_CLIP(((INT32)((Out / STEP) * R->nVolume))); + pSoundBuf++; + Length--; + } +} + void SN76496Write(INT32 Num, INT32 Data) { #if defined FBA_DEBUG diff --git a/src/burn/snd/sn76496.h b/src/burn/snd/sn76496.h index a83874e5f..e1fdaea8f 100644 --- a/src/burn/snd/sn76496.h +++ b/src/burn/snd/sn76496.h @@ -1,4 +1,5 @@ void SN76496Update(INT32 Num, INT16* pSoundBuf, INT32 Length); +void SN76496UpdateToBuffer(INT32 Num, INT16* pSoundBuf, INT32 Length); // output mono void SN76496Write(INT32 Num, INT32 Data); void SN76489Init(INT32 Num, INT32 Clock, INT32 SignalAdd); void SN76489AInit(INT32 Num, INT32 Clock, INT32 SignalAdd);