Annotation of generator/sn76496/sn76496.c, revision 1.1.1.1

1.1       root        1: /* This code comes from MAME 0.53 and according to changes log was written
                      2:    by Nicola Salmoria.  The MAME license says:
                      3: 
                      4:    VI. Reuse of Source Code
                      5:    --------------------------
                      6:    This chapter might not apply to specific portions of MAME (e.g. CPU
                      7:    emulators) which bear different copyright notices.
                      8:    The source code cannot be used in a commercial product without the written
                      9:    authorization of the authors. Use in non-commercial products is allowed, and
                     10:    indeed encouraged.  If you use portions of the MAME source code in your
                     11:    program, however, you must make the full source code freely available as
                     12:    well.
                     13:    Usage of the _information_ contained in the source code is free for any use.
                     14:    However, given the amount of time and energy it took to collect this
                     15:    information, if you find new information we would appreciate if you made it
                     16:    freely available as well.
                     17: 
                     18: */
                     19: 
                     20: /***************************************************************************
                     21: 
                     22:   sn76496.c
                     23: 
                     24:   Routines to emulate the Texas Instruments SN76489 / SN76496 programmable
                     25:   tone /noise generator. Also known as (or at least compatible with) TMS9919.
                     26: 
                     27:   Noise emulation is not accurate due to lack of documentation. The noise
                     28:   generator uses a shift register with a XOR-feedback network, but the exact
                     29:   layout is unknown. It can be set for either period or white noise; again,
                     30:   the details are unknown.
                     31: 
                     32: ***************************************************************************/
                     33: 
                     34: /* get uint16 definition */
                     35: #include "generator.h"
                     36: 
                     37: #include "sn76496.h"
                     38: 
                     39: #define MAX_OUTPUT 0x7fff
                     40: #define STEP 0x10000
                     41: 
                     42: /* Formulas for noise generator */
                     43: /* bit0 = output */
                     44: 
                     45: /* noise feedback for white noise mode */
                     46: #define FB_WNOISE 0x12000       /* bit15.d(16bits) = bit0(out) ^ bit2 */
                     47: //#define FB_WNOISE 0x14000     /* bit15.d(16bits) = bit0(out) ^ bit1 */
                     48: //#define FB_WNOISE 0x28000     /* bit16.d(17bits) = bit0(out) ^ bit2 (same to AY-3-8910) */
                     49: //#define FB_WNOISE 0x50000     /* bit17.d(18bits) = bit0(out) ^ bit2 */
                     50: 
                     51: /* noise feedback for periodic noise mode */
                     52: /* it is correct maybe (it was in the Megadrive sound manual) */
                     53: //#define FB_PNOISE 0x10000     /* 16bit rorate */
                     54: #define FB_PNOISE 0x08000       /* JH 981127 - fixes Do Run Run */
                     55: 
                     56: /* noise generator start preset (for periodic noise) */
                     57: #define NG_PRESET 0x0f35
                     58: 
                     59: struct SN76496 sn[MAX_76496];
                     60: 
                     61: void SN76496Write(int chip, int data)
                     62: {
                     63:   struct SN76496 *R = &sn[chip];
                     64: 
                     65:   /* should update buffer before getting here */
                     66: 
                     67:   if (data & 0x80) {
                     68:     int r = (data & 0x70) >> 4;
                     69:     int c = r / 2;
                     70: 
                     71:     R->LastRegister = r;
                     72:     R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f);
                     73:     switch (r) {
                     74:     case 0:                    /* tone 0 : frequency */
                     75:     case 2:                    /* tone 1 : frequency */
                     76:     case 4:                    /* tone 2 : frequency */
                     77:       R->Period[c] = R->UpdateStep * R->Register[r];
                     78:       if (R->Period[c] == 0)
                     79:         R->Period[c] = R->UpdateStep;
                     80:       if (r == 4) {
                     81:         /* update noise shift frequency */
                     82:         if ((R->Register[6] & 0x03) == 0x03)
                     83:           R->Period[3] = 2 * R->Period[2];
                     84:       }
                     85:       break;
                     86:     case 1:                    /* tone 0 : volume */
                     87:     case 3:                    /* tone 1 : volume */
                     88:     case 5:                    /* tone 2 : volume */
                     89:     case 7:                    /* noise  : volume */
                     90:       R->Volume[c] = R->VolTable[data & 0x0f];
                     91:       break;
                     92:     case 6:                    /* noise  : frequency, mode */
                     93:       {
                     94:         int n = R->Register[6];
                     95:         R->NoiseFB = (n & 4) ? FB_WNOISE : FB_PNOISE;
                     96:         n &= 3;
                     97:         /* N/512,N/1024,N/2048,Tone #3 output */
                     98:         R->Period[3] =
                     99:           (n == 3) ? 2 * R->Period[2] : (R->UpdateStep << (5 + n));
                    100: 
                    101:         /* reset noise shifter */
                    102:         R->RNG = NG_PRESET;
                    103:         R->Output[3] = R->RNG & 1;
                    104:       }
                    105:       break;
                    106:     }
                    107:   } else {
                    108:     int r = R->LastRegister;
                    109:     int c = r / 2;
                    110: 
                    111:     switch (r) {
                    112:     case 0:                    /* tone 0 : frequency */
                    113:     case 2:                    /* tone 1 : frequency */
                    114:     case 4:                    /* tone 2 : frequency */
                    115:       R->Register[r] = (R->Register[r] & 0x0f) | ((data & 0x3f) << 4);
                    116:       R->Period[c] = R->UpdateStep * R->Register[r];
                    117:       if (R->Period[c] == 0)
                    118:         R->Period[c] = R->UpdateStep;
                    119:       if (r == 4) {
                    120:         /* update noise shift frequency */
                    121:         if ((R->Register[6] & 0x03) == 0x03)
                    122:           R->Period[3] = 2 * R->Period[2];
                    123:       }
                    124:       break;
                    125:     }
                    126:   }
                    127: }
                    128: 
                    129: void SN76496Update(int chip, uint16 *buffer, int length)
                    130: {
                    131:   int i;
                    132:   struct SN76496 *R = &sn[chip];
                    133: 
                    134:   /* If the volume is 0, increase the counter */
                    135:   for (i = 0; i < 4; i++) {
                    136:     if (R->Volume[i] == 0) {
                    137:       /* note that I do count += length, NOT count = length + 1. You might
                    138:          think it's the same since the volume is 0, but doing the latter
                    139:          could cause interferencies when the program is rapidly modulating
                    140:          the volume. */
                    141:       if (R->Count[i] <= length * STEP)
                    142:         R->Count[i] += length * STEP;
                    143:     }
                    144:   }
                    145: 
                    146:   while (length > 0) {
                    147:     int vol[4];
                    148:     unsigned int out;
                    149:     int left;
                    150: 
                    151:     /* vol[] keeps track of how long each square wave stays */
                    152:     /* in the 1 position during the sample period. */
                    153:     vol[0] = vol[1] = vol[2] = vol[3] = 0;
                    154: 
                    155:     for (i = 0; i < 3; i++) {
                    156:       if (R->Output[i])
                    157:         vol[i] += R->Count[i];
                    158:       R->Count[i] -= STEP;
                    159:       /* Period[i] is the half period of the square wave. Here, in each */
                    160:       /* loop I add Period[i] twice, so that at the end of the loop the */
                    161:       /* square wave is in the same status (0 or 1) it was at the start. */
                    162:       /* vol[i] is also incremented by Period[i], since the wave has been 1 */
                    163:       /* exactly half of the time, regardless of the initial position. */
                    164:       /* If we exit the loop in the middle, Output[i] has to be inverted */
                    165:       /* and vol[i] incremented only if the exit status of the square */
                    166:       /* wave is 1. */
                    167:       while (R->Count[i] <= 0) {
                    168:         R->Count[i] += R->Period[i];
                    169:         if (R->Count[i] > 0) {
                    170:           R->Output[i] ^= 1;
                    171:           if (R->Output[i])
                    172:             vol[i] += R->Period[i];
                    173:           break;
                    174:         }
                    175:         R->Count[i] += R->Period[i];
                    176:         vol[i] += R->Period[i];
                    177:       }
                    178:       if (R->Output[i])
                    179:         vol[i] -= R->Count[i];
                    180:     }
                    181: 
                    182:     left = STEP;
                    183:     do {
                    184:       int nextevent;
                    185: 
                    186:       if (R->Count[3] < left)
                    187:         nextevent = R->Count[3];
                    188:       else
                    189:         nextevent = left;
                    190:       if (R->Output[3])
                    191:         vol[3] += R->Count[3];
                    192:       R->Count[3] -= nextevent;
                    193:       if (R->Count[3] <= 0) {
                    194:         if (R->RNG & 1)
                    195:           R->RNG ^= R->NoiseFB;
                    196:         R->RNG >>= 1;
                    197:         R->Output[3] = R->RNG & 1;
                    198:         R->Count[3] += R->Period[3];
                    199:         if (R->Output[3])
                    200:           vol[3] += R->Period[3];
                    201:       }
                    202:       if (R->Output[3])
                    203:         vol[3] -= R->Count[3];
                    204:       left -= nextevent;
                    205:     } while (left > 0);
                    206: 
                    207:     out = vol[0] * R->Volume[0] + vol[1] * R->Volume[1] +
                    208:       vol[2] * R->Volume[2] + vol[3] * R->Volume[3];
                    209:     if (out > MAX_OUTPUT * STEP)
                    210:       out = MAX_OUTPUT * STEP;
                    211:     *(buffer++) = out / STEP;
                    212:     length--;
                    213:   }
                    214: }
                    215: 
                    216: static void SN76496_set_clock(int chip, int clock)
                    217: {
                    218:   struct SN76496 *R = &sn[chip];
                    219: 
                    220:   /* the base clock for the tone generators is the chip clock divided by 16; */
                    221:   /* for the noise generator, it is clock / 256. */
                    222:   /* Here we calculate the number of steps which happen during one sample */
                    223:   /* at the given sample rate. No. of events = sample rate / (clock/16). */
                    224:   /* STEP is a multiplier used to turn the fraction into a fixed point */
                    225:   /* number. */
                    226:   R->UpdateStep = ((double)STEP * R->SampleRate * 16) / clock;
                    227: }
                    228: 
                    229: static void SN76496_set_gain(int chip, int gain)
                    230: {
                    231:   struct SN76496 *R = &sn[chip];
                    232:   int i;
                    233:   double out;
                    234: 
                    235:   gain &= 0xff;
                    236:   /* increase max output basing on gain (0.2 dB per step) */
                    237:   out = MAX_OUTPUT / 3;
                    238:   while (gain-- > 0)
                    239:     out *= 1.023292992;         /* = (10 ^ (0.2/20)) */
                    240:   /* build volume table (2dB per step) */
                    241:   for (i = 0; i < 15; i++) {
                    242:     /* limit volume to avoid clipping */
                    243:     if (out > MAX_OUTPUT / 3)
                    244:       R->VolTable[i] = MAX_OUTPUT / 3;
                    245:     else
                    246:       R->VolTable[i] = out;
                    247:     out /= 1.258925412;         /* = 10 ^ (2/20) = 2dB */
                    248:   }
                    249:   R->VolTable[15] = 0;
                    250: }
                    251: 
                    252: int SN76496Init(int chip, int clock, int gain, int sample_rate)
                    253: {
                    254:   int i;
                    255:   struct SN76496 *R = &sn[chip];
                    256:   char name[40];
                    257: 
                    258:   R->SampleRate = sample_rate;
                    259:   SN76496_set_clock(chip, clock);
                    260: 
                    261:   for (i = 0; i < 4; i++)
                    262:     R->Volume[i] = 0;
                    263: 
                    264:   R->LastRegister = 0;
                    265:   for (i = 0; i < 8; i += 2) {
                    266:     R->Register[i] = 0;
                    267:     R->Register[i + 1] = 0x0f;  /* volume = 0 */
                    268:   }
                    269: 
                    270:   for (i = 0; i < 4; i++) {
                    271:     R->Output[i] = 0;
                    272:     R->Period[i] = R->Count[i] = R->UpdateStep;
                    273:   }
                    274:   R->RNG = NG_PRESET;
                    275:   R->Output[3] = R->RNG & 1;
                    276:   SN76496_set_gain(chip, gain & 0xff);
                    277: 
                    278:   return 0;
                    279: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.