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