|
|
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: The update function also triggers the ST interrupts (Timer A and MFP-i7)
12: which are often used in ST programs for setting a new sound frame after
13: the old one has finished.
14:
1.1.1.8 ! root 15: To support programs that write into the frame buffer while it's played,
! 16: we should update dma sound on each video HBL.
! 17: This is also how it works on a real STE : bytes are read by the DMA
! 18: at the end of each HBL and stored in a small FIFO (8 bytes) that is sent
! 19: to the DAC depending on the chosen DMA output freq.
! 20:
1.1.1.7 root 21: Falcon sound emulation is all taken into account in crossbar.c
1.1 root 22:
23:
24: Hardware I/O registers:
25:
26: $FF8900 (word) : DMA sound control register
27: $FF8903 (byte) : Frame Start Hi
28: $FF8905 (byte) : Frame Start Mi
29: $FF8907 (byte) : Frame Start Lo
30: $FF8909 (byte) : Frame Count Hi
31: $FF890B (byte) : Frame Count Mi
32: $FF890D (byte) : Frame Count Lo
33: $FF890F (byte) : Frame End Hi
34: $FF8911 (byte) : Frame End Mi
35: $FF8913 (byte) : Frame End Lo
36: $FF8920 (word) : Sound Mode Control (frequency, mono/stereo)
37: $FF8922 (byte) : Microwire Data Register
38: $FF8924 (byte) : Microwire Mask Register
1.1.1.7 root 39:
40:
41: The Microwire and LMC 1992 commands :
42:
43: a command looks like: 10 CCC DDD DDD
44:
45: chipset address : 10
46: command :
47: 000 XXX XDD Mixing
48: 00 : DMA and (YM2149 - 12dB) mixing
49: 01 : DMA and YM2149 mixing
50: 10 : DMA only
51: 11 : Reserved
52:
53: 001 XXD DDD Bass
54: 0 000 : -12 dB
55: 0 110 : 0 dB
56: 1 100 : +12 dB
57:
58: 002 XXD DDD Treble
59: 0 000 : -12 dB
60: 0 110 : 0 dB
61: 1 100 : +12 dB
62:
63: 003 DDD DDD Master volume
64: 000 000 : -80 dB
65: 010 100 : -40 dB
66: 101 XXX : 0 dB
67:
68: 004 XDD DDD Right channel volume
69: 00 000 : -40 dB
70: 01 010 : -20 dB
71: 10 1XX : 0 dB
72:
73: 005 XDD DDD Left channel volume
74: 00 000 : -40 dB
75: 01 010 : -20 dB
76: 10 1XX : 0 dB
77:
78: Other : undefined
79:
80: LMC1992 IIR code Copyright by David Savinkoff 2010
81:
82: A first order bass filter is multiplied with a
83: first order treble filter to make a single
84: second order IIR shelf filter.
85:
86: Sound is stereo filtered by Boosting or Cutting
87: the Bass and Treble by +/-12dB in 2dB steps.
88:
89: This filter sounds exactly as the Atari TT or STE.
90: Sampling frequency = selectable
91: Bass turnover = 118.276Hz (8.2nF on LM1992 bass)
92: Treble turnover = 8438.756Hz (8.2nF on LM1992 treble)
1.1 root 93: */
1.1.1.7 root 94:
95:
1.1.1.5 root 96: const char DmaSnd_fileid[] = "Hatari dmaSnd.c : " __DATE__ " " __TIME__;
1.1 root 97:
98: #include "main.h"
99: #include "audio.h"
1.1.1.3 root 100: #include "configuration.h"
1.1 root 101: #include "dmaSnd.h"
1.1.1.7 root 102: #include "cycInt.h"
1.1 root 103: #include "ioMem.h"
1.1.1.6 root 104: #include "log.h"
1.1 root 105: #include "memorySnapShot.h"
106: #include "mfp.h"
107: #include "sound.h"
1.1.1.3 root 108: #include "stMemory.h"
1.1.1.7 root 109:
110: #define TONE_STEPS 13
111:
1.1.1.8 ! root 112: #define DMASND_FIFO_SIZE 8 /* 8 bytes : size of the DMA Audio's FIFO, filled on every HBL */
! 113: #define DMASND_FIFO_SIZE_MASK (DMASND_FIFO_SIZE-1) /* mask to keep FIFO_pos in 0-7 range */
! 114:
1.1.1.7 root 115:
116: /* Global variables that can be changed/read from other parts of Hatari */
117:
1.1.1.8 ! root 118: static void DmaSnd_Apply_LMC(int nMixBufIdx, int nSamplesToGenerate);
1.1.1.7 root 119: static void DmaSnd_Set_Tone_Level(int set_bass, int set_treb);
120: static float DmaSnd_IIRfilterL(float xn);
121: static float DmaSnd_IIRfilterR(float xn);
122: static struct first_order_s *DmaSnd_Treble_Shelf(float g, float fc, float Fs);
123: static struct first_order_s *DmaSnd_Bass_Shelf(float g, float fc, float Fs);
1.1.1.8 ! root 124: static Sint16 DmaSnd_LowPassFilterLeft(Sint16 in);
! 125: static Sint16 DmaSnd_LowPassFilterRight(Sint16 in);
! 126: static bool DmaSnd_LowPass;
1.1 root 127:
128:
129: Uint16 nDmaSoundControl; /* Sound control register */
130:
1.1.1.7 root 131: struct first_order_s { float a1, b0, b1; };
132: struct second_order_s { float a1, a2, b0, b1, b2; };
133:
134: struct dma_s {
135: Uint16 soundMode; /* Sound mode register */
136: Uint32 frameStartAddr; /* Sound frame start */
137: Uint32 frameEndAddr; /* Sound frame end */
1.1.1.8 ! root 138: Uint32 frameCounterAddr; /* Sound frame current address counter */
! 139:
! 140: /* Internal 8 byte FIFO */
! 141: Sint8 FIFO[ DMASND_FIFO_SIZE ];
! 142: Uint16 FIFO_Pos; /* from 0 to DMASND_FIFO_SIZE-1 */
! 143: Uint16 FIFO_NbBytes; /* from 0 to DMASND_FIFO_SIZE */
! 144:
! 145: Sint16 FrameMono; /* latest values read from the FIFO */
! 146: Sint16 FrameLeft;
! 147: Sint16 FrameRight;
1.1.1.7 root 148: };
149:
1.1.1.8 ! root 150: Sint64 frameCounter_float = 0;
! 151: bool DmaInitSample = false;
! 152:
! 153:
1.1.1.7 root 154: struct microwire_s {
155: Uint16 data; /* Microwire Data register */
156: Uint16 mask; /* Microwire Mask register */
157: int mwTransferSteps; /* Microwire shifting counter */
158: Uint16 mixing; /* Mixing command */
159: Uint16 bass; /* Bass command */
160: Uint16 treble; /* Treble command */
161: Uint16 masterVolume; /* Master volume command */
162: Uint16 leftVolume; /* Left channel volume command */
163: Uint16 rightVolume; /* Right channel volume command */
164: };
165:
166: struct lmc1992_s {
167: struct first_order_s bass_table[TONE_STEPS];
168: struct first_order_s treb_table[TONE_STEPS];
1.1.1.8 ! root 169: float coef[5]; /* IIR coefficients */
! 170: float left_gain;
! 171: float right_gain;
1.1.1.7 root 172: };
173:
174: static struct dma_s dma;
175: static struct microwire_s microwire;
176: static struct lmc1992_s lmc1992;
177:
178: /* dB = 20log(gain) : gain = antilog(dB/20) */
179: /* Table gain values = (int)(powf(10.0, dB/20.0)*65536.0 + 0.5) 2dB steps */
180:
181: /* Values for LMC1992 Master volume control (*65536) */
182: static const Uint16 LMC1992_Master_Volume_Table[64] =
183: {
184: 7, 8, 10, 13, 16, 21, 26, 33, 41, 52, /* -80dB */
185: 66, 83, 104, 131, 165, 207, 261, 328, 414, 521, /* -60dB */
186: 655, 825, 1039, 1308, 1646, 2072, 2609, 3285, 4135, 5206, /* -40dB */
187: 6554, 8250, 10387, 13076, 16462, 20724, 26090, 32846, 41350, 52057, /* -20dB */
188: 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, /* 0dB */
189: 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, /* 0dB */
190: 65535, 65535, 65535, 65535 /* 0dB */
191: };
1.1.1.6 root 192:
1.1.1.7 root 193: /* Values for LMC1992 Left and right volume control (*65536) */
194: static const Uint16 LMC1992_LeftRight_Volume_Table[32] =
195: {
196: 655, 825, 1039, 1308, 1646, 2072, 2609, 3285, 4135, 5206, /* -40dB */
197: 6554, 8250, 10387, 13076, 16462, 20724, 26090, 32846, 41350, 52057, /* -20dB */
198: 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, /* 0dB */
199: 65535, 65535 /* 0dB */
1.1 root 200: };
201:
1.1.1.7 root 202: /* Values for LMC1992 BASS and TREBLE */
203: static const Sint16 LMC1992_Bass_Treble_Table[16] =
204: {
205: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 12, 12, 12
206: };
1.1 root 207:
1.1.1.7 root 208: static const int DmaSndSampleRates[4] =
1.1.1.3 root 209: {
1.1.1.8 ! root 210: 6258, 12517, 25033, 50066
1.1.1.3 root 211: };
212:
213:
1.1.1.8 ! root 214:
! 215: /*--------------------------------------------------------------*/
! 216: /* Local functions prototypes */
! 217: /*--------------------------------------------------------------*/
! 218:
! 219: static void DmaSnd_FIFO_Refill(void);
! 220: static Sint8 DmaSnd_FIFO_PullByte(void);
! 221: static void DmaSnd_FIFO_SetStereo(void);
! 222:
! 223: static int DmaSnd_DetectSampleRate(void);
! 224: static void DmaSnd_StartNewFrame(void);
! 225: static inline int DmaSnd_EndOfFrameReached(void);
! 226:
! 227:
1.1 root 228: /*-----------------------------------------------------------------------*/
1.1.1.3 root 229: /**
1.1.1.7 root 230: * Init DMA sound variables.
231: */
232: void DmaSnd_Init(void)
233: {
234: DmaSnd_Reset(1);
235: }
236:
237: /**
1.1.1.3 root 238: * Reset DMA sound variables.
239: */
1.1.1.4 root 240: void DmaSnd_Reset(bool bCold)
1.1 root 241: {
242: nDmaSoundControl = 0;
1.1.1.8 ! root 243: dma.soundMode = 0;
! 244:
! 245: /* [NP] Set start/end to 0 even on warm reset ? (fix 'Brace' by Diamond Design) */
! 246: IoMem[0xff8903] = 0; /* frame start addr = 0 */
! 247: IoMem[0xff8905] = 0;
! 248: IoMem[0xff8907] = 0;
! 249: IoMem[0xff890f] = 0; /* frame end addr = 0 */
! 250: IoMem[0xff8911] = 0;
! 251: IoMem[0xff8913] = 0;
! 252:
! 253: dma.FIFO_Pos = 0;
! 254: dma.FIFO_NbBytes = 0;
! 255: dma.FrameMono = 0;
! 256: dma.FrameLeft = 0;
! 257: dma.FrameRight = 0;
1.1 root 258:
1.1.1.8 ! root 259: if ( bCold )
1.1 root 260: {
1.1.1.8 ! root 261: /* Microwire has no reset signal, it will keep its values on warm reset */
! 262: microwire.masterVolume = 7; /* -80 dB ; TOS 1.62 will put 0x28 (ie 65535) = 0 dB (max volume) */
! 263: microwire.leftVolume = 655; /* -40 dB ; TOS 1.62 will put 0x14 (ie 65535) = 0 dB (max volume) */
! 264: microwire.rightVolume = 655; /* -40 db ; TOS 1.62 will put 0x14 (ie 65535) = 0 dB (max volume) */
1.1.1.7 root 265: microwire.mixing = 0;
1.1.1.8 ! root 266: microwire.bass = 6; /* 0 dB (flat) */
! 267: microwire.treble = 6; /* 0 dB (flat) */
1.1 root 268: }
1.1.1.4 root 269:
1.1.1.7 root 270: /* Initialise microwire LMC1992 IIR filter parameters */
271: DmaSnd_Init_Bass_and_Treble_Tables();
1.1.1.6 root 272:
1.1.1.7 root 273: microwire.mwTransferSteps = 0;
1.1 root 274: }
275:
276: /*-----------------------------------------------------------------------*/
1.1.1.3 root 277: /**
278: * Save/Restore snapshot of local variables ('MemorySnapShot_Store' handles type)
279: */
1.1.1.4 root 280: void DmaSnd_MemorySnapShot_Capture(bool bSave)
1.1 root 281: {
282: /* Save/Restore details */
283: MemorySnapShot_Store(&nDmaSoundControl, sizeof(nDmaSoundControl));
1.1.1.7 root 284: MemorySnapShot_Store(&dma, sizeof(dma));
285: MemorySnapShot_Store(µwire, sizeof(microwire));
286: MemorySnapShot_Store(&lmc1992, sizeof(lmc1992));
1.1 root 287: }
288:
289:
1.1.1.8 ! root 290: /*-----------------------------------------------------------------------*/
! 291: /**
! 292: * This function is called on every HBL to ensure the DMA Audio's FIFO
! 293: * is kept full.
! 294: * In Hatari, the FIFO is handled like a ring buffer (to avoid memcopying bytes
! 295: * inside the FIFO when a byte is pushed/pulled).
! 296: * Note that the DMA fetches words, not bytes, so we read new data only
! 297: * when 2 bytes or more are missing.
! 298: * When end of frame is reached, we continue with a new frame if loop mode
! 299: * is on, else we stop DMA Audio.
! 300: */
! 301: static void DmaSnd_FIFO_Refill(void)
! 302: {
! 303: /* If DMA sound is OFF, don't update the FIFO */
! 304: if ( ( nDmaSoundControl & DMASNDCTRL_PLAY ) == 0)
! 305: return;
! 306:
! 307: /* If End Address == Start Address, don't update the FIFO */
! 308: if (dma.frameEndAddr == dma.frameStartAddr)
! 309: {
! 310: DmaSnd_EndOfFrameReached(); /* Stop dma audio if loop mode is off */
! 311: return;
! 312: }
! 313:
! 314: /* Refill the whole FIFO */
! 315: while ( DMASND_FIFO_SIZE - dma.FIFO_NbBytes >= 2 )
! 316: {
! 317: /* Add one word to the FIFO */
! 318: LOG_TRACE(TRACE_DMASND, "DMA snd fifo refill adr=%x pos %d nb %d %x %x\n", dma.frameCounterAddr , dma.FIFO_Pos , dma.FIFO_NbBytes ,
! 319: STRam[ dma.frameCounterAddr ] , STRam[ dma.frameCounterAddr+1 ] );
! 320:
! 321: dma.FIFO[ ( dma.FIFO_Pos+dma.FIFO_NbBytes+0 ) & DMASND_FIFO_SIZE_MASK ] = (Sint8)STRam[ dma.frameCounterAddr ]; /* add upper byte of the word */
! 322: dma.FIFO[ ( dma.FIFO_Pos+dma.FIFO_NbBytes+1 ) & DMASND_FIFO_SIZE_MASK ] = (Sint8)STRam[ dma.frameCounterAddr+1 ]; /* add lower byte of the word */
! 323:
! 324: dma.FIFO_NbBytes += 2; /* One word more in the FIFO */
! 325:
! 326: /* Increase current frame address and check if we reached frame's end */
! 327: dma.frameCounterAddr += 2;
! 328: if ( dma.frameCounterAddr == dma.frameEndAddr ) /* end of frame reached, should we loop or stop dma ? */
! 329: {
! 330: if ( DmaSnd_EndOfFrameReached() )
! 331: break; /* Loop mode off, dma audio is now turned off */
! 332: }
! 333: }
! 334: }
! 335:
! 336:
! 337: /*-----------------------------------------------------------------------*/
! 338: /**
! 339: * Pull one sample/byte from the DMA Audio's FIFO and decrease the number of
! 340: * remaining bytes.
! 341: * If the FIFO is empty, return 0 (empty sample)
! 342: * Note : on a real STE, the 8 bytes FIFO is refilled on each HBL, which gives
! 343: * a total of 313*8=125326 bytes per sec read by the DMA. As the max freq
! 344: * is 50066 Hz, the STE can play 100132 bytes per sec in stereo ; so on a real STE
! 345: * the FIFO can never be empty while DMA is ON.
! 346: * But on Hatari, if the user chooses an audio's output frequency that is much
! 347: * lower than the current DMA freq, audio will be updated less frequently than
! 348: * on each HBL and it could require to process more than DMASND_FIFO_SIZE in one
! 349: * call to DmaSnd_GenerateSamples(). This is why we allow DmaSnd_FIFO_Refill()
! 350: * to be called if FIFO is empty but DMA sound is still ON.
! 351: * This way, sound remains correct even if the user uses very low output freq.
! 352: */
! 353: static Sint8 DmaSnd_FIFO_PullByte(void)
! 354: {
! 355: Sint8 sample;
! 356:
! 357: if ( dma.FIFO_NbBytes == 0 )
! 358: {
! 359: DmaSnd_FIFO_Refill();
! 360: if ( dma.FIFO_NbBytes == 0 ) /* Refill didn't add any new bytes */
! 361: {
! 362: LOG_TRACE(TRACE_DMASND, "DMA snd fifo empty for pull\n" );
! 363: return 0;
! 364: }
! 365: }
! 366:
! 367:
! 368: LOG_TRACE(TRACE_DMASND, "DMA snd fifo pull pos %d nb %d %02x\n", dma.FIFO_Pos , dma.FIFO_NbBytes , (Uint8)dma.FIFO[ dma.FIFO_Pos ] );
! 369:
! 370: sample = dma.FIFO[ dma.FIFO_Pos ]; /* Get oldest byte from the FIFO */
! 371: dma.FIFO_Pos = (dma.FIFO_Pos+1) & DMASND_FIFO_SIZE_MASK;/* Pos to be pulled on next call */
! 372: dma.FIFO_NbBytes--; /* One byte less in the FIFO */
! 373:
! 374: return sample;
! 375: }
! 376:
! 377:
! 378: /*-----------------------------------------------------------------------*/
! 379: /**
! 380: * In case a program switches from mono to stereo, we must ensure that
! 381: * FIFO_pos is on even boundary to keep Left/Right bytes in the correct
! 382: * order (Left byte should be on even addresses and Right byte on odd ones).
! 383: * If this is not the case, we skip one byte.
! 384: */
! 385: static void DmaSnd_FIFO_SetStereo(void)
! 386: {
! 387: Uint16 NewPos;
! 388:
! 389: if ( dma.FIFO_Pos & 1 )
! 390: {
! 391: NewPos = (dma.FIFO_Pos+1) & DMASND_FIFO_SIZE_MASK; /* skip the byte on odd address */
! 392:
! 393: if ( nDmaSoundControl & DMASNDCTRL_PLAY ) /* print a log if we change while playing */
! 394: { LOG_TRACE(TRACE_DMASND, "DMA snd switching to stereo mode while playing mono FIFO_pos %d->%d\n", dma.FIFO_Pos , NewPos ); }
! 395: else
! 396: { LOG_TRACE(TRACE_DMASND, "DMA snd switching to stereo mode FIFO_pos %d->%d\n", dma.FIFO_Pos , NewPos ); }
! 397:
! 398: dma.FIFO_Pos = NewPos;
! 399:
! 400: if ( dma.FIFO_NbBytes > 0 )
! 401: dma.FIFO_NbBytes--; /* remove one byte if FIFO was not already empty */
! 402: }
! 403:
! 404: }
! 405:
! 406:
! 407: /*-----------------------------------------------------------------------*/
! 408: /**
! 409: * Returns the frequency corresponding to the 2 lower bits of dma.soundMode
! 410: */
1.1.1.7 root 411: static int DmaSnd_DetectSampleRate(void)
1.1.1.3 root 412: {
1.1.1.7 root 413: return DmaSndSampleRates[dma.soundMode & 3];
1.1.1.3 root 414: }
415:
416:
1.1 root 417: /*-----------------------------------------------------------------------*/
1.1.1.3 root 418: /**
419: * This function is called when a new sound frame is started.
1.1.1.8 ! root 420: * It copies the start and end address from the I/O registers and set
! 421: * the frame counter addr to the start of this new frame.
1.1.1.3 root 422: */
1.1 root 423: static void DmaSnd_StartNewFrame(void)
424: {
1.1.1.7 root 425: dma.frameStartAddr = (IoMem[0xff8903] << 16) | (IoMem[0xff8905] << 8) | (IoMem[0xff8907] & ~1);
426: dma.frameEndAddr = (IoMem[0xff890f] << 16) | (IoMem[0xff8911] << 8) | (IoMem[0xff8913] & ~1);
1.1 root 427:
1.1.1.8 ! root 428: dma.frameCounterAddr = dma.frameStartAddr;
1.1.1.6 root 429:
1.1.1.8 ! root 430: LOG_TRACE(TRACE_DMASND, "DMA snd new frame start=%x end=%x\n", dma.frameStartAddr, dma.frameEndAddr);
1.1 root 431: }
432:
433:
434: /*-----------------------------------------------------------------------*/
1.1.1.3 root 435: /**
1.1.1.7 root 436: * End-of-frame has been reached. Raise interrupts if needed.
1.1.1.6 root 437: * Returns true if DMA sound processing should be stopped now and false
1.1.1.7 root 438: * if it continues (DMA PLAYLOOP mode).
1.1.1.3 root 439: */
1.1.1.7 root 440: static inline int DmaSnd_EndOfFrameReached(void)
1.1 root 441: {
1.1.1.8 ! root 442: LOG_TRACE(TRACE_DMASND, "DMA snd end of frame\n");
! 443:
1.1.1.7 root 444: /* Raise end-of-frame interrupts (MFP-i7 and Time-A) */
445: MFP_InputOnChannel(MFP_TIMER_GPIP7_BIT, MFP_IERA, &MFP_IPRA);
446: if (MFP_TACR == 0x08) /* Is timer A in Event Count mode? */
447: MFP_TimerA_EventCount_Interrupt();
1.1 root 448:
1.1.1.7 root 449: if (nDmaSoundControl & DMASNDCTRL_PLAYLOOP)
450: {
451: DmaSnd_StartNewFrame();
1.1 root 452: }
1.1.1.7 root 453: else
1.1.1.6 root 454: {
1.1.1.7 root 455: nDmaSoundControl &= ~DMASNDCTRL_PLAY;
456: return true;
1.1.1.6 root 457: }
458:
1.1.1.7 root 459: return false;
1.1 root 460: }
461:
462:
463: /*-----------------------------------------------------------------------*/
1.1.1.3 root 464: /**
465: * Mix DMA sound sample with the normal PSG sound samples.
1.1.1.6 root 466: * Note: We adjust the volume level of the 8-bit DMA samples to factor
1.1.1.7 root 467: * 0.75 compared to the PSG sound samples.
1.1.1.8 ! root 468: *
! 469: * The following formula: -((256*3/4)/4)/4
! 470: *
! 471: * Multiply by 256 to convert 8 to 16 bits;
! 472: * DMA sound is 3/4 level of YM sound;
! 473: * Divide by 4 to account for MixBuffer[];
! 474: * Divide by 4 to account for DmaSnd_LowPassFilter;
! 475: * Multiply DMA sound by -1 because the LMC1992 inverts the signal
! 476: * ( YM sign is +1 :: -1(op-amp) * -1(Lmc1992) ).
1.1.1.3 root 477: */
1.1.1.8 ! root 478:
! 479:
1.1 root 480: void DmaSnd_GenerateSamples(int nMixBufIdx, int nSamplesToGenerate)
481: {
1.1.1.8 ! root 482: int i;
1.1.1.7 root 483: int nBufIdx;
1.1.1.8 ! root 484: Sint8 MonoByte , LeftByte , RightByte;
1.1.1.7 root 485: unsigned n;
1.1.1.8 ! root 486: Sint64 FreqRatio;
! 487:
! 488:
! 489: /* DMA Audio OFF and FIFO empty : process YM2149's output */
! 490: if ( !(nDmaSoundControl & DMASNDCTRL_PLAY) && ( dma.FIFO_NbBytes == 0 ) )
! 491: {
! 492: for (i = 0; i < nSamplesToGenerate; i++)
! 493: {
! 494: nBufIdx = (nMixBufIdx + i) % MIXBUFFER_SIZE;
1.1.1.6 root 495:
1.1.1.8 ! root 496: switch (microwire.mixing) {
! 497: case 1:
! 498: /* YM2149 */
! 499: break;
! 500: default:
! 501: /* YM2149 - 12dB */
! 502: MixBuffer[nBufIdx][0] /= 4;
! 503: MixBuffer[nBufIdx][1] = MixBuffer[nBufIdx][0];
! 504: break;
! 505: }
! 506: }
! 507:
! 508: /* Apply LMC1992 sound modifications (Bass and Treble) */
! 509: DmaSnd_Apply_LMC ( nMixBufIdx , nSamplesToGenerate );
! 510:
1.1 root 511: return;
1.1.1.8 ! root 512: }
! 513:
1.1 root 514:
1.1.1.8 ! root 515: /* DMA Audio ON or FIFO not empty yet */
1.1 root 516:
1.1.1.8 ! root 517: /* Compute ratio between DMA's sound frequency and host computer's sound frequency, */
! 518: /* use << 32 to simulate floating point precision */
! 519: FreqRatio = ( ((Sint64)DmaSnd_DetectSampleRate()) << 32 ) / nAudioFrequency;
1.1.1.7 root 520:
521: if (dma.soundMode & DMASNDMODE_MONO)
1.1.1.3 root 522: {
523: /* Mono 8-bit */
1.1 root 524: for (i = 0; i < nSamplesToGenerate; i++)
525: {
1.1.1.8 ! root 526: if ( DmaInitSample )
! 527: {
! 528: MonoByte = DmaSnd_FIFO_PullByte ();
! 529: dma.FrameMono = DmaSnd_LowPassFilterLeft( (Sint16)MonoByte );
! 530: /* No-Click */ DmaSnd_LowPassFilterRight( (Sint16)MonoByte );
! 531: DmaInitSample = false;
1.1.1.7 root 532: }
533:
1.1 root 534: nBufIdx = (nMixBufIdx + i) % MIXBUFFER_SIZE;
1.1.1.7 root 535:
536: switch (microwire.mixing) {
537: case 1:
538: /* DMA and YM2149 mixing */
1.1.1.8 ! root 539: MixBuffer[nBufIdx][0] = MixBuffer[nBufIdx][0] + dma.FrameMono * -((256*3/4)/4)/4;
1.1.1.7 root 540: break;
541: case 2:
542: /* DMA sound only */
1.1.1.8 ! root 543: MixBuffer[nBufIdx][0] = dma.FrameMono * -((256*3/4)/4)/4;
1.1.1.7 root 544: break;
545: default:
546: /* DMA and (YM2149 - 12dB) mixing */
547: /* instead of 16462 (-12dB), we approximate by 16384 */
1.1.1.8 ! root 548: MixBuffer[nBufIdx][0] = (dma.FrameMono * -((256*3/4)/4)/4) +
1.1.1.7 root 549: (((Sint32)MixBuffer[nBufIdx][0] * 16384)/65536);
550: break;
551: }
552:
1.1.1.8 ! root 553: MixBuffer[nBufIdx][1] = MixBuffer[nBufIdx][0]; /* right = left */
! 554:
! 555: /* Increase freq counter */
! 556: frameCounter_float += FreqRatio;
! 557: n = frameCounter_float >> 32; /* number of samples to skip */
! 558: while ( n > 0 ) /* pull as many bytes from the FIFO as needed */
! 559: {
! 560: MonoByte = DmaSnd_FIFO_PullByte ();
! 561: dma.FrameMono = DmaSnd_LowPassFilterLeft( (Sint16)MonoByte );
! 562: /* No-Click */ DmaSnd_LowPassFilterRight( (Sint16)MonoByte );
! 563: n--;
1.1.1.7 root 564: }
1.1.1.8 ! root 565: frameCounter_float &= 0xffffffff; /* only keep the fractional part */
1.1 root 566: }
567: }
568: else
569: {
1.1.1.3 root 570: /* Stereo 8-bit */
1.1 root 571: for (i = 0; i < nSamplesToGenerate; i++)
572: {
1.1.1.8 ! root 573: if ( DmaInitSample )
! 574: {
! 575: LeftByte = DmaSnd_FIFO_PullByte ();
! 576: RightByte = DmaSnd_FIFO_PullByte ();
! 577: dma.FrameLeft = DmaSnd_LowPassFilterLeft( (Sint16)LeftByte );
! 578: dma.FrameRight = DmaSnd_LowPassFilterRight( (Sint16)RightByte );
! 579: DmaInitSample = false;
1.1.1.7 root 580: }
581:
1.1 root 582: nBufIdx = (nMixBufIdx + i) % MIXBUFFER_SIZE;
1.1.1.8 ! root 583:
1.1.1.7 root 584: switch (microwire.mixing) {
585: case 1:
586: /* DMA and YM2149 mixing */
1.1.1.8 ! root 587: MixBuffer[nBufIdx][0] = MixBuffer[nBufIdx][0] + dma.FrameLeft * -((256*3/4)/4)/4;
! 588: MixBuffer[nBufIdx][1] = MixBuffer[nBufIdx][1] + dma.FrameRight * -((256*3/4)/4)/4;
1.1.1.7 root 589: break;
590: case 2:
591: /* DMA sound only */
1.1.1.8 ! root 592: MixBuffer[nBufIdx][0] = dma.FrameLeft * -((256*3/4)/4)/4;
! 593: MixBuffer[nBufIdx][1] = dma.FrameRight * -((256*3/4)/4)/4;
1.1.1.7 root 594: break;
595: default:
596: /* DMA and (YM2149 - 12dB) mixing */
597: /* instead of 16462 (-12dB), we approximate by 16384 */
1.1.1.8 ! root 598: MixBuffer[nBufIdx][0] = (dma.FrameLeft * -((256*3/4)/4)/4) +
1.1.1.7 root 599: (((Sint32)MixBuffer[nBufIdx][0] * 16384)/65536);
1.1.1.8 ! root 600: MixBuffer[nBufIdx][1] = (dma.FrameRight * -((256*3/4)/4)/4) +
1.1.1.7 root 601: (((Sint32)MixBuffer[nBufIdx][1] * 16384)/65536);
602: break;
603: }
604:
1.1.1.8 ! root 605: /* Increase freq counter */
! 606: frameCounter_float += FreqRatio;
! 607: n = frameCounter_float >> 32; /* number of samples to skip */
! 608: while ( n > 0 ) /* pull as many bytes from the FIFO as needed */
! 609: {
! 610: LeftByte = DmaSnd_FIFO_PullByte ();
! 611: RightByte = DmaSnd_FIFO_PullByte ();
! 612: dma.FrameLeft = DmaSnd_LowPassFilterLeft( (Sint16)LeftByte );
! 613: dma.FrameRight = DmaSnd_LowPassFilterRight( (Sint16)RightByte );
! 614: n--;
1.1.1.7 root 615: }
1.1.1.8 ! root 616: frameCounter_float &= 0xffffffff; /* only keep the fractional part */
1.1 root 617: }
618: }
1.1.1.7 root 619:
1.1.1.8 ! root 620: /* Apply LMC1992 sound modifications (Bass and Treble) */
! 621: DmaSnd_Apply_LMC ( nMixBufIdx , nSamplesToGenerate );
! 622: }
! 623:
! 624:
! 625: /*-----------------------------------------------------------------------*/
! 626: /**
! 627: * Apply LMC1992 sound modifications (Bass and Treble)
! 628: * The Bass and Treble get samples at nAudioFrequency rate.
! 629: * The tone control's sampling frequency must be at least 22050 Hz to sound good.
! 630: */
! 631: static void DmaSnd_Apply_LMC(int nMixBufIdx, int nSamplesToGenerate)
! 632: {
! 633: int nBufIdx;
! 634: int i;
1.1.1.7 root 635:
636: /* Apply LMC1992 sound modifications (Left, Right and Master Volume) */
637: for (i = 0; i < nSamplesToGenerate; i++) {
638: nBufIdx = (nMixBufIdx + i) % MIXBUFFER_SIZE;
1.1.1.8 ! root 639: MixBuffer[nBufIdx][0] = DmaSnd_IIRfilterL(MixBuffer[nBufIdx][0]);
! 640: MixBuffer[nBufIdx][1] = DmaSnd_IIRfilterR(MixBuffer[nBufIdx][1]);
! 641: }
1.1 root 642: }
643:
644:
645: /*-----------------------------------------------------------------------*/
1.1.1.3 root 646: /**
1.1.1.8 ! root 647: * STE DMA sound is using an 8 bytes FIFO that is checked and filled on each HBL
! 648: * (at 50066 Hz 8 bit stereo, the DMA requires approx 6.5 new bytes per HBL)
! 649: * Calling Sound_Update on each HBL allows to emulate some programs that modify
! 650: * the data between FrameStart and FrameEnd while DMA sound is ON
! 651: * (eg the demo 'Mental Hangover' or the game 'Power Up Plus')
! 652: * We first check if the FIFO needs to be refilled, then we call Sound_Update.
! 653: * This function should be called from the HBL's handler (in video.c)
1.1.1.3 root 654: */
1.1.1.8 ! root 655: void DmaSnd_STE_HBL_Update(void)
1.1 root 656: {
1.1.1.8 ! root 657: if ( ( ConfigureParams.System.nMachineType != MACHINE_STE )
! 658: && ( ConfigureParams.System.nMachineType != MACHINE_MEGA_STE ) )
! 659: return;
1.1 root 660:
1.1.1.8 ! root 661:
! 662: /* The DMA starts refilling the FIFO when display is OFF (eg cycle 376 in low res 50 Hz) */
! 663: DmaSnd_FIFO_Refill ();
! 664:
! 665: /* If DMA sound is ON or FIFO is not empty, update sound */
! 666: if ( (nDmaSoundControl & DMASNDCTRL_PLAY) || ( dma.FIFO_NbBytes > 0 ) )
! 667: Sound_Update(false);
! 668:
! 669: /* As long as display is OFF, the DMA will refill the FIFO after playing some samples during the HBL */
! 670: DmaSnd_FIFO_Refill ();
1.1 root 671: }
672:
673:
674: /*-----------------------------------------------------------------------*/
1.1.1.3 root 675: /**
1.1.1.8 ! root 676: * Return current frame counter address (value is always even)
1.1.1.3 root 677: */
1.1 root 678: static Uint32 DmaSnd_GetFrameCount(void)
679: {
680: Uint32 nActCount;
681:
1.1.1.8 ! root 682: /* Update sound to get the current DMA frame address */
! 683: Sound_Update(false);
! 684:
1.1 root 685: if (nDmaSoundControl & DMASNDCTRL_PLAY)
1.1.1.8 ! root 686: nActCount = dma.frameCounterAddr;
1.1 root 687: else
1.1.1.8 ! root 688: nActCount = (IoMem[0xff8903] << 16) | (IoMem[0xff8905] << 8) | (IoMem[0xff8907] & ~1);
1.1 root 689:
690: return nActCount;
691: }
692:
693:
694: /*-----------------------------------------------------------------------*/
1.1.1.3 root 695: /**
696: * Read word from sound control register (0xff8900).
697: */
1.1 root 698: void DmaSnd_SoundControl_ReadWord(void)
699: {
700: IoMem_WriteWord(0xff8900, nDmaSoundControl);
1.1.1.6 root 701:
1.1.1.7 root 702: LOG_TRACE(TRACE_DMASND, "DMA snd control read: 0x%04x\n", nDmaSoundControl);
1.1 root 703: }
704:
705:
706: /*-----------------------------------------------------------------------*/
1.1.1.3 root 707: /**
1.1.1.8 ! root 708: * Write word to sound control register (0xff8900).
! 709: */
! 710: void DmaSnd_SoundControl_WriteWord(void)
! 711: {
! 712: Uint16 nNewSndCtrl;
! 713:
! 714: LOG_TRACE(TRACE_DMASND, "DMA snd control write: 0x%04x\n", IoMem_ReadWord(0xff8900));
! 715:
! 716: /* Before starting/stopping DMA sound, create samples up until this point with current values */
! 717: Sound_Update(false);
! 718:
! 719: nNewSndCtrl = IoMem_ReadWord(0xff8900) & 3;
! 720:
! 721: if (!(nDmaSoundControl & DMASNDCTRL_PLAY) && (nNewSndCtrl & DMASNDCTRL_PLAY))
! 722: {
! 723: LOG_TRACE(TRACE_DMASND, "DMA snd control write: starting dma sound output\n");
! 724: DmaInitSample = true;
! 725: frameCounter_float = 0;
! 726: DmaSnd_StartNewFrame();
! 727: }
! 728: else if ((nDmaSoundControl & DMASNDCTRL_PLAY) && !(nNewSndCtrl & DMASNDCTRL_PLAY))
! 729: {
! 730: LOG_TRACE(TRACE_DMASND, "DMA snd control write: stopping dma sound output\n");
! 731: }
! 732:
! 733: nDmaSoundControl = nNewSndCtrl;
! 734: }
! 735:
! 736:
! 737: /*-----------------------------------------------------------------------*/
! 738: /**
1.1.1.3 root 739: * Read word from sound frame count high register (0xff8909).
740: */
1.1 root 741: void DmaSnd_FrameCountHigh_ReadByte(void)
742: {
743: IoMem_WriteByte(0xff8909, DmaSnd_GetFrameCount() >> 16);
744: }
745:
746:
747: /*-----------------------------------------------------------------------*/
1.1.1.3 root 748: /**
749: * Read word from sound frame count medium register (0xff890b).
750: */
1.1 root 751: void DmaSnd_FrameCountMed_ReadByte(void)
752: {
753: IoMem_WriteByte(0xff890b, DmaSnd_GetFrameCount() >> 8);
754: }
755:
756:
757: /*-----------------------------------------------------------------------*/
1.1.1.3 root 758: /**
759: * Read word from sound frame count low register (0xff890d).
760: */
1.1 root 761: void DmaSnd_FrameCountLow_ReadByte(void)
762: {
763: IoMem_WriteByte(0xff890d, DmaSnd_GetFrameCount());
764: }
765:
766:
767: /*-----------------------------------------------------------------------*/
1.1.1.3 root 768: /**
1.1.1.8 ! root 769: * Write bytes to various registers with no action.
! 770: */
! 771: void DmaSnd_FrameStartHigh_WriteByte(void)
! 772: {
! 773: LOG_TRACE(TRACE_DMASND, "DMA snd frame start high: 0x%02x at pos %d/%d\n", IoMem_ReadByte(0xff8903) ,
! 774: dma.frameCounterAddr - dma.frameStartAddr , dma.frameEndAddr - dma.frameStartAddr );
! 775: }
! 776:
! 777: void DmaSnd_FrameStartMed_WriteByte(void)
! 778: {
! 779: LOG_TRACE(TRACE_DMASND, "DMA snd frame start med: 0x%02x at pos %d/%d\n", IoMem_ReadByte(0xff8905) ,
! 780: dma.frameCounterAddr - dma.frameStartAddr , dma.frameEndAddr - dma.frameStartAddr );
! 781: }
! 782:
! 783: void DmaSnd_FrameStartLow_WriteByte(void)
! 784: {
! 785: LOG_TRACE(TRACE_DMASND, "DMA snd frame start low: 0x%02x at pos %d/%d\n", IoMem_ReadByte(0xff8907) ,
! 786: dma.frameCounterAddr - dma.frameStartAddr , dma.frameEndAddr - dma.frameStartAddr );
! 787: }
! 788:
! 789: void DmaSnd_FrameCountHigh_WriteByte(void)
! 790: {
! 791: LOG_TRACE(TRACE_DMASND, "DMA snd frame count high: 0x%02x at pos %d/%d\n", IoMem_ReadByte(0xff8909) ,
! 792: dma.frameCounterAddr - dma.frameStartAddr , dma.frameEndAddr - dma.frameStartAddr );
! 793: }
! 794:
! 795: void DmaSnd_FrameCountMed_WriteByte(void)
! 796: {
! 797: LOG_TRACE(TRACE_DMASND, "DMA snd frame count med: 0x%02x at pos %d/%d\n", IoMem_ReadByte(0xff890b) ,
! 798: dma.frameCounterAddr - dma.frameStartAddr , dma.frameEndAddr - dma.frameStartAddr );
! 799: }
! 800:
! 801: void DmaSnd_FrameCountLow_WriteByte(void)
! 802: {
! 803: LOG_TRACE(TRACE_DMASND, "DMA snd frame count low: 0x%02x at pos %d/%d\n", IoMem_ReadByte(0xff890d) ,
! 804: dma.frameCounterAddr - dma.frameStartAddr , dma.frameEndAddr - dma.frameStartAddr );
! 805: }
! 806:
! 807: void DmaSnd_FrameEndHigh_WriteByte(void)
! 808: {
! 809: LOG_TRACE(TRACE_DMASND, "DMA snd frame end high: 0x%02x at pos %d/%d\n", IoMem_ReadByte(0xff890f) ,
! 810: dma.frameCounterAddr - dma.frameStartAddr , dma.frameEndAddr - dma.frameStartAddr );
! 811: }
! 812:
! 813: void DmaSnd_FrameEndMed_WriteByte(void)
! 814: {
! 815: LOG_TRACE(TRACE_DMASND, "DMA snd frame end med: 0x%02x at pos %d/%d\n", IoMem_ReadByte(0xff8911) ,
! 816: dma.frameCounterAddr - dma.frameStartAddr , dma.frameEndAddr - dma.frameStartAddr );
! 817: }
! 818:
! 819: void DmaSnd_FrameEndLow_WriteByte(void)
! 820: {
! 821: LOG_TRACE(TRACE_DMASND, "DMA snd frame end low: 0x%02x at pos %d/%d\n", IoMem_ReadByte(0xff8913) ,
! 822: dma.frameCounterAddr - dma.frameStartAddr , dma.frameEndAddr - dma.frameStartAddr );
! 823: }
! 824:
! 825:
! 826: /*-----------------------------------------------------------------------*/
! 827: /**
1.1.1.7 root 828: * Read word from sound mode register (0xff8921).
1.1.1.3 root 829: */
1.1.1.7 root 830: void DmaSnd_SoundModeCtrl_ReadByte(void)
1.1 root 831: {
1.1.1.7 root 832: IoMem_WriteByte(0xff8921, dma.soundMode);
1.1.1.6 root 833:
1.1.1.7 root 834: LOG_TRACE(TRACE_DMASND, "DMA snd mode read: 0x%02x\n", dma.soundMode);
1.1 root 835: }
836:
837:
838: /*-----------------------------------------------------------------------*/
1.1.1.3 root 839: /**
1.1.1.7 root 840: * Write word to sound mode register (0xff8921).
1.1.1.3 root 841: */
1.1.1.7 root 842: void DmaSnd_SoundModeCtrl_WriteByte(void)
1.1 root 843: {
1.1.1.8 ! root 844: Uint16 SoundModeNew;
! 845:
! 846: SoundModeNew = IoMem_ReadByte(0xff8921);
! 847:
! 848: LOG_TRACE(TRACE_DMASND, "DMA snd mode write: 0x%02x mode=%s freq=%d\n", SoundModeNew,
! 849: SoundModeNew & DMASNDMODE_MONO ? "mono" : "stereo" , DmaSndSampleRates[ SoundModeNew & 3 ]);
! 850:
! 851: /* We maskout to only bits that exist on a real STE */
! 852: SoundModeNew &= 0x8f;
1.1.1.3 root 853:
1.1.1.8 ! root 854: /* Are we switching from mono to stereo ? */
! 855: if ( ( dma.soundMode & DMASNDMODE_MONO ) && ( ( SoundModeNew & DMASNDMODE_MONO ) == 0 ) )
! 856: DmaSnd_FIFO_SetStereo ();
! 857:
! 858: dma.soundMode = SoundModeNew;
! 859: /* We also write the masked value back into the emulated hw registers so we have a correct value there */
1.1.1.7 root 860: IoMem_WriteByte(0xff8921, dma.soundMode);
1.1 root 861: }
862:
1.1.1.8 ! root 863:
1.1.1.6 root 864: /* ---------------------- Microwire / LMC 1992 ---------------------- */
865:
1.1.1.3 root 866: /**
1.1.1.4 root 867: * Handle the shifting/rotating of the microwire registers
868: * The microwire regs should be done after 16 usec = 32 NOPs = 128 cycles.
869: * That means we have to shift 16 times with a delay of 8 cycles.
1.1.1.3 root 870: */
1.1.1.4 root 871: void DmaSnd_InterruptHandler_Microwire(void)
1.1 root 872: {
1.1.1.7 root 873: Uint8 i, bit;
874: Uint16 saveData;
875:
1.1.1.4 root 876: /* Remove this interrupt from list and re-order */
1.1.1.7 root 877: CycInt_AcknowledgeInterrupt();
1.1.1.4 root 878:
1.1.1.7 root 879: --microwire.mwTransferSteps;
1.1.1.4 root 880:
881: /* Shift data register until it becomes zero. */
1.1.1.7 root 882: if (microwire.mwTransferSteps > 1)
1.1 root 883: {
1.1.1.7 root 884: IoMem_WriteWord(0xff8922, microwire.data<<(16-microwire.mwTransferSteps));
1.1 root 885: }
886: else
887: {
1.1.1.4 root 888: /* Paradox XMAS 2004 demo continuesly writes to the data
889: * register, but still expects to read a zero inbetween,
890: * so we have to output a zero before we're really done
891: * with the transfer. */
1.1 root 892: IoMem_WriteWord(0xff8922, 0);
893: }
1.1.1.4 root 894:
895: /* Rotate mask register */
1.1.1.7 root 896: IoMem_WriteWord(0xff8924, (microwire.mask<<(16-microwire.mwTransferSteps))
897: |(microwire.mask>>microwire.mwTransferSteps));
1.1.1.4 root 898:
1.1.1.7 root 899: if (microwire.mwTransferSteps > 0)
1.1.1.4 root 900: {
1.1.1.7 root 901: CycInt_AddRelativeInterrupt(8, INT_CPU_CYCLE, INTERRUPT_DMASOUND_MICROWIRE);
1.1.1.4 root 902: }
1.1.1.7 root 903: else {
904: /* Decode the address + command word according to the binary mask */
905: bit = 0;
906: saveData = microwire.data;
907: microwire.data = 0;
908: for (i=0; i<16; i++) {
909: if ((microwire.mask >> i) & 1) {
910: microwire.data += ((saveData >> i) & 1) << bit;
911: bit ++;
912: }
913: }
1.1.1.4 root 914:
1.1.1.7 root 915: /* The LMC 1992 address should be 10 xxx xxx xxx */
916: if ((microwire.data & 0x600) != 0x400)
917: return;
918:
919: /* Update the LMC 1992 commands */
920: switch ((microwire.data >> 6) & 0x7) {
921: case 0:
922: /* Mixing command */
1.1.1.8 ! root 923: LOG_TRACE ( TRACE_DMASND, "Microwire new mixing=0x%x\n", microwire.data & 0x3 );
1.1.1.7 root 924: microwire.mixing = microwire.data & 0x3;
925: break;
926: case 1:
927: /* Bass command */
1.1.1.8 ! root 928: LOG_TRACE ( TRACE_DMASND, "Microwire new bass=0x%x\n", microwire.data & 0xf );
1.1.1.7 root 929: microwire.bass = microwire.data & 0xf;
930: DmaSnd_Set_Tone_Level(LMC1992_Bass_Treble_Table[microwire.bass],
931: LMC1992_Bass_Treble_Table[microwire.treble]);
932: break;
933: case 2:
934: /* Treble command */
1.1.1.8 ! root 935: LOG_TRACE ( TRACE_DMASND, "Microwire new trebble=0x%x\n", microwire.data & 0xf );
1.1.1.7 root 936: microwire.treble = microwire.data & 0xf;
937: DmaSnd_Set_Tone_Level(LMC1992_Bass_Treble_Table[microwire.bass],
938: LMC1992_Bass_Treble_Table[microwire.treble]);
939: break;
940: case 3:
941: /* Master volume command */
1.1.1.8 ! root 942: LOG_TRACE ( TRACE_DMASND, "Microwire new master volume=0x%x\n", microwire.data & 0x3f );
1.1.1.7 root 943: microwire.masterVolume = LMC1992_Master_Volume_Table[microwire.data & 0x3f];
1.1.1.8 ! root 944: lmc1992.left_gain = (microwire.leftVolume * (Uint32)microwire.masterVolume) * (1.0/(65536.0*65536.0));
! 945: lmc1992.right_gain = (microwire.rightVolume * (Uint32)microwire.masterVolume) * (1.0/(65536.0*65536.0));
1.1.1.7 root 946: break;
947: case 4:
948: /* Right channel volume */
1.1.1.8 ! root 949: LOG_TRACE ( TRACE_DMASND, "Microwire new right volume=0x%x\n", microwire.data & 0x1f );
1.1.1.7 root 950: microwire.rightVolume = LMC1992_LeftRight_Volume_Table[microwire.data & 0x1f];
1.1.1.8 ! root 951: lmc1992.right_gain = (microwire.rightVolume * (Uint32)microwire.masterVolume) * (1.0/(65536.0*65536.0));
1.1.1.7 root 952: break;
953: case 5:
954: /* Left channel volume */
1.1.1.8 ! root 955: LOG_TRACE ( TRACE_DMASND, "Microwire new left volume=0x%x\n", microwire.data & 0x1f );
1.1.1.7 root 956: microwire.leftVolume = LMC1992_LeftRight_Volume_Table[microwire.data & 0x1f];
1.1.1.8 ! root 957: lmc1992.left_gain = (microwire.leftVolume * (Uint32)microwire.masterVolume) * (1.0/(65536.0*65536.0));
1.1.1.7 root 958: break;
959: default:
960: /* Do nothing */
961: break;
962: }
963: }
964: }
1.1.1.4 root 965:
966: /**
967: * Read word from microwire data register (0xff8922).
968: */
969: void DmaSnd_MicrowireData_ReadWord(void)
970: {
971: /* Shifting is done in DmaSnd_InterruptHandler_Microwire! */
1.1.1.6 root 972: LOG_TRACE(TRACE_DMASND, "Microwire data read: 0x%x\n", IoMem_ReadWord(0xff8922));
1.1 root 973: }
974:
975:
1.1.1.3 root 976: /**
977: * Write word to microwire data register (0xff8922).
978: */
1.1 root 979: void DmaSnd_MicrowireData_WriteWord(void)
980: {
1.1.1.4 root 981: /* Only update, if no shift is in progress */
1.1.1.7 root 982: if (!microwire.mwTransferSteps)
1.1.1.4 root 983: {
1.1.1.7 root 984: microwire.data = IoMem_ReadWord(0xff8922);
1.1.1.4 root 985: /* Start shifting events to simulate a microwire transfer */
1.1.1.7 root 986: microwire.mwTransferSteps = 16;
987: CycInt_AddRelativeInterrupt(8, INT_CPU_CYCLE, INTERRUPT_DMASOUND_MICROWIRE);
1.1.1.4 root 988: }
989:
1.1.1.6 root 990: LOG_TRACE(TRACE_DMASND, "Microwire data write: 0x%x\n", IoMem_ReadWord(0xff8922));
1.1 root 991: }
992:
993:
1.1.1.3 root 994: /**
995: * Read word from microwire mask register (0xff8924).
996: */
1.1 root 997: void DmaSnd_MicrowireMask_ReadWord(void)
998: {
1.1.1.4 root 999: /* Same as with data register, but mask is rotated, not shifted. */
1.1.1.6 root 1000: LOG_TRACE(TRACE_DMASND, "Microwire mask read: 0x%x\n", IoMem_ReadWord(0xff8924));
1.1 root 1001: }
1002:
1003:
1.1.1.3 root 1004: /**
1005: * Write word to microwire mask register (0xff8924).
1006: */
1.1 root 1007: void DmaSnd_MicrowireMask_WriteWord(void)
1008: {
1.1.1.4 root 1009: /* Only update, if no shift is in progress */
1.1.1.7 root 1010: if (!microwire.mwTransferSteps)
1.1.1.4 root 1011: {
1.1.1.7 root 1012: microwire.mask = IoMem_ReadWord(0xff8924);
1.1.1.4 root 1013: }
1014:
1.1.1.6 root 1015: LOG_TRACE(TRACE_DMASND, "Microwire mask write: 0x%x\n", IoMem_ReadWord(0xff8924));
1016: }
1017:
1018:
1.1.1.7 root 1019: /*-------------------Bass / Treble filter ---------------------------*/
1.1.1.6 root 1020:
1.1.1.7 root 1021: /**
1022: * Left voice Filter for Bass/Treble.
1023: */
1024: static float DmaSnd_IIRfilterL(float xn)
1025: {
1026: static float data[2] = { 0.0, 0.0 };
1027: float a, yn;
1.1.1.6 root 1028:
1.1.1.7 root 1029: /* Input coefficients */
1030: /* biquad1 Note: 'a' coefficients are subtracted */
1.1.1.8 ! root 1031: a = lmc1992.left_gain * xn; /* a=g*xn; */
1.1.1.7 root 1032: a -= lmc1992.coef[0] * data[0]; /* a1; wn-1 */
1033: a -= lmc1992.coef[1] * data[1]; /* a2; wn-2 */
1034: /* If coefficient scale */
1035: /* factor = 0.5 then */
1036: /* multiply by 2 */
1037: /* Output coefficients */
1038: yn = lmc1992.coef[2] * a; /* b0; */
1039: yn += lmc1992.coef[3] * data[0]; /* b1; */
1040: yn += lmc1992.coef[4] * data[1]; /* b2; */
1.1.1.6 root 1041:
1.1.1.7 root 1042: data[1] = data[0]; /* wn-1 -> wn-2; */
1043: data[0] = a; /* wn -> wn-1 */
1044: return yn;
1.1.1.6 root 1045: }
1046:
1047:
1048: /**
1.1.1.7 root 1049: * Right voice Filter for Bass/Treble.
1.1.1.6 root 1050: */
1.1.1.7 root 1051: static float DmaSnd_IIRfilterR(float xn)
1.1.1.6 root 1052: {
1.1.1.7 root 1053: static float data[2] = { 0.0, 0.0 };
1054: float a, yn;
1055:
1056: /* Input coefficients */
1057: /* biquad1 Note: 'a' coefficients are subtracted */
1.1.1.8 ! root 1058: a = lmc1992.right_gain * xn; /* a=g*xn; */
1.1.1.7 root 1059: a -= lmc1992.coef[0]*data[0]; /* a1; wn-1 */
1060: a -= lmc1992.coef[1]*data[1]; /* a2; wn-2 */
1061: /* If coefficient scale */
1062: /* factor = 0.5 then */
1063: /* multiply by 2 */
1064: /* Output coefficients */
1065: yn = lmc1992.coef[2]*a; /* b0; */
1066: yn += lmc1992.coef[3]*data[0]; /* b1; */
1067: yn += lmc1992.coef[4]*data[1]; /* b2; */
1068:
1069: data[1] = data[0]; /* wn-1 -> wn-2; */
1070: data[0] = a; /* wn -> wn-1 */
1071: return yn;
1.1.1.6 root 1072: }
1073:
1074: /**
1.1.1.7 root 1075: * LowPass Filter Left
1.1.1.6 root 1076: */
1.1.1.8 ! root 1077: static Sint16 DmaSnd_LowPassFilterLeft(Sint16 in)
1.1.1.6 root 1078: {
1.1.1.8 ! root 1079: static Sint16 lowPassFilter[2] = { 0, 0 };
! 1080: static Sint16 out = 0;
1.1.1.6 root 1081:
1.1.1.8 ! root 1082: if (DmaSnd_LowPass)
! 1083: {
! 1084: out = lowPassFilter[0] + (lowPassFilter[1]<<1) + in;
! 1085: lowPassFilter[0] = lowPassFilter[1];
! 1086: lowPassFilter[1] = in;
1.1.1.6 root 1087:
1.1.1.8 ! root 1088: return out; /* Filter Gain = 4 */
! 1089: }else
! 1090: {
! 1091: return in << 2;
! 1092: }
1.1.1.6 root 1093: }
1094:
1095: /**
1.1.1.7 root 1096: * LowPass Filter Right
1.1.1.6 root 1097: */
1.1.1.8 ! root 1098: static Sint16 DmaSnd_LowPassFilterRight(Sint16 in)
1.1.1.6 root 1099: {
1.1.1.8 ! root 1100: static Sint16 lowPassFilter[2] = { 0, 0 };
! 1101: static Sint16 out = 0;
1.1.1.6 root 1102:
1.1.1.8 ! root 1103: if (DmaSnd_LowPass)
! 1104: {
! 1105: out = lowPassFilter[0] + (lowPassFilter[1]<<1) + in;
! 1106: lowPassFilter[0] = lowPassFilter[1];
! 1107: lowPassFilter[1] = in;
1.1.1.6 root 1108:
1.1.1.8 ! root 1109: return out; /* Filter Gain = 4 */
! 1110: }else
! 1111: {
! 1112: return in << 2;
! 1113: }
1.1.1.6 root 1114: }
1115:
1116: /**
1.1.1.7 root 1117: * Set Bass and Treble tone level
1.1.1.6 root 1118: */
1.1.1.7 root 1119: static void DmaSnd_Set_Tone_Level(int set_bass, int set_treb)
1120: {
1121: /* 13 levels; 0 through 12 correspond with -12dB to 12dB in 2dB steps */
1122: lmc1992.coef[0] = lmc1992.treb_table[set_treb].a1 + lmc1992.bass_table[set_bass].a1;
1123: lmc1992.coef[1] = lmc1992.treb_table[set_treb].a1 * lmc1992.bass_table[set_bass].a1;
1124: lmc1992.coef[2] = lmc1992.treb_table[set_treb].b0 * lmc1992.bass_table[set_bass].b0;
1125: lmc1992.coef[3] = lmc1992.treb_table[set_treb].b0 * lmc1992.bass_table[set_bass].b1 +
1126: lmc1992.treb_table[set_treb].b1 * lmc1992.bass_table[set_bass].b0;
1127: lmc1992.coef[4] = lmc1992.treb_table[set_treb].b1 * lmc1992.bass_table[set_bass].b1;
1.1.1.6 root 1128: }
1129:
1130:
1131: /**
1.1.1.7 root 1132: * Compute the first order bass shelf
1.1.1.6 root 1133: */
1.1.1.7 root 1134: static struct first_order_s *DmaSnd_Bass_Shelf(float g, float fc, float Fs)
1.1.1.6 root 1135: {
1.1.1.7 root 1136: static struct first_order_s bass;
1137: float a1;
1.1.1.6 root 1138:
1.1.1.7 root 1139: /* g, fc, Fs must be positve real numbers > 0.0 */
1140: if (g < 1.0)
1141: bass.a1 = a1 = (tanf(M_PI*fc/Fs) - g ) / (tanf(M_PI*fc/Fs) + g );
1142: else
1143: bass.a1 = a1 = (tanf(M_PI*fc/Fs) - 1.0) / (tanf(M_PI*fc/Fs) + 1.0);
1.1.1.6 root 1144:
1.1.1.7 root 1145: bass.b0 = (1.0 + a1) * (g - 1.0) / 2.0 + 1.0;
1146: bass.b1 = (1.0 + a1) * (g - 1.0) / 2.0 + a1;
1.1.1.6 root 1147:
1.1.1.7 root 1148: return &bass;
1.1.1.6 root 1149: }
1150:
1151:
1152: /**
1.1.1.7 root 1153: * Compute the first order treble shelf
1.1.1.6 root 1154: */
1.1.1.7 root 1155: static struct first_order_s *DmaSnd_Treble_Shelf(float g, float fc, float Fs)
1.1.1.6 root 1156: {
1.1.1.7 root 1157: static struct first_order_s treb;
1158: float a1;
1.1.1.6 root 1159:
1.1.1.7 root 1160: /* g, fc, Fs must be positve real numbers > 0.0 */
1161: if (g < 1.0)
1162: treb.a1 = a1 = (g*tanf(M_PI*fc/Fs) - 1.0) / (g*tanf(M_PI*fc/Fs) + 1.0);
1163: else
1164: treb.a1 = a1 = (tanf(M_PI*fc/Fs) - 1.0) / (tanf(M_PI*fc/Fs) + 1.0);
1.1.1.6 root 1165:
1.1.1.7 root 1166: treb.b0 = 1.0 + (1.0 - a1) * (g - 1.0) / 2.0;
1167: treb.b1 = a1 + (a1 - 1.0) * (g - 1.0) / 2.0;
1168:
1169: return &treb;
1.1.1.6 root 1170: }
1171:
1.1.1.7 root 1172:
1.1.1.6 root 1173: /**
1.1.1.7 root 1174: * Compute the bass and treble tables (nAudioFrequency)
1.1.1.6 root 1175: */
1.1.1.7 root 1176: void DmaSnd_Init_Bass_and_Treble_Tables(void)
1.1.1.6 root 1177: {
1.1.1.7 root 1178: struct first_order_s *bass;
1179: struct first_order_s *treb;
1180:
1.1.1.8 ! root 1181: float dB_adjusted, dB, g, fc_bt, fc_tt, Fs;
1.1.1.7 root 1182: int n;
1183:
1184: fc_bt = 118.2763;
1185: fc_tt = 8438.756;
1186: Fs = (float)nAudioFrequency;
1187:
1188: if ((Fs < 8000.0) || (Fs > 96000.0))
1189: Fs = 44100.0;
1190:
1.1.1.8 ! root 1191: if (fc_tt > 0.5*0.8*Fs)
! 1192: {
! 1193: fc_tt = 0.5*0.8*Fs;
! 1194: dB_adjusted = 2.0 * 0.5*0.8*Fs/fc_tt;
! 1195: }else
! 1196: {
! 1197: dB_adjusted = 2.0;
! 1198: }
! 1199:
! 1200: for (dB = dB_adjusted*(TONE_STEPS-1)/2, n = TONE_STEPS; n--; dB -= dB_adjusted)
! 1201: {
! 1202: g = powf(10.0, dB/20.0); /* 12dB to -12dB */
! 1203:
! 1204: treb = DmaSnd_Treble_Shelf(g, fc_tt, Fs);
! 1205:
! 1206: lmc1992.treb_table[n].a1 = treb->a1;
! 1207: lmc1992.treb_table[n].b0 = treb->b0;
! 1208: lmc1992.treb_table[n].b1 = treb->b1;
! 1209: }
! 1210:
1.1.1.7 root 1211: for (dB = 12.0, n = TONE_STEPS; n--; dB -= 2.0)
1212: {
1213: g = powf(10.0, dB/20.0); /* 12dB to -12dB */
1214:
1215: bass = DmaSnd_Bass_Shelf(g, fc_bt, Fs);
1216:
1217: lmc1992.bass_table[n].a1 = bass->a1;
1218: lmc1992.bass_table[n].b0 = bass->b0;
1219: lmc1992.bass_table[n].b1 = bass->b1;
1220: }
1221:
1222: DmaSnd_Set_Tone_Level(LMC1992_Bass_Treble_Table[microwire.bass & 0xf],
1223: LMC1992_Bass_Treble_Table[microwire.treble & 0xf]);
1.1.1.8 ! root 1224:
! 1225: /* Initialize IIR Filter Gain and use as a Volume Control */
! 1226: lmc1992.left_gain = (microwire.leftVolume * (Uint32)microwire.masterVolume) * (1.0/(65536.0*65536.0));
! 1227: lmc1992.right_gain = (microwire.rightVolume * (Uint32)microwire.masterVolume) * (1.0/(65536.0*65536.0));
! 1228:
! 1229: /* Anti-alias filter is not required when nAudioFrequency == 50066 Hz */
! 1230: if (nAudioFrequency>50000 && nAudioFrequency<50100)
! 1231: DmaSnd_LowPass = false;
! 1232: else
! 1233: DmaSnd_LowPass = true;
1.1 root 1234: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.