Annotation of hatari/src/dmaSnd.c, revision 1.1.1.15

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(&microwire, 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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.