|
|
1.1 root 1: /*
2: Hatari - dmaSnd.c
3:
4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
6:
7: STE DMA sound emulation. Does not seem to be very hard at first glance,
8: but since the DMA sound has to be mixed together with the PSG sound and
9: the output frequency of the host computer differs from the DMA sound
10: frequency, the copy function is a little bit complicated.
1.1.1.7 ! root 11: For reducing copy latency, we set a cycle-interrupt event with
! 12: CycInt_AddRelativeInterrupt to occur just after a sound frame should be
! 13: finished. There we update the sound.
! 14: The update function also triggers the ST interrupts (Timer A and MFP-i7)
! 15: which are often used in ST programs for setting a new sound frame after
! 16: the old one has finished.
! 17:
! 18: Falcon sound emulation is all taken into account in crossbar.c
1.1 root 19:
20:
21: Hardware I/O registers:
22:
23: $FF8900 (word) : DMA sound control register
24: $FF8903 (byte) : Frame Start Hi
25: $FF8905 (byte) : Frame Start Mi
26: $FF8907 (byte) : Frame Start Lo
27: $FF8909 (byte) : Frame Count Hi
28: $FF890B (byte) : Frame Count Mi
29: $FF890D (byte) : Frame Count Lo
30: $FF890F (byte) : Frame End Hi
31: $FF8911 (byte) : Frame End Mi
32: $FF8913 (byte) : Frame End Lo
33: $FF8920 (word) : Sound Mode Control (frequency, mono/stereo)
34: $FF8922 (byte) : Microwire Data Register
35: $FF8924 (byte) : Microwire Mask Register
1.1.1.7 ! root 36:
! 37:
! 38: The Microwire and LMC 1992 commands :
! 39:
! 40: a command looks like: 10 CCC DDD DDD
! 41:
! 42: chipset address : 10
! 43: command :
! 44: 000 XXX XDD Mixing
! 45: 00 : DMA and (YM2149 - 12dB) mixing
! 46: 01 : DMA and YM2149 mixing
! 47: 10 : DMA only
! 48: 11 : Reserved
! 49:
! 50: 001 XXD DDD Bass
! 51: 0 000 : -12 dB
! 52: 0 110 : 0 dB
! 53: 1 100 : +12 dB
! 54:
! 55: 002 XXD DDD Treble
! 56: 0 000 : -12 dB
! 57: 0 110 : 0 dB
! 58: 1 100 : +12 dB
! 59:
! 60: 003 DDD DDD Master volume
! 61: 000 000 : -80 dB
! 62: 010 100 : -40 dB
! 63: 101 XXX : 0 dB
! 64:
! 65: 004 XDD DDD Right channel volume
! 66: 00 000 : -40 dB
! 67: 01 010 : -20 dB
! 68: 10 1XX : 0 dB
! 69:
! 70: 005 XDD DDD Left channel volume
! 71: 00 000 : -40 dB
! 72: 01 010 : -20 dB
! 73: 10 1XX : 0 dB
! 74:
! 75: Other : undefined
! 76:
! 77: LMC1992 IIR code Copyright by David Savinkoff 2010
! 78:
! 79: A first order bass filter is multiplied with a
! 80: first order treble filter to make a single
! 81: second order IIR shelf filter.
! 82:
! 83: Sound is stereo filtered by Boosting or Cutting
! 84: the Bass and Treble by +/-12dB in 2dB steps.
! 85:
! 86: This filter sounds exactly as the Atari TT or STE.
! 87: Sampling frequency = selectable
! 88: Bass turnover = 118.276Hz (8.2nF on LM1992 bass)
! 89: Treble turnover = 8438.756Hz (8.2nF on LM1992 treble)
1.1 root 90: */
1.1.1.7 ! root 91:
! 92:
1.1.1.5 root 93: const char DmaSnd_fileid[] = "Hatari dmaSnd.c : " __DATE__ " " __TIME__;
1.1 root 94:
95: #include "main.h"
96: #include "audio.h"
1.1.1.3 root 97: #include "configuration.h"
1.1 root 98: #include "dmaSnd.h"
1.1.1.7 ! root 99: #include "cycInt.h"
1.1 root 100: #include "ioMem.h"
1.1.1.6 root 101: #include "log.h"
1.1 root 102: #include "memorySnapShot.h"
103: #include "mfp.h"
104: #include "sound.h"
1.1.1.3 root 105: #include "stMemory.h"
1.1.1.7 ! root 106:
! 107: #define TONE_STEPS 13
! 108:
! 109:
! 110: /* Global variables that can be changed/read from other parts of Hatari */
! 111: void DmaSnd_Init_Bass_and_Treble_Tables(void);
! 112:
! 113: static void DmaSnd_Set_Tone_Level(int set_bass, int set_treb);
! 114: static float DmaSnd_IIRfilterL(float xn);
! 115: static float DmaSnd_IIRfilterR(float xn);
! 116: static struct first_order_s *DmaSnd_Treble_Shelf(float g, float fc, float Fs);
! 117: static struct first_order_s *DmaSnd_Bass_Shelf(float g, float fc, float Fs);
! 118: static Sint8 DmaSnd_LowPassFilterLeft(Sint8 in);
! 119: static Sint8 DmaSnd_LowPassFilterMono(Sint8 in);
! 120: static Sint8 DmaSnd_LowPassFilterRight(Sint8 in);
1.1 root 121:
122:
123: Uint16 nDmaSoundControl; /* Sound control register */
124:
1.1.1.7 ! root 125: struct first_order_s { float a1, b0, b1; };
! 126: struct second_order_s { float a1, a2, b0, b1, b2; };
! 127:
! 128: struct dma_s {
! 129: Uint16 soundMode; /* Sound mode register */
! 130: Uint32 frameStartAddr; /* Sound frame start */
! 131: Uint32 frameEndAddr; /* Sound frame end */
! 132: Uint32 frameCounter_int; /* Counter in current sound frame, integer part */
! 133: Uint32 frameCounter_dec; /* Counter in current sound frame, decimal part */
! 134: Uint32 frameLen; /* Length of the frame */
! 135: };
! 136:
! 137: struct microwire_s {
! 138: Uint16 data; /* Microwire Data register */
! 139: Uint16 mask; /* Microwire Mask register */
! 140: int mwTransferSteps; /* Microwire shifting counter */
! 141: Uint16 mixing; /* Mixing command */
! 142: Uint16 bass; /* Bass command */
! 143: Uint16 treble; /* Treble command */
! 144: Uint16 masterVolume; /* Master volume command */
! 145: Uint16 leftVolume; /* Left channel volume command */
! 146: Uint16 rightVolume; /* Right channel volume command */
! 147: };
! 148:
! 149: struct lmc1992_s {
! 150: struct first_order_s bass_table[TONE_STEPS];
! 151: struct first_order_s treb_table[TONE_STEPS];
! 152: float coef[5]; /* IIR coefs */
! 153: /*float gain;*/ /* IIR gain*/
! 154: };
! 155:
! 156: static struct dma_s dma;
! 157: static struct microwire_s microwire;
! 158: static struct lmc1992_s lmc1992;
! 159:
! 160: /* dB = 20log(gain) : gain = antilog(dB/20) */
! 161: /* Table gain values = (int)(powf(10.0, dB/20.0)*65536.0 + 0.5) 2dB steps */
! 162:
! 163:
! 164: /* Values for LMC1992 Master volume control (*65536) */
! 165: static const Uint16 LMC1992_Master_Volume_Table[64] =
! 166: {
! 167: 7, 8, 10, 13, 16, 21, 26, 33, 41, 52, /* -80dB */
! 168: 66, 83, 104, 131, 165, 207, 261, 328, 414, 521, /* -60dB */
! 169: 655, 825, 1039, 1308, 1646, 2072, 2609, 3285, 4135, 5206, /* -40dB */
! 170: 6554, 8250, 10387, 13076, 16462, 20724, 26090, 32846, 41350, 52057, /* -20dB */
! 171: 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, /* 0dB */
! 172: 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, /* 0dB */
! 173: 65535, 65535, 65535, 65535 /* 0dB */
! 174: };
1.1.1.6 root 175:
1.1.1.7 ! root 176: /* Values for LMC1992 Left and right volume control (*65536) */
! 177: static const Uint16 LMC1992_LeftRight_Volume_Table[32] =
! 178: {
! 179: 655, 825, 1039, 1308, 1646, 2072, 2609, 3285, 4135, 5206, /* -40dB */
! 180: 6554, 8250, 10387, 13076, 16462, 20724, 26090, 32846, 41350, 52057, /* -20dB */
! 181: 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, /* 0dB */
! 182: 65535, 65535 /* 0dB */
1.1 root 183: };
184:
1.1.1.7 ! root 185: /* Values for LMC1992 BASS and TREBLE */
! 186: static const Sint16 LMC1992_Bass_Treble_Table[16] =
! 187: {
! 188: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 12, 12, 12
! 189: };
1.1 root 190:
1.1.1.7 ! root 191: static const int DmaSndSampleRates[4] =
1.1.1.3 root 192: {
1.1.1.7 ! root 193: CPU_FREQ / 1280, /* 6258 Hz */
! 194: CPU_FREQ / 640, /* 12517 Hz */
! 195: CPU_FREQ / 320, /* 25033 Hz */
! 196: CPU_FREQ / 160 /* 50066 Hz */
1.1.1.3 root 197: };
198:
199:
1.1 root 200: /*-----------------------------------------------------------------------*/
1.1.1.3 root 201: /**
1.1.1.7 ! root 202: * Init DMA sound variables.
! 203: */
! 204: void DmaSnd_Init(void)
! 205: {
! 206: DmaSnd_Reset(1);
! 207: }
! 208:
! 209: /**
1.1.1.3 root 210: * Reset DMA sound variables.
211: */
1.1.1.4 root 212: void DmaSnd_Reset(bool bCold)
1.1 root 213: {
214: nDmaSoundControl = 0;
215:
216: if (bCold)
217: {
1.1.1.7 ! root 218: dma.soundMode = 3;
! 219: microwire.masterVolume = 65535;
! 220: microwire.leftVolume = 65535;
! 221: microwire.rightVolume = 65535;
! 222: microwire.mixing = 0;
! 223: microwire.bass = 6;
! 224: microwire.treble = 6;
1.1 root 225: }
1.1.1.4 root 226:
1.1.1.7 ! root 227: /* Initialise microwire LMC1992 IIR filter parameters */
! 228: DmaSnd_Init_Bass_and_Treble_Tables();
1.1.1.6 root 229:
1.1.1.7 ! root 230: microwire.mwTransferSteps = 0;
1.1 root 231: }
232:
233: /*-----------------------------------------------------------------------*/
1.1.1.3 root 234: /**
235: * Save/Restore snapshot of local variables ('MemorySnapShot_Store' handles type)
236: */
1.1.1.4 root 237: void DmaSnd_MemorySnapShot_Capture(bool bSave)
1.1 root 238: {
239: /* Save/Restore details */
240: MemorySnapShot_Store(&nDmaSoundControl, sizeof(nDmaSoundControl));
1.1.1.7 ! root 241: MemorySnapShot_Store(&dma, sizeof(dma));
! 242: MemorySnapShot_Store(µwire, sizeof(microwire));
! 243: MemorySnapShot_Store(&lmc1992, sizeof(lmc1992));
1.1 root 244: }
245:
246:
1.1.1.7 ! root 247: static int DmaSnd_DetectSampleRate(void)
1.1.1.3 root 248: {
1.1.1.7 ! root 249: return DmaSndSampleRates[dma.soundMode & 3];
1.1.1.3 root 250: }
251:
252:
1.1 root 253: /*-----------------------------------------------------------------------*/
1.1.1.3 root 254: /**
255: * This function is called when a new sound frame is started.
256: * It copies the start and end address from the I/O registers, calculates
257: * the sample length, etc.
258: */
1.1 root 259: static void DmaSnd_StartNewFrame(void)
260: {
261: int nCyclesForFrame;
1.1.1.4 root 262:
1.1.1.7 ! root 263: dma.frameStartAddr = (IoMem[0xff8903] << 16) | (IoMem[0xff8905] << 8) | (IoMem[0xff8907] & ~1);
! 264: dma.frameEndAddr = (IoMem[0xff890f] << 16) | (IoMem[0xff8911] << 8) | (IoMem[0xff8913] & ~1);
1.1 root 265:
1.1.1.7 ! root 266: dma.frameCounter_int = 0;
! 267: dma.frameCounter_dec = 0;
! 268:
! 269: dma.frameLen = dma.frameEndAddr - dma.frameStartAddr;
1.1 root 270:
1.1.1.7 ! root 271: if (dma.frameEndAddr <= dma.frameStartAddr)
1.1.1.6 root 272: {
273: Log_Printf(LOG_WARN, "DMA snd: Illegal buffer size (from 0x%x to 0x%x)\n",
1.1.1.7 ! root 274: dma.frameStartAddr, dma.frameEndAddr);
! 275: dma.frameLen = 0;
1.1.1.6 root 276: return;
277: }
278:
1.1 root 279: /* To get smooth sound, set an "interrupt" for the end of the frame that
280: * updates the sound mix buffer. */
1.1.1.7 ! root 281: nCyclesForFrame = dma.frameLen * (CPU_FREQ / DmaSnd_DetectSampleRate());
! 282: if (!(dma.soundMode & DMASNDMODE_MONO)) /* Is it stereo? */
1.1 root 283: nCyclesForFrame = nCyclesForFrame / 2;
1.1.1.7 ! root 284: CycInt_AddRelativeInterrupt(nCyclesForFrame, INT_CPU_CYCLE, INTERRUPT_DMASOUND);
1.1 root 285: }
286:
287:
288: /*-----------------------------------------------------------------------*/
1.1.1.3 root 289: /**
1.1.1.7 ! root 290: * End-of-frame has been reached. Raise interrupts if needed.
1.1.1.6 root 291: * Returns true if DMA sound processing should be stopped now and false
1.1.1.7 ! root 292: * if it continues (DMA PLAYLOOP mode).
1.1.1.3 root 293: */
1.1.1.7 ! root 294: static inline int DmaSnd_EndOfFrameReached(void)
1.1 root 295: {
1.1.1.7 ! root 296: /* Raise end-of-frame interrupts (MFP-i7 and Time-A) */
! 297: MFP_InputOnChannel(MFP_TIMER_GPIP7_BIT, MFP_IERA, &MFP_IPRA);
! 298: if (MFP_TACR == 0x08) /* Is timer A in Event Count mode? */
! 299: MFP_TimerA_EventCount_Interrupt();
1.1 root 300:
1.1.1.7 ! root 301: if (nDmaSoundControl & DMASNDCTRL_PLAYLOOP)
! 302: {
! 303: DmaSnd_StartNewFrame();
1.1 root 304: }
1.1.1.7 ! root 305: else
1.1.1.6 root 306: {
1.1.1.7 ! root 307: nDmaSoundControl &= ~DMASNDCTRL_PLAY;
! 308: return true;
1.1.1.6 root 309: }
310:
1.1.1.7 ! root 311: return false;
1.1 root 312: }
313:
314:
315: /*-----------------------------------------------------------------------*/
1.1.1.3 root 316: /**
317: * Mix DMA sound sample with the normal PSG sound samples.
1.1.1.6 root 318: * Note: We adjust the volume level of the 8-bit DMA samples to factor
1.1.1.7 ! root 319: * 0.75 compared to the PSG sound samples.
1.1.1.3 root 320: */
1.1 root 321: void DmaSnd_GenerateSamples(int nMixBufIdx, int nSamplesToGenerate)
322: {
1.1.1.7 ! root 323: Uint32 FreqRatio;
! 324: int i, intPart;
! 325: int nBufIdx;
! 326: Sint8 *pFrameStart, FrameMono = 0, FrameLeft = 0, FrameRight = 0;
! 327: unsigned n;
1.1.1.6 root 328:
1.1 root 329: if (!(nDmaSoundControl & DMASNDCTRL_PLAY))
330: return;
331:
1.1.1.7 ! root 332: pFrameStart = (Sint8 *)&STRam[dma.frameStartAddr];
1.1 root 333:
1.1.1.7 ! root 334: /* Compute ratio between hatari's sound frequency and host computer's sound frequency */
! 335: FreqRatio = (Uint32)(DmaSnd_DetectSampleRate() / (double)nAudioFrequency * 65536.0 + 0.5);
! 336:
! 337: if (dma.soundMode & DMASNDMODE_MONO)
1.1.1.3 root 338: {
339: /* Mono 8-bit */
1.1.1.7 ! root 340:
! 341: n = dma.frameCounter_int;
! 342:
1.1 root 343: for (i = 0; i < nSamplesToGenerate; i++)
344: {
1.1.1.7 ! root 345: /* Is end of DMA buffer reached ? */
! 346: if (dma.frameCounter_int >= dma.frameLen) {
! 347: if (DmaSnd_EndOfFrameReached())
! 348: break;
! 349: else
! 350: { n = dma.frameCounter_int;
! 351: pFrameStart = (Sint8 *)&STRam[dma.frameStartAddr];
! 352: }
! 353: }
! 354:
! 355: /* Apply anti-aliasing low pass filter ? (mono) */
! 356: for ( ; n <= dma.frameCounter_int; n++) {
! 357: FrameMono = DmaSnd_LowPassFilterMono(pFrameStart[n]);
! 358: }
! 359:
1.1 root 360: nBufIdx = (nMixBufIdx + i) % MIXBUFFER_SIZE;
1.1.1.7 ! root 361:
! 362: switch (microwire.mixing) {
! 363: case 1:
! 364: /* DMA and YM2149 mixing */
! 365: MixBuffer[nBufIdx][0] = MixBuffer[nBufIdx][0] + (Sint16)FrameMono * -(256*3/4)/4;
! 366: break;
! 367: case 2:
! 368: /* DMA sound only */
! 369: MixBuffer[nBufIdx][0] = (Sint16)FrameMono * -(256*3/4)/4;
! 370: break;
! 371: default:
! 372: /* DMA and (YM2149 - 12dB) mixing */
! 373: /* instead of 16462 (-12dB), we approximate by 16384 */
! 374: MixBuffer[nBufIdx][0] = ((Sint16)FrameMono * -(256*3/4)/4) +
! 375: (((Sint32)MixBuffer[nBufIdx][0] * 16384)/65536);
! 376: break;
! 377: }
! 378: MixBuffer[nBufIdx][1] = MixBuffer[nBufIdx][0];
! 379:
! 380: /* Increase ratio pointer to next DMA sample */
! 381: dma.frameCounter_dec += FreqRatio;
! 382: if (dma.frameCounter_dec >= 65536) {
! 383: intPart = dma.frameCounter_dec >> 16;
! 384: dma.frameCounter_int += intPart;
! 385: dma.frameCounter_dec -= intPart* 65536;
! 386: }
1.1 root 387: }
388: }
389: else
390: {
1.1.1.3 root 391: /* Stereo 8-bit */
1.1.1.7 ! root 392:
! 393: FreqRatio *= 2;
! 394: n = dma.frameCounter_int & ~1;
! 395:
1.1 root 396: for (i = 0; i < nSamplesToGenerate; i++)
397: {
1.1.1.7 ! root 398: /* Is end of DMA buffer reached ? */
! 399: if ((dma.frameCounter_int | 1) >= dma.frameLen) {
! 400: if (DmaSnd_EndOfFrameReached())
! 401: break;
! 402: else
! 403: { n = dma.frameCounter_int & ~1;
! 404: pFrameStart = (Sint8 *)&STRam[dma.frameStartAddr];
! 405: }
! 406: }
! 407:
! 408: /* Apply anti-aliasing low pass filter ? (stereo) */
! 409: for ( ; n <= (dma.frameCounter_int & ~1); n += 2) {
! 410: FrameLeft = DmaSnd_LowPassFilterLeft(pFrameStart[n]);
! 411: FrameRight = DmaSnd_LowPassFilterRight(pFrameStart[n+1]);
! 412: }
! 413:
1.1 root 414: nBufIdx = (nMixBufIdx + i) % MIXBUFFER_SIZE;
1.1.1.7 ! root 415:
! 416: switch (microwire.mixing) {
! 417: case 1:
! 418: /* DMA and YM2149 mixing */
! 419: MixBuffer[nBufIdx][0] = MixBuffer[nBufIdx][0] + (Sint16)FrameLeft * -(256*3/4)/4;
! 420: MixBuffer[nBufIdx][1] = MixBuffer[nBufIdx][1] + (Sint16)FrameRight * -(256*3/4)/4;
! 421: break;
! 422: case 2:
! 423: /* DMA sound only */
! 424: MixBuffer[nBufIdx][0] = (Sint16)FrameLeft * -(256*3/4)/4;
! 425: MixBuffer[nBufIdx][1] = (Sint16)FrameRight * -(256*3/4)/4;
! 426: break;
! 427: default:
! 428: /* DMA and (YM2149 - 12dB) mixing */
! 429: /* instead of 16462 (-12dB), we approximate by 16384 */
! 430: MixBuffer[nBufIdx][0] = ((Sint16)FrameLeft * -(256*3/4)/4) +
! 431: (((Sint32)MixBuffer[nBufIdx][0] * 16384)/65536);
! 432: MixBuffer[nBufIdx][1] = ((Sint16)FrameRight * -(256*3/4)/4) +
! 433: (((Sint32)MixBuffer[nBufIdx][1] * 16384)/65536);
! 434: break;
! 435: }
! 436:
! 437: /* Increase ratio pointer to next DMA sample */
! 438: dma.frameCounter_dec += FreqRatio;
! 439: if (dma.frameCounter_dec >= 65536) {
! 440: intPart = dma.frameCounter_dec >> 16;
! 441: dma.frameCounter_int += intPart;
! 442: dma.frameCounter_dec -= intPart* 65536;
! 443: }
1.1 root 444: }
445: }
1.1.1.7 ! root 446:
! 447: /* Apply LMC1992 sound modifications (Bass and Treble)
! 448: The Bass and Treble get samples at nAudioFrequency rate.
! 449: The tone control's sampling frequency must be at least 22050 Hz to sound good.
! 450: */
! 451: for (i = 0; i < nSamplesToGenerate; i++) {
! 452: nBufIdx = (nMixBufIdx + i) % MIXBUFFER_SIZE;
! 453: MixBuffer[nBufIdx][0] = 0.5 + DmaSnd_IIRfilterL(MixBuffer[nBufIdx][0]);
! 454: MixBuffer[nBufIdx][1] = 0.5 + DmaSnd_IIRfilterR(MixBuffer[nBufIdx][1]);
! 455: }
! 456:
! 457: /* Apply LMC1992 sound modifications (Left, Right and Master Volume) */
! 458: for (i = 0; i < nSamplesToGenerate; i++) {
! 459: nBufIdx = (nMixBufIdx + i) % MIXBUFFER_SIZE;
! 460: MixBuffer[nBufIdx][0] = (((MixBuffer[nBufIdx][0] * microwire.leftVolume) >> 16) * microwire.masterVolume) >> 16;
! 461: MixBuffer[nBufIdx][1] = (((MixBuffer[nBufIdx][1] * microwire.rightVolume) >> 16) * microwire.masterVolume) >> 16;
! 462: }
1.1 root 463: }
464:
465:
466: /*-----------------------------------------------------------------------*/
1.1.1.3 root 467: /**
468: * DMA sound end of frame "interrupt". Used for updating the sound after
469: * a frame has been finished.
470: */
1.1 root 471: void DmaSnd_InterruptHandler(void)
472: {
473: /* Remove this interrupt from list and re-order */
1.1.1.7 ! root 474: CycInt_AcknowledgeInterrupt();
1.1 root 475:
476: /* Update sound */
477: Sound_Update();
478: }
479:
480:
481: /*-----------------------------------------------------------------------*/
1.1.1.3 root 482: /**
483: * Create actual position for frame count registers.
484: */
1.1 root 485: static Uint32 DmaSnd_GetFrameCount(void)
486: {
487: Uint32 nActCount;
488:
489: if (nDmaSoundControl & DMASNDCTRL_PLAY)
1.1.1.7 ! root 490: nActCount = dma.frameStartAddr + (int)dma.frameCounter_int;
1.1 root 491: else
492: nActCount = (IoMem[0xff8903] << 16) | (IoMem[0xff8905] << 8) | IoMem[0xff8907];
493:
494: nActCount &= ~1;
495:
496: return nActCount;
497: }
498:
499:
500: /*-----------------------------------------------------------------------*/
1.1.1.3 root 501: /**
502: * Read word from sound control register (0xff8900).
503: */
1.1 root 504: void DmaSnd_SoundControl_ReadWord(void)
505: {
506: IoMem_WriteWord(0xff8900, nDmaSoundControl);
1.1.1.6 root 507:
1.1.1.7 ! root 508: LOG_TRACE(TRACE_DMASND, "DMA snd control read: 0x%04x\n", nDmaSoundControl);
1.1 root 509: }
510:
511:
512: /*-----------------------------------------------------------------------*/
1.1.1.3 root 513: /**
514: * Read word from sound frame count high register (0xff8909).
515: */
1.1 root 516: void DmaSnd_FrameCountHigh_ReadByte(void)
517: {
518: IoMem_WriteByte(0xff8909, DmaSnd_GetFrameCount() >> 16);
519: }
520:
521:
522: /*-----------------------------------------------------------------------*/
1.1.1.3 root 523: /**
524: * Read word from sound frame count medium register (0xff890b).
525: */
1.1 root 526: void DmaSnd_FrameCountMed_ReadByte(void)
527: {
528: IoMem_WriteByte(0xff890b, DmaSnd_GetFrameCount() >> 8);
529: }
530:
531:
532: /*-----------------------------------------------------------------------*/
1.1.1.3 root 533: /**
534: * Read word from sound frame count low register (0xff890d).
535: */
1.1 root 536: void DmaSnd_FrameCountLow_ReadByte(void)
537: {
538: IoMem_WriteByte(0xff890d, DmaSnd_GetFrameCount());
539: }
540:
541:
542: /*-----------------------------------------------------------------------*/
1.1.1.3 root 543: /**
1.1.1.7 ! root 544: * Read word from sound mode register (0xff8921).
1.1.1.3 root 545: */
1.1.1.7 ! root 546: void DmaSnd_SoundModeCtrl_ReadByte(void)
1.1 root 547: {
1.1.1.7 ! root 548: IoMem_WriteByte(0xff8921, dma.soundMode);
1.1.1.6 root 549:
1.1.1.7 ! root 550: LOG_TRACE(TRACE_DMASND, "DMA snd mode read: 0x%02x\n", dma.soundMode);
1.1 root 551: }
552:
553:
554: /*-----------------------------------------------------------------------*/
1.1.1.3 root 555: /**
1.1.1.7 ! root 556: * Write word to sound mode register (0xff8921).
1.1.1.3 root 557: */
1.1.1.7 ! root 558: void DmaSnd_SoundModeCtrl_WriteByte(void)
1.1 root 559: {
1.1.1.7 ! root 560: LOG_TRACE(TRACE_DMASND, "DMA snd mode write: 0x%02x\n", IoMem_ReadWord(0xff8921));
1.1.1.3 root 561:
1.1.1.7 ! root 562: /* STE or TT - hopefully STFM emulation never gets here :)
! 563: * We maskout to only hit bits that exist on a real STE
! 564: */
! 565: dma.soundMode = (IoMem_ReadByte(0xff8921) & 0x8f);
! 566: /* we also write the masked value back into the emulated hw registers so we have a correct value there */
! 567: IoMem_WriteByte(0xff8921, dma.soundMode);
1.1 root 568: }
569:
1.1.1.6 root 570: /* ---------------------- Microwire / LMC 1992 ---------------------- */
571:
1.1.1.3 root 572: /**
1.1.1.4 root 573: * Handle the shifting/rotating of the microwire registers
574: * The microwire regs should be done after 16 usec = 32 NOPs = 128 cycles.
575: * That means we have to shift 16 times with a delay of 8 cycles.
1.1.1.3 root 576: */
1.1.1.4 root 577: void DmaSnd_InterruptHandler_Microwire(void)
1.1 root 578: {
1.1.1.7 ! root 579: Uint8 i, bit;
! 580: Uint16 saveData;
! 581:
1.1.1.4 root 582: /* Remove this interrupt from list and re-order */
1.1.1.7 ! root 583: CycInt_AcknowledgeInterrupt();
1.1.1.4 root 584:
1.1.1.7 ! root 585: --microwire.mwTransferSteps;
1.1.1.4 root 586:
587: /* Shift data register until it becomes zero. */
1.1.1.7 ! root 588: if (microwire.mwTransferSteps > 1)
1.1 root 589: {
1.1.1.7 ! root 590: IoMem_WriteWord(0xff8922, microwire.data<<(16-microwire.mwTransferSteps));
1.1 root 591: }
592: else
593: {
1.1.1.4 root 594: /* Paradox XMAS 2004 demo continuesly writes to the data
595: * register, but still expects to read a zero inbetween,
596: * so we have to output a zero before we're really done
597: * with the transfer. */
1.1 root 598: IoMem_WriteWord(0xff8922, 0);
599: }
1.1.1.4 root 600:
601: /* Rotate mask register */
1.1.1.7 ! root 602: IoMem_WriteWord(0xff8924, (microwire.mask<<(16-microwire.mwTransferSteps))
! 603: |(microwire.mask>>microwire.mwTransferSteps));
1.1.1.4 root 604:
1.1.1.7 ! root 605: if (microwire.mwTransferSteps > 0)
1.1.1.4 root 606: {
1.1.1.7 ! root 607: CycInt_AddRelativeInterrupt(8, INT_CPU_CYCLE, INTERRUPT_DMASOUND_MICROWIRE);
1.1.1.4 root 608: }
1.1.1.7 ! root 609: else {
! 610: /* Decode the address + command word according to the binary mask */
! 611: bit = 0;
! 612: saveData = microwire.data;
! 613: microwire.data = 0;
! 614: for (i=0; i<16; i++) {
! 615: if ((microwire.mask >> i) & 1) {
! 616: microwire.data += ((saveData >> i) & 1) << bit;
! 617: bit ++;
! 618: }
! 619: }
1.1.1.4 root 620:
1.1.1.7 ! root 621: /* The LMC 1992 address should be 10 xxx xxx xxx */
! 622: if ((microwire.data & 0x600) != 0x400)
! 623: return;
! 624:
! 625: /* Update the LMC 1992 commands */
! 626: switch ((microwire.data >> 6) & 0x7) {
! 627: case 0:
! 628: /* Mixing command */
! 629: microwire.mixing = microwire.data & 0x3;
! 630: break;
! 631: case 1:
! 632: /* Bass command */
! 633: microwire.bass = microwire.data & 0xf;
! 634: DmaSnd_Set_Tone_Level(LMC1992_Bass_Treble_Table[microwire.bass],
! 635: LMC1992_Bass_Treble_Table[microwire.treble]);
! 636: break;
! 637: case 2:
! 638: /* Treble command */
! 639: microwire.treble = microwire.data & 0xf;
! 640: DmaSnd_Set_Tone_Level(LMC1992_Bass_Treble_Table[microwire.bass],
! 641: LMC1992_Bass_Treble_Table[microwire.treble]);
! 642: break;
! 643: case 3:
! 644: /* Master volume command */
! 645: microwire.masterVolume = LMC1992_Master_Volume_Table[microwire.data & 0x3f];
! 646: break;
! 647: case 4:
! 648: /* Right channel volume */
! 649: microwire.rightVolume = LMC1992_LeftRight_Volume_Table[microwire.data & 0x1f];
! 650: break;
! 651: case 5:
! 652: /* Left channel volume */
! 653: microwire.leftVolume = LMC1992_LeftRight_Volume_Table[microwire.data & 0x1f];
! 654: break;
! 655: default:
! 656: /* Do nothing */
! 657: break;
! 658: }
! 659: }
! 660: }
1.1.1.4 root 661:
662: /**
663: * Read word from microwire data register (0xff8922).
664: */
665: void DmaSnd_MicrowireData_ReadWord(void)
666: {
667: /* Shifting is done in DmaSnd_InterruptHandler_Microwire! */
1.1.1.6 root 668: LOG_TRACE(TRACE_DMASND, "Microwire data read: 0x%x\n", IoMem_ReadWord(0xff8922));
1.1 root 669: }
670:
671:
1.1.1.3 root 672: /**
673: * Write word to microwire data register (0xff8922).
674: */
1.1 root 675: void DmaSnd_MicrowireData_WriteWord(void)
676: {
1.1.1.4 root 677: /* Only update, if no shift is in progress */
1.1.1.7 ! root 678: if (!microwire.mwTransferSteps)
1.1.1.4 root 679: {
1.1.1.7 ! root 680: microwire.data = IoMem_ReadWord(0xff8922);
1.1.1.4 root 681: /* Start shifting events to simulate a microwire transfer */
1.1.1.7 ! root 682: microwire.mwTransferSteps = 16;
! 683: CycInt_AddRelativeInterrupt(8, INT_CPU_CYCLE, INTERRUPT_DMASOUND_MICROWIRE);
1.1.1.4 root 684: }
685:
1.1.1.6 root 686: LOG_TRACE(TRACE_DMASND, "Microwire data write: 0x%x\n", IoMem_ReadWord(0xff8922));
1.1 root 687: }
688:
689:
1.1.1.3 root 690: /**
691: * Read word from microwire mask register (0xff8924).
692: */
1.1 root 693: void DmaSnd_MicrowireMask_ReadWord(void)
694: {
1.1.1.4 root 695: /* Same as with data register, but mask is rotated, not shifted. */
1.1.1.6 root 696: LOG_TRACE(TRACE_DMASND, "Microwire mask read: 0x%x\n", IoMem_ReadWord(0xff8924));
1.1 root 697: }
698:
699:
1.1.1.3 root 700: /**
701: * Write word to microwire mask register (0xff8924).
702: */
1.1 root 703: void DmaSnd_MicrowireMask_WriteWord(void)
704: {
1.1.1.4 root 705: /* Only update, if no shift is in progress */
1.1.1.7 ! root 706: if (!microwire.mwTransferSteps)
1.1.1.4 root 707: {
1.1.1.7 ! root 708: microwire.mask = IoMem_ReadWord(0xff8924);
1.1.1.4 root 709: }
710:
1.1.1.6 root 711: LOG_TRACE(TRACE_DMASND, "Microwire mask write: 0x%x\n", IoMem_ReadWord(0xff8924));
712: }
713:
714:
1.1.1.7 ! root 715: /*-----------------------------------------------------------------------*/
! 716: /**
! 717: * Write word to sound control register (0xff8900).
! 718: */
! 719: void DmaSnd_SoundControl_WriteWord(void)
1.1.1.6 root 720: {
1.1.1.7 ! root 721: Uint16 nNewSndCtrl;
1.1.1.6 root 722:
1.1.1.7 ! root 723: LOG_TRACE(TRACE_DMASND, "DMA snd control write: 0x%04x\n", IoMem_ReadWord(0xff8900));
1.1.1.6 root 724:
1.1.1.7 ! root 725: nNewSndCtrl = IoMem_ReadWord(0xff8900) & 3;
1.1.1.6 root 726:
1.1.1.7 ! root 727: if (!(nDmaSoundControl & DMASNDCTRL_PLAY) && (nNewSndCtrl & DMASNDCTRL_PLAY))
1.1.1.6 root 728: {
1.1.1.7 ! root 729: //fprintf(stderr, "Turning on DMA sound emulation.\n");
! 730: DmaSnd_StartNewFrame();
1.1.1.6 root 731: }
1.1.1.7 ! root 732: else if ((nDmaSoundControl & DMASNDCTRL_PLAY) && !(nNewSndCtrl & DMASNDCTRL_PLAY))
1.1.1.6 root 733: {
1.1.1.7 ! root 734: //fprintf(stderr, "Turning off DMA sound emulation.\n");
! 735: /* Create samples up until this point with current values */
! 736: Sound_Update();
1.1.1.6 root 737:
1.1.1.7 ! root 738: }
1.1.1.6 root 739:
1.1.1.7 ! root 740: nDmaSoundControl = nNewSndCtrl;
1.1.1.6 root 741: }
742:
743:
1.1.1.7 ! root 744: /*-------------------Bass / Treble filter ---------------------------*/
1.1.1.6 root 745:
1.1.1.7 ! root 746: /**
! 747: * Left voice Filter for Bass/Treble.
! 748: */
! 749: static float DmaSnd_IIRfilterL(float xn)
! 750: {
! 751: static float data[2] = { 0.0, 0.0 };
! 752: float a, yn;
1.1.1.6 root 753:
1.1.1.7 ! root 754: /* Input coefficients */
! 755: /* biquad1 Note: 'a' coefficients are subtracted */
! 756: a = /*lmc1992.gain * */ xn; /* a=g*xn; */
! 757: a -= lmc1992.coef[0] * data[0]; /* a1; wn-1 */
! 758: a -= lmc1992.coef[1] * data[1]; /* a2; wn-2 */
! 759: /* If coefficient scale */
! 760: /* factor = 0.5 then */
! 761: /* multiply by 2 */
! 762: /* Output coefficients */
! 763: yn = lmc1992.coef[2] * a; /* b0; */
! 764: yn += lmc1992.coef[3] * data[0]; /* b1; */
! 765: yn += lmc1992.coef[4] * data[1]; /* b2; */
1.1.1.6 root 766:
1.1.1.7 ! root 767: data[1] = data[0]; /* wn-1 -> wn-2; */
! 768: data[0] = a; /* wn -> wn-1 */
! 769: return yn;
1.1.1.6 root 770: }
771:
772:
773: /**
1.1.1.7 ! root 774: * Right voice Filter for Bass/Treble.
1.1.1.6 root 775: */
1.1.1.7 ! root 776: static float DmaSnd_IIRfilterR(float xn)
1.1.1.6 root 777: {
1.1.1.7 ! root 778: static float data[2] = { 0.0, 0.0 };
! 779: float a, yn;
! 780:
! 781: /* Input coefficients */
! 782: /* biquad1 Note: 'a' coefficients are subtracted */
! 783: a = /*lmc1992.gain * */ xn; /* a=g*xn; */
! 784: a -= lmc1992.coef[0]*data[0]; /* a1; wn-1 */
! 785: a -= lmc1992.coef[1]*data[1]; /* a2; wn-2 */
! 786: /* If coefficient scale */
! 787: /* factor = 0.5 then */
! 788: /* multiply by 2 */
! 789: /* Output coefficients */
! 790: yn = lmc1992.coef[2]*a; /* b0; */
! 791: yn += lmc1992.coef[3]*data[0]; /* b1; */
! 792: yn += lmc1992.coef[4]*data[1]; /* b2; */
! 793:
! 794: data[1] = data[0]; /* wn-1 -> wn-2; */
! 795: data[0] = a; /* wn -> wn-1 */
! 796: return yn;
1.1.1.6 root 797: }
798:
799: /**
1.1.1.7 ! root 800: * LowPass Filter Mono
1.1.1.6 root 801: */
1.1.1.7 ! root 802: static Sint8 DmaSnd_LowPassFilterMono(Sint8 in)
1.1.1.6 root 803: {
1.1.1.7 ! root 804: static int lowPassFilter[2] = { 0, 0 };
! 805: Sint8 out;
1.1.1.6 root 806:
1.1.1.7 ! root 807: out = ((lowPassFilter[0]>>1) + (lowPassFilter[1]) + (in>>1)) >> 1;
! 808: lowPassFilter[0] = lowPassFilter[1];
! 809: lowPassFilter[1] = in;
1.1.1.6 root 810:
1.1.1.7 ! root 811: return out;
1.1.1.6 root 812: }
813:
814: /**
1.1.1.7 ! root 815: * LowPass Filter Left
1.1.1.6 root 816: */
1.1.1.7 ! root 817: static Sint8 DmaSnd_LowPassFilterLeft(Sint8 in)
1.1.1.6 root 818: {
1.1.1.7 ! root 819: static int lowPassFilter[2] = { 0, 0 };
! 820: Sint8 out;
1.1.1.6 root 821:
1.1.1.7 ! root 822: out = ((lowPassFilter[0]>>1) + (lowPassFilter[1]) + (in>>1)) >> 1;
! 823: lowPassFilter[0] = lowPassFilter[1];
! 824: lowPassFilter[1] = in;
1.1.1.6 root 825:
1.1.1.7 ! root 826: return out;
1.1.1.6 root 827: }
828:
829: /**
1.1.1.7 ! root 830: * LowPass Filter Right
1.1.1.6 root 831: */
1.1.1.7 ! root 832: static Sint8 DmaSnd_LowPassFilterRight(Sint8 in)
1.1.1.6 root 833: {
1.1.1.7 ! root 834: static int lowPassFilter[2] = { 0, 0 };
! 835: Sint8 out;
1.1.1.6 root 836:
1.1.1.7 ! root 837: out = ((lowPassFilter[0]>>1) + (lowPassFilter[1]) + (in>>1)) >> 1;
! 838: lowPassFilter[0] = lowPassFilter[1];
! 839: lowPassFilter[1] = in;
1.1.1.6 root 840:
1.1.1.7 ! root 841: return out;
1.1.1.6 root 842: }
843:
844:
845: /**
1.1.1.7 ! root 846: * Set Bass and Treble tone level
1.1.1.6 root 847: */
1.1.1.7 ! root 848: static void DmaSnd_Set_Tone_Level(int set_bass, int set_treb)
! 849: {
! 850: /* 13 levels; 0 through 12 correspond with -12dB to 12dB in 2dB steps */
! 851: lmc1992.coef[0] = lmc1992.treb_table[set_treb].a1 + lmc1992.bass_table[set_bass].a1;
! 852: lmc1992.coef[1] = lmc1992.treb_table[set_treb].a1 * lmc1992.bass_table[set_bass].a1;
! 853: lmc1992.coef[2] = lmc1992.treb_table[set_treb].b0 * lmc1992.bass_table[set_bass].b0;
! 854: lmc1992.coef[3] = lmc1992.treb_table[set_treb].b0 * lmc1992.bass_table[set_bass].b1 +
! 855: lmc1992.treb_table[set_treb].b1 * lmc1992.bass_table[set_bass].b0;
! 856: lmc1992.coef[4] = lmc1992.treb_table[set_treb].b1 * lmc1992.bass_table[set_bass].b1;
1.1.1.6 root 857: }
858:
859:
860: /**
1.1.1.7 ! root 861: * Compute the first order bass shelf
1.1.1.6 root 862: */
1.1.1.7 ! root 863: static struct first_order_s *DmaSnd_Bass_Shelf(float g, float fc, float Fs)
1.1.1.6 root 864: {
1.1.1.7 ! root 865: static struct first_order_s bass;
! 866: float a1;
1.1.1.6 root 867:
1.1.1.7 ! root 868: /* g, fc, Fs must be positve real numbers > 0.0 */
! 869: if (g < 1.0)
! 870: bass.a1 = a1 = (tanf(M_PI*fc/Fs) - g ) / (tanf(M_PI*fc/Fs) + g );
! 871: else
! 872: bass.a1 = a1 = (tanf(M_PI*fc/Fs) - 1.0) / (tanf(M_PI*fc/Fs) + 1.0);
1.1.1.6 root 873:
1.1.1.7 ! root 874: bass.b0 = (1.0 + a1) * (g - 1.0) / 2.0 + 1.0;
! 875: bass.b1 = (1.0 + a1) * (g - 1.0) / 2.0 + a1;
1.1.1.6 root 876:
1.1.1.7 ! root 877: return &bass;
1.1.1.6 root 878: }
879:
880:
881: /**
1.1.1.7 ! root 882: * Compute the first order treble shelf
1.1.1.6 root 883: */
1.1.1.7 ! root 884: static struct first_order_s *DmaSnd_Treble_Shelf(float g, float fc, float Fs)
1.1.1.6 root 885: {
1.1.1.7 ! root 886: static struct first_order_s treb;
! 887: float a1;
1.1.1.6 root 888:
1.1.1.7 ! root 889: /* g, fc, Fs must be positve real numbers > 0.0 */
! 890: if (g < 1.0)
! 891: treb.a1 = a1 = (g*tanf(M_PI*fc/Fs) - 1.0) / (g*tanf(M_PI*fc/Fs) + 1.0);
! 892: else
! 893: treb.a1 = a1 = (tanf(M_PI*fc/Fs) - 1.0) / (tanf(M_PI*fc/Fs) + 1.0);
1.1.1.6 root 894:
1.1.1.7 ! root 895: treb.b0 = 1.0 + (1.0 - a1) * (g - 1.0) / 2.0;
! 896: treb.b1 = a1 + (a1 - 1.0) * (g - 1.0) / 2.0;
! 897:
! 898: return &treb;
1.1.1.6 root 899: }
900:
1.1.1.7 ! root 901:
1.1.1.6 root 902: /**
1.1.1.7 ! root 903: * Compute the bass and treble tables (nAudioFrequency)
1.1.1.6 root 904: */
1.1.1.7 ! root 905: void DmaSnd_Init_Bass_and_Treble_Tables(void)
1.1.1.6 root 906: {
1.1.1.7 ! root 907: struct first_order_s *bass;
! 908: struct first_order_s *treb;
! 909:
! 910: float dB, g, fc_bt, fc_tt, Fs;
! 911: int n;
! 912:
! 913: fc_bt = 118.2763;
! 914: fc_tt = 8438.756;
! 915: Fs = (float)nAudioFrequency;
! 916:
! 917: if ((Fs < 8000.0) || (Fs > 96000.0))
! 918: Fs = 44100.0;
! 919:
! 920: for (dB = 12.0, n = TONE_STEPS; n--; dB -= 2.0)
! 921: {
! 922: g = powf(10.0, dB/20.0); /* 12dB to -12dB */
! 923:
! 924: bass = DmaSnd_Bass_Shelf(g, fc_bt, Fs);
! 925:
! 926: lmc1992.bass_table[n].a1 = bass->a1;
! 927: lmc1992.bass_table[n].b0 = bass->b0;
! 928: lmc1992.bass_table[n].b1 = bass->b1;
! 929:
! 930: treb = DmaSnd_Treble_Shelf(g, fc_tt, Fs);
! 931:
! 932: lmc1992.treb_table[n].a1 = treb->a1;
! 933: lmc1992.treb_table[n].b0 = treb->b0;
! 934: lmc1992.treb_table[n].b1 = treb->b1;
! 935: }
! 936:
! 937: DmaSnd_Set_Tone_Level(LMC1992_Bass_Treble_Table[microwire.bass & 0xf],
! 938: LMC1992_Bass_Treble_Table[microwire.treble & 0xf]);
1.1 root 939: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.