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