DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/snd_pc98/sound/psggeng.c
00001 #include    "np2glue.h"
00002 //#include      "compiler.h"
00003 #include        "parts.h"
00004 #include        "sound.h"
00005 #include        "psggen.h"
00006 
00007 
00008 extern  PSGGENCFG       psggencfg;
00009 
00010 
00011 void SOUNDCALL psggen_getpcm(PSGGEN psg, SINT32 *pcm, UINT count) {
00012 
00013 //      SINT32  noisevol;
00014         UINT    noisetbl = 0;
00015         PSGTONE *tone;
00016         SINT32  samp;
00017 //      UINT    psgvol;
00018         SINT32  vol;
00019         UINT    i;
00020         UINT    noise;
00021 
00022         if ((psg->mixer & 0x3f) == 0) {
00023                 count = min(count, psg->puchicount);
00024                 psg->puchicount -= count;
00025         }
00026         if (count == 0) {
00027                 return;
00028         }
00029         do {
00030 //              noisevol = 0;
00031                 if (psg->envcnt) {
00032                         psg->envcnt--;
00033                         if (psg->envcnt == 0) {
00034                                 psg->envvolcnt--;
00035                                 if (psg->envvolcnt < 0) {
00036                                         if (psg->envmode & PSGENV_ONESHOT) {
00037                                                 psg->envvol = (psg->envmode & PSGENV_LASTON)?15:0;
00038                                         }
00039                                         else {
00040                                                 psg->envvolcnt = 15;
00041                                                 if (!(psg->envmode & PSGENV_ONECYCLE)) {
00042                                                         psg->envmode ^= PSGENV_INC;
00043                                                 }
00044                                                 psg->envcnt = psg->envmax;
00045                                                 psg->envvol = (psg->envvolcnt ^ psg->envmode) & 0x0f;
00046                                         }
00047                                 }
00048                                 else {
00049                                         psg->envcnt = psg->envmax;
00050                                         psg->envvol = (psg->envvolcnt ^ psg->envmode) & 0x0f;
00051                                 }
00052                                 psg->evol = psggencfg.volume[psg->envvol];
00053                         }
00054                 }
00055                 UINT8 mixer = psg->mixer;
00056                 if (mixer & 0x38) {
00057             /* NTS: This code relies on signed integer underflow to determine when to advance
00058                     the pseudo-random noise generation sequence. It assumes that it can detect
00059                     SINT32 carry by copying the value, subtracting the original, and then
00060                     testing to see if the result is larger than the original.
00061 
00062                     Unfortunately, Clang/LLVM break this code by promoting both to long (64-bit)
00063                     before comparing, which turns the noise into DC bias popping noises.
00064 
00065                     This hack, with long type masks, emulates the original behavior even if the
00066                     compare is promoted to signed long (64-bit) and allows the noise generation
00067                     to work even with Clang/LLVM --J.C */
00068             const long sint32sign = 1L << (((long)(CHAR_BIT * sizeof(long))) - 1L);
00069             const long sint32mask = sint32sign + 0x7FFFFFFFL;
00070 
00071                         for (i=0; i<(1 << PSGADDEDBIT); i++) {
00072                                 SINT32 countbak;
00073                                 countbak = psg->noise.count;
00074                                 psg->noise.count -= psg->noise.freq;
00075                                 if (((long)psg->noise.count & sint32mask) > ((long)countbak & sint32mask)) {
00076 //                                      psg->noise.base = GETRAND() & (1 << (1 << PSGADDEDBIT));
00077                                         psg->noise.base = rand_get() & (1 << (1 << PSGADDEDBIT));
00078                                 }
00079                                 noisetbl += psg->noise.base;
00080                                 noisetbl >>= 1;
00081                         }
00082                 }
00083                 tone = psg->tone;
00084                 PSGTONE *toneterm = tone + 3;
00085                 do {
00086                         vol = *(tone->pvol);
00087                         if (vol) {
00088                                 samp = 0;
00089                                 switch(mixer & 9) {
00090                                         case 0:                                                 // no mix
00091                                                 if (tone->puchi) {
00092                                                         tone->puchi--;
00093                                                         samp += vol << PSGADDEDBIT;
00094                                                 }
00095                                                 break;
00096 
00097                                         case 1:                                                 // tone only
00098                                                 for (i=0; i<(1 << PSGADDEDBIT); i++) {
00099                                                         tone->count += tone->freq;
00100                                                         samp += vol * ((tone->count>=0)?1:-1);
00101                                                 }
00102                                                 break;
00103 
00104                                         case 8:                                                 // noise only
00105                                                 noise = noisetbl;
00106                                                 for (i=0; i<(1 << PSGADDEDBIT); i++) {
00107                                                         samp += vol * ((noise & 1)?1:-1);
00108                                                         noise >>= 1;
00109                                                 }
00110                                                 break;
00111 
00112                                         case 9:
00113                                                 noise = noisetbl;
00114                                                 for (i=0; i<(1 << PSGADDEDBIT); i++) {
00115                                                         tone->count += tone->freq;
00116                                                         if ((tone->count >= 0) || (noise & 1)) {
00117                                                                 samp += vol;
00118                                                         }
00119                                                         else {
00120                                                                 samp -= vol;
00121                                                         }
00122                                                         noise >>= 1;
00123                                                 }
00124                                                 break;
00125                                 }
00126                                 if (!(tone->pan & 1)) {
00127                                         pcm[0] += samp;
00128                                 }
00129                                 if (!(tone->pan & 2)) {
00130                                         pcm[1] += samp;
00131                                 }
00132                         }
00133                         mixer >>= 1;
00134                 } while(++tone < toneterm);
00135                 pcm += 2;
00136         } while(--count);
00137 }
00138