|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.