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

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

unix.superglobalmegacorp.com

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